mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 08:14:09 -08:00
wasm gc: implement backend-specific virtual table builder
This commit is contained in:
parent
eb0eb1f146
commit
1aebe51256
|
@ -118,7 +118,6 @@ public class WasmGCTarget implements TeaVMTarget {
|
|||
var declarationsGenerator = new WasmGCDeclarationsGenerator(
|
||||
module,
|
||||
classes,
|
||||
controller::isVirtual,
|
||||
controller.getClassInitializerInfo(),
|
||||
controller.getDependencyInfo(),
|
||||
controller.getDiagnostics(),
|
||||
|
|
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
* Copyright 2024 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.gc.vtable;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.teavm.model.MethodDescriptor;
|
||||
import org.teavm.model.MethodReference;
|
||||
|
||||
public class WasmGCVirtualTable {
|
||||
private WasmGCVirtualTable parent;
|
||||
private String className;
|
||||
List<WasmGCVirtualTableEntry> entries;
|
||||
MethodReference[] implementors;
|
||||
private Map<MethodDescriptor, WasmGCVirtualTableEntry> entryMap;
|
||||
|
||||
WasmGCVirtualTable(WasmGCVirtualTable parent, String className) {
|
||||
this.parent = parent;
|
||||
this.className = className;
|
||||
}
|
||||
|
||||
public WasmGCVirtualTable getParent() {
|
||||
return parent;
|
||||
}
|
||||
|
||||
public String getClassName() {
|
||||
return className;
|
||||
}
|
||||
|
||||
public List<? extends WasmGCVirtualTableEntry> getEntries() {
|
||||
return entries;
|
||||
}
|
||||
|
||||
public MethodReference implementor(WasmGCVirtualTableEntry entry) {
|
||||
return implementors[entry.getIndex()];
|
||||
}
|
||||
|
||||
public WasmGCVirtualTableEntry entry(MethodDescriptor method) {
|
||||
if (entryMap == null) {
|
||||
entryMap = new HashMap<>();
|
||||
for (var entry : entries) {
|
||||
entryMap.put(entry.getMethod(), entry);
|
||||
}
|
||||
}
|
||||
return entryMap.get(method);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,243 @@
|
|||
/*
|
||||
* Copyright 2024 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.gc.vtable;
|
||||
|
||||
import com.carrotsearch.hppc.ObjectIntHashMap;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import org.teavm.common.LCATree;
|
||||
import org.teavm.model.ClassReader;
|
||||
import org.teavm.model.ElementModifier;
|
||||
import org.teavm.model.ListableClassReaderSource;
|
||||
import org.teavm.model.MethodDescriptor;
|
||||
import org.teavm.model.MethodReference;
|
||||
|
||||
class WasmGCVirtualTableBuilder {
|
||||
ListableClassReaderSource classes;
|
||||
Collection<MethodReference> methodsAtCallSites;
|
||||
private Map<String, Set<MethodDescriptor>> groupedMethodsAtCallSites = new HashMap<>();
|
||||
private List<Table> tables = new ArrayList<>();
|
||||
private Map<String, Table> tableMap = new HashMap<>();
|
||||
private LCATree lcaTree;
|
||||
private Map<String, Table> interfaceImplementors = new HashMap<>();
|
||||
Map<String, WasmGCVirtualTable> result = new HashMap<>();
|
||||
|
||||
void build() {
|
||||
initTables();
|
||||
buildLCA();
|
||||
fillInterfaceImplementors();
|
||||
groupMethodsFromCallSites();
|
||||
fillTables();
|
||||
buildResult();
|
||||
}
|
||||
|
||||
private void initTables() {
|
||||
for (var className : classes.getClassNames()) {
|
||||
initTable(className);
|
||||
}
|
||||
}
|
||||
|
||||
private void initTable(String className) {
|
||||
var cls = classes.get(className);
|
||||
if (!cls.hasModifier(ElementModifier.INTERFACE) && !tableMap.containsKey(className)) {
|
||||
if (cls.getParent() != null) {
|
||||
initTable(cls.getParent());
|
||||
}
|
||||
var table = new Table(cls, tables.size());
|
||||
tables.add(table);
|
||||
tableMap.put(className, table);
|
||||
}
|
||||
}
|
||||
|
||||
private void buildLCA() {
|
||||
lcaTree = new LCATree(tables.size() + 1);
|
||||
for (var i = 0; i < tables.size(); i++) {
|
||||
var table = tables.get(i);
|
||||
var parentTable = table.cls.getParent() != null ? tableMap.get(table.cls.getParent()) : null;
|
||||
lcaTree.addNode(parentTable != null ? parentTable.index + 1 : 0);
|
||||
}
|
||||
}
|
||||
|
||||
private void fillInterfaceImplementors() {
|
||||
for (var className : classes.getClassNames()) {
|
||||
var cls = classes.get(className);
|
||||
if (!cls.hasModifier(ElementModifier.INTERFACE)) {
|
||||
var visited = new HashSet<String>();
|
||||
do {
|
||||
var table = tableMap.get(cls.getName());
|
||||
for (var itfName : cls.getInterfaces()) {
|
||||
addImplementorToInterface(itfName, table, visited);
|
||||
}
|
||||
cls = cls.getParent() != null ? classes.get(cls.getParent()) : null;
|
||||
} while (cls != null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void addImplementorToInterface(String interfaceName, Table newImplementor, Set<String> visited) {
|
||||
if (!visited.add(interfaceName)) {
|
||||
return;
|
||||
}
|
||||
var knownImplementor = interfaceImplementors.get(interfaceName);
|
||||
if (knownImplementor == null) {
|
||||
interfaceImplementors.put(interfaceName, newImplementor);
|
||||
} else {
|
||||
var lcaIndex = lcaTree.lcaOf(newImplementor.index + 1, knownImplementor.index + 1);
|
||||
if (lcaIndex > 0) {
|
||||
interfaceImplementors.put(interfaceName, tables.get(lcaIndex - 1));
|
||||
}
|
||||
}
|
||||
var cls = classes.get(interfaceName);
|
||||
if (cls != null) {
|
||||
for (var superInterface : cls.getInterfaces()) {
|
||||
addImplementorToInterface(superInterface, newImplementor, visited);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void groupMethodsFromCallSites() {
|
||||
for (var methodRef : methodsAtCallSites) {
|
||||
var className = mapInterface(methodRef.getClassName());
|
||||
var group = groupedMethodsAtCallSites.computeIfAbsent(className, k -> new LinkedHashSet<>());
|
||||
group.add(methodRef.getDescriptor());
|
||||
}
|
||||
}
|
||||
|
||||
private String mapInterface(String name) {
|
||||
var cls = classes.get(name);
|
||||
if (cls == null || !cls.hasModifier(ElementModifier.INTERFACE)) {
|
||||
return name;
|
||||
}
|
||||
var implementor = interfaceImplementors.get(cls.getName());
|
||||
if (implementor == null) {
|
||||
return name;
|
||||
}
|
||||
return implementor.cls.getName();
|
||||
}
|
||||
|
||||
private void fillTables() {
|
||||
for (var className : classes.getClassNames()) {
|
||||
var table = tableMap.get(className);
|
||||
if (table != null) {
|
||||
fillTable(table);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void fillTable(Table table) {
|
||||
if (table.filled) {
|
||||
return;
|
||||
}
|
||||
table.filled = true;
|
||||
var parent = table.cls.getParent() != null ? tableMap.get(table.cls.getParent()) : null;
|
||||
table.parent = parent;
|
||||
var indexes = new ObjectIntHashMap<MethodDescriptor>();
|
||||
if (parent != null) {
|
||||
fillTable(parent);
|
||||
table.entries.addAll(parent.entries);
|
||||
table.implementors.addAll(parent.implementors);
|
||||
for (var entry : table.entries) {
|
||||
indexes.put(entry.method, entry.index);
|
||||
}
|
||||
}
|
||||
|
||||
var group = groupedMethodsAtCallSites.get(table.cls.getName());
|
||||
if (group != null) {
|
||||
for (var method : group) {
|
||||
if (indexes.getOrDefault(method, -1) < 0) {
|
||||
var entry = new Entry(method, table, table.entries.size());
|
||||
table.entries.add(entry);
|
||||
indexes.put(method, entry.index);
|
||||
table.implementors.add(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (var method : table.cls.getMethods()) {
|
||||
if (!method.hasModifier(ElementModifier.STATIC) && !method.hasModifier(ElementModifier.ABSTRACT)) {
|
||||
var index = indexes.getOrDefault(method.getDescriptor(), -1);
|
||||
if (index >= 0) {
|
||||
table.implementors.set(index, method.getReference());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void buildResult() {
|
||||
for (var className : classes.getClassNames()) {
|
||||
var cls = classes.get(className);
|
||||
var table = !cls.hasModifier(ElementModifier.INTERFACE)
|
||||
? tableMap.get(className)
|
||||
: interfaceImplementors.get(className);
|
||||
if (table != null) {
|
||||
result.put(className, table.getBuildResult());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class Table {
|
||||
final ClassReader cls;
|
||||
int index;
|
||||
boolean filled;
|
||||
Table parent;
|
||||
List<Entry> entries = new ArrayList<>();
|
||||
List<MethodReference> implementors = new ArrayList<>();
|
||||
private WasmGCVirtualTable buildResult;
|
||||
|
||||
Table(ClassReader cls, int index) {
|
||||
this.cls = cls;
|
||||
this.index = index;
|
||||
}
|
||||
|
||||
WasmGCVirtualTable getBuildResult() {
|
||||
if (buildResult == null) {
|
||||
buildResult = new WasmGCVirtualTable(parent != null ? parent.getBuildResult() : null, cls.getName());
|
||||
buildResult.entries = entries.stream()
|
||||
.map(Entry::getBuildResult)
|
||||
.collect(Collectors.toList());
|
||||
buildResult.implementors = implementors.toArray(new MethodReference[0]);
|
||||
}
|
||||
return buildResult;
|
||||
}
|
||||
}
|
||||
|
||||
private static class Entry {
|
||||
MethodDescriptor method;
|
||||
Table origin;
|
||||
int index;
|
||||
private WasmGCVirtualTableEntry buildResult;
|
||||
|
||||
Entry(MethodDescriptor method, Table origin, int index) {
|
||||
this.method = method;
|
||||
this.origin = origin;
|
||||
this.index = index;
|
||||
}
|
||||
|
||||
WasmGCVirtualTableEntry getBuildResult() {
|
||||
if (buildResult == null) {
|
||||
buildResult = new WasmGCVirtualTableEntry(origin.getBuildResult(), method, index);
|
||||
}
|
||||
return buildResult;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* Copyright 2024 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.gc.vtable;
|
||||
|
||||
import org.teavm.model.MethodDescriptor;
|
||||
|
||||
public class WasmGCVirtualTableEntry {
|
||||
private WasmGCVirtualTable origin;
|
||||
private MethodDescriptor method;
|
||||
private int index;
|
||||
|
||||
WasmGCVirtualTableEntry(WasmGCVirtualTable origin, MethodDescriptor method, int index) {
|
||||
this.origin = origin;
|
||||
this.method = method;
|
||||
this.index = index;
|
||||
}
|
||||
|
||||
public WasmGCVirtualTable getOrigin() {
|
||||
return origin;
|
||||
}
|
||||
|
||||
public MethodDescriptor getMethod() {
|
||||
return method;
|
||||
}
|
||||
|
||||
public int getIndex() {
|
||||
return index;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* Copyright 2024 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.gc.vtable;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
import org.teavm.model.ListableClassReaderSource;
|
||||
import org.teavm.model.MethodReference;
|
||||
|
||||
public class WasmGCVirtualTableProvider {
|
||||
private Map<String, WasmGCVirtualTable> virtualTables;
|
||||
|
||||
public WasmGCVirtualTableProvider(ListableClassReaderSource classes,
|
||||
Collection<MethodReference> methodsAtCallSites) {
|
||||
var builder = new WasmGCVirtualTableBuilder();
|
||||
builder.classes = classes;
|
||||
builder.methodsAtCallSites = methodsAtCallSites;
|
||||
builder.build();
|
||||
virtualTables = builder.result;
|
||||
}
|
||||
|
||||
public WasmGCVirtualTable lookup(String name) {
|
||||
return virtualTables.get(name);
|
||||
}
|
||||
}
|
|
@ -16,9 +16,9 @@
|
|||
package org.teavm.backend.wasm.generate.gc;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.function.Predicate;
|
||||
import org.teavm.backend.wasm.BaseWasmFunctionRepository;
|
||||
import org.teavm.backend.wasm.WasmFunctionTypes;
|
||||
import org.teavm.backend.wasm.gc.vtable.WasmGCVirtualTableProvider;
|
||||
import org.teavm.backend.wasm.generate.WasmNameProvider;
|
||||
import org.teavm.backend.wasm.generate.gc.classes.WasmGCClassGenerator;
|
||||
import org.teavm.backend.wasm.generate.gc.classes.WasmGCClassInfoProvider;
|
||||
|
@ -33,12 +33,10 @@ import org.teavm.dependency.DependencyInfo;
|
|||
import org.teavm.diagnostics.Diagnostics;
|
||||
import org.teavm.model.ClassHierarchy;
|
||||
import org.teavm.model.ListableClassHolderSource;
|
||||
import org.teavm.model.MethodReference;
|
||||
import org.teavm.model.analysis.ClassInitializerInfo;
|
||||
import org.teavm.model.analysis.ClassMetadataRequirements;
|
||||
import org.teavm.model.classes.TagRegistry;
|
||||
import org.teavm.model.classes.VirtualTableBuilder;
|
||||
import org.teavm.model.classes.VirtualTableProvider;
|
||||
|
||||
public class WasmGCDeclarationsGenerator {
|
||||
public final ClassHierarchy hierarchy;
|
||||
|
@ -50,7 +48,6 @@ public class WasmGCDeclarationsGenerator {
|
|||
public WasmGCDeclarationsGenerator(
|
||||
WasmModule module,
|
||||
ListableClassHolderSource classes,
|
||||
Predicate<MethodReference> virtualMethods,
|
||||
ClassInitializerInfo classInitializerInfo,
|
||||
DependencyInfo dependencyInfo,
|
||||
Diagnostics diagnostics,
|
||||
|
@ -59,7 +56,7 @@ public class WasmGCDeclarationsGenerator {
|
|||
) {
|
||||
this.module = module;
|
||||
hierarchy = new ClassHierarchy(classes);
|
||||
var virtualTables = createVirtualTableProvider(classes, virtualMethods);
|
||||
var virtualTables = createVirtualTableProvider(classes);
|
||||
functionTypes = new WasmFunctionTypes(module);
|
||||
var names = new WasmNameProvider();
|
||||
methodGenerator = new WasmGCMethodGenerator(
|
||||
|
@ -133,12 +130,8 @@ public class WasmGCDeclarationsGenerator {
|
|||
}
|
||||
}
|
||||
|
||||
private static VirtualTableProvider createVirtualTableProvider(ListableClassHolderSource classes,
|
||||
Predicate<MethodReference> virtualMethods) {
|
||||
var builder = new VirtualTableBuilder(classes);
|
||||
builder.setMethodsUsedAtCallSites(VirtualTableBuilder.getMethodsUsedOnCallSites(classes, false));
|
||||
builder.setMethodCalledVirtually(virtualMethods);
|
||||
return builder.build();
|
||||
private static WasmGCVirtualTableProvider createVirtualTableProvider(ListableClassHolderSource classes) {
|
||||
return new WasmGCVirtualTableProvider(classes, VirtualTableBuilder.getMethodsUsedOnCallSites(classes, false));
|
||||
}
|
||||
|
||||
public WasmFunction dummyInitializer() {
|
||||
|
|
|
@ -20,16 +20,16 @@ import com.carrotsearch.hppc.ObjectIntMap;
|
|||
import java.util.ArrayDeque;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Queue;
|
||||
import java.util.Set;
|
||||
import java.util.function.Consumer;
|
||||
import org.teavm.backend.lowlevel.generate.NameProvider;
|
||||
import org.teavm.backend.wasm.BaseWasmFunctionRepository;
|
||||
import org.teavm.backend.wasm.WasmFunctionTypes;
|
||||
import org.teavm.backend.wasm.gc.vtable.WasmGCVirtualTable;
|
||||
import org.teavm.backend.wasm.gc.vtable.WasmGCVirtualTableProvider;
|
||||
import org.teavm.backend.wasm.generate.gc.WasmGCInitializerContributor;
|
||||
import org.teavm.backend.wasm.generate.gc.strings.WasmGCStringPool;
|
||||
import org.teavm.backend.wasm.model.WasmArray;
|
||||
|
@ -66,8 +66,6 @@ import org.teavm.model.ValueType;
|
|||
import org.teavm.model.analysis.ClassInitializerInfo;
|
||||
import org.teavm.model.analysis.ClassMetadataRequirements;
|
||||
import org.teavm.model.classes.TagRegistry;
|
||||
import org.teavm.model.classes.VirtualTable;
|
||||
import org.teavm.model.classes.VirtualTableProvider;
|
||||
import org.teavm.model.util.ReflectionUtil;
|
||||
|
||||
public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInitializerContributor {
|
||||
|
@ -82,7 +80,7 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
|
|||
private WasmFunctionTypes functionTypes;
|
||||
private TagRegistry tagRegistry;
|
||||
private ClassMetadataRequirements metadataRequirements;
|
||||
private VirtualTableProvider virtualTables;
|
||||
private WasmGCVirtualTableProvider virtualTables;
|
||||
private BaseWasmFunctionRepository functionProvider;
|
||||
private Map<ValueType, WasmGCClassInfo> classInfoMap = new LinkedHashMap<>();
|
||||
private Queue<WasmGCClassInfo> classInfoQueue = new ArrayDeque<>();
|
||||
|
@ -113,7 +111,7 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
|
|||
|
||||
public WasmGCClassGenerator(WasmModule module, ClassReaderSource classSource,
|
||||
WasmFunctionTypes functionTypes, TagRegistry tagRegistry,
|
||||
ClassMetadataRequirements metadataRequirements, VirtualTableProvider virtualTables,
|
||||
ClassMetadataRequirements metadataRequirements, WasmGCVirtualTableProvider virtualTables,
|
||||
BaseWasmFunctionRepository functionProvider, NameProvider names,
|
||||
ClassInitializerInfo classInitializerInfo) {
|
||||
this.module = module;
|
||||
|
@ -236,7 +234,7 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
|
|||
classInfo = new WasmGCClassInfo(type);
|
||||
classInfoQueue.add(classInfo);
|
||||
classInfoMap.put(type, classInfo);
|
||||
VirtualTable virtualTable = null;
|
||||
WasmGCVirtualTable virtualTable = null;
|
||||
if (!(type instanceof ValueType.Primitive)) {
|
||||
var name = type instanceof ValueType.Object
|
||||
? ((ValueType.Object) type).getClassName()
|
||||
|
@ -265,7 +263,7 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
|
|||
}
|
||||
}
|
||||
var pointerName = names.forClassInstance(type);
|
||||
classInfo.hasOwnVirtualTable = virtualTable != null && virtualTable.hasValidEntries();
|
||||
classInfo.hasOwnVirtualTable = virtualTable != null && !virtualTable.getEntries().isEmpty();
|
||||
var classStructure = classInfo.hasOwnVirtualTable
|
||||
? initRegularClassStructure(((ValueType.Object) type).getClassName())
|
||||
: standardClasses.classClass().getStructure();
|
||||
|
@ -366,8 +364,8 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
|
|||
};
|
||||
}
|
||||
|
||||
private void initRegularClass(WasmGCClassInfo classInfo, VirtualTable virtualTable, WasmStructure classStructure,
|
||||
String name) {
|
||||
private void initRegularClass(WasmGCClassInfo classInfo, WasmGCVirtualTable virtualTable,
|
||||
WasmStructure classStructure, String name) {
|
||||
var cls = classSource.get(name);
|
||||
if (classInitializerInfo.isDynamicInitializer(name)) {
|
||||
if (cls != null && cls.getMethod(CLINIT_METHOD_DESC) != null) {
|
||||
|
@ -396,39 +394,34 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
|
|||
target.add(setClassField(classInfo, classParentOffset, new WasmGetGlobal(parent.pointer)));
|
||||
}
|
||||
}
|
||||
if (virtualTable != null && virtualTable.hasValidEntries()) {
|
||||
fillVirtualTableMethods(target, classStructure, classInfo.pointer, virtualTable, virtualTable,
|
||||
new HashSet<>());
|
||||
if (virtualTable != null) {
|
||||
fillVirtualTableMethods(target, classStructure, classInfo.pointer, virtualTable);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private void fillVirtualTableMethods(List<WasmExpression> target, WasmStructure structure, WasmGlobal global,
|
||||
VirtualTable virtualTable, VirtualTable original, Set<MethodDescriptor> filled) {
|
||||
if (virtualTable.getParent() != null) {
|
||||
fillVirtualTableMethods(target, structure, global, virtualTable.getParent(), original, filled);
|
||||
}
|
||||
for (var method : virtualTable.getMethods()) {
|
||||
var entry = original.getEntry(method);
|
||||
if (entry != null && entry.getImplementor() != null && filled.add(method)
|
||||
&& !method.equals(GET_CLASS_METHOD)) {
|
||||
WasmGCVirtualTable virtualTable) {
|
||||
for (var entry : virtualTable.getEntries()) {
|
||||
var implementor = virtualTable.implementor(entry);
|
||||
if (implementor != null && !entry.getMethod().equals(GET_CLASS_METHOD)) {
|
||||
var fieldIndex = virtualTableFieldOffset + entry.getIndex();
|
||||
var expectedType = (WasmType.CompositeReference) structure.getFields().get(fieldIndex)
|
||||
.getUnpackedType();
|
||||
var expectedFunctionType = (WasmFunctionType) expectedType.composite;
|
||||
var function = functionProvider.forInstanceMethod(entry.getImplementor());
|
||||
if (!virtualTable.getClassName().equals(entry.getImplementor().getClassName())
|
||||
var function = functionProvider.forInstanceMethod(implementor);
|
||||
if (entry.getOrigin().getClassName().equals(implementor.getClassName())
|
||||
|| expectedFunctionType != function.getType()) {
|
||||
var wrapperFunction = new WasmFunction(expectedFunctionType);
|
||||
module.functions.add(wrapperFunction);
|
||||
var call = new WasmCall(function);
|
||||
var instanceParam = new WasmLocal(getClassInfo(virtualTable.getClassName()).getType());
|
||||
wrapperFunction.add(instanceParam);
|
||||
var castTarget = getClassInfo(entry.getImplementor().getClassName()).getType();
|
||||
var castTarget = getClassInfo(implementor.getClassName()).getType();
|
||||
call.getArguments().add(new WasmCast(new WasmGetLocal(instanceParam), castTarget));
|
||||
var params = new WasmLocal[method.parameterCount()];
|
||||
for (var i = 0; i < method.parameterCount(); ++i) {
|
||||
params[i] = new WasmLocal(typeMapper.mapType(method.parameterType(i)));
|
||||
var params = new WasmLocal[entry.getMethod().parameterCount()];
|
||||
for (var i = 0; i < entry.getMethod().parameterCount(); ++i) {
|
||||
params[i] = new WasmLocal(typeMapper.mapType(entry.getMethod().parameterType(i)));
|
||||
call.getArguments().add(new WasmGetLocal(params[i]));
|
||||
wrapperFunction.add(params[i]);
|
||||
}
|
||||
|
@ -462,22 +455,14 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
|
|||
fields.add(monitorField);
|
||||
}
|
||||
|
||||
private void addVirtualTableFields(WasmStructure structure, VirtualTable virtualTable) {
|
||||
if (virtualTable.getParent() != null) {
|
||||
addVirtualTableFields(structure, virtualTable.getParent());
|
||||
}
|
||||
for (var methodDesc : virtualTable.getMethods()) {
|
||||
if (methodDesc == null) {
|
||||
structure.getFields().add(new WasmField(WasmType.Reference.FUNC.asStorage()));
|
||||
} else {
|
||||
var originalVirtualTable = virtualTable.findMethodContainer(methodDesc);
|
||||
var functionType = typeMapper.getFunctionType(originalVirtualTable.getClassName(), methodDesc, false);
|
||||
private void addVirtualTableFields(WasmStructure structure, WasmGCVirtualTable virtualTable) {
|
||||
for (var entry : virtualTable.getEntries()) {
|
||||
var functionType = typeMapper.getFunctionType(entry.getOrigin().getClassName(), entry.getMethod(), false);
|
||||
var field = new WasmField(functionType.getReference().asStorage());
|
||||
field.setName(names.forVirtualMethod(methodDesc));
|
||||
field.setName(names.forVirtualMethod(entry.getMethod()));
|
||||
structure.getFields().add(field);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void initArrayClass(WasmGCClassInfo classInfo, ValueType.Array type) {
|
||||
classInfo.initializer = target -> {
|
||||
|
|
|
@ -23,6 +23,7 @@ import java.util.Map;
|
|||
import java.util.Set;
|
||||
import org.teavm.backend.wasm.BaseWasmFunctionRepository;
|
||||
import org.teavm.backend.wasm.WasmFunctionTypes;
|
||||
import org.teavm.backend.wasm.gc.vtable.WasmGCVirtualTableProvider;
|
||||
import org.teavm.backend.wasm.generate.common.methods.BaseWasmGenerationContext;
|
||||
import org.teavm.backend.wasm.generate.gc.classes.WasmGCClassInfoProvider;
|
||||
import org.teavm.backend.wasm.generate.gc.classes.WasmGCStandardClasses;
|
||||
|
@ -40,14 +41,13 @@ import org.teavm.model.ClassReaderSource;
|
|||
import org.teavm.model.ElementModifier;
|
||||
import org.teavm.model.ListableClassReaderSource;
|
||||
import org.teavm.model.MethodReference;
|
||||
import org.teavm.model.classes.VirtualTableProvider;
|
||||
|
||||
public class WasmGCGenerationContext implements BaseWasmGenerationContext {
|
||||
private WasmModule module;
|
||||
private WasmGCClassInfoProvider classInfoProvider;
|
||||
private WasmGCStandardClasses standardClasses;
|
||||
private WasmGCStringProvider strings;
|
||||
private VirtualTableProvider virtualTables;
|
||||
private WasmGCVirtualTableProvider virtualTables;
|
||||
private WasmGCTypeMapper typeMapper;
|
||||
private WasmFunctionTypes functionTypes;
|
||||
private ListableClassReaderSource classes;
|
||||
|
@ -63,7 +63,7 @@ public class WasmGCGenerationContext implements BaseWasmGenerationContext {
|
|||
private WasmTag exceptionTag;
|
||||
private Map<String, Set<String>> interfaceImplementors;
|
||||
|
||||
public WasmGCGenerationContext(WasmModule module, VirtualTableProvider virtualTables,
|
||||
public WasmGCGenerationContext(WasmModule module, WasmGCVirtualTableProvider virtualTables,
|
||||
WasmGCTypeMapper typeMapper, WasmFunctionTypes functionTypes, ListableClassReaderSource classes,
|
||||
ClassHierarchy hierarchy, BaseWasmFunctionRepository functions,
|
||||
WasmGCSupertypeFunctionProvider supertypeFunctions, WasmGCClassInfoProvider classInfoProvider,
|
||||
|
@ -96,7 +96,7 @@ public class WasmGCGenerationContext implements BaseWasmGenerationContext {
|
|||
return strings;
|
||||
}
|
||||
|
||||
public VirtualTableProvider virtualTables() {
|
||||
public WasmGCVirtualTableProvider virtualTables() {
|
||||
return virtualTables;
|
||||
}
|
||||
|
||||
|
|
|
@ -62,13 +62,10 @@ import org.teavm.backend.wasm.model.expression.WasmStructSet;
|
|||
import org.teavm.backend.wasm.model.expression.WasmThrow;
|
||||
import org.teavm.backend.wasm.model.expression.WasmUnreachable;
|
||||
import org.teavm.model.ClassHierarchy;
|
||||
import org.teavm.model.ElementModifier;
|
||||
import org.teavm.model.FieldReference;
|
||||
import org.teavm.model.MethodDescriptor;
|
||||
import org.teavm.model.MethodReference;
|
||||
import org.teavm.model.TextLocation;
|
||||
import org.teavm.model.ValueType;
|
||||
import org.teavm.model.classes.VirtualTable;
|
||||
|
||||
public class WasmGCGenerationVisitor extends BaseWasmGenerationVisitor {
|
||||
private WasmGCGenerationContext context;
|
||||
|
@ -259,26 +256,18 @@ public class WasmGCGenerationVisitor extends BaseWasmGenerationVisitor {
|
|||
protected WasmExpression generateVirtualCall(WasmLocal instance, MethodReference method,
|
||||
List<WasmExpression> arguments) {
|
||||
var vtable = context.virtualTables().lookup(method.getClassName());
|
||||
if (vtable != null) {
|
||||
var cls = context.classes().get(method.getClassName());
|
||||
assert cls != null : "Virtual table can't be generated for absent class";
|
||||
if (cls.hasModifier(ElementModifier.INTERFACE)) {
|
||||
vtable = pickVirtualTableForInterfaceCall(vtable, method.getDescriptor());
|
||||
}
|
||||
vtable = vtable.findMethodContainer(method.getDescriptor());
|
||||
}
|
||||
if (vtable == null) {
|
||||
return new WasmUnreachable();
|
||||
}
|
||||
|
||||
int vtableIndex = vtable.getMethods().indexOf(method.getDescriptor());
|
||||
if (vtable.getParent() != null) {
|
||||
vtableIndex += vtable.getParent().size();
|
||||
var entry = vtable.entry(method.getDescriptor());
|
||||
if (entry == null) {
|
||||
return new WasmUnreachable();
|
||||
}
|
||||
|
||||
WasmExpression classRef = new WasmStructGet(context.standardClasses().objectClass().getStructure(),
|
||||
new WasmGetLocal(instance), WasmGCClassInfoProvider.CLASS_FIELD_OFFSET);
|
||||
var index = context.classInfoProvider().getVirtualMethodsOffset() + vtableIndex;
|
||||
var index = context.classInfoProvider().getVirtualMethodsOffset() + entry.getIndex();
|
||||
var expectedInstanceClassInfo = context.classInfoProvider().getClassInfo(vtable.getClassName());
|
||||
var vtableStruct = expectedInstanceClassInfo.getVirtualTableStructure();
|
||||
classRef = new WasmCast(classRef, vtableStruct.getReference());
|
||||
|
@ -298,20 +287,6 @@ public class WasmGCGenerationVisitor extends BaseWasmGenerationVisitor {
|
|||
return invoke;
|
||||
}
|
||||
|
||||
private VirtualTable pickVirtualTableForInterfaceCall(VirtualTable virtualTable, MethodDescriptor descriptor) {
|
||||
var implementors = context.getInterfaceImplementors(virtualTable.getClassName());
|
||||
for (var implementor : implementors) {
|
||||
var implementorVtable = context.virtualTables().lookup(implementor);
|
||||
if (implementorVtable != null && implementorVtable.hasMethod(descriptor)) {
|
||||
while (implementorVtable.getParent() != null && implementorVtable.getParent().hasMethod(descriptor)) {
|
||||
implementorVtable = implementorVtable.getParent();
|
||||
}
|
||||
return implementorVtable;
|
||||
}
|
||||
}
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void allocateObject(String className, TextLocation location, WasmLocal local,
|
||||
List<WasmExpression> target) {
|
||||
|
|
|
@ -26,6 +26,7 @@ import org.teavm.backend.lowlevel.generate.NameProvider;
|
|||
import org.teavm.backend.wasm.BaseWasmFunctionRepository;
|
||||
import org.teavm.backend.wasm.WasmFunctionTypes;
|
||||
import org.teavm.backend.wasm.gc.WasmGCVariableCategoryProvider;
|
||||
import org.teavm.backend.wasm.gc.vtable.WasmGCVirtualTableProvider;
|
||||
import org.teavm.backend.wasm.generate.gc.classes.WasmGCClassInfoProvider;
|
||||
import org.teavm.backend.wasm.generate.gc.classes.WasmGCStandardClasses;
|
||||
import org.teavm.backend.wasm.generate.gc.classes.WasmGCSupertypeFunctionProvider;
|
||||
|
@ -51,14 +52,13 @@ import org.teavm.model.MethodReader;
|
|||
import org.teavm.model.MethodReference;
|
||||
import org.teavm.model.ValueType;
|
||||
import org.teavm.model.analysis.ClassInitializerInfo;
|
||||
import org.teavm.model.classes.VirtualTableProvider;
|
||||
import org.teavm.model.util.RegisterAllocator;
|
||||
|
||||
public class WasmGCMethodGenerator implements BaseWasmFunctionRepository {
|
||||
private WasmModule module;
|
||||
private ClassHierarchy hierarchy;
|
||||
private ListableClassHolderSource classes;
|
||||
private VirtualTableProvider virtualTables;
|
||||
private WasmGCVirtualTableProvider virtualTables;
|
||||
private ClassInitializerInfo classInitInfo;
|
||||
private WasmFunctionTypes functionTypes;
|
||||
private WasmGCSupertypeFunctionProvider supertypeFunctions;
|
||||
|
@ -82,7 +82,7 @@ public class WasmGCMethodGenerator implements BaseWasmFunctionRepository {
|
|||
WasmModule module,
|
||||
ClassHierarchy hierarchy,
|
||||
ListableClassHolderSource classes,
|
||||
VirtualTableProvider virtualTables,
|
||||
WasmGCVirtualTableProvider virtualTables,
|
||||
ClassInitializerInfo classInitInfo,
|
||||
WasmFunctionTypes functionTypes,
|
||||
NameProvider names,
|
||||
|
|
|
@ -25,7 +25,7 @@ public class LCATree {
|
|||
pathsToRoot = new int[capacity][];
|
||||
sz = 1;
|
||||
depths[0] = 0;
|
||||
pathsToRoot[0] = new int[0];
|
||||
pathsToRoot[0] = new int[] { 0 };
|
||||
}
|
||||
|
||||
public int size() {
|
||||
|
|
|
@ -15,11 +15,21 @@
|
|||
*/
|
||||
package org.teavm.junit;
|
||||
|
||||
import org.teavm.classlib.impl.console.JSStdoutPrintStream;
|
||||
|
||||
final class TestWasmGCEntryPoint {
|
||||
private TestWasmGCEntryPoint() {
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Throwable {
|
||||
try {
|
||||
TestEntryPoint.run(args.length > 0 ? args[0] : null);
|
||||
new JSStdoutPrintStream().println("SUCCESS");
|
||||
} catch (Throwable e) {
|
||||
var out = new JSStdoutPrintStream();
|
||||
e.printStackTrace(out);
|
||||
out.println("FAILURE");
|
||||
}
|
||||
TestEntryPoint.run(args.length > 0 ? args[0] : null);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user