C backend: major improvements to interop

1. Function.get that allows to convert static Java method
   to a C function pointer
2. Address.ofData that gets address (void*) of Java array data
3. `@Include` annotation to add `#include` to generated C
   when using some method or class
This commit is contained in:
Alexey Andreev 2018-04-24 00:36:25 +03:00
parent 38267980fb
commit fa07100024
22 changed files with 813 additions and 50 deletions

View File

@ -4,14 +4,15 @@
<option name="configuration"> <option name="configuration">
<map> <map>
<entry key="active-configuration" value="LOCAL_FILE:$PRJ_DIR$/checkstyle.xml:TeaVM" /> <entry key="active-configuration" value="LOCAL_FILE:$PRJ_DIR$/checkstyle.xml:TeaVM" />
<entry key="checkstyle-version" value="7.8.1" /> <entry key="checkstyle-version" value="7.8.2" />
<entry key="location-0" value="LOCAL_FILE:$PRJ_DIR$/checkstyle.xml:TeaVM" /> <entry key="copy-libs" value="false" />
<entry key="location-1" value="CLASSPATH:/sun_checks.xml:The default Checkstyle rules" /> <entry key="location-0" value="BUNDLED:(bundled):Sun Checks" />
<entry key="property-0.config_loc" value="." /> <entry key="location-1" value="BUNDLED:(bundled):Google Checks" />
<entry key="location-2" value="LOCAL_FILE:$PRJ_DIR$/checkstyle.xml:TeaVM" />
<entry key="property-2.config_loc" value="." />
<entry key="scan-before-checkin" value="false" /> <entry key="scan-before-checkin" value="false" />
<entry key="scanscope" value="JavaOnlyWithTests" /> <entry key="scanscope" value="JavaOnlyWithTests" />
<entry key="suppress-errors" value="false" /> <entry key="suppress-errors" value="false" />
<entry key="thirdparty-classpath" value="" />
</map> </map>
</option> </option>
</component> </component>

View File

