C backend: implement support for simple cases of resources

This commit is contained in:
Alexey Andreev 2018-04-28 19:40:08 +03:00 committed by Alexey Andreev
parent ee2f389027
commit 4530167061
20 changed files with 470 additions and 21 deletions

View File

@ -15,17 +15,21 @@
*/ */
package org.teavm.classlib.impl; package org.teavm.classlib.impl;
import java.util.Collection;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import org.teavm.model.ClassReader; import org.teavm.model.ClassReader;
import org.teavm.model.MethodReference; import org.teavm.model.MethodReference;
import org.teavm.platform.metadata.*; import org.teavm.platform.metadata.ClassScopedMetadataGenerator;
import org.teavm.platform.metadata.MetadataGeneratorContext;
import org.teavm.platform.metadata.Resource;
public class DeclaringClassMetadataGenerator implements ClassScopedMetadataGenerator { public class DeclaringClassMetadataGenerator implements ClassScopedMetadataGenerator {
@Override @Override
public Map<String, Resource> generateMetadata(MetadataGeneratorContext context, MethodReference method) { public Map<String, Resource> generateMetadata(MetadataGeneratorContext context,
Collection<? extends String> classNames, MethodReference method) {
Map<String, Resource> result = new HashMap<>(); Map<String, Resource> result = new HashMap<>();
for (String clsName : context.getClassSource().getClassNames()) { for (String clsName : classNames) {
ClassReader cls = context.getClassSource().get(clsName); ClassReader cls = context.getClassSource().get(clsName);
if (cls.getOwnerName() != null) { if (cls.getOwnerName() != null) {
result.put(clsName, context.createClassResource(cls.getOwnerName())); result.put(clsName, context.createClassResource(cls.getOwnerName()));

View File

@ -47,6 +47,7 @@ import org.teavm.backend.c.intrinsic.ExceptionHandlingIntrinsic;
import org.teavm.backend.c.intrinsic.FunctionIntrinsic; import org.teavm.backend.c.intrinsic.FunctionIntrinsic;
import org.teavm.backend.c.intrinsic.GCIntrinsic; import org.teavm.backend.c.intrinsic.GCIntrinsic;
import org.teavm.backend.c.intrinsic.Intrinsic; import org.teavm.backend.c.intrinsic.Intrinsic;
import org.teavm.backend.c.intrinsic.IntrinsicFactory;
import org.teavm.backend.c.intrinsic.MutatorIntrinsic; import org.teavm.backend.c.intrinsic.MutatorIntrinsic;
import org.teavm.backend.c.intrinsic.PlatformClassIntrinsic; import org.teavm.backend.c.intrinsic.PlatformClassIntrinsic;
import org.teavm.backend.c.intrinsic.PlatformClassMetadataIntrinsic; import org.teavm.backend.c.intrinsic.PlatformClassMetadataIntrinsic;
@ -100,7 +101,7 @@ import org.teavm.vm.TeaVMTarget;
import org.teavm.vm.TeaVMTargetController; import org.teavm.vm.TeaVMTargetController;
import org.teavm.vm.spi.TeaVMHostExtension; import org.teavm.vm.spi.TeaVMHostExtension;
public class CTarget implements TeaVMTarget { public class CTarget implements TeaVMTarget, TeaVMCHost {
private TeaVMTargetController controller; private TeaVMTargetController controller;
private ClassInitializerInsertionTransformer clinitInsertionTransformer; private ClassInitializerInsertionTransformer clinitInsertionTransformer;
private ClassInitializerEliminator classInitializerEliminator; private ClassInitializerEliminator classInitializerEliminator;
@ -110,6 +111,7 @@ public class CTarget implements TeaVMTarget {
private NullCheckTransformation nullCheckTransformation; private NullCheckTransformation nullCheckTransformation;
private ExportDependencyListener exportDependencyListener = new ExportDependencyListener(); private ExportDependencyListener exportDependencyListener = new ExportDependencyListener();
private int minHeapSize = 32 * 1024 * 1024; private int minHeapSize = 32 * 1024 * 1024;
private List<IntrinsicFactory> intrinsicFactories = new ArrayList<>();
public void setMinHeapSize(int minHeapSize) { public void setMinHeapSize(int minHeapSize) {
this.minHeapSize = minHeapSize; this.minHeapSize = minHeapSize;
@ -142,7 +144,12 @@ public class CTarget implements TeaVMTarget {
@Override @Override
public List<TeaVMHostExtension> getHostExtensions() { public List<TeaVMHostExtension> getHostExtensions() {
return Collections.emptyList(); return Collections.singletonList(this);
}
@Override
public void addIntrinsic(IntrinsicFactory intrinsicFactory) {
intrinsicFactories.add(intrinsicFactory);
} }
@Override @Override
@ -236,6 +243,13 @@ public class CTarget implements TeaVMTarget {
ClassGenerator classGenerator = new ClassGenerator(context, controller.getUnprocessedClassSource(), ClassGenerator classGenerator = new ClassGenerator(context, controller.getUnprocessedClassSource(),
tagRegistry, decompiler, codeWriter); tagRegistry, decompiler, codeWriter);
IntrinsicFactoryContextImpl intrinsicFactoryContext = new IntrinsicFactoryContextImpl(
classGenerator.getStructuresWriter(), classGenerator.getPreCodeWriter(),
controller.getUnprocessedClassSource(), controller.getClassLoader(), controller.getServices(),
controller.getProperties());
for (IntrinsicFactory intrinsicFactory : intrinsicFactories) {
context.addIntrinsic(intrinsicFactory.createIntrinsic(intrinsicFactoryContext));
}
generateClasses(classes, classGenerator); generateClasses(classes, classGenerator);
generateSpecialFunctions(context, codeWriter); generateSpecialFunctions(context, codeWriter);

View File

@ -0,0 +1,72 @@
/*
* Copyright 2018 Alexey Andreev.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.teavm.backend.c;
import java.util.Properties;
import org.teavm.backend.c.generate.CodeWriter;
import org.teavm.backend.c.intrinsic.IntrinsicFactoryContext;
import org.teavm.common.ServiceRepository;
import org.teavm.model.ClassReaderSource;
class IntrinsicFactoryContextImpl implements IntrinsicFactoryContext {
private CodeWriter structureCodeWriter;
private CodeWriter staticFieldsInitWriter;
private ClassReaderSource classSource;
private ClassLoader classLoader;
private ServiceRepository services;
private Properties properties;
IntrinsicFactoryContextImpl(CodeWriter structureCodeWriter, CodeWriter staticFieldsInitWriter,
ClassReaderSource classSource, ClassLoader classLoader, ServiceRepository services,
Properties properties) {
this.structureCodeWriter = structureCodeWriter;
this.staticFieldsInitWriter = staticFieldsInitWriter;
this.classSource = classSource;
this.classLoader = classLoader;
this.services = services;
this.properties = properties;
}
@Override
public CodeWriter getStructureCodeWriter() {
return structureCodeWriter;
}
@Override
public CodeWriter getStaticFieldsInitWriter() {
return staticFieldsInitWriter;
}
@Override
public ClassReaderSource getClassSource() {
return classSource;
}
@Override
public ClassLoader getClassLoader() {
return classLoader;
}
@Override
public ServiceRepository getServices() {
return services;
}
@Override
public Properties getProperties() {
return properties;
}
}

View File

@ -15,5 +15,9 @@
*/ */
package org.teavm.backend.c; package org.teavm.backend.c;
public class TeaVMCHost { import org.teavm.backend.c.intrinsic.IntrinsicFactory;
import org.teavm.vm.spi.TeaVMHostExtension;
public interface TeaVMCHost extends TeaVMHostExtension {
void addIntrinsic(IntrinsicFactory intrinsicFactory);
} }

View File

@ -74,6 +74,7 @@ public class ClassGenerator {
private CodeWriter isSupertypeWriter; private CodeWriter isSupertypeWriter;
private CodeWriter staticGcRootsWriter; private CodeWriter staticGcRootsWriter;
private CodeWriter callSiteWriter; private CodeWriter callSiteWriter;
private CodeWriter preCodeWriter;
private CodeWriter codeWriter; private CodeWriter codeWriter;
private CodeWriter staticFieldInitWriter; private CodeWriter staticFieldInitWriter;
@ -95,6 +96,7 @@ public class ClassGenerator {
isSupertypeWriter = writer.fragment(); isSupertypeWriter = writer.fragment();
staticGcRootsWriter = writer.fragment(); staticGcRootsWriter = writer.fragment();
callSiteWriter = writer.fragment(); callSiteWriter = writer.fragment();
preCodeWriter = writer.fragment();
codeWriter = writer.fragment(); codeWriter = writer.fragment();
writer.println("static void initStaticFields() {").indent(); writer.println("static void initStaticFields() {").indent();
@ -104,6 +106,14 @@ public class ClassGenerator {
codeGenerator = new CodeGenerator(context, codeWriter, includes); codeGenerator = new CodeGenerator(context, codeWriter, includes);
} }
public CodeWriter getPreCodeWriter() {
return preCodeWriter;
}
public CodeWriter getStructuresWriter() {
return structuresWriter;
}
public void generateClass(ClassHolder cls) { public void generateClass(ClassHolder cls) {
generateClassStructure(cls); generateClassStructure(cls);
generateClassMethods(cls); generateClassMethods(cls);

View File

@ -693,5 +693,10 @@ public class CodeGenerationVisitor implements ExprVisitor, StatementVisitor {
public MethodReference getCallingMethod() { public MethodReference getCallingMethod() {
return callingMethod; return callingMethod;
} }
@Override
public StringPool getStringPool() {
return context.getStringPool();
}
}; };
} }

View File

@ -51,6 +51,10 @@ public class GenerationContext {
this.generators = new ArrayList<>(generators); this.generators = new ArrayList<>(generators);
} }
public void addIntrinsic(Intrinsic intrinsic) {
intrinsics.add(intrinsic);
}
public VirtualTableProvider getVirtualTableProvider() { public VirtualTableProvider getVirtualTableProvider() {
return virtualTableProvider; return virtualTableProvider;
} }

View File

@ -18,6 +18,7 @@ package org.teavm.backend.c.intrinsic;
import org.teavm.ast.Expr; import org.teavm.ast.Expr;
import org.teavm.backend.c.generate.CodeWriter; import org.teavm.backend.c.generate.CodeWriter;
import org.teavm.backend.c.generate.NameProvider; import org.teavm.backend.c.generate.NameProvider;
import org.teavm.backend.c.generate.StringPool;
import org.teavm.diagnostics.Diagnostics; import org.teavm.diagnostics.Diagnostics;
import org.teavm.model.MethodReference; import org.teavm.model.MethodReference;
@ -31,4 +32,6 @@ public interface IntrinsicContext {
Diagnostics getDiagnotics(); Diagnostics getDiagnotics();
MethodReference getCallingMethod(); MethodReference getCallingMethod();
StringPool getStringPool();
} }

View File

@ -0,0 +1,20 @@
/*
* 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.intrinsic;
public interface IntrinsicFactory {
Intrinsic createIntrinsic(IntrinsicFactoryContext context);
}

View File

@ -0,0 +1,35 @@
/*
* 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.intrinsic;
import java.util.Properties;
import org.teavm.backend.c.generate.CodeWriter;
import org.teavm.common.ServiceRepository;
import org.teavm.model.ClassReaderSource;
public interface IntrinsicFactoryContext {
CodeWriter getStructureCodeWriter();
CodeWriter getStaticFieldsInitWriter();
ClassReaderSource getClassSource();
ClassLoader getClassLoader();
ServiceRepository getServices();
Properties getProperties();
}

View File

@ -15,6 +15,7 @@
*/ */
package org.teavm.platform.metadata; package org.teavm.platform.metadata;
import java.util.Collection;
import java.util.Map; import java.util.Map;
import org.teavm.model.MethodReference; import org.teavm.model.MethodReference;
import org.teavm.platform.PlatformClass; import org.teavm.platform.PlatformClass;
@ -23,7 +24,7 @@ import org.teavm.platform.PlatformClass;
* <p>Behaviour of this class is similar to {@link MetadataGenerator}. The difference is that method, marked with * <p>Behaviour of this class is similar to {@link MetadataGenerator}. The difference is that method, marked with
* {@link ClassScopedMetadataProvider} must take one argument of type {@link PlatformClass}. It will * {@link ClassScopedMetadataProvider} must take one argument of type {@link PlatformClass}. It will
* return different resource for each given class, corresponding to map entries, produced by * return different resource for each given class, corresponding to map entries, produced by
* {@link #generateMetadata(MetadataGeneratorContext, MethodReference)}. * {@link #generateMetadata(MetadataGeneratorContext, Collection, MethodReference)}.
* *
* @see ClassScopedMetadataProvider * @see ClassScopedMetadataProvider
* @see MetadataGenerator * @see MetadataGenerator
@ -31,5 +32,6 @@ import org.teavm.platform.PlatformClass;
* @author Alexey Andreev * @author Alexey Andreev
*/ */
public interface ClassScopedMetadataGenerator { public interface ClassScopedMetadataGenerator {
Map<String, Resource> generateMetadata(MetadataGeneratorContext context, MethodReference method); Map<String, Resource> generateMetadata(MetadataGeneratorContext context, Collection<? extends String> classNames,
MethodReference method);
} }

View File

@ -17,9 +17,10 @@ package org.teavm.platform.metadata;
import java.util.Properties; import java.util.Properties;
import org.teavm.common.ServiceRepository; import org.teavm.common.ServiceRepository;
import org.teavm.model.ClassReaderSource;
import org.teavm.model.FieldReference; import org.teavm.model.FieldReference;
import org.teavm.model.ListableClassReaderSource;
import org.teavm.platform.Platform; import org.teavm.platform.Platform;
import org.teavm.platform.plugin.ResourceTypeDescriptor;
import org.teavm.vm.TeaVM; import org.teavm.vm.TeaVM;
/** /**
@ -34,7 +35,7 @@ public interface MetadataGeneratorContext extends ServiceRepository {
* *
* @return class source. * @return class source.
*/ */
ListableClassReaderSource getClassSource(); ClassReaderSource getClassSource();
/** /**
* Gets the class loader that is used by the compiler. * Gets the class loader that is used by the compiler.
@ -89,4 +90,6 @@ public interface MetadataGeneratorContext extends ServiceRepository {
* @return a new resource. * @return a new resource.
*/ */
<T extends Resource> ResourceMap<T> createResourceMap(); <T extends Resource> ResourceMap<T> createResourceMap();
ResourceTypeDescriptor getTypeDescriptor(Class<? extends Resource> type);
} }

View File

@ -34,7 +34,11 @@ class BuildTimeResourceProxyBuilder {
} }
public BuildTimeResourceProxy buildProxy(Class<?> iface) { public BuildTimeResourceProxy buildProxy(Class<?> iface) {
return factories.computeIfAbsent(iface, k -> createFactory(iface)).create(); return getProxyFactory(iface).create();
}
public BuildTimeResourceProxyFactory getProxyFactory(Class<?> iface) {
return factories.computeIfAbsent(iface, k -> createFactory(iface));
} }
private BuildTimeResourceProxyFactory createFactory(Class<?> iface) { private BuildTimeResourceProxyFactory createFactory(Class<?> iface) {
@ -103,7 +107,7 @@ class BuildTimeResourceProxyBuilder {
} }
} }
return new BuildTimeResourceProxyFactory(methods, initialData); return new BuildTimeResourceProxyFactory(methods, initialData, descriptor);
} }
private int getPropertyIndex(String propertyName) { private int getPropertyIndex(String propertyName) {

View File

@ -16,16 +16,18 @@
package org.teavm.platform.plugin; package org.teavm.platform.plugin;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map; import java.util.Map;
class BuildTimeResourceProxyFactory { class BuildTimeResourceProxyFactory {
private Map<Method, BuildTimeResourceMethod> methods = new HashMap<>(); private Map<Method, BuildTimeResourceMethod> methods;
private Object[] initialData; private Object[] initialData;
ResourceTypeDescriptor typeDescriptor;
public BuildTimeResourceProxyFactory(Map<Method, BuildTimeResourceMethod> methods, Object[] initialData) { public BuildTimeResourceProxyFactory(Map<Method, BuildTimeResourceMethod> methods, Object[] initialData,
ResourceTypeDescriptor typeDescriptor) {
this.methods = methods; this.methods = methods;
this.initialData = initialData; this.initialData = initialData;
this.typeDescriptor = typeDescriptor;
} }
BuildTimeResourceProxy create() { BuildTimeResourceProxy create() {

View File

@ -81,7 +81,8 @@ public class ClassScopedMetadataProviderNativeGenerator implements Generator {
DefaultMetadataGeneratorContext metadataContext = new DefaultMetadataGeneratorContext(context.getClassSource(), DefaultMetadataGeneratorContext metadataContext = new DefaultMetadataGeneratorContext(context.getClassSource(),
context.getClassLoader(), context.getProperties(), context); context.getClassLoader(), context.getProperties(), context);
Map<String, Resource> resourceMap = generator.generateMetadata(metadataContext, methodRef); Map<String, Resource> resourceMap = generator.generateMetadata(metadataContext,
context.getClassSource().getClassNames(), methodRef);
writer.append("var p").ws().append("=").ws().append("\"" + RenderingUtil.escapeString("$$res_" writer.append("var p").ws().append("=").ws().append("\"" + RenderingUtil.escapeString("$$res_"
+ writer.getNaming().getFullNameFor(methodRef)) + "\"").append(";").softNewLine(); + writer.getNaming().getFullNameFor(methodRef)) + "\"").append(";").softNewLine();
for (Map.Entry<String, Resource> entry : resourceMap.entrySet()) { for (Map.Entry<String, Resource> entry : resourceMap.entrySet()) {

View File

@ -18,18 +18,23 @@ package org.teavm.platform.plugin;
import java.lang.reflect.Proxy; import java.lang.reflect.Proxy;
import java.util.Properties; import java.util.Properties;
import org.teavm.common.ServiceRepository; import org.teavm.common.ServiceRepository;
import org.teavm.model.ClassReaderSource;
import org.teavm.model.FieldReference; import org.teavm.model.FieldReference;
import org.teavm.model.ListableClassReaderSource; import org.teavm.platform.metadata.ClassResource;
import org.teavm.platform.metadata.*; import org.teavm.platform.metadata.MetadataGeneratorContext;
import org.teavm.platform.metadata.Resource;
import org.teavm.platform.metadata.ResourceArray;
import org.teavm.platform.metadata.ResourceMap;
import org.teavm.platform.metadata.StaticFieldResource;
class DefaultMetadataGeneratorContext implements MetadataGeneratorContext { class DefaultMetadataGeneratorContext implements MetadataGeneratorContext {
private ListableClassReaderSource classSource; private ClassReaderSource classSource;
private ClassLoader classLoader; private ClassLoader classLoader;
private Properties properties; private Properties properties;
private BuildTimeResourceProxyBuilder proxyBuilder = new BuildTimeResourceProxyBuilder(); private BuildTimeResourceProxyBuilder proxyBuilder = new BuildTimeResourceProxyBuilder();
private ServiceRepository services; private ServiceRepository services;
DefaultMetadataGeneratorContext(ListableClassReaderSource classSource, ClassLoader classLoader, DefaultMetadataGeneratorContext(ClassReaderSource classSource, ClassLoader classLoader,
Properties properties, ServiceRepository services) { Properties properties, ServiceRepository services) {
this.classSource = classSource; this.classSource = classSource;
this.classLoader = classLoader; this.classLoader = classLoader;
@ -38,7 +43,7 @@ class DefaultMetadataGeneratorContext implements MetadataGeneratorContext {
} }
@Override @Override
public ListableClassReaderSource getClassSource() { public ClassReaderSource getClassSource() {
return classSource; return classSource;
} }
@ -59,6 +64,11 @@ class DefaultMetadataGeneratorContext implements MetadataGeneratorContext {
proxyBuilder.buildProxy(resourceType))); proxyBuilder.buildProxy(resourceType)));
} }
@Override
public ResourceTypeDescriptor getTypeDescriptor(Class<? extends Resource> type) {
return proxyBuilder.getProxyFactory(type).typeDescriptor;
}
@Override @Override
public <T extends Resource> ResourceArray<T> createResourceArray() { public <T extends Resource> ResourceArray<T> createResourceArray() {
return new BuildTimeResourceArray<>(); return new BuildTimeResourceArray<>();

View File

@ -0,0 +1,177 @@
/*
* 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.platform.plugin;
import java.util.HashSet;
import java.util.Properties;
import java.util.Set;
import org.teavm.ast.InvocationExpr;
import org.teavm.backend.c.generate.CodeWriter;
import org.teavm.backend.c.intrinsic.Intrinsic;
import org.teavm.backend.c.intrinsic.IntrinsicContext;
import org.teavm.common.ServiceRepository;
import org.teavm.model.CallLocation;
import org.teavm.model.ClassReaderSource;
import org.teavm.model.MethodReader;
import org.teavm.model.MethodReference;
import org.teavm.platform.metadata.MetadataGenerator;
import org.teavm.platform.metadata.MetadataProvider;
import org.teavm.platform.metadata.Resource;
public class MetadataCIntrinsic implements Intrinsic {
private ClassReaderSource classSource;
private ClassLoader classLoader;
private Set<String> writtenStructures = new HashSet<>();
private Set<MethodReference> writtenInitializers = new HashSet<>();
private CodeWriter structuresWriter;
private CodeWriter staticFieldInitWriter;
private DefaultMetadataGeneratorContext metadataContext;
public MetadataCIntrinsic(ClassReaderSource classSource, ClassLoader classLoader,
ServiceRepository services, Properties properties, CodeWriter structuresWriter,
CodeWriter staticFieldInitWriter) {
this.classSource = classSource;
this.classLoader = classLoader;
this.structuresWriter = structuresWriter;
this.staticFieldInitWriter = staticFieldInitWriter;
metadataContext = new DefaultMetadataGeneratorContext(classSource, classLoader, properties, services);
}
@Override
public boolean canHandle(MethodReference methodReference) {
MethodReader method = classSource.resolve(methodReference);
if (method == null) {
return false;
}
return method.getAnnotations().get(MetadataProvider.class.getName()) != null;
}
@Override
public void apply(IntrinsicContext context, InvocationExpr invocation) {
writeInitializer(context, invocation);
context.writer().print(context.names().forMethod(invocation.getMethod()));
}
private void writeInitializer(IntrinsicContext context, InvocationExpr invocation) {
MethodReference methodReference = invocation.getMethod();
if (!writtenInitializers.add(methodReference)) {
return;
}
MethodReader method = classSource.resolve(methodReference);
MetadataGenerator generator = MetadataUtils.createMetadataGenerator(classLoader, method,
new CallLocation(invocation.getMethod()), context.getDiagnotics());
String variableName = context.names().forMethod(methodReference);
staticFieldInitWriter.print("static ").printType(method.getResultType()).print(" ")
.print(variableName).print(" = ");
if (generator == null) {
staticFieldInitWriter.print("NULL");
} else {
Resource resource = generator.generateMetadata(metadataContext, invocation.getMethod());
writeValue(context, resource);
}
staticFieldInitWriter.println(";");
}
private void writeValue(IntrinsicContext context, Object value) {
if (value instanceof String) {
int stringIndex = context.getStringPool().getStringIndex((String) value);
staticFieldInitWriter.print("(stringPool + " + stringIndex + ")");
} else if (value instanceof ResourceTypeDescriptorProvider && value instanceof Resource) {
writeResource(context, (ResourceTypeDescriptorProvider) value);
} else {
throw new IllegalArgumentException("Don't know how to write resource: " + value);
}
}
private void writeResource(IntrinsicContext context, ResourceTypeDescriptorProvider resourceType) {
writeResourceStructure(context, resourceType.getDescriptor());
String structureName = context.names().forClass(resourceType.getDescriptor().getRootInterface().getName());
Object[] propertyValues = resourceType.getValues();
staticFieldInitWriter.print("&(" + structureName + ") {").indent();
boolean first = true;
for (String propertyName : resourceType.getDescriptor().getPropertyTypes().keySet()) {
if (!first) {
staticFieldInitWriter.print(",");
}
first = false;
staticFieldInitWriter.println().print(".").print(propertyName).print(" = ");
int index = resourceType.getPropertyIndex(propertyName);
Object propertyValue = propertyValues[index];
writeValue(context, propertyValue);
}
staticFieldInitWriter.println().outdent().print("}");
}
private void writeResourceStructure(IntrinsicContext context, ResourceTypeDescriptor structure) {
String className = structure.getRootInterface().getName();
if (!writtenStructures.add(className)) {
return;
}
for (Class<?> propertyType : structure.getPropertyTypes().values()) {
if (Resource.class.isAssignableFrom(propertyType)) {
ResourceTypeDescriptor propertyStructure = metadataContext.getTypeDescriptor(
propertyType.asSubclass(Resource.class));
writeResourceStructure(context, propertyStructure);
}
}
String structureName = context.names().forClass(className);
structuresWriter.println("typedef struct " + structureName + " {").indent();
for (String propertyName : structure.getPropertyTypes().keySet()) {
Class<?> propertyType = structure.getPropertyTypes().get(propertyName);
structuresWriter.println(typeToString(context, propertyType) + " " + propertyName + ";");
}
structuresWriter.outdent().println("} " + structureName + ";");
}
private String typeToString(IntrinsicContext context, Class<?> cls) {
if (cls == boolean.class || cls == byte.class) {
return "int8_t";
} else if (cls == short.class || cls == char.class) {
return "int16_t";
} else if (cls == int.class) {
return "int32_t";
} else if (cls == float.class) {
return "float";
} else if (cls == long.class) {
return "int64_t";
} else if (cls == double.class) {
return "double";
} else if (Resource.class.isAssignableFrom(cls)) {
return "&" + context.names().forClass(cls.getName());
} else if (cls == String.class) {
return "JavaObject*";
} else {
throw new IllegalArgumentException("Don't know how to write resource type " + cls);
}
}
static class MethodContext {
String baseName;
int suffix;
MethodContext(String baseName) {
this.baseName = baseName;
}
}
}

View File

@ -16,6 +16,9 @@
package org.teavm.platform.plugin; package org.teavm.platform.plugin;
import org.teavm.ast.InvocationExpr; import org.teavm.ast.InvocationExpr;
import org.teavm.backend.c.TeaVMCHost;
import org.teavm.backend.c.intrinsic.Intrinsic;
import org.teavm.backend.c.intrinsic.IntrinsicContext;
import org.teavm.backend.javascript.TeaVMJavaScriptHost; import org.teavm.backend.javascript.TeaVMJavaScriptHost;
import org.teavm.backend.wasm.TeaVMWasmHost; import org.teavm.backend.wasm.TeaVMWasmHost;
import org.teavm.backend.wasm.intrinsics.WasmIntrinsic; import org.teavm.backend.wasm.intrinsics.WasmIntrinsic;
@ -75,6 +78,25 @@ public class PlatformPlugin implements TeaVMPlugin {
} }
}); });
} }
TeaVMCHost cHost = host.getExtension(TeaVMCHost.class);
if (cHost != null) {
cHost.addIntrinsic(ctx -> new MetadataCIntrinsic(ctx.getClassSource(), ctx.getClassLoader(),
ctx.getServices(), ctx.getProperties(), ctx.getStructureCodeWriter(),
ctx.getStaticFieldsInitWriter()));
cHost.addIntrinsic(ctx -> new ResourceReadCIntrinsic(ctx.getClassSource()));
cHost.addIntrinsic(ctx -> new Intrinsic() {
@Override
public boolean canHandle(MethodReference method) {
return method.getClassName().equals(StringAmplifier.class.getName());
}
@Override
public void apply(IntrinsicContext context, InvocationExpr invocation) {
context.emit(invocation.getArguments().get(0));
}
});
}
} }
host.add(new AsyncMethodProcessor()); host.add(new AsyncMethodProcessor());

View File

@ -0,0 +1,55 @@
/*
* 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.platform.plugin;
import org.teavm.ast.InvocationExpr;
import org.teavm.backend.c.intrinsic.Intrinsic;
import org.teavm.backend.c.intrinsic.IntrinsicContext;
import org.teavm.model.ClassReaderSource;
import org.teavm.model.MethodReference;
import org.teavm.platform.metadata.Resource;
public class ResourceReadCIntrinsic implements Intrinsic {
private ClassReaderSource classSource;
public ResourceReadCIntrinsic(ClassReaderSource classSource) {
this.classSource = classSource;
}
@Override
public boolean canHandle(MethodReference method) {
return classSource.isSuperType(Resource.class.getTypeName(), method.getClassName()).orElse(false);
}
@Override
public void apply(IntrinsicContext context, InvocationExpr invocation) {
String name = invocation.getMethod().getName();
if (name.startsWith("get")) {
name = name.substring(3);
} else if (name.startsWith("is")) {
name = name.substring(2);
} else {
throw new IllegalArgumentException();
}
name = Character.toLowerCase(name.charAt(0)) + name.substring(1);
context.writer().print("FIELD(");
context.emit(invocation.getArguments().get(0));
context.writer().print(", ").print(context.names().forClass(invocation.getMethod().getClassName()));
context.writer().print(", ").print(name).print(")");
}
}

View File

@ -16,11 +16,13 @@
package org.teavm.platform.plugin; package org.teavm.platform.plugin;
import org.teavm.dependency.PluggableDependency; import org.teavm.dependency.PluggableDependency;
import org.teavm.interop.Unmanaged;
final class StringAmplifier { final class StringAmplifier {
private StringAmplifier() { private StringAmplifier() {
} }
@PluggableDependency(StringAmplifierDependencyPlugin.class) @PluggableDependency(StringAmplifierDependencyPlugin.class)
@Unmanaged
static native String amplify(String string); static native String amplify(String string);
} }