Rename target package to backend to avoid gitignore

This commit is contained in:
Alexey Andreev 2016-07-29 10:46:33 +03:00
parent 89c16b9807
commit 47997cde87
10 changed files with 384 additions and 8 deletions

View File

@ -24,7 +24,7 @@ import java.util.ServiceLoader;
import org.teavm.classlib.impl.lambda.LambdaMetafactorySubstitutor;
import org.teavm.classlib.impl.unicode.CLDRReader;
import org.teavm.classlib.java.lang.reflect.AnnotationDependencyListener;
import org.teavm.javascript.target.TeaVMJavaScriptHost;
import org.teavm.javascript.backend.TeaVMJavaScriptHost;
import org.teavm.model.MethodReference;
import org.teavm.platform.PlatformClass;
import org.teavm.vm.spi.TeaVMHost;

View File

@ -0,0 +1,346 @@
/*
* 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.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.ElementModifier;
import org.teavm.model.InstructionLocation;
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<MethodReference, Generator> methodGenerators = new HashMap<>();
private final Map<MethodReference, Injector> methodInjectors = new HashMap<>();
private final List<RendererListener> rendererListeners = new ArrayList<>();
private DebugInformationEmitter debugEmitter;
private MethodNodeCache astCache = new EmptyRegularMethodNodeCache();
private final Set<MethodReference> asyncMethods = new HashSet<>();
private final Set<MethodReference> asyncFamilyMethods = new HashSet<>();
@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<TeaVMHostExtension> 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, "<init>", 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, "<init>", 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, "<init>",
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, "<init>",
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<ClassNode> 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<MethodReference, Injector> 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<String, TeaVMEntryPoint> 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<String, String> 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<ClassNode> 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<MethodReference, Generator> entry : methodGenerators.entrySet()) {
decompiler.addGenerator(entry.getKey(), entry.getValue());
}
for (MethodReference injectedMethod : methodInjectors.keySet()) {
decompiler.addMethodToSkip(injectedMethod);
}
List<String> classOrder = decompiler.getClassOrdering(classes.getClassNames());
List<ClassNode> 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, "<init>", 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<InstructionLocation, InstructionLocation[]> cfg = ProgramUtils.getLocationCFG(program);
for (Map.Entry<InstructionLocation, InstructionLocation[]> 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(InstructionLocation location) {
if (location == null) {
return null;
}
return new SourceLocation(location.getFileName(), location.getLine());
}
}

View File

@ -0,0 +1,30 @@
/*
* 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 org.teavm.javascript.spi.Generator;
import org.teavm.javascript.spi.Injector;
import org.teavm.model.MethodReference;
import org.teavm.vm.spi.RendererListener;
import org.teavm.vm.spi.TeaVMHostExtension;
public interface TeaVMJavaScriptHost extends TeaVMHostExtension {
void add(MethodReference methodRef, Generator generator);
void add(MethodReference methodRef, Injector injector);
void add(RendererListener listener);
}

View File

@ -15,7 +15,7 @@
*/
package org.teavm.html4j;
import org.teavm.javascript.target.TeaVMJavaScriptHost;
import org.teavm.javascript.backend.TeaVMJavaScriptHost;
import org.teavm.vm.spi.TeaVMHost;
import org.teavm.vm.spi.TeaVMPlugin;

View File

@ -15,7 +15,7 @@
*/
package org.teavm.jso.impl;
import org.teavm.javascript.target.TeaVMJavaScriptHost;
import org.teavm.javascript.backend.TeaVMJavaScriptHost;
import org.teavm.vm.spi.TeaVMHost;
import org.teavm.vm.spi.TeaVMPlugin;

View File

@ -16,7 +16,7 @@
package org.teavm.platform.plugin;
import org.teavm.diagnostics.Diagnostics;
import org.teavm.javascript.target.TeaVMJavaScriptHost;
import org.teavm.javascript.backend.TeaVMJavaScriptHost;
import org.teavm.model.*;
import org.teavm.vm.spi.TeaVMHost;

View File

@ -19,7 +19,7 @@ import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import org.apache.commons.io.output.ByteArrayOutputStream;
import org.junit.Test;
import org.teavm.javascript.target.JavaScriptTarget;
import org.teavm.javascript.backend.JavaScriptTarget;
import org.teavm.model.MethodReference;
import org.teavm.model.ValueType;
import org.teavm.tooling.TeaVMProblemRenderer;

View File

@ -22,7 +22,7 @@ import java.io.ByteArrayOutputStream;
import java.util.List;
import org.junit.Test;
import org.teavm.diagnostics.Problem;
import org.teavm.javascript.target.JavaScriptTarget;
import org.teavm.javascript.backend.JavaScriptTarget;
import org.teavm.jso.JSBody;
import org.teavm.model.MethodReference;
import org.teavm.model.ValueType;

View File

@ -43,7 +43,7 @@ import org.teavm.debugging.information.DebugInformationBuilder;
import org.teavm.dependency.DependencyInfo;
import org.teavm.diagnostics.ProblemProvider;
import org.teavm.javascript.RenderingContext;
import org.teavm.javascript.target.JavaScriptTarget;
import org.teavm.javascript.backend.JavaScriptTarget;
import org.teavm.model.ClassHolderSource;
import org.teavm.model.ClassHolderTransformer;
import org.teavm.model.ClassReader;

View File

@ -47,7 +47,7 @@ import org.junit.runners.model.InitializationError;
import org.teavm.callgraph.CallGraph;
import org.teavm.diagnostics.DefaultProblemTextConsumer;
import org.teavm.diagnostics.Problem;
import org.teavm.javascript.target.JavaScriptTarget;
import org.teavm.javascript.backend.JavaScriptTarget;
import org.teavm.model.ClassHolder;
import org.teavm.model.ClassHolderSource;
import org.teavm.model.MethodDescriptor;