mirror of
https://github.com/konsoletyper/teavm.git
synced 2024-11-21 01:00:54 +08:00
C: implement ServiceLoader
This commit is contained in:
parent
4a62b58f82
commit
73bd139b7e
@ -67,15 +67,22 @@ public class JCLPlugin implements TeaVMPlugin {
|
||||
host.add(new ObfuscationHacks());
|
||||
|
||||
if (!isBootstrap()) {
|
||||
ServiceLoaderSupport serviceLoaderSupp = new ServiceLoaderSupport(host.getClassLoader());
|
||||
host.add(serviceLoaderSupp);
|
||||
ServiceLoaderSupport serviceLoaderSupport = new ServiceLoaderSupport(host.getClassLoader());
|
||||
host.add(serviceLoaderSupport);
|
||||
host.registerService(ServiceLoaderInformation.class, serviceLoaderSupport);
|
||||
MethodReference loadServicesMethod = new MethodReference(ServiceLoader.class, "loadServices",
|
||||
PlatformClass.class, Object[].class);
|
||||
|
||||
TeaVMJavaScriptHost jsExtension = host.getExtension(TeaVMJavaScriptHost.class);
|
||||
if (jsExtension != null) {
|
||||
jsExtension.add(loadServicesMethod, serviceLoaderSupp);
|
||||
jsExtension.add(loadServicesMethod, new ServiceLoaderJSSupport());
|
||||
jsExtension.addVirtualMethods(new AnnotationVirtualMethods());
|
||||
}
|
||||
|
||||
TeaVMCHost cHost = host.getExtension(TeaVMCHost.class);
|
||||
if (cHost != null) {
|
||||
cHost.addGenerator(new ServiceLoaderCSupport());
|
||||
}
|
||||
}
|
||||
|
||||
if (!isBootstrap()) {
|
||||
|
@ -0,0 +1,150 @@
|
||||
/*
|
||||
* Copyright 2021 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.classlib.impl;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.ServiceLoader;
|
||||
import org.teavm.backend.c.generate.CodeWriter;
|
||||
import org.teavm.backend.c.generators.Generator;
|
||||
import org.teavm.backend.c.generators.GeneratorContext;
|
||||
import org.teavm.backend.c.generators.GeneratorFactory;
|
||||
import org.teavm.backend.c.generators.GeneratorFactoryContext;
|
||||
import org.teavm.backend.lowlevel.generate.NameProvider;
|
||||
import org.teavm.interop.Address;
|
||||
import org.teavm.model.MethodDescriptor;
|
||||
import org.teavm.model.MethodReference;
|
||||
import org.teavm.model.ValueType;
|
||||
import org.teavm.model.lowlevel.CallSiteDescriptor;
|
||||
import org.teavm.model.lowlevel.CallSiteLocation;
|
||||
import org.teavm.model.lowlevel.ExceptionHandlerDescriptor;
|
||||
import org.teavm.runtime.Allocator;
|
||||
import org.teavm.runtime.RuntimeClass;
|
||||
|
||||
public class ServiceLoaderCSupport implements GeneratorFactory {
|
||||
static final MethodReference ALLOC_ARRAY_METHOD = new MethodReference(Allocator.class,
|
||||
"allocateArray", RuntimeClass.class, int.class, Address.class);
|
||||
static final MethodReference ALLOC_METHOD = new MethodReference(Allocator.class,
|
||||
"allocate", RuntimeClass.class, Address.class);
|
||||
static final MethodDescriptor INIT_METHOD = new MethodDescriptor("<init>", ValueType.VOID);
|
||||
|
||||
@Override
|
||||
public Generator createGenerator(GeneratorFactoryContext context) {
|
||||
return new ServiceLoaderIntrinsic(context.getServices().getService(ServiceLoaderInformation.class));
|
||||
}
|
||||
|
||||
static class ServiceLoaderIntrinsic implements Generator {
|
||||
private ServiceLoaderInformation information;
|
||||
|
||||
ServiceLoaderIntrinsic(ServiceLoaderInformation information) {
|
||||
this.information = information;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canHandle(MethodReference method) {
|
||||
if (!method.getClassName().equals(ServiceLoader.class.getName())) {
|
||||
return false;
|
||||
}
|
||||
return method.getName().equals("loadServices");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void generate(GeneratorContext context, MethodReference method) {
|
||||
CodeWriter writer = context.writer();
|
||||
CodeWriter beforeWriter = context.writerBefore();
|
||||
NameProvider names = context.names();
|
||||
context.includes().addInclude("<stdbool.h>");
|
||||
Collection<? extends String> serviceTypes = information.serviceTypes();
|
||||
|
||||
writer.println("static bool initialized = false;");
|
||||
writer.println("if (!initialized) {").indent();
|
||||
String methodName = names.forMethod(method);
|
||||
int index = 0;
|
||||
for (String serviceType : serviceTypes) {
|
||||
Collection<? extends String> implementations = information.serviceImplementations(serviceType);
|
||||
if (implementations.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
String staticFieldName = methodName + "_" + index++;
|
||||
context.includes().includeClass(serviceType);
|
||||
writer.print(names.forClassInstance(ValueType.object(serviceType)))
|
||||
.print(".services = (TeaVM_Services*) &").print(staticFieldName).println(";");
|
||||
|
||||
beforeWriter.print("static struct { int32_t size; ")
|
||||
.print("TeaVM_Service entries[" + implementations.size() + "]; } ")
|
||||
.print(staticFieldName + " = { .size = " + implementations.size() + ", ")
|
||||
.print(".entries = {").indent();
|
||||
boolean first = true;
|
||||
for (String implementation : implementations) {
|
||||
if (!first) {
|
||||
beforeWriter.print(",");
|
||||
}
|
||||
first = false;
|
||||
context.includes().includeClass(implementation);
|
||||
MethodReference constructor = new MethodReference(implementation, INIT_METHOD);
|
||||
context.importMethod(constructor, false);
|
||||
beforeWriter.println().print("{ .cls = (TeaVM_Class*) &")
|
||||
.print(names.forClassInstance(ValueType.object(implementation)))
|
||||
.print(", .constructor = &").print(names.forMethod(constructor))
|
||||
.print(" }");
|
||||
}
|
||||
if (!first) {
|
||||
beforeWriter.println();
|
||||
}
|
||||
beforeWriter.outdent().println("}};");
|
||||
}
|
||||
writer.outdent().println("}");
|
||||
|
||||
CallSiteLocation location = new CallSiteLocation(null, method.getClassName(), method.getName(), -1);
|
||||
CallSiteDescriptor callSite = context.createCallSite(new CallSiteLocation[] { location },
|
||||
new ExceptionHandlerDescriptor[0]);
|
||||
writer.println("TEAVM_ALLOC_STACK(INT32_C(2));");
|
||||
writer.println("TEAVM_CALL_SITE(" + callSite.getId() + ");");
|
||||
|
||||
writer.println("TeaVM_Array* result = NULL;");
|
||||
writer.print("TeaVM_Services* services = ((TeaVM_Class*) ").print(context.parameterName(1))
|
||||
.println(")->services;");
|
||||
writer.println("if (services == NULL) goto exit;");
|
||||
writer.println("TEAVM_GC_ROOT_RELEASE(0);");
|
||||
writer.println("TEAVM_GC_ROOT_RELEASE(1);");
|
||||
writer.print("result = ")
|
||||
.print(names.forMethod(ALLOC_ARRAY_METHOD)).print("(&")
|
||||
.print(names.forClassInstance(ValueType.parse(Object[].class))).print(", ")
|
||||
.println("services->size);");
|
||||
if (!context.usesLongjmp()) {
|
||||
writer.println("if (TEAVM_EXCEPTION_HANDLER != " + callSite.getId() + ") goto exit;");
|
||||
}
|
||||
|
||||
writer.println("TEAVM_GC_ROOT(0, result);");
|
||||
writer.println("void** arrayData = (void**) TEAVM_ARRAY_DATA(result, void*);");
|
||||
writer.println("for (int32_t i = 0; i < services->size; ++i) {").indent();
|
||||
writer.print("void* obj = ").print(names.forMethod(ALLOC_METHOD)).println("(services->entries[i].cls);");
|
||||
if (!context.usesLongjmp()) {
|
||||
writer.println("if (TEAVM_EXCEPTION_HANDLER != " + callSite.getId() + ") goto exit;");
|
||||
}
|
||||
writer.println("TEAVM_GC_ROOT(1, obj);");
|
||||
writer.println("services->entries[i].constructor(obj);");
|
||||
if (!context.usesLongjmp()) {
|
||||
writer.println("if (TEAVM_EXCEPTION_HANDLER != " + callSite.getId() + ") goto exit;");
|
||||
}
|
||||
writer.println("arrayData[i] = obj;");
|
||||
writer.outdent().println("}");
|
||||
|
||||
writer.println("exit: TEAVM_RELEASE_STACK;");
|
||||
writer.println("return result;");
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright 2021 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.classlib.impl;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
public interface ServiceLoaderInformation {
|
||||
Collection<? extends String> serviceTypes();
|
||||
|
||||
Collection<? extends String> serviceImplementations(String type);
|
||||
}
|
@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright 2021 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.classlib.impl;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collection;
|
||||
import org.teavm.backend.javascript.codegen.SourceWriter;
|
||||
import org.teavm.backend.javascript.spi.Generator;
|
||||
import org.teavm.backend.javascript.spi.GeneratorContext;
|
||||
import org.teavm.model.MethodDescriptor;
|
||||
import org.teavm.model.MethodReference;
|
||||
|
||||
public class ServiceLoaderJSSupport implements Generator {
|
||||
private static final MethodDescriptor INIT_METHOD = new MethodDescriptor("<init>", void.class);
|
||||
|
||||
@Override
|
||||
public void generate(GeneratorContext context, SourceWriter writer, MethodReference methodRef) throws IOException {
|
||||
ServiceLoaderInformation information = context.getService(ServiceLoaderInformation.class);
|
||||
writer.append("if (!").appendClass("java.util.ServiceLoader").append(".$$services$$) {").indent()
|
||||
.softNewLine();
|
||||
writer.appendClass("java.util.ServiceLoader").append(".$$services$$ = true;").softNewLine();
|
||||
for (String serviceType : information.serviceTypes()) {
|
||||
writer.appendClass(serviceType).append(".$$serviceList$$ = [");
|
||||
Collection<? extends String> implementations = information.serviceImplementations(serviceType);
|
||||
boolean first = true;
|
||||
for (String implName : implementations) {
|
||||
if (context.getClassSource().getClassNames().contains(implName)) {
|
||||
if (!first) {
|
||||
writer.append(", ");
|
||||
}
|
||||
first = false;
|
||||
writer.append("[").appendClass(implName).append(", ").appendMethodBody(
|
||||
new MethodReference(implName, INIT_METHOD))
|
||||
.append("]");
|
||||
}
|
||||
}
|
||||
writer.append("];").softNewLine();
|
||||
}
|
||||
writer.outdent().append("}").softNewLine();
|
||||
String param = context.getParameterName(1);
|
||||
writer.append("var cls = " + param + ";").softNewLine();
|
||||
writer.append("if (!cls.$$serviceList$$) {").indent().softNewLine();
|
||||
writer.append("return $rt_createArray($rt_objcls(), 0);").softNewLine();
|
||||
writer.outdent().append("}").softNewLine();
|
||||
writer.append("var result = $rt_createArray($rt_objcls(), cls.$$serviceList$$.length);").softNewLine();
|
||||
writer.append("for (var i = 0; i < result.data.length; ++i) {").indent().softNewLine();
|
||||
writer.append("var serviceDesc = cls.$$serviceList$$[i];").softNewLine();
|
||||
writer.append("result.data[i] = new serviceDesc[0]();").softNewLine();
|
||||
writer.append("serviceDesc[1](result.data[i]);").softNewLine();
|
||||
writer.outdent().append("}").softNewLine();
|
||||
writer.append("return result;").softNewLine();
|
||||
}
|
||||
}
|
@ -23,6 +23,8 @@ import java.lang.reflect.InvocationTargetException;
|
||||
import java.net.URL;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
@ -30,9 +32,6 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.ServiceLoader;
|
||||
import java.util.Set;
|
||||
import org.teavm.backend.javascript.codegen.SourceWriter;
|
||||
import org.teavm.backend.javascript.spi.Generator;
|
||||
import org.teavm.backend.javascript.spi.GeneratorContext;
|
||||
import org.teavm.classlib.ServiceLoaderFilter;
|
||||
import org.teavm.dependency.AbstractDependencyListener;
|
||||
import org.teavm.dependency.DependencyAgent;
|
||||
@ -42,7 +41,7 @@ import org.teavm.model.CallLocation;
|
||||
import org.teavm.model.MethodDescriptor;
|
||||
import org.teavm.model.MethodReference;
|
||||
|
||||
public class ServiceLoaderSupport extends AbstractDependencyListener implements Generator {
|
||||
public class ServiceLoaderSupport extends AbstractDependencyListener implements ServiceLoaderInformation {
|
||||
private static final MethodReference LOAD_METHOD = new MethodReference(ServiceLoader.class, "load", Class.class,
|
||||
ServiceLoader.class);
|
||||
private static final MethodDescriptor INIT_METHOD = new MethodDescriptor("<init>", void.class);
|
||||
@ -54,40 +53,17 @@ public class ServiceLoaderSupport extends AbstractDependencyListener implements
|
||||
}
|
||||
|
||||
@Override
|
||||
public void generate(GeneratorContext context, SourceWriter writer, MethodReference methodRef) throws IOException {
|
||||
writer.append("if (!").appendClass("java.util.ServiceLoader").append(".$$services$$) {").indent()
|
||||
.softNewLine();
|
||||
writer.appendClass("java.util.ServiceLoader").append(".$$services$$ = true;").softNewLine();
|
||||
for (Map.Entry<String, List<String>> entry : serviceMap.entrySet()) {
|
||||
writer.appendClass(entry.getKey()).append(".$$serviceList$$ = [");
|
||||
List<String> implementations = entry.getValue();
|
||||
boolean first = true;
|
||||
for (String implName : implementations) {
|
||||
if (context.getClassSource().getClassNames().contains(implName)) {
|
||||
if (!first) {
|
||||
writer.append(", ");
|
||||
}
|
||||
first = false;
|
||||
writer.append("[").appendClass(implName).append(", ").appendMethodBody(
|
||||
new MethodReference(implName, INIT_METHOD))
|
||||
.append("]");
|
||||
}
|
||||
}
|
||||
writer.append("];").softNewLine();
|
||||
public Collection<? extends String> serviceTypes() {
|
||||
return serviceMap.keySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<? extends String> serviceImplementations(String type) {
|
||||
Collection<? extends String> result = serviceMap.get(type);
|
||||
if (result == null) {
|
||||
result = Collections.emptyList();
|
||||
}
|
||||
writer.outdent().append("}").softNewLine();
|
||||
String param = context.getParameterName(1);
|
||||
writer.append("var cls = " + param + ";").softNewLine();
|
||||
writer.append("if (!cls.$$serviceList$$) {").indent().softNewLine();
|
||||
writer.append("return $rt_createArray($rt_objcls(), 0);").softNewLine();
|
||||
writer.outdent().append("}").softNewLine();
|
||||
writer.append("var result = $rt_createArray($rt_objcls(), cls.$$serviceList$$.length);").softNewLine();
|
||||
writer.append("for (var i = 0; i < result.data.length; ++i) {").indent().softNewLine();
|
||||
writer.append("var serviceDesc = cls.$$serviceList$$[i];").softNewLine();
|
||||
writer.append("result.data[i] = new serviceDesc[0]();").softNewLine();
|
||||
writer.append("serviceDesc[1](result.data[i]);").softNewLine();
|
||||
writer.outdent().append("}").softNewLine();
|
||||
writer.append("return result;").softNewLine();
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -18,11 +18,6 @@ package org.teavm.classlib.java.util;
|
||||
import org.teavm.classlib.java.lang.*;
|
||||
import org.teavm.platform.PlatformClass;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Alexey Andreev
|
||||
* @param <S>
|
||||
*/
|
||||
public final class TServiceLoader<S> extends TObject implements TIterable<S> {
|
||||
private Object[] services;
|
||||
|
||||
@ -50,7 +45,7 @@ public final class TServiceLoader<S> extends TObject implements TIterable<S> {
|
||||
}
|
||||
|
||||
public static <S> TServiceLoader<S> load(TClass<S> service) {
|
||||
return new TServiceLoader<>(loadServices(service.getPlatformClass()));
|
||||
return new TServiceLoader<>(doLoadServices(service.getPlatformClass()));
|
||||
}
|
||||
|
||||
public static <S> TServiceLoader<S> load(TClass<S> service, @SuppressWarnings("unused") TClassLoader loader) {
|
||||
@ -61,7 +56,15 @@ public final class TServiceLoader<S> extends TObject implements TIterable<S> {
|
||||
return load(service);
|
||||
}
|
||||
|
||||
private static native <T> T[] loadServices(PlatformClass cls);
|
||||
private static Object[] doLoadServices(PlatformClass cls) {
|
||||
Object[] result = loadServices(cls);
|
||||
if (result == null) {
|
||||
result = new Object[0];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static native Object[] loadServices(PlatformClass cls);
|
||||
|
||||
public void reload() {
|
||||
// Do nothing, services are bound at build time
|
||||
|
@ -1272,7 +1272,7 @@ public class ClassGenerator {
|
||||
codeWriter.outdent().println("}");
|
||||
|
||||
GeneratorContextImpl generatorContext = new GeneratorContextImpl(codeGenerator.getClassContext(),
|
||||
bodyWriter, writerBefore, codeWriter, includes);
|
||||
bodyWriter, writerBefore, codeWriter, includes, callSites, context.isLongjmp());
|
||||
generator.generate(generatorContext, methodRef);
|
||||
try {
|
||||
generatorContext.flush();
|
||||
|
@ -17,6 +17,7 @@ package org.teavm.backend.c.generate;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import org.teavm.backend.c.generators.GeneratorContext;
|
||||
import org.teavm.backend.lowlevel.generate.NameProvider;
|
||||
@ -24,6 +25,9 @@ import org.teavm.dependency.DependencyInfo;
|
||||
import org.teavm.diagnostics.Diagnostics;
|
||||
import org.teavm.model.ClassReaderSource;
|
||||
import org.teavm.model.MethodReference;
|
||||
import org.teavm.model.lowlevel.CallSiteDescriptor;
|
||||
import org.teavm.model.lowlevel.CallSiteLocation;
|
||||
import org.teavm.model.lowlevel.ExceptionHandlerDescriptor;
|
||||
|
||||
class GeneratorContextImpl implements GeneratorContext {
|
||||
private GenerationContext context;
|
||||
@ -33,15 +37,20 @@ class GeneratorContextImpl implements GeneratorContext {
|
||||
private CodeWriter writerAfter;
|
||||
private IncludeManager includes;
|
||||
private List<FileGeneratorImpl> fileGenerators = new ArrayList<>();
|
||||
private List<CallSiteDescriptor> callSites;
|
||||
private boolean longjmp;
|
||||
|
||||
public GeneratorContextImpl(ClassGenerationContext classContext, CodeWriter bodyWriter,
|
||||
CodeWriter writerBefore, CodeWriter writerAfter, IncludeManager includes) {
|
||||
CodeWriter writerBefore, CodeWriter writerAfter, IncludeManager includes,
|
||||
List<CallSiteDescriptor> callSites, boolean longjmp) {
|
||||
this.context = classContext.getContext();
|
||||
this.classContext = classContext;
|
||||
this.bodyWriter = bodyWriter;
|
||||
this.writerBefore = writerBefore;
|
||||
this.writerAfter = writerAfter;
|
||||
this.includes = includes;
|
||||
this.callSites = callSites;
|
||||
this.longjmp = longjmp;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -126,6 +135,20 @@ class GeneratorContextImpl implements GeneratorContext {
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CallSiteDescriptor createCallSite(CallSiteLocation[] locations,
|
||||
ExceptionHandlerDescriptor[] exceptionHandlers) {
|
||||
CallSiteDescriptor callSite = new CallSiteDescriptor(callSites.size(), locations);
|
||||
callSite.getHandlers().addAll(Arrays.asList(exceptionHandlers));
|
||||
callSites.add(callSite);
|
||||
return callSite;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean usesLongjmp() {
|
||||
return longjmp;
|
||||
}
|
||||
|
||||
void flush() throws IOException {
|
||||
for (FileGeneratorImpl generator : fileGenerators) {
|
||||
OutputFileUtil.write(generator.writer, generator.path, context.getBuildTarget());
|
||||
|
@ -24,6 +24,9 @@ import org.teavm.dependency.DependencyInfo;
|
||||
import org.teavm.diagnostics.Diagnostics;
|
||||
import org.teavm.model.ClassReaderSource;
|
||||
import org.teavm.model.MethodReference;
|
||||
import org.teavm.model.lowlevel.CallSiteDescriptor;
|
||||
import org.teavm.model.lowlevel.CallSiteLocation;
|
||||
import org.teavm.model.lowlevel.ExceptionHandlerDescriptor;
|
||||
|
||||
public interface GeneratorContext {
|
||||
CodeWriter writer();
|
||||
@ -53,4 +56,8 @@ public interface GeneratorContext {
|
||||
String escapeFileName(String name);
|
||||
|
||||
void importMethod(MethodReference method, boolean isStatic);
|
||||
|
||||
boolean usesLongjmp();
|
||||
|
||||
CallSiteDescriptor createCallSite(CallSiteLocation[] locations, ExceptionHandlerDescriptor[] exceptionHandlers);
|
||||
}
|
||||
|
55
core/src/main/java/org/teavm/common/HashUtils.java
Normal file
55
core/src/main/java/org/teavm/common/HashUtils.java
Normal file
@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright 2021 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.common;
|
||||
|
||||
public final class HashUtils {
|
||||
private HashUtils() {
|
||||
}
|
||||
|
||||
public static String[] createHashTable(String[] values) {
|
||||
int tableSize = values.length * 2;
|
||||
int maxTableSize = Math.min(values.length * 5 / 2, tableSize + 10);
|
||||
|
||||
String[] bestTable = null;
|
||||
int bestCollisionRatio = 0;
|
||||
while (tableSize <= maxTableSize) {
|
||||
String[] table = new String[tableSize];
|
||||
int maxCollisionRatio = 0;
|
||||
for (String key : values) {
|
||||
int hashCode = key.hashCode();
|
||||
int collisionRatio = 0;
|
||||
while (true) {
|
||||
int index = Integer.remainderUnsigned(hashCode++, table.length);
|
||||
if (table[index] == null) {
|
||||
table[index] = key;
|
||||
break;
|
||||
}
|
||||
collisionRatio++;
|
||||
}
|
||||
maxCollisionRatio = Math.max(maxCollisionRatio, collisionRatio);
|
||||
}
|
||||
|
||||
if (bestTable == null || bestCollisionRatio > maxCollisionRatio) {
|
||||
bestCollisionRatio = maxCollisionRatio;
|
||||
bestTable = table;
|
||||
}
|
||||
|
||||
tableSize++;
|
||||
}
|
||||
|
||||
return bestTable;
|
||||
}
|
||||
}
|
@ -122,7 +122,10 @@ public final class ExceptionHandling {
|
||||
if (stackFrame == null) {
|
||||
stackFrame = ShadowStack.getStackTop();
|
||||
while (stackFrame != null) {
|
||||
ShadowStack.setExceptionHandlerId(stackFrame, ShadowStack.getCallSiteId(stackFrame) + 1);
|
||||
int callSiteId = ShadowStack.getCallSiteId(stackFrame);
|
||||
if (callSiteId >= 0) {
|
||||
ShadowStack.setExceptionHandlerId(stackFrame, callSiteId + 1);
|
||||
}
|
||||
stackFrame = ShadowStack.getNextStackFrame(stackFrame);
|
||||
}
|
||||
printStack();
|
||||
|
@ -70,6 +70,7 @@ void teavm_initClasses() {
|
||||
int32_t classHeader = TEAVM_PACK_CLASS(teavm_classClass) | (int32_t) INT32_C(0x80000000);
|
||||
for (int i = 0; i < teavm_classReferencesCount; ++i) {
|
||||
teavm_classReferences[i]->parent.header = classHeader;
|
||||
teavm_classReferences[i]->services = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -22,6 +22,8 @@ typedef struct TeaVM_Array {
|
||||
int32_t size;
|
||||
} TeaVM_Array;
|
||||
|
||||
struct TeaVM_Services;
|
||||
|
||||
typedef struct TeaVM_Class {
|
||||
TeaVM_Object parent;
|
||||
int32_t size;
|
||||
@ -44,12 +46,23 @@ typedef struct TeaVM_Class {
|
||||
TeaVM_Object** simpleName;
|
||||
TeaVM_Object* simpleNameCache;
|
||||
TeaVM_Object* canonicalName;
|
||||
struct TeaVM_Services* services;
|
||||
#if TEAVM_HEAP_DUMP
|
||||
TeaVM_FieldDescriptors* fieldDescriptors;
|
||||
TeaVM_StaticFieldDescriptors* staticFieldDescriptors;
|
||||
#endif
|
||||
} TeaVM_Class;
|
||||
|
||||
typedef struct TeaVM_Service {
|
||||
TeaVM_Class* cls;
|
||||
void (*constructor)(void*);
|
||||
} TeaVM_Service;
|
||||
|
||||
typedef struct TeaVM_Services {
|
||||
int32_t size;
|
||||
TeaVM_Service entries[1];
|
||||
} TeaVM_Services;
|
||||
|
||||
typedef struct TeaVM_String {
|
||||
TeaVM_Object parent;
|
||||
TeaVM_Array* characters;
|
||||
|
@ -23,6 +23,7 @@ import java.util.Set;
|
||||
import org.teavm.backend.c.generate.FileGenerator;
|
||||
import org.teavm.backend.c.generators.Generator;
|
||||
import org.teavm.backend.c.generators.GeneratorContext;
|
||||
import org.teavm.common.HashUtils;
|
||||
import org.teavm.common.ServiceRepository;
|
||||
import org.teavm.model.ClassReaderSource;
|
||||
import org.teavm.model.MethodReference;
|
||||
@ -191,37 +192,7 @@ class MetadataCIntrinsic implements Generator {
|
||||
}
|
||||
|
||||
private void writeResourceMap(GeneratorContext context, ResourceMap<?> resourceMap) {
|
||||
String[] keys = resourceMap.keys();
|
||||
int tableSize = keys.length * 2;
|
||||
int maxTableSize = Math.min(keys.length * 5 / 2, tableSize + 10);
|
||||
|
||||
String[] bestTable = null;
|
||||
int bestCollisionRatio = 0;
|
||||
while (tableSize <= maxTableSize) {
|
||||
String[] table = new String[tableSize];
|
||||
int maxCollisionRatio = 0;
|
||||
for (String key : keys) {
|
||||
int hashCode = key.hashCode();
|
||||
int collisionRatio = 0;
|
||||
while (true) {
|
||||
int index = Integer.remainderUnsigned(hashCode++, table.length);
|
||||
if (table[index] == null) {
|
||||
table[index] = key;
|
||||
break;
|
||||
}
|
||||
collisionRatio++;
|
||||
}
|
||||
maxCollisionRatio = Math.max(maxCollisionRatio, collisionRatio);
|
||||
}
|
||||
|
||||
if (bestTable == null || bestCollisionRatio > maxCollisionRatio) {
|
||||
bestCollisionRatio = maxCollisionRatio;
|
||||
bestTable = table;
|
||||
}
|
||||
|
||||
tableSize++;
|
||||
}
|
||||
|
||||
String[] bestTable = HashUtils.createHashTable(resourceMap.keys());
|
||||
context.includes().includePath("resource.h");
|
||||
context.writerBefore().println("&(struct { int32_t size; TeaVM_ResourceMapEntry entries["
|
||||
+ bestTable.length + "]; }) {").indent();
|
||||
|
Loading…
Reference in New Issue
Block a user