mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 08:14:09 -08:00
wasm gc: fix support of legacy Object.cast method
This commit is contained in:
parent
551f0505c7
commit
0bd7bc6ca9
|
@ -265,7 +265,7 @@ public abstract class DependencyAnalyzer implements DependencyInfo {
|
||||||
dep.used = false;
|
dep.used = false;
|
||||||
lock(dep, false);
|
lock(dep, false);
|
||||||
deferredTasks.add(() -> {
|
deferredTasks.add(() -> {
|
||||||
classSource.getReferenceResolver().use(dep.method.getReference(), diagnostics);
|
classSource.getReferenceResolver().use(dep.method.getReference());
|
||||||
processMethod(dep);
|
processMethod(dep);
|
||||||
dep.used = true;
|
dep.used = true;
|
||||||
});
|
});
|
||||||
|
@ -476,9 +476,9 @@ public abstract class DependencyAnalyzer implements DependencyInfo {
|
||||||
abstract DependencyNode createClassValueNode(int degree, DependencyNode parent);
|
abstract DependencyNode createClassValueNode(int degree, DependencyNode parent);
|
||||||
|
|
||||||
void scheduleMethodAnalysis(MethodDependency dep) {
|
void scheduleMethodAnalysis(MethodDependency dep) {
|
||||||
classSource.getReferenceResolver().use(dep.getReference(), diagnostics);
|
classSource.getReferenceResolver().use(dep.getReference());
|
||||||
deferredTasks.add(() -> {
|
deferredTasks.add(() -> {
|
||||||
classSource.getReferenceResolver().use(dep.getReference(), diagnostics);
|
classSource.getReferenceResolver().use(dep.getReference());
|
||||||
processMethod(dep);
|
processMethod(dep);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -72,7 +72,7 @@ class DependencyClassSource implements ClassHolderSource {
|
||||||
this.diagnostics = diagnostics;
|
this.diagnostics = diagnostics;
|
||||||
innerHierarchy = new ClassHierarchy(innerSource);
|
innerHierarchy = new ClassHierarchy(innerSource);
|
||||||
this.dependencyRegistration = dependencyRegistration;
|
this.dependencyRegistration = dependencyRegistration;
|
||||||
referenceResolver = new ReferenceResolver(this, platformTags);
|
referenceResolver = new ReferenceResolver(this, platformTags, diagnostics);
|
||||||
classInitInsertion = new ClassInitInsertion(this);
|
classInitInsertion = new ClassInitInsertion(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -125,6 +125,9 @@ class DependencyClassSource implements ClassHolderSource {
|
||||||
if (method.getProgram() != null) {
|
if (method.getProgram() != null) {
|
||||||
var program = method.getProgram();
|
var program = method.getProgram();
|
||||||
method.setProgramSupplier(m -> {
|
method.setProgramSupplier(m -> {
|
||||||
|
if (disposed) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
referenceResolver.resolve(m, program);
|
referenceResolver.resolve(m, program);
|
||||||
classInitInsertion.apply(m, program);
|
classInitInsertion.apply(m, program);
|
||||||
return program;
|
return program;
|
||||||
|
|
|
@ -22,7 +22,6 @@ import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.function.Consumer;
|
|
||||||
import org.teavm.diagnostics.Diagnostics;
|
import org.teavm.diagnostics.Diagnostics;
|
||||||
import org.teavm.interop.SupportedOn;
|
import org.teavm.interop.SupportedOn;
|
||||||
import org.teavm.interop.UnsupportedOn;
|
import org.teavm.interop.UnsupportedOn;
|
||||||
|
@ -64,6 +63,7 @@ import org.teavm.model.util.ProgramUtils;
|
||||||
public class ReferenceResolver {
|
public class ReferenceResolver {
|
||||||
private ClassReaderSource classSource;
|
private ClassReaderSource classSource;
|
||||||
private MethodReference currentMethod;
|
private MethodReference currentMethod;
|
||||||
|
private Diagnostics diagnostics;
|
||||||
private Program program;
|
private Program program;
|
||||||
private boolean modified;
|
private boolean modified;
|
||||||
private List<Instruction> instructionsToAdd = new ArrayList<>();
|
private List<Instruction> instructionsToAdd = new ArrayList<>();
|
||||||
|
@ -71,20 +71,23 @@ public class ReferenceResolver {
|
||||||
private Map<String, Map<MethodDescriptor, Optional<MethodReader>>> methodCache = new HashMap<>(1000, 0.5f);
|
private Map<String, Map<MethodDescriptor, Optional<MethodReader>>> methodCache = new HashMap<>(1000, 0.5f);
|
||||||
private Set<String> platformTags = new HashSet<>();
|
private Set<String> platformTags = new HashSet<>();
|
||||||
private UnreachableBasicBlockEliminator unreachableBlockEliminator;
|
private UnreachableBasicBlockEliminator unreachableBlockEliminator;
|
||||||
private Map<MethodReference, List<Consumer<Diagnostics>>> pendingErrors = new HashMap<>();
|
private Map<MethodReference, List<Runnable>> pendingErrors = new HashMap<>();
|
||||||
|
private Set<MethodReference> usedMethods = new HashSet<>();
|
||||||
private boolean shouldStop;
|
private boolean shouldStop;
|
||||||
|
|
||||||
public ReferenceResolver(ClassReaderSource classSource, String[] platformTags) {
|
public ReferenceResolver(ClassReaderSource classSource, String[] platformTags, Diagnostics diagnostics) {
|
||||||
this.classSource = classSource;
|
this.classSource = classSource;
|
||||||
this.platformTags.addAll(List.of(platformTags));
|
this.platformTags.addAll(List.of(platformTags));
|
||||||
unreachableBlockEliminator = new UnreachableBasicBlockEliminator();
|
unreachableBlockEliminator = new UnreachableBasicBlockEliminator();
|
||||||
|
this.diagnostics = diagnostics;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void use(MethodReference method, Diagnostics diagnostics) {
|
public void use(MethodReference method) {
|
||||||
|
usedMethods.add(method);
|
||||||
var errors = pendingErrors.remove(method);
|
var errors = pendingErrors.remove(method);
|
||||||
if (errors != null) {
|
if (errors != null) {
|
||||||
for (var error : errors) {
|
for (var error : errors) {
|
||||||
error.accept(diagnostics);
|
error.run();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -394,9 +397,13 @@ public class ReferenceResolver {
|
||||||
|
|
||||||
private void reportError(TextLocation location, String message, Object param) {
|
private void reportError(TextLocation location, String message, Object param) {
|
||||||
var method = currentMethod;
|
var method = currentMethod;
|
||||||
pendingErrors.computeIfAbsent(method, k -> new ArrayList<>()).add(diagnostics ->
|
if (usedMethods.contains(method)) {
|
||||||
|
diagnostics.error(new CallLocation(method, location), message, param);
|
||||||
|
} else {
|
||||||
|
pendingErrors.computeIfAbsent(method, k -> new ArrayList<>()).add(() ->
|
||||||
diagnostics.error(new CallLocation(method, location), message, param));
|
diagnostics.error(new CallLocation(method, location), message, param));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static class FieldWrapper {
|
private static class FieldWrapper {
|
||||||
final FieldReader value;
|
final FieldReader value;
|
||||||
|
|
|
@ -20,6 +20,9 @@ TeaVM.wasm = function() {
|
||||||
let getGlobalName = function(name) {
|
let getGlobalName = function(name) {
|
||||||
return eval(name);
|
return eval(name);
|
||||||
}
|
}
|
||||||
|
let setGlobalName = function(name, value) {
|
||||||
|
new Function("value", name + " = value;")(value);
|
||||||
|
}
|
||||||
|
|
||||||
function defaults(imports) {
|
function defaults(imports) {
|
||||||
dateImports(imports);
|
dateImports(imports);
|
||||||
|
@ -146,6 +149,13 @@ TeaVM.wasm = function() {
|
||||||
function isIdentifierPart(s) {
|
function isIdentifierPart(s) {
|
||||||
return isIdentifierStart(s) || s >= '0' && s <= '9';
|
return isIdentifierStart(s) || s >= '0' && s <= '9';
|
||||||
}
|
}
|
||||||
|
function setProperty(obj, prop, value) {
|
||||||
|
if (obj === null) {
|
||||||
|
setGlobalName(prop, value);
|
||||||
|
} else {
|
||||||
|
obj[prop] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
imports.teavmJso = {
|
imports.teavmJso = {
|
||||||
emptyString: () => "",
|
emptyString: () => "",
|
||||||
stringFromCharCode: code => String.fromCharCode(code),
|
stringFromCharCode: code => String.fromCharCode(code),
|
||||||
|
@ -158,8 +168,8 @@ TeaVM.wasm = function() {
|
||||||
wrapBoolean: value => !!value,
|
wrapBoolean: value => !!value,
|
||||||
getProperty: (obj, prop) => obj !== null ? obj[prop] : getGlobalName(prop),
|
getProperty: (obj, prop) => obj !== null ? obj[prop] : getGlobalName(prop),
|
||||||
getPropertyPure: (obj, prop) => obj !== null ? obj[prop] : getGlobalName(prop),
|
getPropertyPure: (obj, prop) => obj !== null ? obj[prop] : getGlobalName(prop),
|
||||||
setProperty: (obj, prop, value) => obj[prop] = value,
|
setProperty: setProperty,
|
||||||
setPropertyPure: (obj, prop) => obj[prop] = value,
|
setPropertyPure: setProperty,
|
||||||
global: getGlobalName,
|
global: getGlobalName,
|
||||||
createClass(name) {
|
createClass(name) {
|
||||||
let fn = new Function(
|
let fn = new Function(
|
||||||
|
|
|
@ -60,6 +60,7 @@ package org.teavm.jso;
|
||||||
*/
|
*/
|
||||||
public interface JSObject {
|
public interface JSObject {
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
|
@Deprecated
|
||||||
default <T extends JSObject> T cast() {
|
default <T extends JSObject> T cast() {
|
||||||
return (T) this;
|
return (T) this;
|
||||||
}
|
}
|
||||||
|
|
|
@ -376,6 +376,9 @@ class JSObjectClassTransformer implements ClassHolderTransformer {
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isJavaScriptClass(ClassReader cls) {
|
private boolean isJavaScriptClass(ClassReader cls) {
|
||||||
|
if (typeHelper.isJavaScriptClass(cls.getName())) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
if (cls.getParent() != null && typeHelper.isJavaScriptClass(cls.getParent())) {
|
if (cls.getParent() != null && typeHelper.isJavaScriptClass(cls.getParent())) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,4 +45,7 @@ public class ClassWithConstructor implements JSObject {
|
||||||
@JSTopLevel
|
@JSTopLevel
|
||||||
@JSProperty
|
@JSProperty
|
||||||
public static native void setTopLevelProperty(String value);
|
public static native void setTopLevelProperty(String value);
|
||||||
|
|
||||||
|
@JSTopLevel
|
||||||
|
public static native JSObject createClass(boolean subclass);
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,7 +30,7 @@ import org.teavm.junit.TestPlatform;
|
||||||
|
|
||||||
@RunWith(TeaVMTestRunner.class)
|
@RunWith(TeaVMTestRunner.class)
|
||||||
@SkipJVM
|
@SkipJVM
|
||||||
@OnlyPlatform(TestPlatform.JAVASCRIPT)
|
@OnlyPlatform({TestPlatform.JAVASCRIPT, TestPlatform.WEBASSEMBLY_GC})
|
||||||
@EachTestCompiledSeparately
|
@EachTestCompiledSeparately
|
||||||
public class ImportClassTest {
|
public class ImportClassTest {
|
||||||
@Test
|
@Test
|
||||||
|
@ -75,6 +75,13 @@ public class ImportClassTest {
|
||||||
assertEquals("update2", ClassWithConstructor.getTopLevelProperty());
|
assertEquals("update2", ClassWithConstructor.getTopLevelProperty());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@AttachJavaScript("org/teavm/jso/test/classWithConstructor.js")
|
||||||
|
public void legacyCastMethod() {
|
||||||
|
SubclassWithConstructor o = ClassWithConstructor.createClass(true).cast();
|
||||||
|
assertEquals("subclass", o.baz());
|
||||||
|
}
|
||||||
|
|
||||||
@JSBody(script = "return {};")
|
@JSBody(script = "return {};")
|
||||||
private static native O create();
|
private static native O create();
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
/*
|
||||||
|
* 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.jso.test;
|
||||||
|
|
||||||
|
import org.teavm.jso.JSClass;
|
||||||
|
|
||||||
|
@JSClass
|
||||||
|
public class SubclassWithConstructor extends ClassWithConstructor {
|
||||||
|
public native String baz();
|
||||||
|
}
|
|
@ -32,6 +32,20 @@ class ClassWithConstructor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class SubclassWithConstructor extends ClassWithConstructor {
|
||||||
|
constructor(foo) {
|
||||||
|
super(foo);
|
||||||
|
}
|
||||||
|
|
||||||
|
baz() {
|
||||||
|
return "subclass";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function createClass(subclass) {
|
||||||
|
return subclass ? new SubclassWithConstructor(23) : new ClassWithConstructor(42);
|
||||||
|
}
|
||||||
|
|
||||||
function topLevelFunction() {
|
function topLevelFunction() {
|
||||||
return "top level";
|
return "top level";
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,7 +44,9 @@ window.addEventListener("message", event => {
|
||||||
|
|
||||||
case "WASM_GC": {
|
case "WASM_GC": {
|
||||||
const runtimeFile = request.file.path + "-runtime.js";
|
const runtimeFile = request.file.path + "-runtime.js";
|
||||||
appendFiles([{ path: runtimeFile, type: "regular" }], 0, () => {
|
const runtimeFileObj = { path: runtimeFile, type: "regular" };
|
||||||
|
const files = request.additionalFiles ? [...request.additionalFiles, runtimeFileObj] : [runtimeFileObj]
|
||||||
|
appendFiles(files, 0, () => {
|
||||||
launchWasmGCTest(request.file, request.argument, response => {
|
launchWasmGCTest(request.file, request.argument, response => {
|
||||||
event.source.postMessage(response, "*");
|
event.source.postMessage(response, "*");
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in New Issue
Block a user