@ -93,15 +93,17 @@ public class Decompiler {
private Deque<Block> stack; private Deque<Block> stack;
private Program program; private Program program;
private boolean friendlyToDebugger; private boolean friendlyToDebugger;
private boolean moveConstants;
public Decompiler(ClassHolderSource classSource, ClassLoader classLoader, Set<MethodReference> asyncMethods, public Decompiler(ClassHolderSource classSource, ClassLoader classLoader, Set<MethodReference> asyncMethods,
Set<MethodReference> asyncFamilyMethods, boolean friendlyToDebugger) { Set<MethodReference> asyncFamilyMethods, boolean friendlyToDebugger, boolean moveConstants) {
this.classSource = classSource; this.classSource = classSource;
this.classLoader = classLoader; this.classLoader = classLoader;
this.asyncMethods = asyncMethods; this.asyncMethods = asyncMethods;
splitMethods.addAll(asyncMethods); splitMethods.addAll(asyncMethods);
splitMethods.addAll(asyncFamilyMethods); splitMethods.addAll(asyncFamilyMethods);
this.friendlyToDebugger = friendlyToDebugger; this.friendlyToDebugger = friendlyToDebugger;
this.moveConstants = moveConstants;
} }
public MethodNodeCache getRegularMethodCache() { public MethodNodeCache getRegularMethodCache() {
@ -283,7 +285,7 @@ public class Decompiler {
methodNode.getVariables().add(variable); methodNode.getVariables().add(variable);
} }
Optimizer optimizer = new Optimizer(); Optimizer optimizer = new Optimizer(moveConstants);
optimizer.optimize(methodNode, method.getProgram(), friendlyToDebugger); optimizer.optimize(methodNode, method.getProgram(), friendlyToDebugger);
methodNode.getModifiers().addAll(method.getModifiers()); methodNode.getModifiers().addAll(method.getModifiers());
@ -347,7 +349,7 @@ public class Decompiler {
node.getVariables().add(variable); node.getVariables().add(variable);
} }
Optimizer optimizer = new Optimizer(); Optimizer optimizer = new Optimizer(moveConstants);
optimizer.optimize(node, splitter, friendlyToDebugger); optimizer.optimize(node, splitter, friendlyToDebugger);
node.getModifiers().addAll(method.getModifiers()); node.getModifiers().addAll(method.getModifiers());

View File

@ -18,9 +18,7 @@ package org.teavm.ast.optimization;
import java.util.BitSet; import java.util.BitSet;
import org.teavm.ast.AsyncMethodNode; import org.teavm.ast.AsyncMethodNode;
import org.teavm.ast.AsyncMethodPart; import org.teavm.ast.AsyncMethodPart;
import org.teavm.ast.MethodNode;
import org.teavm.ast.RegularMethodNode; import org.teavm.ast.RegularMethodNode;
import org.teavm.ast.VariableNode;
import org.teavm.common.Graph; import org.teavm.common.Graph;
import org.teavm.model.BasicBlock; import org.teavm.model.BasicBlock;
import org.teavm.model.Instruction; import org.teavm.model.Instruction;
@ -33,6 +31,12 @@ import org.teavm.model.util.ProgramUtils;
import org.teavm.model.util.UsageExtractor; import org.teavm.model.util.UsageExtractor;
public class Optimizer { public class Optimizer {
private boolean moveConstants;
public Optimizer(boolean moveConstants) {
this.moveConstants = moveConstants;
}
public void optimize(RegularMethodNode method, Program program, boolean friendlyToDebugger) { public void optimize(RegularMethodNode method, Program program, boolean friendlyToDebugger) {
ReadWriteStatsBuilder stats = new ReadWriteStatsBuilder(method.getVariables().size()); ReadWriteStatsBuilder stats = new ReadWriteStatsBuilder(method.getVariables().size());
stats.analyze(program); stats.analyze(program);
@ -40,7 +44,7 @@ public class Optimizer {
BreakEliminator breakEliminator = new BreakEliminator(); BreakEliminator breakEliminator = new BreakEliminator();
breakEliminator.eliminate(method.getBody()); breakEliminator.eliminate(method.getBody());
OptimizingVisitor optimizer = new OptimizingVisitor(preservedVars, stats.writes, stats.reads, OptimizingVisitor optimizer = new OptimizingVisitor(preservedVars, stats.writes, stats.reads,
friendlyToDebugger); moveConstants ? stats.constants : new Object[stats.constants.length], friendlyToDebugger);
method.getBody().acceptVisitor(optimizer); method.getBody().acceptVisitor(optimizer);
method.setBody(optimizer.resultStmt); method.setBody(optimizer.resultStmt);
int paramCount = method.getReference().parameterCount(); int paramCount = method.getReference().parameterCount();
@ -74,7 +78,7 @@ public class Optimizer {
breakEliminator.eliminate(part.getStatement()); breakEliminator.eliminate(part.getStatement());
findEscapingLiveVars(liveness, cfg, splitter, i, preservedVars); findEscapingLiveVars(liveness, cfg, splitter, i, preservedVars);
OptimizingVisitor optimizer = new OptimizingVisitor(preservedVars, stats.writes, stats.reads, OptimizingVisitor optimizer = new OptimizingVisitor(preservedVars, stats.writes, stats.reads,
friendlyToDebugger); moveConstants ? stats.constants : new Object[stats.constants.length], friendlyToDebugger);
part.getStatement().acceptVisitor(optimizer); part.getStatement().acceptVisitor(optimizer);
part.setStatement(optimizer.resultStmt); part.setStatement(optimizer.resultStmt);
} }
@ -97,14 +101,6 @@ public class Optimizer {
} }
} }
private void preserveDebuggableVars(boolean[] variablesToPreserve, MethodNode methodNode) {
for (VariableNode varNode : methodNode.getVariables()) {
if (varNode.getName() != null) {
variablesToPreserve[varNode.getIndex()] = true;
}
}
}
private void findEscapingLiveVars(LivenessAnalyzer liveness, Graph cfg, AsyncProgramSplitter splitter, private void findEscapingLiveVars(LivenessAnalyzer liveness, Graph cfg, AsyncProgramSplitter splitter,
int partIndex, boolean[] output) { int partIndex, boolean[] output) {
Program originalProgram = splitter.getOriginalProgram(); Program originalProgram = splitter.getOriginalProgram();

View File

@ -69,17 +69,19 @@ class OptimizingVisitor implements StatementVisitor, ExprVisitor {
private final boolean[] preservedVars; private final boolean[] preservedVars;
private final int[] writeFrequencies; private final int[] writeFrequencies;
private final int[] readFrequencies; private final int[] readFrequencies;
private final Object[] constants;
private List<Statement> resultSequence; private List<Statement> resultSequence;
private boolean friendlyToDebugger; private boolean friendlyToDebugger;
private TextLocation currentLocation; private TextLocation currentLocation;
private Deque<TextLocation> locationStack = new LinkedList<>(); private Deque<TextLocation> locationStack = new LinkedList<>();
private Deque<TextLocation> notNullLocationStack = new ArrayDeque<>(); private Deque<TextLocation> notNullLocationStack = new ArrayDeque<>();
OptimizingVisitor(boolean[] preservedVars, int[] writeFrequencies, int[] readFrequencies, OptimizingVisitor(boolean[] preservedVars, int[] writeFrequencies, int[] readFrequencies, Object[] constants,
boolean friendlyToDebugger) { boolean friendlyToDebugger) {
this.preservedVars = preservedVars; this.preservedVars = preservedVars;
this.writeFrequencies = writeFrequencies; this.writeFrequencies = writeFrequencies;
this.readFrequencies = readFrequencies; this.readFrequencies = readFrequencies;
this.constants = constants;
this.friendlyToDebugger = friendlyToDebugger; this.friendlyToDebugger = friendlyToDebugger;
} }
@ -273,6 +275,15 @@ class OptimizingVisitor implements StatementVisitor, ExprVisitor {
if (writeFrequencies[index] != 1) { if (writeFrequencies[index] != 1) {
return; return;
} }
if (constants[index] != null) {
ConstantExpr constantExpr = new ConstantExpr();
constantExpr.setValue(constants[index]);
constantExpr.setLocation(expr.getLocation());
resultExpr = constantExpr;
return;
}
if (readFrequencies[index] != 1 || preservedVars[index]) { if (readFrequencies[index] != 1 || preservedVars[index]) {
return; return;
} }
@ -542,6 +553,12 @@ class OptimizingVisitor implements StatementVisitor, ExprVisitor {
if (!(statement.getLeftValue() instanceof VariableExpr)) { if (!(statement.getLeftValue() instanceof VariableExpr)) {
statement.getLeftValue().acceptVisitor(this); statement.getLeftValue().acceptVisitor(this);
left = resultExpr; left = resultExpr;
} else {
int varIndex = ((VariableExpr) statement.getLeftValue()).getIndex();
if (writeFrequencies[varIndex] == 1 && constants[varIndex] != null) {
resultStmt = new SequentialStatement();
return;
}
} }
statement.setLeftValue(left); statement.setLeftValue(left);
statement.setRightValue(right); statement.setRightValue(right);

View File

@ -20,6 +20,8 @@ import org.teavm.common.Graph;
import org.teavm.common.GraphUtils; import org.teavm.common.GraphUtils;
import org.teavm.common.IntegerStack; import org.teavm.common.IntegerStack;
import org.teavm.model.*; import org.teavm.model.*;
import org.teavm.model.instructions.ClassConstantInstruction;
import org.teavm.model.instructions.StringConstantInstruction;
import org.teavm.model.util.DefinitionExtractor; import org.teavm.model.util.DefinitionExtractor;
import org.teavm.model.util.ProgramUtils; import org.teavm.model.util.ProgramUtils;
import org.teavm.model.util.UsageExtractor; import org.teavm.model.util.UsageExtractor;
@ -27,6 +29,7 @@ import org.teavm.model.util.UsageExtractor;
class ReadWriteStatsBuilder { class ReadWriteStatsBuilder {
public int[] reads; public int[] reads;
public int[] writes; public int[] writes;
public Object[] constants;
private ReadWriteStatsBuilder() { private ReadWriteStatsBuilder() {
} }
@ -34,6 +37,7 @@ class ReadWriteStatsBuilder {
public ReadWriteStatsBuilder(int variableCount) { public ReadWriteStatsBuilder(int variableCount) {
reads = new int[variableCount]; reads = new int[variableCount];
writes = new int[variableCount]; writes = new int[variableCount];
constants = new Object[variableCount];
} }
public ReadWriteStatsBuilder copy() { public ReadWriteStatsBuilder copy() {
@ -68,6 +72,14 @@ class ReadWriteStatsBuilder {
for (Variable var : useExtractor.getUsedVariables()) { for (Variable var : useExtractor.getUsedVariables()) {
reads[var.getIndex()]++; reads[var.getIndex()]++;
} }
if (insn instanceof StringConstantInstruction) {
StringConstantInstruction stringConstant = (StringConstantInstruction) insn;
constants[stringConstant.getReceiver().getIndex()] = stringConstant.getConstant();
} else if (insn instanceof ClassConstantInstruction) {
ClassConstantInstruction classConstant = (ClassConstantInstruction) insn;
constants[classConstant.getReceiver().getIndex()] = classConstant.getConstant();
}
} }
for (Phi phi : block.getPhis()) { for (Phi phi : block.getPhis()) {

View File

@ -83,6 +83,7 @@ import org.teavm.model.instructions.InvokeInstruction;
import org.teavm.model.lowlevel.Characteristics; import org.teavm.model.lowlevel.Characteristics;
import org.teavm.model.lowlevel.ClassInitializerEliminator; import org.teavm.model.lowlevel.ClassInitializerEliminator;
import org.teavm.model.lowlevel.ClassInitializerTransformer; import org.teavm.model.lowlevel.ClassInitializerTransformer;
import org.teavm.model.lowlevel.ExportDependencyListener;
import org.teavm.model.lowlevel.NullCheckInsertion; import org.teavm.model.lowlevel.NullCheckInsertion;
import org.teavm.model.lowlevel.NullCheckTransformation; import org.teavm.model.lowlevel.NullCheckTransformation;
import org.teavm.model.lowlevel.ShadowStackTransformer; import org.teavm.model.lowlevel.ShadowStackTransformer;
@ -107,6 +108,7 @@ public class CTarget implements TeaVMTarget {
private ShadowStackTransformer shadowStackTransformer; private ShadowStackTransformer shadowStackTransformer;
private NullCheckInsertion nullCheckInsertion; private NullCheckInsertion nullCheckInsertion;
private NullCheckTransformation nullCheckTransformation; private NullCheckTransformation nullCheckTransformation;
private ExportDependencyListener exportDependencyListener = new ExportDependencyListener();
private int minHeapSize = 32 * 1024 * 1024; private int minHeapSize = 32 * 1024 * 1024;
public void setMinHeapSize(int minHeapSize) { public void setMinHeapSize(int minHeapSize) {
@ -123,7 +125,7 @@ public class CTarget implements TeaVMTarget {
@Override @Override
public List<DependencyListener> getDependencyListeners() { public List<DependencyListener> getDependencyListeners() {
return Collections.singletonList(new CDependencyListener()); return Arrays.asList(new CDependencyListener(), exportDependencyListener);
} }
@Override @Override
@ -204,7 +206,7 @@ public class CTarget implements TeaVMTarget {
StringPool stringPool = new StringPool(); StringPool stringPool = new StringPool();
Decompiler decompiler = new Decompiler(classes, controller.getClassLoader(), new HashSet<>(), Decompiler decompiler = new Decompiler(classes, controller.getClassLoader(), new HashSet<>(),
new HashSet<>(), false); new HashSet<>(), false, true);
Characteristics characteristics = new Characteristics(controller.getUnprocessedClassSource()); Characteristics characteristics = new Characteristics(controller.getUnprocessedClassSource());
NameProvider nameProvider = new NameProvider(controller.getUnprocessedClassSource()); NameProvider nameProvider = new NameProvider(controller.getUnprocessedClassSource());
@ -221,7 +223,7 @@ public class CTarget implements TeaVMTarget {
intrinsics.add(new GCIntrinsic()); intrinsics.add(new GCIntrinsic());
intrinsics.add(new MutatorIntrinsic()); intrinsics.add(new MutatorIntrinsic());
intrinsics.add(new ExceptionHandlingIntrinsic()); intrinsics.add(new ExceptionHandlingIntrinsic());
intrinsics.add(new FunctionIntrinsic(characteristics)); intrinsics.add(new FunctionIntrinsic(characteristics, exportDependencyListener.getResolvedMethods()));
List<Generator> generators = new ArrayList<>(); List<Generator> generators = new ArrayList<>();
generators.add(new ArrayGenerator()); generators.add(new ArrayGenerator());

View File

@ -62,6 +62,8 @@ public class ClassGenerator {
private List<FieldReference[]> layouts = new ArrayList<>(); private List<FieldReference[]> layouts = new ArrayList<>();
private int currentLayoutIndex; private int currentLayoutIndex;
private Set<ValueType> types = new LinkedHashSet<>(); private Set<ValueType> types = new LinkedHashSet<>();
private Set<String> includes = new LinkedHashSet<>();
private CodeWriter includesWriter;
private CodeWriter forwardDeclarationsWriter; private CodeWriter forwardDeclarationsWriter;
private CodeWriter structuresWriter; private CodeWriter structuresWriter;
private CodeWriter vtableStructuresWriter; private CodeWriter vtableStructuresWriter;
@ -81,6 +83,7 @@ public class ClassGenerator {
this.tagRegistry = tagRegistry; this.tagRegistry = tagRegistry;
this.decompiler = decompiler; this.decompiler = decompiler;
includesWriter = writer.fragment();
forwardDeclarationsWriter = writer.fragment(); forwardDeclarationsWriter = writer.fragment();
structuresWriter = writer.fragment(); structuresWriter = writer.fragment();
vtableStructuresWriter = writer.fragment(); vtableStructuresWriter = writer.fragment();
@ -93,7 +96,7 @@ public class ClassGenerator {
callSiteWriter = writer.fragment(); callSiteWriter = writer.fragment();
codeWriter = writer.fragment(); codeWriter = writer.fragment();
codeGenerator = new CodeGenerator(context, codeWriter); codeGenerator = new CodeGenerator(context, codeWriter, includes);
} }
public void generateClass(ClassHolder cls) { public void generateClass(ClassHolder cls) {
@ -113,6 +116,10 @@ public class ClassGenerator {
generateLayoutArray(); generateLayoutArray();
new StringPoolGenerator(stringPoolWriter, context.getNames()).generate(context.getStringPool().getStrings()); new StringPoolGenerator(stringPoolWriter, context.getNames()).generate(context.getStringPool().getStrings());
for (String include : includes) {
includesWriter.println("#include " + include);
}
} }
public Set<ValueType> getTypes() { public Set<ValueType> getTypes() {

View File

@ -16,6 +16,7 @@
package org.teavm.backend.c.generate; package org.teavm.backend.c.generate;
import java.util.List; import java.util.List;
import java.util.Set;
import org.teavm.ast.ArrayType; import org.teavm.ast.ArrayType;
import org.teavm.ast.AssignmentStatement; import org.teavm.ast.AssignmentStatement;
import org.teavm.ast.BinaryExpr; import org.teavm.ast.BinaryExpr;
@ -57,6 +58,11 @@ import org.teavm.backend.c.intrinsic.Intrinsic;
import org.teavm.backend.c.intrinsic.IntrinsicContext; import org.teavm.backend.c.intrinsic.IntrinsicContext;
import org.teavm.diagnostics.Diagnostics; import org.teavm.diagnostics.Diagnostics;
import org.teavm.interop.Address; import org.teavm.interop.Address;
import org.teavm.interop.c.Include;
import org.teavm.model.AnnotationContainerReader;
import org.teavm.model.AnnotationReader;
import org.teavm.model.AnnotationValue;
import org.teavm.model.ClassReader;
import org.teavm.model.MethodReader; import org.teavm.model.MethodReader;
import org.teavm.model.MethodReference; import org.teavm.model.MethodReference;
import org.teavm.model.ValueType; import org.teavm.model.ValueType;
@ -80,11 +86,13 @@ public class CodeGenerationVisitor implements ExprVisitor, StatementVisitor {
private int temporaryReceiverLevel; private int temporaryReceiverLevel;
private int maxTemporaryReceiverLevel; private int maxTemporaryReceiverLevel;
private MethodReference callingMethod; private MethodReference callingMethod;
private Set<? super String> includes;
public CodeGenerationVisitor(GenerationContext context, CodeWriter writer) { public CodeGenerationVisitor(GenerationContext context, CodeWriter writer, Set<? super String> includes) {
this.context = context; this.context = context;
this.writer = writer; this.writer = writer;
this.names = context.getNames(); this.names = context.getNames();
this.includes = includes;
} }
public int getTemporaryReceivers() { public int getTemporaryReceivers() {
@ -371,6 +379,15 @@ public class CodeGenerationVisitor implements ExprVisitor, StatementVisitor {
@Override @Override
public void visit(InvocationExpr expr) { public void visit(InvocationExpr expr) {
ClassReader cls = context.getClassSource().get(expr.getMethod().getClassName());
if (cls != null) {
processInclude(cls.getAnnotations());
MethodReader method = cls.getMethod(expr.getMethod().getDescriptor());
if (method != null) {
processInclude(method.getAnnotations());
}
}
Intrinsic intrinsic = context.getIntrinsic(expr.getMethod()); Intrinsic intrinsic = context.getIntrinsic(expr.getMethod());
if (intrinsic != null) { if (intrinsic != null) {
intrinsic.apply(intrinsicContext, expr); intrinsic.apply(intrinsicContext, expr);
@ -439,6 +456,23 @@ public class CodeGenerationVisitor implements ExprVisitor, StatementVisitor {
} }
} }
private void processInclude(AnnotationContainerReader container) {
AnnotationReader annot = container.get(Include.class.getName());
if (annot == null) {
return;
}
String includeString = annot.getValue("value").getString();
AnnotationValue systemValue = annot.getValue("isSystem");
if (systemValue == null || systemValue.getBoolean()) {
includeString = "<" + includeString + ">";
} else {
includeString = "\"" + includeString + "\"";
}
includes.add(includeString);
}
@Override @Override
public void visit(QualificationExpr expr) { public void visit(QualificationExpr expr) {
if (expr.getQualified() != null) { if (expr.getQualified() != null) {

View File

@ -15,6 +15,7 @@
*/ */
package org.teavm.backend.c.generate; package org.teavm.backend.c.generate;
import java.util.Set;
import org.teavm.ast.RegularMethodNode; import org.teavm.ast.RegularMethodNode;
import org.teavm.ast.VariableNode; import org.teavm.ast.VariableNode;
import org.teavm.model.ElementModifier; import org.teavm.model.ElementModifier;
@ -26,11 +27,13 @@ public class CodeGenerator {
private CodeWriter writer; private CodeWriter writer;
private CodeWriter localsWriter; private CodeWriter localsWriter;
private NameProvider names; private NameProvider names;
private Set<? super String> includes;
public CodeGenerator(GenerationContext context, CodeWriter writer) { public CodeGenerator(GenerationContext context, CodeWriter writer, Set<? super String> includes) {
this.context = context; this.context = context;
this.writer = writer; this.writer = writer;
this.names = context.getNames(); this.names = context.getNames();
this.includes = includes;
} }
public void generateMethod(RegularMethodNode methodNode) { public void generateMethod(RegularMethodNode methodNode) {
@ -41,7 +44,7 @@ public class CodeGenerator {
localsWriter = writer.fragment(); localsWriter = writer.fragment();
CodeGenerationVisitor visitor = new CodeGenerationVisitor(context, writer); CodeGenerationVisitor visitor = new CodeGenerationVisitor(context, writer, includes);
visitor.setCallingMethod(methodNode.getReference()); visitor.setCallingMethod(methodNode.getReference());
methodNode.getBody().acceptVisitor(visitor); methodNode.getBody().acceptVisitor(visitor);

View File

@ -16,8 +16,10 @@
package org.teavm.backend.c.intrinsic; package org.teavm.backend.c.intrinsic;
import org.teavm.ast.InvocationExpr; import org.teavm.ast.InvocationExpr;
import org.teavm.backend.c.util.ConstantUtil;
import org.teavm.interop.Address; import org.teavm.interop.Address;
import org.teavm.model.MethodReference; import org.teavm.model.MethodReference;
import org.teavm.model.ValueType;
public class AddressIntrinsic implements Intrinsic { public class AddressIntrinsic implements Intrinsic {
@Override @Override
@ -56,6 +58,8 @@ public class AddressIntrinsic implements Intrinsic {
case "isLessThan": case "isLessThan":
case "align": case "align":
case "sizeOf": case "sizeOf":
case "ofData":
return true; return true;
default: default:
return false; return false;
@ -165,7 +169,7 @@ public class AddressIntrinsic implements Intrinsic {
context.writer().print("ADDRESS_ADD("); context.writer().print("ADDRESS_ADD(");
context.emit(invocation.getArguments().get(0)); context.emit(invocation.getArguments().get(0));
context.writer().print(", "); context.writer().print(", ");
String className = StructureIntrinsic.getClassLiteral(context, invocation, String className = ConstantUtil.getClassLiteral(context, invocation,
invocation.getArguments().get(1)); invocation.getArguments().get(1));
context.emit(invocation.getArguments().get(2)); context.emit(invocation.getArguments().get(2));
context.writer().print(" * sizeof(") context.writer().print(" * sizeof(")
@ -191,6 +195,14 @@ public class AddressIntrinsic implements Intrinsic {
case "sizeOf": case "sizeOf":
context.writer().print("sizeof(void*)"); context.writer().print("sizeof(void*)");
break; break;
case "ofData": {
ValueType.Array type = (ValueType.Array) invocation.getMethod().parameterType(0);
context.writer().print("((char*) ");
context.emit(invocation.getArguments().get(0));
context.writer().print(" + sizeof(JavaArray) + (intptr_t) ALIGN(NULL, "
+ sizeOf(type.getItemType()) + "))");
break;
}
} }
} }
@ -207,4 +219,22 @@ public class AddressIntrinsic implements Intrinsic {
context.emit(invocation.getArguments().get(1)); context.emit(invocation.getArguments().get(1));
context.writer().print(")"); context.writer().print(")");
} }
private int sizeOf(ValueType type) {
switch (((ValueType.Primitive) type).getKind()) {
case BYTE:
return 1;
case SHORT:
return 2;
case INTEGER:
case FLOAT:
return 4;
case LONG:
case DOUBLE:
return 8;
default:
break;
}
return 0;
}
} }

View File

@ -15,25 +15,41 @@
*/ */
package org.teavm.backend.c.intrinsic; package org.teavm.backend.c.intrinsic;
import java.util.Map;
import org.teavm.ast.ConstantExpr;
import org.teavm.ast.InvocationExpr; import org.teavm.ast.InvocationExpr;
import org.teavm.interop.Function;
import org.teavm.model.MethodReference; import org.teavm.model.MethodReference;
import org.teavm.model.ValueType;
import org.teavm.model.lowlevel.Characteristics; import org.teavm.model.lowlevel.Characteristics;
import org.teavm.model.lowlevel.ExportedMethodKey;
public class FunctionIntrinsic implements Intrinsic { public class FunctionIntrinsic implements Intrinsic {
private Characteristics characteristics; private Characteristics characteristics;
private Map<? extends ExportedMethodKey, ? extends MethodReference> resolvedMethods;
public FunctionIntrinsic(Characteristics characteristics) { public FunctionIntrinsic(Characteristics characteristics,
Map<? extends ExportedMethodKey, ? extends MethodReference> resolvedMethods) {
this.characteristics = characteristics; this.characteristics = characteristics;
this.resolvedMethods = resolvedMethods;
} }
@Override @Override
public boolean canHandle(MethodReference method) { public boolean canHandle(MethodReference method) {
if (method.getClassName().equals(Function.class.getName()) && method.getName().equals("get")) {
return true;
}
return characteristics.isFunction(method.getClassName()); return characteristics.isFunction(method.getClassName());
} }
@Override @Override
public void apply(IntrinsicContext context, InvocationExpr invocation) { public void apply(IntrinsicContext context, InvocationExpr invocation) {
MethodReference method = invocation.getMethod(); MethodReference method = invocation.getMethod();
if (method.getClassName().equals(Function.class.getName())) {
generateGetFunction(context, invocation);
return;
}
context.writer().print("(((").printType(method.getReturnType()).print(" (*)("); context.writer().print("(((").printType(method.getReturnType()).print(" (*)(");
if (method.parameterCount() > 0) { if (method.parameterCount() > 0) {
context.writer().printType(method.parameterType(0)); context.writer().printType(method.parameterType(0));
@ -54,4 +70,32 @@ public class FunctionIntrinsic implements Intrinsic {
} }
context.writer().print("))"); context.writer().print("))");
} }
private void generateGetFunction(IntrinsicContext context, InvocationExpr invocation) {
if (!(invocation.getArguments().get(0) instanceof ConstantExpr)
|| !(invocation.getArguments().get(1) instanceof ConstantExpr)
|| !(invocation.getArguments().get(2) instanceof ConstantExpr)) {
return;
}
Object functionClassValue = ((ConstantExpr) invocation.getArguments().get(0)).getValue();
Object classValue = ((ConstantExpr) invocation.getArguments().get(1)).getValue();
Object methodValue = ((ConstantExpr) invocation.getArguments().get(2)).getValue();
if (!(functionClassValue instanceof ValueType.Object)
|| !(classValue instanceof ValueType.Object)
|| !(methodValue instanceof String)) {
return;
}
String functionClassName = ((ValueType.Object) functionClassValue).getClassName();
String className = ((ValueType.Object) classValue).getClassName();
String methodName = (String) methodValue;
ExportedMethodKey key = new ExportedMethodKey(functionClassName, className, methodName);
MethodReference method = resolvedMethods.get(key);
if (method == null) {
return;
}
context.writer().print("&").print(context.names().forMethod(method));
}
} }

View File

@ -15,11 +15,9 @@
*/ */
package org.teavm.backend.c.intrinsic; package org.teavm.backend.c.intrinsic;
import org.teavm.ast.ConstantExpr;
import org.teavm.ast.Expr;
import org.teavm.ast.InvocationExpr; import org.teavm.ast.InvocationExpr;
import org.teavm.backend.c.util.ConstantUtil;
import org.teavm.interop.Structure; import org.teavm.interop.Structure;
import org.teavm.model.CallLocation;
import org.teavm.model.MethodReference; import org.teavm.model.MethodReference;
import org.teavm.model.ValueType; import org.teavm.model.ValueType;
import org.teavm.model.lowlevel.Characteristics; import org.teavm.model.lowlevel.Characteristics;
@ -62,14 +60,14 @@ public class StructureIntrinsic implements Intrinsic {
context.emit(invocation.getArguments().get(0)); context.emit(invocation.getArguments().get(0));
break; break;
case "sizeOf": { case "sizeOf": {
String className = getClassLiteral(context, invocation, invocation.getArguments().get(0)); String className = ConstantUtil.getClassLiteral(context, invocation, invocation.getArguments().get(0));
if (className != null) { if (className != null) {
context.writer().print("sizeof(").print(context.names().forClass(className)).print(")"); context.writer().print("sizeof(").print(context.names().forClass(className)).print(")");
} }
break; break;
} }
case "add": { case "add": {
String className = getClassLiteral(context, invocation, invocation.getArguments().get(0)); String className = ConstantUtil.getClassLiteral(context, invocation, invocation.getArguments().get(0));
if (className != null) { if (className != null) {
context.writer().print("STRUCTURE_ADD(").print(context.names().forClass(className)).print(", "); context.writer().print("STRUCTURE_ADD(").print(context.names().forClass(className)).print(", ");
context.emit(invocation.getArguments().get(1)); context.emit(invocation.getArguments().get(1));
@ -81,17 +79,4 @@ public class StructureIntrinsic implements Intrinsic {
} }
} }
} }
static String getClassLiteral(IntrinsicContext context, InvocationExpr invocation, Expr expr) {
if (expr instanceof ConstantExpr) {
Object cst = ((ConstantExpr) expr).getValue();
if (cst instanceof ValueType.Object) {
return ((ValueType.Object) cst).getClassName();
}
}
context.getDiagnotics().error(
new CallLocation(context.getCallingMethod(), invocation.getLocation()),
"This method should take class literal");
return "";
}
} }

View File

@ -0,0 +1,54 @@
/*
* 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.util;
import org.teavm.ast.ConstantExpr;
import org.teavm.ast.Expr;
import org.teavm.ast.InvocationExpr;
import org.teavm.backend.c.intrinsic.IntrinsicContext;
import org.teavm.model.CallLocation;
import org.teavm.model.ValueType;
public final class ConstantUtil {
private ConstantUtil() {
}
public static String getClassLiteral(IntrinsicContext context, InvocationExpr invocation, Expr expr) {
if (expr instanceof ConstantExpr) {
Object cst = ((ConstantExpr) expr).getValue();
if (cst instanceof ValueType.Object) {
return ((ValueType.Object) cst).getClassName();
}
}
context.getDiagnotics().error(
new CallLocation(context.getCallingMethod(), invocation.getLocation()),
"This method should take class literal");
return "java.lang.Object";
}
public static String getStringLiteral(IntrinsicContext context, InvocationExpr invocation, Expr expr) {
if (expr instanceof ConstantExpr) {
Object cst = ((ConstantExpr) expr).getValue();
if (cst instanceof String) {
return (String) cst;
}
}
context.getDiagnotics().error(
new CallLocation(context.getCallingMethod(), invocation.getLocation()),
"This method should take string literal");
return "";
}
}

View File

@ -313,7 +313,7 @@ public class JavaScriptTarget implements TeaVMTarget, TeaVMJavaScriptHost {
asyncFamilyMethods.addAll(asyncFinder.getAsyncFamilyMethods()); asyncFamilyMethods.addAll(asyncFinder.getAsyncFamilyMethods());
Decompiler decompiler = new Decompiler(classes, controller.getClassLoader(), asyncMethods, asyncFamilyMethods, Decompiler decompiler = new Decompiler(classes, controller.getClassLoader(), asyncMethods, asyncFamilyMethods,
controller.isFriendlyToDebugger()); controller.isFriendlyToDebugger(), false);
decompiler.setRegularMethodCache(controller.isIncremental() ? astCache : null); decompiler.setRegularMethodCache(controller.isIncremental() ? astCache : null);
for (Map.Entry<MethodReference, Generator> entry : methodGenerators.entrySet()) { for (Map.Entry<MethodReference, Generator> entry : methodGenerators.entrySet()) {

View File

@ -0,0 +1,146 @@
/*
* 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.wasm;
import java.util.HashSet;
import java.util.Set;
import org.teavm.interop.Address;
import org.teavm.interop.Function;
import org.teavm.interop.Import;
import org.teavm.interop.Structure;
import org.teavm.interop.c.Include;
public final class GtkExample {
private static Set<Object> pinnedObjects = new HashSet<>();
private GtkExample() {
}
public static void main(String[] args) {
Gtk.init(0, null);
Gtk.Window window = Gtk.windowNew(Gtk.WINDOW_TOPLEVEL);
CString deleteEventString = new CString("delete-event");
CString destroyString = new CString("destroy");
GLib.signalConnect(window, deleteEventString.data,
Function.get(GLib.Callback.class, GtkExample.class, "windowDeleted"), null);
GLib.signalConnect(window, destroyString.data,
Function.get(GLib.Callback.class, GtkExample.class, "destroy"), null);
deleteEventString.dispose();
destroyString.dispose();
Gtk.setBorderWidth(window, 10);
CString helloWorld = new CString("Hello, world");
Gtk.Button button = Gtk.buttonNewWithLabel(helloWorld.data);
helloWorld.dispose();
CString clickedString = new CString("clicked");
GLib.signalConnect(button, clickedString.data,
Function.get(GLib.Callback.class, GtkExample.class, "hello"), null);
Gtk.add(window, button);
Gtk.show(button);
Gtk.show(window);
Gtk.main();
}
private static void hello(Gtk.Widget widget, Address data) {
System.out.println("Hello, world!");
}
private static boolean windowDeleted(Gtk.Widget widget, Address event, Address data) {
System.out.println("System event occurred");
return false;
}
private static void destroy(Gtk.Widget widget, Address data) {
Gtk.mainQuit();
}
@Include("gtk/gtk.h")
static class Gtk {
static class Widget extends GLib.GObject {
}
static class Window extends Container {
}
static class Container extends Widget {
}
static class Button extends Widget {
}
@Import(name = "gtk_init")
static native void init(int argc, Address argv);
@Import(name = "gtk_window_new")
static native Window windowNew(int type);
@Import(name = "gtk_widget_show")
static native void show(Widget widget);
@Import(name = "gtk_main")
static native void main();
@Import(name = "gtk_main_quit")
static native void mainQuit();
@Import(name = "gtk_container_set_border_width")
static native void setBorderWidth(Container container, int width);
@Import(name = "gtk_button_new_with_label")
static native Button buttonNewWithLabel(Address label);
@Import(name = "gtk_container_add")
static native void add(Container container, Widget widget);
static final int WINDOW_TOPLEVEL = 0;
static final int WINDOW_POPUP = 1;
}
static class GLib {
static class GObject extends Structure {
}
@Import(name = "g_signal_connect")
static native long signalConnect(GObject instance, Address signalName, Callback callback, Address data);
static abstract class Callback extends Function {
abstract void call();
}
}
static class CString {
final Address data;
private final byte[] array;
CString(String str) {
array = new byte[str.length() + 1];
for (int i = 0; i < str.length(); ++i) {
array[i] = (byte) str.charAt(i);
}
pinnedObjects.add(array);
data = Address.ofData(array);
}
void dispose() {
pinnedObjects.remove(array);
}
}
}

View File

@ -301,7 +301,7 @@ public class WasmTarget implements TeaVMTarget, TeaVMWasmHost {
controller.getUnprocessedClassSource(), vtableProvider, tagRegistry, binaryWriter); controller.getUnprocessedClassSource(), vtableProvider, tagRegistry, binaryWriter);
Decompiler decompiler = new Decompiler(classes, controller.getClassLoader(), new HashSet<>(), Decompiler decompiler = new Decompiler(classes, controller.getClassLoader(), new HashSet<>(),
new HashSet<>(), false); new HashSet<>(), false, true);
WasmStringPool stringPool = classGenerator.getStringPool(); WasmStringPool stringPool = classGenerator.getStringPool();
WasmGenerationContext context = new WasmGenerationContext(classes, module, controller.getDiagnostics(), WasmGenerationContext context = new WasmGenerationContext(classes, module, controller.getDiagnostics(),
vtableProvider, tagRegistry, stringPool); vtableProvider, tagRegistry, stringPool);

View File

@ -0,0 +1,311 @@
/*
* 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.model.lowlevel;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import org.teavm.common.DisjointSet;
import org.teavm.dependency.AbstractDependencyListener;
import org.teavm.dependency.DependencyAgent;
import org.teavm.dependency.MethodDependency;
import org.teavm.diagnostics.Diagnostics;
import org.teavm.interop.Function;
import org.teavm.model.BasicBlockReader;
import org.teavm.model.CallLocation;
import org.teavm.model.ClassReader;
import org.teavm.model.ClassReaderSource;
import org.teavm.model.ElementModifier;
import org.teavm.model.MethodReader;
import org.teavm.model.MethodReference;
import org.teavm.model.ProgramReader;
import org.teavm.model.TextLocation;
import org.teavm.model.ValueType;
import org.teavm.model.VariableReader;
import org.teavm.model.instructions.AbstractInstructionReader;
import org.teavm.model.instructions.InvocationType;
public class ExportDependencyListener extends AbstractDependencyListener {
private Set<MethodReference> exportedMethods = new LinkedHashSet<>();
private Set<? extends MethodReference> readonlyExportedMethods = Collections.unmodifiableSet(exportedMethods);
private Map<ExportedMethodKey, MethodReference> resolvedMethods = new HashMap<>();
private Map<? extends ExportedMethodKey, ? extends MethodReference> readonlyResolvedMethods =
Collections.unmodifiableMap(resolvedMethods);
private Characteristics characteristics;
@Override
public void started(DependencyAgent agent) {
characteristics = new Characteristics(agent.getClassSource());
}
public Set<? extends MethodReference> getExportedMethods() {
return readonlyExportedMethods;
}
public Map<? extends ExportedMethodKey, ? extends MethodReference> getResolvedMethods() {
return readonlyResolvedMethods;
}
@Override
public void methodReached(DependencyAgent agent, MethodDependency method, CallLocation location) {
if (method.getMethod() == null || method.getMethod().getProgram() == null) {
return;
}
ProgramReader program = method.getMethod().getProgram();
FunctionGetFinder finder = new FunctionGetFinder(program.variableCount());
for (BasicBlockReader block : program.getBasicBlocks()) {
block.readAllInstructions(finder);
}
if (!finder.invocations.isEmpty()) {
processInvocations(agent, method.getMethod(), finder);
}
}
private void processInvocations(DependencyAgent agent, MethodReader method, FunctionGetFinder finder) {
int[] variableClasses = finder.variableClasses.pack(method.getProgram().variableCount());
String[] stringConstants = new String[finder.stringConstants.length];
ValueType[] classConstants = new ValueType[finder.classConstants.length];
for (int i = 0; i < stringConstants.length; ++i) {
stringConstants[variableClasses[i]] = finder.stringConstants[i];
classConstants[variableClasses[i]] = finder.classConstants[i];
}
Diagnostics diagnostics = agent.getDiagnostics();
for (Invocation invocation : finder.invocations) {
ValueType functionClass = classConstants[variableClasses[invocation.functionClassVar]];
ValueType targetClass = classConstants[variableClasses[invocation.classVar]];
String methodName = stringConstants[variableClasses[invocation.methodVar]];
CallLocation location = new CallLocation(method.getReference(), invocation.location);
boolean valid = true;
if (!(functionClass instanceof ValueType.Object)) {
diagnostics.error(location, "First argument must be class literal representing "
+ "non-array and no-primitive class");
valid = false;
}
if (!(targetClass instanceof ValueType.Object)) {
diagnostics.error(location, "Second argument must be class literal representing "
+ "non-array and no-primitive class");
valid = false;
}
if (methodName == null) {
diagnostics.error(location, "Third argument must be string literal");
valid = false;
}
if (valid) {
processInvocation(agent, location, ((ValueType.Object) functionClass).getClassName(),
((ValueType.Object) targetClass).getClassName(), methodName);
}
}
}
private void processInvocation(DependencyAgent agent, CallLocation location, String functionClassName,
String targetClassName, String methodName) {
Diagnostics diagnostics = agent.getDiagnostics();
ClassReaderSource classSource = agent.getClassSource();
boolean valid = true;
ClassReader functionClass = classSource.get(functionClassName);
if (functionClass == null) {
diagnostics.error(location, "Class '{{c0}}' not found in class path", functionClassName);
valid = false;
} else if (!characteristics.isFunction(functionClassName)) {
diagnostics.error(location, "Class '{{c0}}' does not represent a function", functionClassName);
valid = false;
}
ClassReader targetClass = classSource.get(targetClassName);
if (targetClass == null) {
diagnostics.error(location, "Class '{{c0}}' not found in class path", functionClassName);
valid = false;
}
if (!valid) {
return;
}
MethodReader sam = extractSingleMethod(diagnostics, location, functionClass);
if (sam == null) {
valid = false;
}
List<MethodReader> candidates = targetClass.getMethods().stream()
.filter(method -> method.getName().equals(methodName) && method.hasModifier(ElementModifier.STATIC))
.collect(Collectors.toList());
if (candidates.isEmpty()) {
diagnostics.error(location, "There's no static method '" + methodName + "' in class '{{c0}}'",
targetClass);
valid = false;
}
if (!valid) {
return;
}
List<MethodReader> signatureCandidates = candidates.stream()
.filter(method -> matchSignature(classSource, sam, method))
.collect(Collectors.toList());
if (signatureCandidates.isEmpty()) {
if (candidates.size() == 1) {
diagnostics.error(location, "Method '{{m0}}' does not match signature of function method '{{m1}}'",
candidates.get(0).getReference(), sam.getReference());
} else {
diagnostics.error(location, "None of '" + methodName + "' methods match signature of function "
+ "method '{{m0}}'", sam.getReference());
}
return;
}
MethodReader resolvedMethod = findMostSpecific(diagnostics, location, classSource, signatureCandidates);
if (resolvedMethod != null) {
MethodReference reference = resolvedMethod.getReference();
resolvedMethods.put(new ExportedMethodKey(functionClassName, targetClassName, methodName), reference);
exportedMethods.add(reference);
agent.linkMethod(reference, location).use();
}
}
private MethodReader extractSingleMethod(Diagnostics diagnostics, CallLocation location, ClassReader cls) {
MethodReader candidate = null;
for (MethodReader method : cls.getMethods()) {
if (method.hasModifier(ElementModifier.STATIC) || !method.hasModifier(ElementModifier.ABSTRACT)) {
continue;
}
if (candidate != null) {
diagnostics.error(location, "Function class {{c0}} must have one abstract method, it has multiple",
cls.getName());
return null;
} else {
candidate = method;
}
}
if (candidate == null) {
diagnostics.error(location, "Function class {{c0}} must have one abstract method, it has none",
cls.getName());
return null;
}
return candidate;
}
private MethodReader findMostSpecific(Diagnostics diagnostics, CallLocation location,
ClassReaderSource classSource, List<MethodReader> methods) {
MethodReader mostSpecificSoFar = methods.get(0);
for (int i = 1; i < methods.size(); ++i) {
MethodReader candidate = methods.get(i);
if (matchSignature(classSource, mostSpecificSoFar, candidate)) {
mostSpecificSoFar = candidate;
} else if (!matchSignature(classSource, candidate, mostSpecificSoFar)) {
diagnostics.error(location, "Ambiguous methods found for this export, examples are '{{m0}}' "
+ "and {{m1}}", candidate, mostSpecificSoFar);
return null;
}
}
return mostSpecificSoFar;
}
private boolean matchSignature(ClassReaderSource classSource, MethodReader functionMethod,
MethodReader candidateMethod) {
if (functionMethod.parameterCount() > candidateMethod.parameterCount()) {
return false;
}
for (int i = 0; i < functionMethod.parameterCount(); ++i) {
if (!classSource.isSuperType(functionMethod.parameterType(i),
candidateMethod.parameterType(i)).orElse(false)) {
return false;
}
}
return true;
}
class FunctionGetFinder extends AbstractInstructionReader {
DisjointSet variableClasses = new DisjointSet();
String[] stringConstants;
ValueType[] classConstants;
List<Invocation> invocations = new ArrayList<>();
private TextLocation location;
FunctionGetFinder(int variableCount) {
for (int i = 0; i < variableCount; ++i) {
variableClasses.create();
}
stringConstants = new String[variableCount];
classConstants = new ValueType[variableCount];
}
@Override
public void location(TextLocation location) {
this.location = location;
}
@Override
public void classConstant(VariableReader receiver, ValueType cst) {
classConstants[receiver.getIndex()] = cst;
}
@Override
public void stringConstant(VariableReader receiver, String cst) {
stringConstants[receiver.getIndex()] = cst;
}
@Override
public void assign(VariableReader receiver, VariableReader assignee) {
variableClasses.union(receiver.getIndex(), assignee.getIndex());
}
@Override
public void invoke(VariableReader receiver, VariableReader instance, MethodReference method,
List<? extends VariableReader> arguments, InvocationType type) {
if (method.getClassName().equals(Function.class.getName()) && method.getName().equals("get")
&& type == InvocationType.SPECIAL && instance == null && arguments.size() == 3) {
Invocation invocation = new Invocation(location, arguments.get(0).getIndex(),
arguments.get(1).getIndex(), arguments.get(2).getIndex());
invocations.add(invocation);
}
}
}
static class Invocation {
TextLocation location;
int functionClassVar;
int classVar;
int methodVar;
Invocation(TextLocation location, int functionClassVar, int classVar, int methodVar) {
this.location = location;
this.functionClassVar = functionClassVar;
this.classVar = classVar;
this.methodVar = methodVar;
}
}
}

View File

@ -0,0 +1,49 @@
/*
* 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.model.lowlevel;
import java.util.Objects;
public class ExportedMethodKey {
public final String functionClassName;
public final String className;
public final String methodName;
public ExportedMethodKey(String functionClassName, String className, String methodName) {
this.functionClassName = functionClassName;
this.className = className;
this.methodName = methodName;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
ExportedMethodKey that = (ExportedMethodKey) o;
return Objects.equals(functionClassName, that.functionClassName)
&& Objects.equals(className, that.className)
&& Objects.equals(methodName, that.methodName);
}
@Override
public int hashCode() {
return Objects.hash(functionClassName, className, methodName);
}
}

View File

@ -68,6 +68,20 @@ public final class Address {
public static native Address ofObject(Object obj); public static native Address ofObject(Object obj);
public static native Address ofData(byte[] data);
public static native Address ofData(char[] data);
public static native Address ofData(short[] data);
public static native Address ofData(int[] data);
public static native Address ofData(long[] data);
public static native Address ofData(float[] data);
public static native Address ofData(double[] data);
public static native Address align(Address address, int alignment); public static native Address align(Address address, int alignment);
public static native int sizeOf(); public static native int sizeOf();

View File

@ -16,4 +16,5 @@
package org.teavm.interop; package org.teavm.interop;
public abstract class Function { public abstract class Function {
public static native <T extends Function> T get(Class<T> functionType, Class<?> cls, String methodName);
} }

View File

@ -0,0 +1,29 @@
/*
* 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.interop.c;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.TYPE, ElementType.METHOD })
public @interface Include {
String value();
boolean isSystem() default true;
}

View File

@ -0,0 +1,26 @@
/*
* 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.interop.c;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.PARAMETER)
public @interface PlatformInt {
}