diff --git a/.idea/checkstyle-idea.xml b/.idea/checkstyle-idea.xml
index dd1eb8841..19fcd1bed 100644
--- a/.idea/checkstyle-idea.xml
+++ b/.idea/checkstyle-idea.xml
@@ -4,14 +4,15 @@
diff --git a/core/src/main/java/org/teavm/ast/decompilation/Decompiler.java b/core/src/main/java/org/teavm/ast/decompilation/Decompiler.java
index 1eb19529c..793c3a95d 100644
--- a/core/src/main/java/org/teavm/ast/decompilation/Decompiler.java
+++ b/core/src/main/java/org/teavm/ast/decompilation/Decompiler.java
@@ -93,15 +93,17 @@ public class Decompiler {
private Deque stack;
private Program program;
private boolean friendlyToDebugger;
+ private boolean moveConstants;
public Decompiler(ClassHolderSource classSource, ClassLoader classLoader, Set asyncMethods,
- Set asyncFamilyMethods, boolean friendlyToDebugger) {
+ Set asyncFamilyMethods, boolean friendlyToDebugger, boolean moveConstants) {
this.classSource = classSource;
this.classLoader = classLoader;
this.asyncMethods = asyncMethods;
splitMethods.addAll(asyncMethods);
splitMethods.addAll(asyncFamilyMethods);
this.friendlyToDebugger = friendlyToDebugger;
+ this.moveConstants = moveConstants;
}
public MethodNodeCache getRegularMethodCache() {
@@ -283,7 +285,7 @@ public class Decompiler {
methodNode.getVariables().add(variable);
}
- Optimizer optimizer = new Optimizer();
+ Optimizer optimizer = new Optimizer(moveConstants);
optimizer.optimize(methodNode, method.getProgram(), friendlyToDebugger);
methodNode.getModifiers().addAll(method.getModifiers());
@@ -347,7 +349,7 @@ public class Decompiler {
node.getVariables().add(variable);
}
- Optimizer optimizer = new Optimizer();
+ Optimizer optimizer = new Optimizer(moveConstants);
optimizer.optimize(node, splitter, friendlyToDebugger);
node.getModifiers().addAll(method.getModifiers());
diff --git a/core/src/main/java/org/teavm/ast/optimization/Optimizer.java b/core/src/main/java/org/teavm/ast/optimization/Optimizer.java
index a977fa287..b66c5d19e 100644
--- a/core/src/main/java/org/teavm/ast/optimization/Optimizer.java
+++ b/core/src/main/java/org/teavm/ast/optimization/Optimizer.java
@@ -18,9 +18,7 @@ package org.teavm.ast.optimization;
import java.util.BitSet;
import org.teavm.ast.AsyncMethodNode;
import org.teavm.ast.AsyncMethodPart;
-import org.teavm.ast.MethodNode;
import org.teavm.ast.RegularMethodNode;
-import org.teavm.ast.VariableNode;
import org.teavm.common.Graph;
import org.teavm.model.BasicBlock;
import org.teavm.model.Instruction;
@@ -33,6 +31,12 @@ import org.teavm.model.util.ProgramUtils;
import org.teavm.model.util.UsageExtractor;
public class Optimizer {
+ private boolean moveConstants;
+
+ public Optimizer(boolean moveConstants) {
+ this.moveConstants = moveConstants;
+ }
+
public void optimize(RegularMethodNode method, Program program, boolean friendlyToDebugger) {
ReadWriteStatsBuilder stats = new ReadWriteStatsBuilder(method.getVariables().size());
stats.analyze(program);
@@ -40,7 +44,7 @@ public class Optimizer {
BreakEliminator breakEliminator = new BreakEliminator();
breakEliminator.eliminate(method.getBody());
OptimizingVisitor optimizer = new OptimizingVisitor(preservedVars, stats.writes, stats.reads,
- friendlyToDebugger);
+ moveConstants ? stats.constants : new Object[stats.constants.length], friendlyToDebugger);
method.getBody().acceptVisitor(optimizer);
method.setBody(optimizer.resultStmt);
int paramCount = method.getReference().parameterCount();
@@ -74,7 +78,7 @@ public class Optimizer {
breakEliminator.eliminate(part.getStatement());
findEscapingLiveVars(liveness, cfg, splitter, i, preservedVars);
OptimizingVisitor optimizer = new OptimizingVisitor(preservedVars, stats.writes, stats.reads,
- friendlyToDebugger);
+ moveConstants ? stats.constants : new Object[stats.constants.length], friendlyToDebugger);
part.getStatement().acceptVisitor(optimizer);
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,
int partIndex, boolean[] output) {
Program originalProgram = splitter.getOriginalProgram();
diff --git a/core/src/main/java/org/teavm/ast/optimization/OptimizingVisitor.java b/core/src/main/java/org/teavm/ast/optimization/OptimizingVisitor.java
index c35159531..af37a28f9 100644
--- a/core/src/main/java/org/teavm/ast/optimization/OptimizingVisitor.java
+++ b/core/src/main/java/org/teavm/ast/optimization/OptimizingVisitor.java
@@ -69,17 +69,19 @@ class OptimizingVisitor implements StatementVisitor, ExprVisitor {
private final boolean[] preservedVars;
private final int[] writeFrequencies;
private final int[] readFrequencies;
+ private final Object[] constants;
private List resultSequence;
private boolean friendlyToDebugger;
private TextLocation currentLocation;
private Deque locationStack = new LinkedList<>();
private Deque notNullLocationStack = new ArrayDeque<>();
- OptimizingVisitor(boolean[] preservedVars, int[] writeFrequencies, int[] readFrequencies,
+ OptimizingVisitor(boolean[] preservedVars, int[] writeFrequencies, int[] readFrequencies, Object[] constants,
boolean friendlyToDebugger) {
this.preservedVars = preservedVars;
this.writeFrequencies = writeFrequencies;
this.readFrequencies = readFrequencies;
+ this.constants = constants;
this.friendlyToDebugger = friendlyToDebugger;
}
@@ -273,6 +275,15 @@ class OptimizingVisitor implements StatementVisitor, ExprVisitor {
if (writeFrequencies[index] != 1) {
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]) {
return;
}
@@ -542,6 +553,12 @@ class OptimizingVisitor implements StatementVisitor, ExprVisitor {
if (!(statement.getLeftValue() instanceof VariableExpr)) {
statement.getLeftValue().acceptVisitor(this);
left = resultExpr;
+ } else {
+ int varIndex = ((VariableExpr) statement.getLeftValue()).getIndex();
+ if (writeFrequencies[varIndex] == 1 && constants[varIndex] != null) {
+ resultStmt = new SequentialStatement();
+ return;
+ }
}
statement.setLeftValue(left);
statement.setRightValue(right);
diff --git a/core/src/main/java/org/teavm/ast/optimization/ReadWriteStatsBuilder.java b/core/src/main/java/org/teavm/ast/optimization/ReadWriteStatsBuilder.java
index 5a685a198..43a2cecfd 100644
--- a/core/src/main/java/org/teavm/ast/optimization/ReadWriteStatsBuilder.java
+++ b/core/src/main/java/org/teavm/ast/optimization/ReadWriteStatsBuilder.java
@@ -20,6 +20,8 @@ import org.teavm.common.Graph;
import org.teavm.common.GraphUtils;
import org.teavm.common.IntegerStack;
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.ProgramUtils;
import org.teavm.model.util.UsageExtractor;
@@ -27,6 +29,7 @@ import org.teavm.model.util.UsageExtractor;
class ReadWriteStatsBuilder {
public int[] reads;
public int[] writes;
+ public Object[] constants;
private ReadWriteStatsBuilder() {
}
@@ -34,6 +37,7 @@ class ReadWriteStatsBuilder {
public ReadWriteStatsBuilder(int variableCount) {
reads = new int[variableCount];
writes = new int[variableCount];
+ constants = new Object[variableCount];
}
public ReadWriteStatsBuilder copy() {
@@ -68,6 +72,14 @@ class ReadWriteStatsBuilder {
for (Variable var : useExtractor.getUsedVariables()) {
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()) {
diff --git a/core/src/main/java/org/teavm/backend/c/CTarget.java b/core/src/main/java/org/teavm/backend/c/CTarget.java
index 10e65b349..0f34a8132 100644
--- a/core/src/main/java/org/teavm/backend/c/CTarget.java
+++ b/core/src/main/java/org/teavm/backend/c/CTarget.java
@@ -83,6 +83,7 @@ import org.teavm.model.instructions.InvokeInstruction;
import org.teavm.model.lowlevel.Characteristics;
import org.teavm.model.lowlevel.ClassInitializerEliminator;
import org.teavm.model.lowlevel.ClassInitializerTransformer;
+import org.teavm.model.lowlevel.ExportDependencyListener;
import org.teavm.model.lowlevel.NullCheckInsertion;
import org.teavm.model.lowlevel.NullCheckTransformation;
import org.teavm.model.lowlevel.ShadowStackTransformer;
@@ -107,6 +108,7 @@ public class CTarget implements TeaVMTarget {
private ShadowStackTransformer shadowStackTransformer;
private NullCheckInsertion nullCheckInsertion;
private NullCheckTransformation nullCheckTransformation;
+ private ExportDependencyListener exportDependencyListener = new ExportDependencyListener();
private int minHeapSize = 32 * 1024 * 1024;
public void setMinHeapSize(int minHeapSize) {
@@ -123,7 +125,7 @@ public class CTarget implements TeaVMTarget {
@Override
public List getDependencyListeners() {
- return Collections.singletonList(new CDependencyListener());
+ return Arrays.asList(new CDependencyListener(), exportDependencyListener);
}
@Override
@@ -204,7 +206,7 @@ public class CTarget implements TeaVMTarget {
StringPool stringPool = new StringPool();
Decompiler decompiler = new Decompiler(classes, controller.getClassLoader(), new HashSet<>(),
- new HashSet<>(), false);
+ new HashSet<>(), false, true);
Characteristics characteristics = new Characteristics(controller.getUnprocessedClassSource());
NameProvider nameProvider = new NameProvider(controller.getUnprocessedClassSource());
@@ -221,7 +223,7 @@ public class CTarget implements TeaVMTarget {
intrinsics.add(new GCIntrinsic());
intrinsics.add(new MutatorIntrinsic());
intrinsics.add(new ExceptionHandlingIntrinsic());
- intrinsics.add(new FunctionIntrinsic(characteristics));
+ intrinsics.add(new FunctionIntrinsic(characteristics, exportDependencyListener.getResolvedMethods()));
List generators = new ArrayList<>();
generators.add(new ArrayGenerator());
diff --git a/core/src/main/java/org/teavm/backend/c/generate/ClassGenerator.java b/core/src/main/java/org/teavm/backend/c/generate/ClassGenerator.java
index 328ab6443..e4b30382f 100644
--- a/core/src/main/java/org/teavm/backend/c/generate/ClassGenerator.java
+++ b/core/src/main/java/org/teavm/backend/c/generate/ClassGenerator.java
@@ -62,6 +62,8 @@ public class ClassGenerator {
private List layouts = new ArrayList<>();
private int currentLayoutIndex;
private Set types = new LinkedHashSet<>();
+ private Set includes = new LinkedHashSet<>();
+ private CodeWriter includesWriter;
private CodeWriter forwardDeclarationsWriter;
private CodeWriter structuresWriter;
private CodeWriter vtableStructuresWriter;
@@ -81,6 +83,7 @@ public class ClassGenerator {
this.tagRegistry = tagRegistry;
this.decompiler = decompiler;
+ includesWriter = writer.fragment();
forwardDeclarationsWriter = writer.fragment();
structuresWriter = writer.fragment();
vtableStructuresWriter = writer.fragment();
@@ -93,7 +96,7 @@ public class ClassGenerator {
callSiteWriter = writer.fragment();
codeWriter = writer.fragment();
- codeGenerator = new CodeGenerator(context, codeWriter);
+ codeGenerator = new CodeGenerator(context, codeWriter, includes);
}
public void generateClass(ClassHolder cls) {
@@ -113,6 +116,10 @@ public class ClassGenerator {
generateLayoutArray();
new StringPoolGenerator(stringPoolWriter, context.getNames()).generate(context.getStringPool().getStrings());
+
+ for (String include : includes) {
+ includesWriter.println("#include " + include);
+ }
}
public Set getTypes() {
diff --git a/core/src/main/java/org/teavm/backend/c/generate/CodeGenerationVisitor.java b/core/src/main/java/org/teavm/backend/c/generate/CodeGenerationVisitor.java
index f730e5cd5..42d972c3e 100644
--- a/core/src/main/java/org/teavm/backend/c/generate/CodeGenerationVisitor.java
+++ b/core/src/main/java/org/teavm/backend/c/generate/CodeGenerationVisitor.java
@@ -16,6 +16,7 @@
package org.teavm.backend.c.generate;
import java.util.List;
+import java.util.Set;
import org.teavm.ast.ArrayType;
import org.teavm.ast.AssignmentStatement;
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.diagnostics.Diagnostics;
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.MethodReference;
import org.teavm.model.ValueType;
@@ -80,11 +86,13 @@ public class CodeGenerationVisitor implements ExprVisitor, StatementVisitor {
private int temporaryReceiverLevel;
private int maxTemporaryReceiverLevel;
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.writer = writer;
this.names = context.getNames();
+ this.includes = includes;
}
public int getTemporaryReceivers() {
@@ -371,6 +379,15 @@ public class CodeGenerationVisitor implements ExprVisitor, StatementVisitor {
@Override
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());
if (intrinsic != null) {
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
public void visit(QualificationExpr expr) {
if (expr.getQualified() != null) {
diff --git a/core/src/main/java/org/teavm/backend/c/generate/CodeGenerator.java b/core/src/main/java/org/teavm/backend/c/generate/CodeGenerator.java
index 49b1a2ff1..9211b5873 100644
--- a/core/src/main/java/org/teavm/backend/c/generate/CodeGenerator.java
+++ b/core/src/main/java/org/teavm/backend/c/generate/CodeGenerator.java
@@ -15,6 +15,7 @@
*/
package org.teavm.backend.c.generate;
+import java.util.Set;
import org.teavm.ast.RegularMethodNode;
import org.teavm.ast.VariableNode;
import org.teavm.model.ElementModifier;
@@ -26,11 +27,13 @@ public class CodeGenerator {
private CodeWriter writer;
private CodeWriter localsWriter;
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.writer = writer;
this.names = context.getNames();
+ this.includes = includes;
}
public void generateMethod(RegularMethodNode methodNode) {
@@ -41,7 +44,7 @@ public class CodeGenerator {
localsWriter = writer.fragment();
- CodeGenerationVisitor visitor = new CodeGenerationVisitor(context, writer);
+ CodeGenerationVisitor visitor = new CodeGenerationVisitor(context, writer, includes);
visitor.setCallingMethod(methodNode.getReference());
methodNode.getBody().acceptVisitor(visitor);
diff --git a/core/src/main/java/org/teavm/backend/c/intrinsic/AddressIntrinsic.java b/core/src/main/java/org/teavm/backend/c/intrinsic/AddressIntrinsic.java
index 248c0ae40..517547b3b 100644
--- a/core/src/main/java/org/teavm/backend/c/intrinsic/AddressIntrinsic.java
+++ b/core/src/main/java/org/teavm/backend/c/intrinsic/AddressIntrinsic.java
@@ -16,8 +16,10 @@
package org.teavm.backend.c.intrinsic;
import org.teavm.ast.InvocationExpr;
+import org.teavm.backend.c.util.ConstantUtil;
import org.teavm.interop.Address;
import org.teavm.model.MethodReference;
+import org.teavm.model.ValueType;
public class AddressIntrinsic implements Intrinsic {
@Override
@@ -56,6 +58,8 @@ public class AddressIntrinsic implements Intrinsic {
case "isLessThan":
case "align":
case "sizeOf":
+
+ case "ofData":
return true;
default:
return false;
@@ -165,7 +169,7 @@ public class AddressIntrinsic implements Intrinsic {
context.writer().print("ADDRESS_ADD(");
context.emit(invocation.getArguments().get(0));
context.writer().print(", ");
- String className = StructureIntrinsic.getClassLiteral(context, invocation,
+ String className = ConstantUtil.getClassLiteral(context, invocation,
invocation.getArguments().get(1));
context.emit(invocation.getArguments().get(2));
context.writer().print(" * sizeof(")
@@ -191,6 +195,14 @@ public class AddressIntrinsic implements Intrinsic {
case "sizeOf":
context.writer().print("sizeof(void*)");
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.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;
+ }
}
diff --git a/core/src/main/java/org/teavm/backend/c/intrinsic/FunctionIntrinsic.java b/core/src/main/java/org/teavm/backend/c/intrinsic/FunctionIntrinsic.java
index 6aa9258ec..380dad851 100644
--- a/core/src/main/java/org/teavm/backend/c/intrinsic/FunctionIntrinsic.java
+++ b/core/src/main/java/org/teavm/backend/c/intrinsic/FunctionIntrinsic.java
@@ -15,25 +15,41 @@
*/
package org.teavm.backend.c.intrinsic;
+import java.util.Map;
+import org.teavm.ast.ConstantExpr;
import org.teavm.ast.InvocationExpr;
+import org.teavm.interop.Function;
import org.teavm.model.MethodReference;
+import org.teavm.model.ValueType;
import org.teavm.model.lowlevel.Characteristics;
+import org.teavm.model.lowlevel.ExportedMethodKey;
public class FunctionIntrinsic implements Intrinsic {
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.resolvedMethods = resolvedMethods;
}
@Override
public boolean canHandle(MethodReference method) {
+ if (method.getClassName().equals(Function.class.getName()) && method.getName().equals("get")) {
+ return true;
+ }
return characteristics.isFunction(method.getClassName());
}
@Override
public void apply(IntrinsicContext context, InvocationExpr invocation) {
MethodReference method = invocation.getMethod();
+ if (method.getClassName().equals(Function.class.getName())) {
+ generateGetFunction(context, invocation);
+ return;
+ }
+
context.writer().print("(((").printType(method.getReturnType()).print(" (*)(");
if (method.parameterCount() > 0) {
context.writer().printType(method.parameterType(0));
@@ -54,4 +70,32 @@ public class FunctionIntrinsic implements Intrinsic {
}
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));
+ }
}
diff --git a/core/src/main/java/org/teavm/backend/c/intrinsic/StructureIntrinsic.java b/core/src/main/java/org/teavm/backend/c/intrinsic/StructureIntrinsic.java
index 1a4462bd6..96bd661aa 100644
--- a/core/src/main/java/org/teavm/backend/c/intrinsic/StructureIntrinsic.java
+++ b/core/src/main/java/org/teavm/backend/c/intrinsic/StructureIntrinsic.java
@@ -15,11 +15,9 @@
*/
package org.teavm.backend.c.intrinsic;
-import org.teavm.ast.ConstantExpr;
-import org.teavm.ast.Expr;
import org.teavm.ast.InvocationExpr;
+import org.teavm.backend.c.util.ConstantUtil;
import org.teavm.interop.Structure;
-import org.teavm.model.CallLocation;
import org.teavm.model.MethodReference;
import org.teavm.model.ValueType;
import org.teavm.model.lowlevel.Characteristics;
@@ -62,14 +60,14 @@ public class StructureIntrinsic implements Intrinsic {
context.emit(invocation.getArguments().get(0));
break;
case "sizeOf": {
- String className = getClassLiteral(context, invocation, invocation.getArguments().get(0));
+ String className = ConstantUtil.getClassLiteral(context, invocation, invocation.getArguments().get(0));
if (className != null) {
context.writer().print("sizeof(").print(context.names().forClass(className)).print(")");
}
break;
}
case "add": {
- String className = getClassLiteral(context, invocation, invocation.getArguments().get(0));
+ String className = ConstantUtil.getClassLiteral(context, invocation, invocation.getArguments().get(0));
if (className != null) {
context.writer().print("STRUCTURE_ADD(").print(context.names().forClass(className)).print(", ");
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 "";
- }
}
diff --git a/core/src/main/java/org/teavm/backend/c/util/ConstantUtil.java b/core/src/main/java/org/teavm/backend/c/util/ConstantUtil.java
new file mode 100644
index 000000000..344edf7ad
--- /dev/null
+++ b/core/src/main/java/org/teavm/backend/c/util/ConstantUtil.java
@@ -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 "";
+ }
+}
diff --git a/core/src/main/java/org/teavm/backend/javascript/JavaScriptTarget.java b/core/src/main/java/org/teavm/backend/javascript/JavaScriptTarget.java
index cc72b066c..6e69610b0 100644
--- a/core/src/main/java/org/teavm/backend/javascript/JavaScriptTarget.java
+++ b/core/src/main/java/org/teavm/backend/javascript/JavaScriptTarget.java
@@ -313,7 +313,7 @@ public class JavaScriptTarget implements TeaVMTarget, TeaVMJavaScriptHost {
asyncFamilyMethods.addAll(asyncFinder.getAsyncFamilyMethods());
Decompiler decompiler = new Decompiler(classes, controller.getClassLoader(), asyncMethods, asyncFamilyMethods,
- controller.isFriendlyToDebugger());
+ controller.isFriendlyToDebugger(), false);
decompiler.setRegularMethodCache(controller.isIncremental() ? astCache : null);
for (Map.Entry entry : methodGenerators.entrySet()) {
diff --git a/core/src/main/java/org/teavm/backend/wasm/GtkExample.java b/core/src/main/java/org/teavm/backend/wasm/GtkExample.java
new file mode 100644
index 000000000..d109a5c24
--- /dev/null
+++ b/core/src/main/java/org/teavm/backend/wasm/GtkExample.java
@@ -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