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 fbdaf861d..c3de9c33c 100644 --- a/core/src/main/java/org/teavm/backend/c/CTarget.java +++ b/core/src/main/java/org/teavm/backend/c/CTarget.java @@ -346,7 +346,9 @@ public class CTarget implements TeaVMTarget, TeaVMCHost { for (String className : classNames) { ClassHolder cls = classes.get(className); - classGenerator.generateClass(cls); + if (cls != null) { + classGenerator.generateClass(cls); + } } classGenerator.generateRemainingData(classNames, shadowStackTransformer); @@ -369,8 +371,7 @@ public class CTarget implements TeaVMTarget, TeaVMCHost { if (parent == null) { parent = RuntimeObject.class.getName(); } - if (!parent.equals(Structure.class.getName()) - && stateMap.getOrDefault(cls.getParent(), (byte) 0) == 0) { + if (!parent.equals(Structure.class.getName()) && stateMap.getOrDefault(parent, (byte) 0) == 0) { stack.push(parent); } break; 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 7c1156165..bcbf6c6a3 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 @@ -491,6 +491,9 @@ public class ClassGenerator { } private void generateVirtualTableStructure(ClassReader cls) { + if (cls == null) { + return; + } String name = context.getNames().forClassClass(cls.getName()); vtableStructuresWriter.print("typedef struct ").print(name).println(" {").indent(); 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 cf818dab6..82902bff3 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 @@ -60,9 +60,11 @@ 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.interop.c.Variable; import org.teavm.model.AnnotationContainerReader; import org.teavm.model.AnnotationReader; import org.teavm.model.AnnotationValue; +import org.teavm.model.CallLocation; import org.teavm.model.ClassReader; import org.teavm.model.ElementModifier; import org.teavm.model.FieldReference; @@ -469,6 +471,7 @@ public class CodeGenerationVisitor implements ExprVisitor, StatementVisitor { for (int i = 0; i < expr.getArguments().size(); ++i) { temporaries.add(allocTemporaryVariable(CVariableType.PTR)); } + boolean stringResult = method.getResultType().isObject(String.class); writer.print("("); for (int i = 0; i < expr.getArguments().size(); ++i) { @@ -482,6 +485,10 @@ public class CodeGenerationVisitor implements ExprVisitor, StatementVisitor { expr.getArguments().get(i).acceptVisitor(this); writer.print(")"); stringTemporaries.add(tmp); + } else if (isPrimitiveArray(type)) { + writer.print("ARRAY_DATA("); + expr.getArguments().get(i).acceptVisitor(this); + writer.print(", ").printStrictType(((ValueType.Array) type).getItemType()).print(")"); } else { expr.getArguments().get(i).acceptVisitor(this); } @@ -492,28 +499,49 @@ public class CodeGenerationVisitor implements ExprVisitor, StatementVisitor { if (resultTmp != null) { writer.print(resultTmp + " = "); } - writer.print(names.forMethod(method.getReference())).print("("); - for (int i = 0; i < temporaries.size(); ++i) { - if (i > 0) { - writer.print(", "); + writer.print(names.forMethod(method.getReference())); + if (method.getAnnotations().get(Variable.class.getName()) == null) { + writer.print("("); + for (int i = 0; i < temporaries.size(); ++i) { + if (i > 0) { + writer.print(", "); + } + writer.print(temporaries.get(i)); + freeTemporaryVariable(CVariableType.PTR); } - writer.print(temporaries.get(i)); - freeTemporaryVariable(CVariableType.PTR); + writer.print(")"); + } else if (method.parameterCount() > 0 || method.getResultType() == ValueType.VOID) { + context.getDiagnostics().error(new CallLocation(method.getReference()), + "'@Variable' annotation is not applicable to method {{m0}}", method.getReference()); } - writer.print(")"); for (String tmp : stringTemporaries) { writer.print(", teavm_free(" + tmp + ")"); } if (resultTmp != null) { - writer.print(", " + resultTmp); + writer.print(", "); + if (stringResult) { + writer.print("teavm_cToString("); + } + writer.print(resultTmp); + if (stringResult) { + writer.print(")"); + } freeTemporaryVariable(typeToCType(method.getResultType())); } writer.print(")"); } + private static boolean isPrimitiveArray(ValueType type) { + if (!(type instanceof ValueType.Array)) { + return false; + } + + return ((ValueType.Array) type).getItemType() instanceof ValueType.Primitive; + } + private boolean isWrappedNativeCall(MethodReader method) { if (!method.hasModifier(ElementModifier.NATIVE)) { return false; diff --git a/core/src/main/java/org/teavm/backend/c/intrinsic/StringsIntrinsic.java b/core/src/main/java/org/teavm/backend/c/intrinsic/StringsIntrinsic.java new file mode 100644 index 000000000..2fc862f4d --- /dev/null +++ b/core/src/main/java/org/teavm/backend/c/intrinsic/StringsIntrinsic.java @@ -0,0 +1,43 @@ +/* + * Copyright 2019 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.intrinsic; + +import org.teavm.ast.InvocationExpr; +import org.teavm.interop.Strings; +import org.teavm.model.MethodReference; + +public class StringsIntrinsic implements Intrinsic { + @Override + public boolean canHandle(MethodReference method) { + return method.getClassName().equals(Strings.class.getName()); + } + + @Override + public void apply(IntrinsicContext context, InvocationExpr invocation) { + switch (invocation.getMethod().getName()) { + case "toC": + context.writer().print("teavm_stringToC("); + context.emit(invocation.getArguments().get(0)); + context.writer().print(")"); + break; + case "fromC": + context.writer().print("teavm_cToString("); + context.emit(invocation.getArguments().get(0)); + context.writer().print(")"); + break; + } + } +} diff --git a/interop/core/src/main/java/org/teavm/interop/Strings.java b/interop/core/src/main/java/org/teavm/interop/Strings.java new file mode 100644 index 000000000..2831c2d1f --- /dev/null +++ b/interop/core/src/main/java/org/teavm/interop/Strings.java @@ -0,0 +1,25 @@ +/* + * Copyright 2019 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; + +public final class Strings { + private Strings() { + } + + public static native Address toC(String javaString); + + public static native String fromC(Address cString); +} diff --git a/interop/core/src/main/java/org/teavm/interop/c/Variable.java b/interop/core/src/main/java/org/teavm/interop/c/Variable.java new file mode 100644 index 000000000..5a753175b --- /dev/null +++ b/interop/core/src/main/java/org/teavm/interop/c/Variable.java @@ -0,0 +1,26 @@ +/* + * Copyright 2019 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.METHOD) +public @interface Variable { +}