mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 08:14:09 -08:00
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:
parent
38267980fb
commit
fa07100024
|
@ -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>
|
||||||
|
|
|
@ -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());
|
||||||
|
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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()) {
|
||||||
|
|
|
@ -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());
|
||||||
|
|
|
@ -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() {
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 "";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 "";
|
||||||
|
}
|
||||||
|
}
|
|
@ -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()) {
|
||||||
|
|
146
core/src/main/java/org/teavm/backend/wasm/GtkExample.java
Normal file
146
core/src/main/java/org/teavm/backend/wasm/GtkExample.java
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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();
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
29
interop/core/src/main/java/org/teavm/interop/c/Include.java
Normal file
29
interop/core/src/main/java/org/teavm/interop/c/Include.java
Normal 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;
|
||||||
|
}
|
|
@ -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 {
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user