Don't report compile-0time error when there's possible way to reach suspension point. Generate runtime error instead.

This commit is contained in:
Alexey Andreev 2019-06-22 23:30:05 +03:00
parent c28d9ef68d
commit 62b3c68a5b
8 changed files with 7 additions and 78 deletions

View File

@ -25,7 +25,6 @@ import org.teavm.interop.NoSideEffects;
import org.teavm.interop.Rename; import org.teavm.interop.Rename;
import org.teavm.interop.Structure; import org.teavm.interop.Structure;
import org.teavm.interop.Superclass; import org.teavm.interop.Superclass;
import org.teavm.interop.Sync;
import org.teavm.interop.Unmanaged; import org.teavm.interop.Unmanaged;
import org.teavm.jso.browser.TimerHandler; import org.teavm.jso.browser.TimerHandler;
import org.teavm.platform.Platform; import org.teavm.platform.Platform;
@ -141,12 +140,10 @@ public class TObject {
}); });
} }
@Sync
static void monitorExit(TObject o) { static void monitorExit(TObject o) {
monitorExit(o, 1); monitorExit(o, 1);
} }
@Sync
static void monitorExit(TObject o, int count) { static void monitorExit(TObject o, int count) {
if (o.isEmptyMonitor() || o.monitor.owner != TThread.currentThread()) { if (o.isEmptyMonitor() || o.monitor.owner != TThread.currentThread()) {
throw new TIllegalMonitorStateException(); throw new TIllegalMonitorStateException();
@ -353,7 +350,6 @@ public class TObject {
return copy; return copy;
} }
@Sync
@Rename("notify") @Rename("notify")
public final void notify0() { public final void notify0() {
if (!holdsLock(this)) { if (!holdsLock(this)) {
@ -379,7 +375,6 @@ public class TObject {
} }
} }
@Sync
@Rename("notifyAll") @Rename("notifyAll")
public final void notifyAll0() { public final void notifyAll0() {
if (!holdsLock(this)) { if (!holdsLock(this)) {

View File

@ -29,7 +29,6 @@ import org.teavm.classlib.java.util.TCollection;
import org.teavm.classlib.java.util.TIterator; import org.teavm.classlib.java.util.TIterator;
import org.teavm.interop.Async; import org.teavm.interop.Async;
import org.teavm.interop.AsyncCallback; import org.teavm.interop.AsyncCallback;
import org.teavm.interop.Sync;
import org.teavm.platform.Platform; import org.teavm.platform.Platform;
import org.teavm.platform.PlatformQueue; import org.teavm.platform.PlatformQueue;
import org.teavm.platform.PlatformRunnable; import org.teavm.platform.PlatformRunnable;
@ -392,7 +391,6 @@ public class TArrayBlockingQueue<E> extends TAbstractQueue<E> implements TBlocki
} }
} }
@Sync
private void addImpl(E e) { private void addImpl(E e) {
array[tail++] = e; array[tail++] = e;
if (tail == array.length) { if (tail == array.length) {
@ -401,7 +399,6 @@ public class TArrayBlockingQueue<E> extends TAbstractQueue<E> implements TBlocki
notifyChange(); notifyChange();
} }
@Sync
private E removeImpl() { private E removeImpl() {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
E result = (E) array[head]; E result = (E) array[head];

View File

@ -22,15 +22,11 @@ import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import org.teavm.backend.javascript.spi.InjectedBy;
import org.teavm.callgraph.CallGraph; import org.teavm.callgraph.CallGraph;
import org.teavm.callgraph.CallGraphNode; import org.teavm.callgraph.CallGraphNode;
import org.teavm.callgraph.CallSite; import org.teavm.callgraph.CallSite;
import org.teavm.diagnostics.Diagnostics; import org.teavm.diagnostics.Diagnostics;
import org.teavm.interop.Async; import org.teavm.interop.Async;
import org.teavm.interop.SuppressSyncErrors;
import org.teavm.interop.Sync;
import org.teavm.model.CallLocation;
import org.teavm.model.ClassReader; import org.teavm.model.ClassReader;
import org.teavm.model.ElementModifier; import org.teavm.model.ElementModifier;
import org.teavm.model.ListableClassReaderSource; import org.teavm.model.ListableClassReaderSource;
@ -162,20 +158,6 @@ public class AsyncMethodFinder {
if (method == null) { if (method == null) {
return; return;
} }
if (method.getAnnotations().get(Sync.class.getName()) != null
|| method.getAnnotations().get(InjectedBy.class.getName()) != null) {
if (method.getAnnotations().get(SuppressSyncErrors.class.getName()) == null) {
diagnostics.error(new CallLocation(methodRef), "Method {{m0}} is claimed to be "
+ "synchronous, but it is has invocations of asynchronous methods:"
+ stack.toString(), methodRef);
return;
} else {
diagnostics.warning(new CallLocation(methodRef), "Error as Warning because "
+ " Method {{m0}} has @SuppressSyncErrors annotation. Method {{m0}} "
+ "is claimed to be synchronous, but it is has invocations of "
+ "asynchronous methods:" + stack.toString(), methodRef);
}
}
if (!hasAsyncMethods && methodRef.getClassName().equals("java.lang.Object") if (!hasAsyncMethods && methodRef.getClassName().equals("java.lang.Object")
&& (methodRef.getName().equals("monitorEnter") || methodRef.getName().equals("monitorExit"))) { && (methodRef.getName().equals("monitorEnter") || methodRef.getName().equals("monitorExit"))) {

View File

@ -97,7 +97,11 @@ function $rt_resuming() {
return thread != null && thread.isResuming(); return thread != null && thread.isResuming();
} }
function $rt_suspend(callback) { function $rt_suspend(callback) {
return $rt_nativeThread().suspend(callback); var nativeThread = $rt_nativeThread();
if (nativeThread === null) {
throw new Error("Suspension point reached from non-threading context (perhaps, from native JS method).");
}
return nativeThread.suspend(callback);
} }
function $rt_startThread(runner, callback) { function $rt_startThread(runner, callback) {
new TeaVMThread(runner).start(callback); new TeaVMThread(runner).start(callback);

View File

@ -23,6 +23,7 @@ import java.lang.annotation.*;
*/ */
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD) @Target(ElementType.METHOD)
@Deprecated
public @interface SuppressSyncErrors { public @interface SuppressSyncErrors {
} }

View File

@ -20,5 +20,6 @@ import java.lang.annotation.*;
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD) @Target(ElementType.METHOD)
@Inherited @Inherited
@Deprecated
public @interface Sync { public @interface Sync {
} }

View File

@ -33,7 +33,6 @@ import org.teavm.backend.javascript.rendering.JSParser;
import org.teavm.cache.IncrementalDependencyRegistration; import org.teavm.cache.IncrementalDependencyRegistration;
import org.teavm.diagnostics.Diagnostics; import org.teavm.diagnostics.Diagnostics;
import org.teavm.interop.NoSideEffects; import org.teavm.interop.NoSideEffects;
import org.teavm.interop.Sync;
import org.teavm.jso.JSBody; import org.teavm.jso.JSBody;
import org.teavm.jso.JSByRef; import org.teavm.jso.JSByRef;
import org.teavm.jso.JSFunctor; import org.teavm.jso.JSFunctor;
@ -41,7 +40,6 @@ import org.teavm.jso.JSIndexer;
import org.teavm.jso.JSMethod; import org.teavm.jso.JSMethod;
import org.teavm.jso.JSObject; import org.teavm.jso.JSObject;
import org.teavm.jso.JSProperty; import org.teavm.jso.JSProperty;
import org.teavm.model.AccessLevel;
import org.teavm.model.AnnotationContainerReader; import org.teavm.model.AnnotationContainerReader;
import org.teavm.model.AnnotationHolder; import org.teavm.model.AnnotationHolder;
import org.teavm.model.AnnotationReader; import org.teavm.model.AnnotationReader;
@ -191,50 +189,6 @@ class JSClassProcessor {
.orElse(null); .orElse(null);
} }
void makeSync(ClassHolder cls) {
Set<MethodDescriptor> methods = new HashSet<>();
findInheritedMethods(cls, methods, new HashSet<>());
for (MethodHolder method : cls.getMethods()) {
if (methods.contains(method.getDescriptor())) {
makeSync(method);
}
}
}
static void makeSync(MethodHolder method) {
if (method.getAnnotations().get(Sync.class.getName()) == null) {
AnnotationHolder annot = new AnnotationHolder(Sync.class.getName());
method.getAnnotations().add(annot);
}
}
private void findInheritedMethods(ClassReader cls, Set<MethodDescriptor> methods, Set<String> visited) {
if (!visited.add(cls.getName())) {
return;
}
if (typeHelper.isJavaScriptClass(cls.getName())) {
for (MethodReader method : cls.getMethods()) {
if (!method.hasModifier(ElementModifier.STATIC) && !method.hasModifier(ElementModifier.FINAL)
&& method.getLevel() != AccessLevel.PRIVATE) {
methods.add(method.getDescriptor());
}
}
} else if (typeHelper.isJavaScriptImplementation(cls.getName())) {
if (cls.getParent() != null) {
ClassReader parentCls = classSource.get(cls.getParent());
if (parentCls != null) {
findInheritedMethods(parentCls, methods, visited);
}
}
for (String iface : cls.getInterfaces()) {
ClassReader parentCls = classSource.get(iface);
if (parentCls != null) {
findInheritedMethods(parentCls, methods, visited);
}
}
}
}
private static ValueType[] getStaticSignature(MethodReference method) { private static ValueType[] getStaticSignature(MethodReference method) {
ValueType[] signature = method.getSignature(); ValueType[] signature = method.getSignature();
ValueType[] staticSignature = new ValueType[signature.length + 1]; ValueType[] staticSignature = new ValueType[signature.length + 1];

View File

@ -73,9 +73,6 @@ class JSObjectClassTransformer implements ClassHolderTransformer {
if (typeHelper.isJavaScriptClass(cls.getName())) { if (typeHelper.isJavaScriptClass(cls.getName())) {
processor.processMemberMethods(cls); processor.processMemberMethods(cls);
} }
if (typeHelper.isJavaScriptImplementation(cls.getName())) {
processor.makeSync(cls);
}
for (MethodHolder method : cls.getMethods().toArray(new MethodHolder[0])) { for (MethodHolder method : cls.getMethods().toArray(new MethodHolder[0])) {
if (method.getProgram() != null) { if (method.getProgram() != null) {
@ -156,8 +153,6 @@ class JSObjectClassTransformer implements ClassHolderTransformer {
basicBlock.add(exit); basicBlock.add(exit);
classHolder.addMethod(exportedMethod); classHolder.addMethod(exportedMethod);
MethodHolder methodToCall = classHolder.getMethod(method);
JSClassProcessor.makeSync(methodToCall != null ? methodToCall : exportedMethod);
String publicAlias = classToExpose.methods.get(method); String publicAlias = classToExpose.methods.get(method);
AnnotationHolder annot = new AnnotationHolder(JSMethodToExpose.class.getName()); AnnotationHolder annot = new AnnotationHolder(JSMethodToExpose.class.getName());