diff --git a/classlib/src/main/java/org/teavm/classlib/java/util/TCollections.java b/classlib/src/main/java/org/teavm/classlib/java/util/TCollections.java index 54ddd7625..f35c3c075 100644 --- a/classlib/src/main/java/org/teavm/classlib/java/util/TCollections.java +++ b/classlib/src/main/java/org/teavm/classlib/java/util/TCollections.java @@ -238,6 +238,7 @@ public class TCollections extends TObject { return binarySearch(list, key, naturalOrder); } + @SuppressWarnings("unchecked") private static TComparator naturalOrder = (o1, o2) -> o1 != null ? ((TComparable) o1).compareTo(o2) : -((TComparable) o2).compareTo(o1); diff --git a/core/src/main/java/org/teavm/common/CommutatedWriter.java b/core/src/main/java/org/teavm/common/CommutatedWriter.java deleted file mode 100644 index adcc208f8..000000000 --- a/core/src/main/java/org/teavm/common/CommutatedWriter.java +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright 2014 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.common; - -import java.io.IOException; -import java.io.Writer; - -/** - * - * @author Alexey Andreev - */ -public class CommutatedWriter extends Writer { - private ThreadLocal buffer = new ThreadLocal<>(); - private Writer innerWriter; - - public CommutatedWriter(Writer innerWriter) { - this.innerWriter = innerWriter; - } - - private StringBuilder getBuffer() { - if (buffer.get() == null) { - buffer.set(new StringBuilder()); - } - return buffer.get(); - } - - @Override - public void write(int c) throws IOException { - getBuffer().append(c); - } - - @Override - public void write(char[] cbuf) throws IOException { - getBuffer().append(cbuf); - } - - @Override - public void write(char[] cbuf, int off, int len) throws IOException { - getBuffer().append(cbuf, off, len); - } - - @Override - public void write(String str) throws IOException { - getBuffer().append(str); - } - - @Override - public void write(String str, int off, int len) throws IOException { - getBuffer().append(str, off, len + off); - } - - @Override - public Writer append(CharSequence csq) throws IOException { - getBuffer().append(csq); - return this; - } - - @Override - public Writer append(CharSequence csq, int start, int end) throws IOException { - getBuffer().append(csq, start, end); - return this; - } - - @Override - public Writer append(char c) throws IOException { - getBuffer().append(c); - return this; - } - - @Override - public void flush() throws IOException { - } - - @Override - public void close() throws IOException { - StringBuilder sb = getBuffer(); - innerWriter.write(sb.toString()); - buffer.set(null); - } -} diff --git a/core/src/main/java/org/teavm/common/FiniteExecutor.java b/core/src/main/java/org/teavm/common/FiniteExecutor.java deleted file mode 100644 index 24263f4e9..000000000 --- a/core/src/main/java/org/teavm/common/FiniteExecutor.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright 2014 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.common; - -import java.util.concurrent.Executor; - -/** - * - * @author Alexey Andreev - */ -public interface FiniteExecutor extends Executor { - void complete(); - - void executeFast(Runnable runnable); -} diff --git a/core/src/main/java/org/teavm/common/SimpleFiniteExecutor.java b/core/src/main/java/org/teavm/common/SimpleFiniteExecutor.java deleted file mode 100644 index 953746cf4..000000000 --- a/core/src/main/java/org/teavm/common/SimpleFiniteExecutor.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright 2014 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.common; - -import java.util.LinkedList; -import java.util.Queue; - -/** - * - * @author Alexey Andreev - */ -public class SimpleFiniteExecutor implements FiniteExecutor { - private Queue queue = new LinkedList<>(); - - @Override - public void execute(Runnable command) { - queue.add(command); - } - - @Override - public void executeFast(Runnable runnable) { - execute(runnable); - } - - @Override - public void complete() { - while (!queue.isEmpty()) { - queue.remove().run(); - } - } -} diff --git a/core/src/main/java/org/teavm/common/ThreadPoolFiniteExecutor.java b/core/src/main/java/org/teavm/common/ThreadPoolFiniteExecutor.java deleted file mode 100644 index a3e7aadc6..000000000 --- a/core/src/main/java/org/teavm/common/ThreadPoolFiniteExecutor.java +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Copyright 2014 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.common; - -import java.util.ArrayDeque; -import java.util.ArrayList; -import java.util.List; -import java.util.Queue; -import java.util.concurrent.BlockingQueue; -import java.util.concurrent.LinkedBlockingQueue; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.atomic.AtomicReference; - -/** - * - * @author Alexey Andreev - */ -public class ThreadPoolFiniteExecutor implements FiniteExecutor { - private List threads = new ArrayList<>(); - private BlockingQueue queue = new LinkedBlockingQueue<>(); - private AtomicInteger runningTasks = new AtomicInteger(); - private final Object monitor = new Object(); - private AtomicReference thrownException = new AtomicReference<>(); - private ThreadLocal> localQueueues = new ThreadLocal<>(); - - public ThreadPoolFiniteExecutor(int numThreads) { - for (int i = 0; i < numThreads; ++i) { - Thread thread = new Thread(this::takeTask); - threads.add(thread); - thread.start(); - } - } - - @Override - public void execute(Runnable command) { - runningTasks.incrementAndGet(); - try { - queue.put(command); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - } - } - - @Override - public void executeFast(Runnable runnable) { - localQueueues.get().add(runnable); - } - - @Override - public void complete() { - synchronized (monitor) { - while (true) { - if (thrownException.get() != null) { - throw thrownException.get(); - } - if (runningTasks.get() == 0) { - return; - } - try { - monitor.wait(); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - return; - } - } - } - } - - private void takeTask() { - Queue localQueue = new ArrayDeque<>(); - localQueueues.set(localQueue); - try { - while (true) { - Runnable task = queue.take(); - try { - task.run(); - while (!localQueue.isEmpty()) { - localQueue.remove().run(); - } - } catch (RuntimeException e) { - thrownException.set(e); - } finally { - if (runningTasks.decrementAndGet() == 0 || thrownException.get() != null) { - synchronized (monitor) { - monitor.notifyAll(); - } - } - } - } - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - } - } - - public void stop() { - for (Thread thread : threads) { - thread.interrupt(); - } - } -} diff --git a/core/src/main/java/org/teavm/javascript/backend/JavaScriptTarget.java b/core/src/main/java/org/teavm/javascript/backend/JavaScriptTarget.java deleted file mode 100644 index 76f0d7178..000000000 --- a/core/src/main/java/org/teavm/javascript/backend/JavaScriptTarget.java +++ /dev/null @@ -1,358 +0,0 @@ -/* - * Copyright 2016 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.javascript.backend; - -import java.io.IOException; -import java.io.OutputStream; -import java.io.OutputStreamWriter; -import java.io.Writer; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import org.teavm.ast.ClassNode; -import org.teavm.ast.cache.EmptyRegularMethodNodeCache; -import org.teavm.ast.cache.MethodNodeCache; -import org.teavm.ast.decompilation.Decompiler; -import org.teavm.codegen.AliasProvider; -import org.teavm.codegen.DefaultAliasProvider; -import org.teavm.codegen.DefaultNamingStrategy; -import org.teavm.codegen.MinifyingAliasProvider; -import org.teavm.codegen.SourceWriter; -import org.teavm.codegen.SourceWriterBuilder; -import org.teavm.debugging.information.DebugInformationEmitter; -import org.teavm.debugging.information.SourceLocation; -import org.teavm.dependency.DependencyChecker; -import org.teavm.dependency.DependencyListener; -import org.teavm.dependency.MethodDependency; -import org.teavm.javascript.Renderer; -import org.teavm.javascript.RenderingException; -import org.teavm.javascript.spi.GeneratedBy; -import org.teavm.javascript.spi.Generator; -import org.teavm.javascript.spi.InjectedBy; -import org.teavm.javascript.spi.Injector; -import org.teavm.model.BasicBlock; -import org.teavm.model.CallLocation; -import org.teavm.model.ClassHolder; -import org.teavm.model.ClassHolderTransformer; -import org.teavm.model.ElementModifier; -import org.teavm.model.TextLocation; -import org.teavm.model.ListableClassHolderSource; -import org.teavm.model.MethodHolder; -import org.teavm.model.MethodReference; -import org.teavm.model.Program; -import org.teavm.model.ValueType; -import org.teavm.model.Variable; -import org.teavm.model.instructions.ConstructInstruction; -import org.teavm.model.instructions.InvocationType; -import org.teavm.model.instructions.InvokeInstruction; -import org.teavm.model.instructions.RaiseInstruction; -import org.teavm.model.instructions.StringConstantInstruction; -import org.teavm.model.util.AsyncMethodFinder; -import org.teavm.model.util.ProgramUtils; -import org.teavm.vm.BuildTarget; -import org.teavm.vm.TeaVMEntryPoint; -import org.teavm.vm.TeaVMTarget; -import org.teavm.vm.TeaVMTargetController; -import org.teavm.vm.spi.RendererListener; -import org.teavm.vm.spi.TeaVMHostExtension; - -public class JavaScriptTarget implements TeaVMTarget, TeaVMJavaScriptHost { - private TeaVMTargetController controller; - private boolean minifying = true; - private final Map methodGenerators = new HashMap<>(); - private final Map methodInjectors = new HashMap<>(); - private final List rendererListeners = new ArrayList<>(); - private DebugInformationEmitter debugEmitter; - private MethodNodeCache astCache = new EmptyRegularMethodNodeCache(); - private final Set asyncMethods = new HashSet<>(); - private final Set asyncFamilyMethods = new HashSet<>(); - - @Override - public List getTransformers() { - return Collections.emptyList(); - } - - @Override - public List getDependencyListeners() { - return Collections.emptyList(); - } - - @Override - public void setController(TeaVMTargetController controller) { - this.controller = controller; - } - - @Override - public void add(RendererListener listener) { - rendererListeners.add(listener); - } - - @Override - public void add(MethodReference methodRef, Generator generator) { - methodGenerators.put(methodRef, generator); - } - - @Override - public void add(MethodReference methodRef, Injector injector) { - methodInjectors.put(methodRef, injector); - } - - /** - * Reports whether this TeaVM instance uses obfuscation when generating the JavaScript code. - * - * @see #setMinifying(boolean) - * @return whether TeaVM produces obfuscated code. - */ - public boolean isMinifying() { - return minifying; - } - - /** - * Specifies whether this TeaVM instance uses obfuscation when generating the JavaScript code. - * - * @see #isMinifying() - * @param minifying whether TeaVM should obfuscate code. - */ - public void setMinifying(boolean minifying) { - this.minifying = minifying; - } - - public MethodNodeCache getAstCache() { - return astCache; - } - - public void setAstCache(MethodNodeCache methodAstCache) { - this.astCache = methodAstCache; - } - - public DebugInformationEmitter getDebugEmitter() { - return debugEmitter; - } - - public void setDebugEmitter(DebugInformationEmitter debugEmitter) { - this.debugEmitter = debugEmitter; - } - - @Override - public boolean requiresRegisterAllocation() { - return true; - } - - @Override - public List getHostExtensions() { - return Collections.singletonList(this); - } - - @Override - public void contributeDependencies(DependencyChecker dependencyChecker) { - dependencyChecker.linkMethod(new MethodReference(Class.class.getName(), "getClass", - ValueType.object("org.teavm.platform.PlatformClass"), ValueType.parse(Class.class)), null).use(); - dependencyChecker.linkMethod(new MethodReference(String.class, "", char[].class, void.class), - null).use(); - dependencyChecker.linkMethod(new MethodReference(String.class, "getChars", int.class, int.class, char[].class, - int.class, void.class), null).use(); - - MethodDependency internDep = dependencyChecker.linkMethod(new MethodReference(String.class, "intern", - String.class), null); - internDep.getVariable(0).propagate(dependencyChecker.getType("java.lang.String")); - internDep.use(); - - dependencyChecker.linkMethod(new MethodReference(String.class, "length", int.class), null).use(); - dependencyChecker.linkMethod(new MethodReference(Object.class, "clone", Object.class), null).use(); - dependencyChecker.linkMethod(new MethodReference(Thread.class, "currentThread", Thread.class), null).use(); - dependencyChecker.linkMethod(new MethodReference(Thread.class, "getMainThread", Thread.class), null).use(); - dependencyChecker.linkMethod( - new MethodReference(Thread.class, "setCurrentThread", Thread.class, void.class), null).use(); - MethodDependency exceptionCons = dependencyChecker.linkMethod(new MethodReference( - NoClassDefFoundError.class, "", String.class, void.class), null); - - exceptionCons.getVariable(0).propagate(dependencyChecker.getType(NoClassDefFoundError.class.getName())); - exceptionCons.getVariable(1).propagate(dependencyChecker.getType("java.lang.String")); - exceptionCons = dependencyChecker.linkMethod(new MethodReference(NoSuchFieldError.class, "", - String.class, void.class), null); - exceptionCons.use(); - exceptionCons.getVariable(0).propagate(dependencyChecker.getType(NoSuchFieldError.class.getName())); - exceptionCons.getVariable(1).propagate(dependencyChecker.getType("java.lang.String")); - exceptionCons = dependencyChecker.linkMethod(new MethodReference(NoSuchMethodError.class, "", - String.class, void.class), null); - exceptionCons.use(); - exceptionCons.getVariable(0).propagate(dependencyChecker.getType(NoSuchMethodError.class.getName())); - exceptionCons.getVariable(1).propagate(dependencyChecker.getType("java.lang.String")); - } - - @Override - public void emit(ListableClassHolderSource classes, OutputStream output, BuildTarget target) { - try (Writer writer = new OutputStreamWriter(output, "UTF-8")) { - emit(classes, writer, target); - } catch (IOException e) { - throw new RenderingException(e); - } - } - - private void emit(ListableClassHolderSource classes, Writer writer, BuildTarget target) { - List clsNodes = modelToAst(classes); - if (controller.wasCancelled()) { - return; - } - - AliasProvider aliasProvider = minifying ? new MinifyingAliasProvider() : new DefaultAliasProvider(); - DefaultNamingStrategy naming = new DefaultNamingStrategy(aliasProvider, controller.getUnprocessedClassSource()); - SourceWriterBuilder builder = new SourceWriterBuilder(naming); - builder.setMinified(minifying); - SourceWriter sourceWriter = builder.build(writer); - - Renderer renderer = new Renderer(sourceWriter, classes, controller.getClassLoader(), controller.getServices(), - asyncMethods, asyncFamilyMethods, controller.getDiagnostics()); - renderer.setProperties(controller.getProperties()); - renderer.setMinifying(minifying); - if (debugEmitter != null) { - for (String className : classes.getClassNames()) { - ClassHolder cls = classes.get(className); - for (MethodHolder method : cls.getMethods()) { - if (method.getProgram() != null) { - emitCFG(debugEmitter, method.getProgram()); - } - } - if (controller.wasCancelled()) { - return; - } - } - renderer.setDebugEmitter(debugEmitter); - } - renderer.getDebugEmitter().setLocationProvider(sourceWriter); - for (Map.Entry entry : methodInjectors.entrySet()) { - renderer.addInjector(entry.getKey(), entry.getValue()); - } - try { - for (RendererListener listener : rendererListeners) { - listener.begin(renderer, target); - } - sourceWriter.append("\"use strict\";").newLine(); - renderer.renderRuntime(); - renderer.render(clsNodes); - renderer.renderStringPool(); - for (Map.Entry entry : controller.getEntryPoints().entrySet()) { - sourceWriter.append("var ").append(entry.getKey()).ws().append("=").ws(); - MethodReference ref = entry.getValue().getReference(); - sourceWriter.append(naming.getFullNameFor(ref)); - sourceWriter.append(";").newLine(); - } - for (Map.Entry entry : controller.getExportedClasses().entrySet()) { - sourceWriter.append("var ").append(entry.getKey()).ws().append("=").ws() - .appendClass(entry.getValue()).append(";").newLine(); - } - for (RendererListener listener : rendererListeners) { - listener.complete(); - } - } catch (IOException e) { - throw new RenderingException("IO Error occured", e); - } - } - - private List modelToAst(ListableClassHolderSource classes) { - AsyncMethodFinder asyncFinder = new AsyncMethodFinder(controller.getDependencyInfo().getCallGraph(), - controller.getDiagnostics()); - asyncFinder.find(classes); - asyncMethods.addAll(asyncFinder.getAsyncMethods()); - asyncFamilyMethods.addAll(asyncFinder.getAsyncFamilyMethods()); - - Decompiler decompiler = new Decompiler(classes, controller.getClassLoader(), asyncMethods, asyncFamilyMethods); - decompiler.setRegularMethodCache(controller.isIncremental() ? astCache : null); - - for (Map.Entry entry : methodGenerators.entrySet()) { - decompiler.addGenerator(entry.getKey(), entry.getValue()); - } - for (MethodReference injectedMethod : methodInjectors.keySet()) { - decompiler.addMethodToSkip(injectedMethod); - } - List classOrder = decompiler.getClassOrdering(classes.getClassNames()); - List classNodes = new ArrayList<>(); - for (String className : classOrder) { - ClassHolder cls = classes.get(className); - for (MethodHolder method : cls.getMethods()) { - preprocessNativeMethod(method); - if (controller.wasCancelled()) { - break; - } - } - classNodes.add(decompiler.decompile(cls)); - } - return classNodes; - } - - private void preprocessNativeMethod(MethodHolder method) { - if (!method.getModifiers().contains(ElementModifier.NATIVE) - || methodGenerators.get(method.getReference()) != null - || methodInjectors.get(method.getReference()) != null - || method.getAnnotations().get(GeneratedBy.class.getName()) != null - || method.getAnnotations().get(InjectedBy.class.getName()) != null) { - return; - } - method.getModifiers().remove(ElementModifier.NATIVE); - - Program program = new Program(); - method.setProgram(program); - BasicBlock block = program.createBasicBlock(); - Variable exceptionVar = program.createVariable(); - ConstructInstruction newExceptionInsn = new ConstructInstruction(); - newExceptionInsn.setType(NoSuchMethodError.class.getName()); - newExceptionInsn.setReceiver(exceptionVar); - block.getInstructions().add(newExceptionInsn); - - Variable constVar = program.createVariable(); - StringConstantInstruction constInsn = new StringConstantInstruction(); - constInsn.setConstant("Native method implementation not found: " + method.getReference()); - constInsn.setReceiver(constVar); - block.getInstructions().add(constInsn); - - InvokeInstruction initExceptionInsn = new InvokeInstruction(); - initExceptionInsn.setInstance(exceptionVar); - initExceptionInsn.setMethod(new MethodReference(NoSuchMethodError.class, "", String.class, void.class)); - initExceptionInsn.setType(InvocationType.SPECIAL); - initExceptionInsn.getArguments().add(constVar); - block.getInstructions().add(initExceptionInsn); - - RaiseInstruction raiseInsn = new RaiseInstruction(); - raiseInsn.setException(exceptionVar); - block.getInstructions().add(raiseInsn); - - controller.getDiagnostics().error(new CallLocation(method.getReference()), - "Native method {{m0}} has no implementation", method.getReference()); - } - - private void emitCFG(DebugInformationEmitter emitter, Program program) { - Map cfg = ProgramUtils.getLocationCFG(program); - for (Map.Entry entry : cfg.entrySet()) { - SourceLocation location = map(entry.getKey()); - SourceLocation[] successors = new SourceLocation[entry.getValue().length]; - for (int i = 0; i < entry.getValue().length; ++i) { - successors[i] = map(entry.getValue()[i]); - } - emitter.addSuccessors(location, successors); - } - } - - private static SourceLocation map(TextLocation location) { - if (location == null) { - return null; - } - return new SourceLocation(location.getFileName(), location.getLine()); - } -}