mirror of
https://github.com/konsoletyper/teavm.git
synced 2024-11-21 01:00:54 +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;
|
||||
lock(dep, false);
|
||||
deferredTasks.add(() -> {
|
||||
classSource.getReferenceResolver().use(dep.method.getReference(), diagnostics);
|
||||
classSource.getReferenceResolver().use(dep.method.getReference());
|
||||
processMethod(dep);
|
||||
dep.used = true;
|
||||
});
|
||||
@ -476,9 +476,9 @@ public abstract class DependencyAnalyzer implements DependencyInfo {
|
||||
abstract DependencyNode createClassValueNode(int degree, DependencyNode parent);
|
||||
|
||||
void scheduleMethodAnalysis(MethodDependency dep) {
|
||||
classSource.getReferenceResolver().use(dep.getReference(), diagnostics);
|
||||
classSource.getReferenceResolver().use(dep.getReference());
|
||||
deferredTasks.add(() -> {
|
||||
classSource.getReferenceResolver().use(dep.getReference(), diagnostics);
|
||||
classSource.getReferenceResolver().use(dep.getReference());
|
||||
processMethod(dep);
|
||||
});
|
||||
}
|
||||
|
@ -72,7 +72,7 @@ class DependencyClassSource implements ClassHolderSource {
|
||||
this.diagnostics = diagnostics;
|
||||
innerHierarchy = new ClassHierarchy(innerSource);
|
||||
this.dependencyRegistration = dependencyRegistration;
|
||||
referenceResolver = new ReferenceResolver(this, platformTags);
|
||||
referenceResolver = new ReferenceResolver(this, platformTags, diagnostics);
|
||||
classInitInsertion = new ClassInitInsertion(this);
|
||||
}
|
||||
|
||||
@ -125,6 +125,9 @@ class DependencyClassSource implements ClassHolderSource {
|
||||
if (method.getProgram() != null) {
|
||||
var program = method.getProgram();
|
||||
method.setProgramSupplier(m -> {
|
||||
if (disposed) {
|
||||
return null;
|
||||
}
|
||||
referenceResolver.resolve(m, program);
|
||||
classInitInsertion.apply(m, program);
|
||||
return program;
|
||||
|
@ -22,7 +22,6 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.function.Consumer;
|
||||
import org.teavm.diagnostics.Diagnostics;
|
||||
import org.teavm.interop.SupportedOn;
|
||||
import org.teavm.interop.UnsupportedOn;
|
||||
@ -64,6 +63,7 @@ import org.teavm.model.util.ProgramUtils;
|
||||
public class ReferenceResolver {
|
||||
private ClassReaderSource classSource;
|
||||
private MethodReference currentMethod;
|
||||
private Diagnostics diagnostics;
|
||||
private Program program;
|
||||
private boolean modified;
|
||||
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 Set<String> platformTags = new HashSet<>();
|
||||
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;
|
||||
|
||||
public ReferenceResolver(ClassReaderSource classSource, String[] platformTags) {
|
||||
public ReferenceResolver(ClassReaderSource classSource, String[] platformTags, Diagnostics diagnostics) {
|
||||
this.classSource = classSource;
|
||||
this.platformTags.addAll(List.of(platformTags));
|
||||
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);
|
||||
if (errors != null) {
|
||||
for (var error : errors) {
|
||||
error.accept(diagnostics);
|
||||
error.run();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -394,8 +397,12 @@ public class ReferenceResolver {
|
||||
|
||||
private void reportError(TextLocation location, String message, Object param) {
|
||||
var method = currentMethod;
|
||||
pendingErrors.computeIfAbsent(method, k -> new ArrayList<>()).add(diagnostics ->
|
||||
diagnostics.error(new CallLocation(method, location), message, param));
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
private static class FieldWrapper {
|
||||
|
@ -20,6 +20,9 @@ TeaVM.wasm = function() {
|
||||
let getGlobalName = function(name) {
|
||||
return eval(name);
|
||||
}
|
||||
let setGlobalName = function(name, value) {
|
||||
new Function("value", name + " = value;")(value);
|
||||
}
|
||||
|
||||
function defaults(imports) {
|
||||
dateImports(imports);
|
||||
@ -146,6 +149,13 @@ TeaVM.wasm = function() {
|
||||
function isIdentifierPart(s) {
|
||||
return isIdentifierStart(s) || s >= '0' && s <= '9';
|
||||
}
|
||||
function setProperty(obj, prop, value) {
|
||||
if (obj === null) {
|
||||
setGlobalName(prop, value);
|
||||
} else {
|
||||
obj[prop] = value;
|
||||
}
|
||||
}
|
||||
imports.teavmJso = {
|
||||
emptyString: () => "",
|
||||
stringFromCharCode: code => String.fromCharCode(code),
|
||||
@ -158,8 +168,8 @@ TeaVM.wasm = function() {
|
||||
wrapBoolean: value => !!value,
|
||||
getProperty: (obj, prop) => obj !== null ? obj[prop] : getGlobalName(prop),
|
||||
getPropertyPure: (obj, prop) => obj !== null ? obj[prop] : getGlobalName(prop),
|
||||
setProperty: (obj, prop, value) => obj[prop] = value,
|
||||
setPropertyPure: (obj, prop) => obj[prop] = value,
|
||||
setProperty: setProperty,
|
||||
setPropertyPure: setProperty,
|
||||
global: getGlobalName,
|
||||
createClass(name) {
|
||||
let fn = new Function(
|
||||
|
@ -60,6 +60,7 @@ package org.teavm.jso;
|
||||
*/
|
||||
public interface JSObject {
|
||||
@SuppressWarnings("unchecked")
|
||||
@Deprecated
|
||||
default <T extends JSObject> T cast() {
|
||||
return (T) this;
|
||||
}
|
||||
|
@ -376,6 +376,9 @@ class JSObjectClassTransformer implements ClassHolderTransformer {
|
||||
}
|
||||
|
||||
private boolean isJavaScriptClass(ClassReader cls) {
|
||||
if (typeHelper.isJavaScriptClass(cls.getName())) {
|
||||
return true;
|
||||
}
|
||||
if (cls.getParent() != null && typeHelper.isJavaScriptClass(cls.getParent())) {
|
||||
return true;
|
||||
}
|
||||
|
@ -45,4 +45,7 @@ public class ClassWithConstructor implements JSObject {
|
||||
@JSTopLevel
|
||||
@JSProperty
|
||||
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)
|
||||
@SkipJVM
|
||||
@OnlyPlatform(TestPlatform.JAVASCRIPT)
|
||||
@OnlyPlatform({TestPlatform.JAVASCRIPT, TestPlatform.WEBASSEMBLY_GC})
|
||||
@EachTestCompiledSeparately
|
||||
public class ImportClassTest {
|
||||
@Test
|
||||
@ -75,6 +75,13 @@ public class ImportClassTest {
|
||||
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 {};")
|
||||
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() {
|
||||
return "top level";
|
||||
}
|
||||
|
@ -44,7 +44,9 @@ window.addEventListener("message", event => {
|
||||
|
||||
case "WASM_GC": {
|
||||
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 => {
|
||||
event.source.postMessage(response, "*");
|
||||
});
|
||||
|
Loading…
Reference in New Issue
Block a user