diff --git a/classlib/src/main/java/org/teavm/classlib/impl/ServiceLoaderSupport.java b/classlib/src/main/java/org/teavm/classlib/impl/ServiceLoaderSupport.java index 92c16b3e0..44d38671e 100644 --- a/classlib/src/main/java/org/teavm/classlib/impl/ServiceLoaderSupport.java +++ b/classlib/src/main/java/org/teavm/classlib/impl/ServiceLoaderSupport.java @@ -27,6 +27,7 @@ import java.util.HashMap; import java.util.HashSet; 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; @@ -126,12 +127,14 @@ public class ServiceLoaderSupport extends AbstractDependencyListener implements } @Override - public void methodReached(final DependencyAgent agent, MethodDependency method, final CallLocation location) { + public void methodReached(DependencyAgent agent, MethodDependency method, CallLocation location) { MethodReference ref = method.getReference(); if (ref.getClassName().equals("java.util.ServiceLoader") && ref.getName().equals("loadServices")) { method.getResult().propagate(agent.getType("[Ljava/lang/Object;")); - allClassesNode.connect(method.getResult().getArrayItem()); - method.getResult().getArrayItem().addConsumer(type -> initConstructor(agent, type.getName(), location)); + DependencyNode sourceNode = agent.linkMethod(new MethodReference(ServiceLoader.class, "load", Class.class, + ServiceLoader.class), null).getVariable(1).getClassValueNode(); + sourceNode.connect(method.getResult().getArrayItem()); + sourceNode.addConsumer(type -> initConstructor(agent, type.getName(), location)); } } diff --git a/classlib/src/main/java/org/teavm/classlib/java/security/TAccessController.java b/classlib/src/main/java/org/teavm/classlib/java/security/TAccessController.java new file mode 100644 index 000000000..d2f9cc43c --- /dev/null +++ b/classlib/src/main/java/org/teavm/classlib/java/security/TAccessController.java @@ -0,0 +1,25 @@ +/* + * Copyright 2018 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.java.security; + +public final class TAccessController { + private TAccessController() { + } + + public static T doPrivileged(TPrivilegedAction action) { + return action.run(); + } +} diff --git a/classlib/src/main/java/org/teavm/classlib/java/security/TPrivilegedAction.java b/classlib/src/main/java/org/teavm/classlib/java/security/TPrivilegedAction.java new file mode 100644 index 000000000..e21adf501 --- /dev/null +++ b/classlib/src/main/java/org/teavm/classlib/java/security/TPrivilegedAction.java @@ -0,0 +1,20 @@ +/* + * Copyright 2018 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.java.security; + +public interface TPrivilegedAction { + T run(); +} diff --git a/classlib/src/main/java/org/teavm/classlib/java/util/concurrent/atomic/TAtomicInteger.java b/classlib/src/main/java/org/teavm/classlib/java/util/concurrent/atomic/TAtomicInteger.java index faed3070d..6a3690119 100644 --- a/classlib/src/main/java/org/teavm/classlib/java/util/concurrent/atomic/TAtomicInteger.java +++ b/classlib/src/main/java/org/teavm/classlib/java/util/concurrent/atomic/TAtomicInteger.java @@ -21,6 +21,7 @@ import java.util.function.IntUnaryOperator; public class TAtomicInteger extends Number implements Serializable { private int value; + private int version; public TAtomicInteger() { } @@ -35,15 +36,18 @@ public class TAtomicInteger extends Number implements Serializable { public final void set(int newValue) { value = newValue; + version++; } public final void lazySet(int newValue) { value = newValue; + version++; } public final int getAndSet(int newValue) { int result = value; value = newValue; + version++; return result; } @@ -52,6 +56,7 @@ public class TAtomicInteger extends Number implements Serializable { return false; } value = update; + version++; return true; } @@ -60,56 +65,93 @@ public class TAtomicInteger extends Number implements Serializable { return false; } value = update; + version++; return true; } public final int getAndIncrement() { + version++; return value++; } public final int getAndDecrement() { + version++; return value--; } public final int getAndAdd(int delta) { + version++; int result = value; value += delta; return result; } public final int incrementAndGet() { + version++; return ++value; } public final int decrementAndGet() { + version++; return --value; } public final int addAndGet(int delta) { + version++; value += delta; return value; } public final int getAndUpdate(IntUnaryOperator updateFunction) { - int result = value; - value = updateFunction.applyAsInt(value); + int expectedVersion; + int result; + int newValue; + do { + expectedVersion = version; + result = value; + newValue = updateFunction.applyAsInt(value); + } while (expectedVersion != version); + ++version; + value = newValue; return result; } public final int updateAndGet(IntUnaryOperator updateFunction) { - value = updateFunction.applyAsInt(value); - return value; + int expectedVersion; + int newValue; + do { + expectedVersion = version; + newValue = updateFunction.applyAsInt(value); + } while (expectedVersion != version); + ++version; + value = newValue; + return newValue; } public final int getAndAccumulate(int x, IntBinaryOperator accumulatorFunction) { - int result = value; - value = accumulatorFunction.applyAsInt(value, x); + int expectedVersion; + int newValue; + int result; + do { + expectedVersion = version; + result = value; + newValue = accumulatorFunction.applyAsInt(value, x); + } while (expectedVersion != version); + ++version; + value = newValue; return result; } public final int accumulateAndGet(int x, IntBinaryOperator accumulatorFunction) { - value = accumulatorFunction.applyAsInt(value, x); - return value; + int expectedVersion; + int newValue; + do { + expectedVersion = version; + newValue = accumulatorFunction.applyAsInt(value, x); + } while (expectedVersion != version); + ++version; + value = newValue; + return newValue; } @Override diff --git a/classlib/src/main/java/org/teavm/classlib/java/util/concurrent/atomic/TAtomicLong.java b/classlib/src/main/java/org/teavm/classlib/java/util/concurrent/atomic/TAtomicLong.java new file mode 100644 index 000000000..f0834c3a8 --- /dev/null +++ b/classlib/src/main/java/org/teavm/classlib/java/util/concurrent/atomic/TAtomicLong.java @@ -0,0 +1,181 @@ +/* + * Copyright 2018 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.java.util.concurrent.atomic; + +import java.io.Serializable; +import java.util.function.LongBinaryOperator; +import java.util.function.LongUnaryOperator; + +public class TAtomicLong extends Number implements Serializable { + private long value; + private int version; + + public TAtomicLong() { + } + + public TAtomicLong(long value) { + this.value = value; + } + + public final long get() { + return value; + } + + public final void set(long newValue) { + value = newValue; + version++; + } + + public final void lazySet(long newValue) { + value = newValue; + version++; + } + + public final long getAndSet(long newValue) { + long result = value; + value = newValue; + version++; + return result; + } + + public final boolean compareAndSet(long expect, long update) { + if (value != expect) { + return false; + } + value = update; + version++; + return true; + } + + public final boolean weakCompareAndSet(long expect, long update) { + if (value != expect) { + return false; + } + value = update; + version++; + return true; + } + + public final long getAndIncrement() { + version++; + return value++; + } + + public final long getAndDecrement() { + version++; + return value--; + } + + public final long getAndAdd(long delta) { + version++; + long result = value; + value += delta; + return result; + } + + public final long incrementAndGet() { + version++; + return ++value; + } + + public final long decrementAndGet() { + version++; + return --value; + } + + public final long addAndGet(long delta) { + version++; + value += delta; + return value; + } + + public final long getAndUpdate(LongUnaryOperator updateFunction) { + int expectedVersion; + long result; + long newValue; + do { + expectedVersion = version; + result = value; + newValue = updateFunction.applyAsLong(value); + } while (expectedVersion != version); + ++version; + value = newValue; + return result; + } + + public final long updateAndGet(LongUnaryOperator updateFunction) { + int expectedVersion; + long newValue; + do { + expectedVersion = version; + newValue = updateFunction.applyAsLong(value); + } while (expectedVersion != version); + ++version; + value = newValue; + return newValue; + } + + public final long getAndAccumulate(long x, LongBinaryOperator accumulatorFunction) { + int expectedVersion; + long newValue; + long result; + do { + expectedVersion = version; + result = value; + newValue = accumulatorFunction.applyAsLong(value, x); + } while (expectedVersion != version); + ++version; + value = newValue; + return result; + } + + public final long accumulateAndGet(long x, LongBinaryOperator accumulatorFunction) { + int expectedVersion; + long newValue; + do { + expectedVersion = version; + newValue = accumulatorFunction.applyAsLong(value, x); + } while (expectedVersion != version); + ++version; + value = newValue; + return newValue; + } + + @Override + public String toString() { + return String.valueOf(value); + } + + @Override + public int intValue() { + return (int) value; + } + + @Override + public long longValue() { + return value; + } + + @Override + public float floatValue() { + return value; + } + + @Override + public double doubleValue() { + return value; + } +} diff --git a/core/src/main/java/org/teavm/model/util/AsyncMethodFinder.java b/core/src/main/java/org/teavm/model/util/AsyncMethodFinder.java index f6668b9e5..70ed8c28b 100644 --- a/core/src/main/java/org/teavm/model/util/AsyncMethodFinder.java +++ b/core/src/main/java/org/teavm/model/util/AsyncMethodFinder.java @@ -49,6 +49,7 @@ public class AsyncMethodFinder { private CallGraph callGraph; private Diagnostics diagnostics; private ListableClassReaderSource classSource; + private boolean hasAsyncMethods; public AsyncMethodFinder(CallGraph callGraph, Diagnostics diagnostics) { this.callGraph = callGraph; @@ -65,6 +66,7 @@ public class AsyncMethodFinder { public void find(ListableClassReaderSource classSource) { this.classSource = classSource; + hasAsyncMethods = hasAsyncMethods(); for (String clsName : classSource.getClassNames()) { ClassReader cls = classSource.get(clsName); for (MethodReader method : cls.getMethods()) { @@ -76,7 +78,7 @@ public class AsyncMethodFinder { } } } - if (hasAsyncMethods()) { + if (hasAsyncMethods) { for (String clsName : classSource.getClassNames()) { ClassReader cls = classSource.get(clsName); for (MethodReader method : cls.getMethods()) { @@ -169,6 +171,11 @@ public class AsyncMethodFinder { + "asynchronous methods:" + stack.toString(), methodRef); } } + + if (!hasAsyncMethods && methodRef.getClassName().equals("java.lang.Object") + && (methodRef.getName().equals("monitorEnter") || methodRef.getName().equals("monitorExit"))) { + return; + } for (CallSite callSite : node.getCallerCallSites()) { MethodReference nextMethod = callSite.getCaller().getMethod(); add(nextMethod, new CallStack(nextMethod, stack));