Merge branch 'master' into idea-plugin

This commit is contained in:
Alexey Andreev 2016-06-25 15:59:52 +03:00
commit feafa032df
141 changed files with 4765 additions and 1572 deletions

View File

@ -17,8 +17,8 @@
<inspection_tool class="CloneCallsSuperClone" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
<inspection_tool class="CloneDeclaresCloneNotSupported" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
<inspection_tool class="CodeBlock2Expr" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
<inspection_tool class="ConstantConditions" enabled="true" level="WARNING" enabled_by_default="true">
<scope name="classlib" level="WEAK WARNING" enabled="true">
<inspection_tool class="ConstantConditions" enabled="false" level="WARNING" enabled_by_default="false">
<scope name="classlib" level="WEAK WARNING" enabled="false">
<option name="SUGGEST_NULLABLE_ANNOTATIONS" value="false" />
<option name="DONT_REPORT_TRUE_ASSERT_STATEMENTS" value="false" />
</scope>

View File

@ -64,6 +64,14 @@
<option value="$PROJECT_DIR$/pom.xml" />
</list>
</option>
<option name="ignoredFiles">
<set>
<option value="$PROJECT_DIR$/tools/eclipse/core-plugin/pom.xml" />
<option value="$PROJECT_DIR$/tools/eclipse/m2e-plugin/pom.xml" />
<option value="$PROJECT_DIR$/tools/eclipse/plugin/pom.xml" />
<option value="$PROJECT_DIR$/tools/eclipse/pom.xml" />
</set>
</option>
</component>
<component name="ProjectLevelVcsManager" settingsEditedManually="false">
<OptionsSetting value="true" id="Add" />

View File

@ -13,7 +13,7 @@
<option name="MAIN_CLASS_NAME" value="" />
<option name="METHOD_NAME" value="" />
<option name="TEST_OBJECT" value="package" />
<option name="VM_PARAMETERS" value="-ea -Dteavm.junit.target=target/js-tests -Dteavm.junit.js.runner=htmlunit -Dteavm.junit.js.threads=2" />
<option name="VM_PARAMETERS" value="-ea -Dteavm.junit.target=out -Dteavm.junit.js.runner=htmlunit -Dteavm.junit.js.threads=2" />
<option name="PARAMETERS" value="" />
<option name="WORKING_DIRECTORY" value="file://$MODULE_DIR$" />
<option name="ENV_VARIABLES" />

View File

@ -8,10 +8,12 @@ branches:
only:
- master
- /^release-.+$/
env:
- MAVEN_OPTS="-Xmx1024m -XX:MaxPermSize=256m"
script: >
mvn test \
-Dteavm.test.skip=false \
-Dteavm.test.selenium="http://$SAUCE_USER_NAME:$SAUCE_ACCESS_KEY@ondemand.saucelabs.com:80/wd/hub" \
-Dteavm.test.threads=2
mvn -e test \
-Dteavm.junit.target=target/js-tests \
-Dteavm.junit.js.runner=htmlunit \
-Dteavm.junit.js.threads=1
after_script:
- rm -rf $HOME/.m2/repository/org/teavm

View File

@ -167,13 +167,28 @@ public class TPrintStream extends TFilterOutputStream {
printSB();
}
public void println(int i) {
sb.append(i).append('\n');
public void print(long l) {
sb.append(l);
printSB();
}
public void print(long l) {
sb.append(l);
public void print(double d) {
sb.append(d);
printSB();
}
public void print(TString s) {
sb.append(s);
printSB();
}
public void print(TObject s) {
sb.append(s);
printSB();
}
public void println(int i) {
sb.append(i).append('\n');
printSB();
}
@ -187,11 +202,6 @@ public class TPrintStream extends TFilterOutputStream {
printSB();
}
public void print(TString s) {
sb.append(s);
printSB();
}
public void println(TString s) {
sb.append(s).append('\n');
printSB();

View File

@ -21,6 +21,7 @@ import org.teavm.javascript.spi.Superclass;
import org.teavm.javascript.spi.Sync;
import org.teavm.jso.browser.TimerHandler;
import org.teavm.platform.Platform;
import org.teavm.platform.PlatformObject;
import org.teavm.platform.PlatformQueue;
import org.teavm.platform.PlatformRunnable;
import org.teavm.platform.async.AsyncCallback;
@ -168,7 +169,6 @@ public class TObject {
@Rename("<init>")
private void init() {
Platform.getPlatformObject(this).setId(Platform.nextObjectId());
}
@Rename("getClass")
@ -192,6 +192,10 @@ public class TObject {
}
int identity() {
PlatformObject platformThis = Platform.getPlatformObject(this);
if (platformThis.getId() == 0) {
platformThis.setId(Platform.nextObjectId());
}
return Platform.getPlatformObject(this).getId();
}

View File

@ -38,6 +38,7 @@
<orderEntry type="module" module-name="teavm-metaprogramming-api" />
<orderEntry type="library" name="Maven: commons-io:commons-io:2.4" level="project" />
<orderEntry type="library" name="Maven: com.carrotsearch:hppc:0.6.1" level="project" />
<orderEntry type="library" name="Maven: org.objenesis:objenesis:2.4" level="project" />
<orderEntry type="module" module-name="teavm-jso" />
<orderEntry type="module" module-name="teavm-jso-apis" />
<orderEntry type="module" module-name="teavm-jso-impl" />

View File

@ -58,6 +58,11 @@
<artifactId>jackson-annotations</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.objenesis</groupId>
<artifactId>objenesis</artifactId>
<version>2.4</version>
</dependency>
</dependencies>
<build>

View File

@ -26,18 +26,14 @@ import org.teavm.model.MethodReference;
import org.teavm.model.ValueType;
import org.teavm.model.instructions.ArrayElementType;
/**
*
* @author Alexey Andreev
*/
public class AstIO {
private static NodeModifier[] nodeModifiers = NodeModifier.values();
private static BinaryOperation[] binaryOperations = BinaryOperation.values();
private static UnaryOperation[] unaryOperations = UnaryOperation.values();
private static ArrayElementType[] arrayElementTypes = ArrayElementType.values();
private SymbolTable symbolTable;
private SymbolTable fileTable;
private Map<String, IdentifiedStatement> statementMap = new HashMap<>();
private static final NodeModifier[] nodeModifiers = NodeModifier.values();
private static final BinaryOperation[] binaryOperations = BinaryOperation.values();
private static final UnaryOperation[] unaryOperations = UnaryOperation.values();
private static final ArrayElementType[] arrayElementTypes = ArrayElementType.values();
private final SymbolTable symbolTable;
private final SymbolTable fileTable;
private final Map<String, IdentifiedStatement> statementMap = new HashMap<>();
public AstIO(SymbolTable symbolTable, SymbolTable fileTable) {
this.symbolTable = symbolTable;
@ -51,14 +47,7 @@ public class AstIO {
output.writeShort(var);
}
output.writeShort(method.getParameterDebugNames().size());
for (Set<String> debugNames : method.getParameterDebugNames()) {
output.writeShort(debugNames != null ? debugNames.size() : 0);
if (debugNames != null) {
for (String debugName : debugNames) {
output.writeUTF(debugName);
}
}
}
writeParameters(output, method);
try {
method.getBody().acceptVisitor(new NodeWriter(output));
} catch (IOExceptionWrapper e) {
@ -73,15 +62,7 @@ public class AstIO {
for (int i = 0; i < varCount; ++i) {
node.getVariables().add((int) input.readShort());
}
int paramDebugNameCount = input.readShort();
for (int i = 0; i < paramDebugNameCount; ++i) {
int debugNameCount = input.readShort();
Set<String> debugNames = new HashSet<>();
for (int j = 0; j < debugNameCount; ++j) {
debugNames.add(input.readUTF());
}
node.getParameterDebugNames().add(debugNames);
}
readParameters(input, node);
node.setBody(readStatement(input));
return node;
}
@ -93,14 +74,7 @@ public class AstIO {
output.writeShort(var);
}
output.writeShort(method.getParameterDebugNames().size());
for (Set<String> debugNames : method.getParameterDebugNames()) {
output.writeShort(debugNames != null ? debugNames.size() : 0);
if (debugNames != null) {
for (String debugName : debugNames) {
output.writeUTF(debugName);
}
}
}
writeParameters(output, method);
try {
output.writeShort(method.getBody().size());
for (int i = 0; i < method.getBody().size(); ++i) {
@ -111,6 +85,17 @@ public class AstIO {
}
}
private void writeParameters(DataOutput output, MethodNode method) throws IOException {
for (Set<String> debugNames : method.getParameterDebugNames()) {
output.writeShort(debugNames != null ? debugNames.size() : 0);
if (debugNames != null) {
for (String debugName : debugNames) {
output.writeUTF(debugName);
}
}
}
}
public AsyncMethodNode readAsync(DataInput input, MethodReference method) throws IOException {
AsyncMethodNode node = new AsyncMethodNode(method);
node.getModifiers().addAll(unpackModifiers(input.readInt()));
@ -118,6 +103,17 @@ public class AstIO {
for (int i = 0; i < varCount; ++i) {
node.getVariables().add((int) input.readShort());
}
readParameters(input, node);
int partCount = input.readShort();
for (int i = 0; i < partCount; ++i) {
AsyncMethodPart part = new AsyncMethodPart();
part.setStatement(readStatement(input));
node.getBody().add(part);
}
return node;
}
private void readParameters(DataInput input, MethodNode node) throws IOException {
int paramDebugNameCount = input.readShort();
for (int i = 0; i < paramDebugNameCount; ++i) {
int debugNameCount = input.readShort();
@ -127,13 +123,6 @@ public class AstIO {
}
node.getParameterDebugNames().add(debugNames);
}
int partCount = input.readShort();
for (int i = 0; i < partCount; ++i) {
AsyncMethodPart part = new AsyncMethodPart();
part.setStatement(readStatement(input));
node.getBody().add(part);
}
return node;
}
private int packModifiers(Set<NodeModifier> modifiers) {
@ -154,15 +143,15 @@ public class AstIO {
return modifiers;
}
class NodeWriter implements ExprVisitor, StatementVisitor {
private DataOutput output;
private class NodeWriter implements ExprVisitor, StatementVisitor {
private final DataOutput output;
public NodeWriter(DataOutput output) {
NodeWriter(DataOutput output) {
super();
this.output = output;
}
public void writeExpr(Expr expr) throws IOException {
void writeExpr(Expr expr) throws IOException {
writeLocation(expr.getLocation());
expr.acceptVisitor(this);
}
@ -515,8 +504,10 @@ public class AstIO {
@Override
public void visit(QualificationExpr expr) {
try {
output.writeByte(17);
writeExpr(expr.getQualified());
output.writeByte(expr.getQualified() != null ? 17 : 18);
if (expr.getQualified() != null) {
writeExpr(expr.getQualified());
}
output.writeInt(symbolTable.lookup(expr.getField().getClassName()));
output.writeInt(symbolTable.lookup(expr.getField().getFieldName()));
} catch (IOException e) {
@ -527,7 +518,7 @@ public class AstIO {
@Override
public void visit(NewExpr expr) {
try {
output.writeByte(18);
output.writeByte(19);
output.writeInt(symbolTable.lookup(expr.getConstructedClass()));
} catch (IOException e) {
throw new IOExceptionWrapper(e);
@ -537,7 +528,7 @@ public class AstIO {
@Override
public void visit(NewArrayExpr expr) {
try {
output.writeByte(19);
output.writeByte(20);
writeExpr(expr.getLength());
output.writeInt(symbolTable.lookup(expr.getType().toString()));
} catch (IOException e) {
@ -548,7 +539,7 @@ public class AstIO {
@Override
public void visit(NewMultiArrayExpr expr) {
try {
output.writeByte(20);
output.writeByte(21);
output.writeByte(expr.getDimensions().size());
for (Expr dimension : expr.getDimensions()) {
writeExpr(dimension);
@ -561,19 +552,9 @@ public class AstIO {
@Override
public void visit(InstanceOfExpr expr) {
try {
output.writeByte(21);
writeExpr(expr.getExpr());
output.writeInt(symbolTable.lookup(expr.getType().toString()));
} catch (IOException e) {
throw new IOExceptionWrapper(e);
}
}
@Override
public void visit(StaticClassExpr expr) {
try {
output.writeByte(22);
writeExpr(expr.getExpr());
output.writeInt(symbolTable.lookup(expr.getType().toString()));
} catch (IOException e) {
throw new IOExceptionWrapper(e);
@ -856,24 +837,31 @@ public class AstIO {
return parseInvocationExpr(InvocationType.DYNAMIC, input);
case 17: {
QualificationExpr expr = new QualificationExpr();
expr.setQualified(readExpr(input));
String className = symbolTable.at(input.readInt());
String fieldName = symbolTable.at(input.readInt());
expr.setField(new FieldReference(className, fieldName));
return expr;
}
case 18: {
QualificationExpr expr = new QualificationExpr();
expr.setQualified(readExpr(input));
String className = symbolTable.at(input.readInt());
String fieldName = symbolTable.at(input.readInt());
expr.setField(new FieldReference(className, fieldName));
return expr;
}
case 19: {
NewExpr expr = new NewExpr();
expr.setConstructedClass(symbolTable.at(input.readInt()));
return expr;
}
case 19: {
case 20: {
NewArrayExpr expr = new NewArrayExpr();
expr.setLength(readExpr(input));
expr.setType(ValueType.parse(symbolTable.at(input.readInt())));
return expr;
}
case 20: {
case 21: {
NewMultiArrayExpr expr = new NewMultiArrayExpr();
int dimensionCount = input.readByte();
for (int i = 0; i < dimensionCount; ++i) {
@ -882,17 +870,12 @@ public class AstIO {
expr.setType(ValueType.parse(symbolTable.at(input.readInt())));
return expr;
}
case 21: {
case 22: {
InstanceOfExpr expr = new InstanceOfExpr();
expr.setExpr(readExpr(input));
expr.setType(ValueType.parse(symbolTable.at(input.readInt())));
return expr;
}
case 22: {
StaticClassExpr expr = new StaticClassExpr();
expr.setType(ValueType.parse(symbolTable.at(input.readInt())));
return expr;
}
default:
throw new RuntimeException("Unknown expression type: " + type);
}
@ -911,10 +894,10 @@ public class AstIO {
return expr;
}
static class IOExceptionWrapper extends RuntimeException {
private static class IOExceptionWrapper extends RuntimeException {
private static final long serialVersionUID = -7566355431593608333L;
public IOExceptionWrapper(Throwable cause) {
IOExceptionWrapper(Throwable cause) {
super(cause);
}
}

View File

@ -22,18 +22,14 @@ import org.teavm.javascript.ast.*;
import org.teavm.model.MethodReference;
import org.teavm.parsing.ClassDateProvider;
/**
*
* @author Alexey Andreev
*/
public class DiskRegularMethodNodeCache implements MethodNodeCache {
private File directory;
private AstIO astIO;
private ClassDateProvider classDateProvider;
private Map<MethodReference, Item> cache = new HashMap<>();
private Map<MethodReference, AsyncItem> asyncCache = new HashMap<>();
private Set<MethodReference> newMethods = new HashSet<>();
private Set<MethodReference> newAsyncMethods = new HashSet<>();
private final File directory;
private final AstIO astIO;
private final ClassDateProvider classDateProvider;
private final Map<MethodReference, Item> cache = new HashMap<>();
private final Map<MethodReference, AsyncItem> asyncCache = new HashMap<>();
private final Set<MethodReference> newMethods = new HashSet<>();
private final Set<MethodReference> newAsyncMethods = new HashSet<>();
public DiskRegularMethodNodeCache(File directory, SymbolTable symbolTable, SymbolTable fileTable,
ClassDateProvider classDateProvider) {
@ -52,17 +48,7 @@ public class DiskRegularMethodNodeCache implements MethodNodeCache {
if (file.exists()) {
try (InputStream stream = new BufferedInputStream(new FileInputStream(file))) {
DataInput input = new DataInputStream(stream);
int depCount = input.readShort();
boolean dependenciesChanged = false;
for (int i = 0; i < depCount; ++i) {
String depClass = input.readUTF();
Date depDate = classDateProvider.getModificationDate(depClass);
if (depDate == null || depDate.after(new Date(file.lastModified()))) {
dependenciesChanged = true;
break;
}
}
if (!dependenciesChanged) {
if (!checkIfDependenciesChanged(input, file)) {
item.node = astIO.read(input, methodReference);
}
} catch (IOException e) {
@ -91,17 +77,7 @@ public class DiskRegularMethodNodeCache implements MethodNodeCache {
if (file.exists()) {
try (InputStream stream = new BufferedInputStream(new FileInputStream(file))) {
DataInput input = new DataInputStream(stream);
int depCount = input.readShort();
boolean dependenciesChanged = false;
for (int i = 0; i < depCount; ++i) {
String depClass = input.readUTF();
Date depDate = classDateProvider.getModificationDate(depClass);
if (depDate == null || depDate.after(new Date(file.lastModified()))) {
dependenciesChanged = true;
break;
}
}
if (!dependenciesChanged) {
if (!checkIfDependenciesChanged(input, file)) {
item.node = astIO.readAsync(input, methodReference);
}
} catch (IOException e) {
@ -112,6 +88,18 @@ public class DiskRegularMethodNodeCache implements MethodNodeCache {
return item.node;
}
private boolean checkIfDependenciesChanged(DataInput input, File file) throws IOException {
int depCount = input.readShort();
for (int i = 0; i < depCount; ++i) {
String depClass = input.readUTF();
Date depDate = classDateProvider.getModificationDate(depClass);
if (depDate == null || depDate.after(new Date(file.lastModified()))) {
return true;
}
}
return false;
}
@Override
public void storeAsync(MethodReference methodReference, AsyncMethodNode node) {
AsyncItem item = new AsyncItem();
@ -159,8 +147,8 @@ public class DiskRegularMethodNodeCache implements MethodNodeCache {
+ (async ? "-async" : ""));
}
static class AstDependencyAnalyzer implements StatementVisitor, ExprVisitor {
Set<String> dependencies = new HashSet<>();
private static class AstDependencyAnalyzer implements StatementVisitor, ExprVisitor {
final Set<String> dependencies = new HashSet<>();
private void visitSequence(List<Statement> statements) {
for (Statement stmt : statements) {
@ -288,7 +276,9 @@ public class DiskRegularMethodNodeCache implements MethodNodeCache {
@Override
public void visit(QualificationExpr expr) {
dependencies.add(expr.getField().getClassName());
expr.getQualified().acceptVisitor(this);
if (expr.getQualified() != null) {
expr.getQualified().acceptVisitor(this);
}
}
@Override
@ -312,10 +302,6 @@ public class DiskRegularMethodNodeCache implements MethodNodeCache {
expr.getExpr().acceptVisitor(this);
}
@Override
public void visit(StaticClassExpr expr) {
}
@Override
public void visit(GotoPartStatement statement) {
}
@ -330,11 +316,11 @@ public class DiskRegularMethodNodeCache implements MethodNodeCache {
}
}
static class Item {
private static class Item {
RegularMethodNode node;
}
static class AsyncItem {
private static class AsyncItem {
AsyncMethodNode node;
}
}

View File

@ -20,10 +20,6 @@ import java.util.Objects;
import org.teavm.model.*;
import org.teavm.model.instructions.*;
/**
*
* @author Alexey Andreev
*/
public class ProgramIO {
private SymbolTable symbolTable;
private SymbolTable fileTable;
@ -71,6 +67,15 @@ public class ProgramIO {
? tryCatch.getExceptionVariable().getIndex() : -1);
data.writeShort(tryCatch.getHandler().getIndex());
}
data.writeShort(basicBlock.getTryCatchJoints().size());
for (TryCatchJoint joint : basicBlock.getTryCatchJoints()) {
data.writeShort(joint.getSource().getIndex());
data.writeShort(joint.getReceiver().getIndex());
data.writeShort(joint.getSourceVariables().size());
for (Variable sourceVar : joint.getSourceVariables()) {
data.writeShort(sourceVar.getIndex());
}
}
InstructionLocation location = null;
InstructionWriter insnWriter = new InstructionWriter(data);
for (Instruction insn : basicBlock.getInstructions()) {
@ -139,6 +144,19 @@ public class ProgramIO {
tryCatch.setHandler(program.basicBlockAt(data.readShort()));
block.getTryCatchBlocks().add(tryCatch);
}
int jointCount = data.readShort();
for (int j = 0; j < jointCount; ++j) {
TryCatchJoint joint = new TryCatchJoint();
joint.setSource(program.basicBlockAt(data.readShort()));
joint.setReceiver(program.variableAt(data.readShort()));
int jointSourceCount = data.readShort();
for (int k = 0; k < jointSourceCount; ++k) {
joint.getSourceVariables().add(program.variableAt(data.readShort()));
}
block.getTryCatchJoints().add(joint);
}
InstructionLocation location = null;
insnLoop: while (true) {
byte insnType = data.readByte();

View File

@ -19,18 +19,16 @@ import org.teavm.model.FieldReference;
import org.teavm.model.MethodDescriptor;
import org.teavm.model.MethodReference;
/**
*
* @author Alexey Andreev
*/
public interface AliasProvider {
String getAlias(FieldReference field);
String getFieldAlias(FieldReference field);
String getAlias(MethodReference method);
String getStaticFieldAlias(FieldReference field);
String getAlias(MethodDescriptor method);
String getStaticMethodAlias(MethodReference method);
String getAlias(String className);
String getMethodAlias(MethodDescriptor method);
String getClassAlias(String className);
String getFunctionAlias(String name);
}

View File

@ -15,81 +15,88 @@
*/
package org.teavm.codegen;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.teavm.model.FieldReference;
import org.teavm.model.MethodDescriptor;
import org.teavm.model.MethodReference;
/**
*
* @author Alexey Andreev
*/
public class DefaultAliasProvider implements AliasProvider {
private int lastSuffix;
private int lastVirtualSuffix;
private Set<String> usedAliases = new HashSet<>();
private final Map<String, String> classAliases = new HashMap<>();
private final Set<String> knownAliases = new HashSet<>();
private final Set<String> knownVirtualAliases = new HashSet<>();
@Override
public String getAlias(String cls) {
StringBuilder alias = new StringBuilder();
int lastIndex = 0;
while (true) {
int index = cls.indexOf('.', lastIndex);
if (index == -1) {
if (lastIndex > 0) {
alias.append("_");
public String getClassAlias(String cls) {
return classAliases.computeIfAbsent(cls, key -> {
StringBuilder alias = new StringBuilder();
int lastIndex = 0;
while (true) {
int index = cls.indexOf('.', lastIndex);
if (index == -1) {
if (lastIndex > 0) {
alias.append("_");
}
alias.append(cls.substring(lastIndex));
break;
} else {
if (index > lastIndex) {
alias.append(cls.charAt(lastIndex));
}
lastIndex = index + 1;
}
alias.append(cls.substring(lastIndex));
break;
} else {
if (index > lastIndex) {
alias.append(cls.charAt(lastIndex));
}
lastIndex = index + 1;
}
}
alias.append(lastSuffix++);
return alias.toString();
return makeUnique(knownAliases, alias.toString());
});
}
@Override
public String getAlias(MethodDescriptor method) {
public String getMethodAlias(MethodDescriptor method) {
String alias = method.getName();
if (alias.equals("<init>")) {
alias = "$init";
} else if (alias.equals("<clinit>")) {
alias = "$clinit";
}
String result;
do {
result = alias + lastVirtualSuffix++;
} while (!usedAliases.add(result));
return result;
return makeUnique(knownVirtualAliases, alias);
}
@Override
public String getAlias(MethodReference method) {
public String getStaticMethodAlias(MethodReference method) {
String alias = method.getDescriptor().getName();
if (alias.equals("<init>")) {
alias = "$init";
} else if (alias.equals("<clinit>")) {
alias = "$clinit";
}
return alias + lastSuffix++;
return makeUnique(knownAliases, getClassAlias(method.getClassName()) + "_" + alias);
}
@Override
public String getAlias(FieldReference field) {
String result;
do {
result = field.getFieldName() + lastSuffix++;
} while (!usedAliases.add(result));
return result;
public String getFieldAlias(FieldReference field) {
return makeUnique(knownVirtualAliases, field.getFieldName());
}
@Override
public String getStaticFieldAlias(FieldReference field) {
return makeUnique(knownAliases, getClassAlias(field.getClassName()) + "_" + field.getFieldName());
}
@Override
public String getFunctionAlias(String name) {
return name;
}
private String makeUnique(Set<String> knowAliases, String alias) {
String uniqueAlias = alias;
int index = 1;
while (!knowAliases.add(uniqueAlias)) {
uniqueAlias = alias + index++;
}
return uniqueAlias;
}
}

View File

@ -19,41 +19,24 @@ import java.util.HashMap;
import java.util.Map;
import org.teavm.model.*;
/**
*
* @author Alexey Andreev
*/
public class DefaultNamingStrategy implements NamingStrategy {
private AliasProvider aliasProvider;
private ClassReaderSource classSource;
private Map<String, String> aliases = new HashMap<>();
private Map<String, String> privateAliases = new HashMap<>();
private Map<String, String> classAliases = new HashMap<>();
private Map<String, String> fieldAliases = new HashMap<>();
private Map<String, String> functionAliases = new HashMap<>();
private boolean minifying;
private final AliasProvider aliasProvider;
private final ClassReaderSource classSource;
private final Map<String, String> aliases = new HashMap<>();
private final Map<String, String> privateAliases = new HashMap<>();
private final Map<String, String> classAliases = new HashMap<>();
private final Map<String, String> fieldAliases = new HashMap<>();
private final Map<String, String> staticFieldAliases = new HashMap<>();
private final Map<String, String> functionAliases = new HashMap<>();
public DefaultNamingStrategy(AliasProvider aliasProvider, ClassReaderSource classSource) {
this.aliasProvider = aliasProvider;
this.classSource = classSource;
}
public boolean isMinifying() {
return minifying;
}
public void setMinifying(boolean minifying) {
this.minifying = minifying;
}
@Override
public String getNameFor(String cls) {
String name = classAliases.get(cls);
if (name == null) {
name = aliasProvider.getAlias(cls);
classAliases.put(cls, name);
}
return name;
return classAliases.computeIfAbsent(cls, key -> aliasProvider.getClassAlias(cls));
}
@Override
@ -65,7 +48,7 @@ public class DefaultNamingStrategy implements NamingStrategy {
String key = classifier + method.toString();
String alias = aliases.get(key);
if (alias == null) {
alias = aliasProvider.getAlias(method);
alias = aliasProvider.getMethodAlias(method);
aliases.put(key, alias);
}
return alias;
@ -87,16 +70,10 @@ public class DefaultNamingStrategy implements NamingStrategy {
if (method == null) {
throw new NamingException("Can't provide name for method as it was not found: " + originalMethod);
}
if (!minifying) {
return getNameFor(method.getClassName()) + "_" + getNameFor(method.getDescriptor(), classifier);
}
String key = classifier + method.toString();
String alias = privateAliases.get(key);
if (alias == null) {
alias = aliasProvider.getAlias(method);
privateAliases.put(key, alias);
}
return alias;
MethodReference resolvedMethod = method;
return privateAliases.computeIfAbsent(classifier + method.toString(),
key -> aliasProvider.getStaticMethodAlias(resolvedMethod));
}
@Override
@ -107,27 +84,26 @@ public class DefaultNamingStrategy implements NamingStrategy {
fieldAliases.put(field.getClassName() + "#" + field, alias);
return alias;
} else {
String key = realCls + "#" + field;
String alias = fieldAliases.get(key);
if (alias == null) {
alias = aliasProvider.getAlias(field);
fieldAliases.put(key, alias);
}
return fieldAliases.computeIfAbsent(realCls + "#" + field, key -> aliasProvider.getFieldAlias(field));
}
}
@Override
public String getFullNameFor(FieldReference field) throws NamingException {
String realCls = getRealFieldOwner(field.getClassName(), field.getFieldName());
if (!realCls.equals(field.getClassName())) {
String alias = getNameFor(new FieldReference(realCls, field.getFieldName()));
staticFieldAliases.put(field.getClassName() + "#" + field, alias);
return alias;
} else {
return staticFieldAliases.computeIfAbsent(realCls + "#" + field,
key -> aliasProvider.getStaticFieldAlias(field));
}
}
@Override
public String getNameForFunction(String name) throws NamingException {
if (!minifying) {
return name;
}
String alias = functionAliases.get(name);
if (alias == null) {
alias = aliasProvider.getFunctionAlias(name);
functionAliases.put(name, alias);
}
return alias;
return functionAliases.computeIfAbsent(name, key -> aliasProvider.getFunctionAlias(name));
}
private MethodReference getRealMethod(MethodReference methodRef) {

View File

@ -22,22 +22,18 @@ import org.teavm.model.FieldReference;
import org.teavm.model.MethodDescriptor;
import org.teavm.model.MethodReference;
/**
*
* @author Alexey Andreev
*/
public class MinifyingAliasProvider implements AliasProvider {
private static Set<String> keywords = new HashSet<>(Arrays.asList("do", "if", "else", "for", "case",
private static final Set<String> keywords = new HashSet<>(Arrays.asList("do", "if", "else", "for", "case",
"goto", "in", "let", "new", "this", "try", "var", "void", "with"));
private static String startLetters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
private static String letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
private static String startVirtualLetters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
private static final String startLetters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
private static final String letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
private static final String startVirtualLetters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
private int lastSuffix;
private int lastVirtual;
private Set<String> usedAliases = new HashSet<>();
private final Set<String> usedAliases = new HashSet<>();
@Override
public String getAlias(FieldReference field) {
public String getFieldAlias(FieldReference field) {
String result;
do {
result = getNewAlias(lastVirtual++, startVirtualLetters);
@ -46,12 +42,21 @@ public class MinifyingAliasProvider implements AliasProvider {
}
@Override
public String getAlias(MethodReference method) {
public String getStaticFieldAlias(FieldReference field) {
String result;
do {
result = getNewAlias(lastSuffix++, startLetters);
} while (!usedAliases.add(result) || keywords.contains(result));
return result;
}
@Override
public String getStaticMethodAlias(MethodReference method) {
return getNewAlias(lastSuffix++, startLetters);
}
@Override
public String getAlias(MethodDescriptor method) {
public String getMethodAlias(MethodDescriptor method) {
String result;
do {
result = getNewAlias(lastVirtual++, startVirtualLetters);
@ -60,7 +65,7 @@ public class MinifyingAliasProvider implements AliasProvider {
}
@Override
public String getAlias(String className) {
public String getClassAlias(String className) {
return getNewAlias(lastSuffix++, startLetters);
}

View File

@ -19,10 +19,6 @@ import org.teavm.model.FieldReference;
import org.teavm.model.MethodDescriptor;
import org.teavm.model.MethodReference;
/**
*
* @author Alexey Andreev
*/
public interface NamingStrategy {
String getNameFor(String cls) throws NamingException;
@ -34,5 +30,7 @@ public interface NamingStrategy {
String getNameFor(FieldReference field) throws NamingException;
String getFullNameFor(FieldReference method) throws NamingException;
String getNameForFunction(String name) throws NamingException;
}

View File

@ -21,17 +21,13 @@ import org.teavm.model.MethodDescriptor;
import org.teavm.model.MethodReference;
import org.teavm.model.ValueType;
/**
*
* @author Alexey Andreev
*/
public class SourceWriter implements Appendable, LocationProvider {
private Appendable innerWriter;
private final Appendable innerWriter;
private int indentSize;
private NamingStrategy naming;
private final NamingStrategy naming;
private boolean lineStart;
private boolean minified;
private int lineWidth;
private final int lineWidth;
private int column;
private int line;
@ -111,6 +107,10 @@ public class SourceWriter implements Appendable, LocationProvider {
return append(naming.getNameFor(field));
}
public SourceWriter appendStaticField(FieldReference field) throws NamingException, IOException {
return append(naming.getFullNameFor(field));
}
public SourceWriter appendMethod(MethodDescriptor method) throws NamingException, IOException {
return append(naming.getNameFor(method));
}

View File

@ -29,4 +29,16 @@ public interface DominatorTree {
int immediateDominatorOf(int a);
int levelOf(int a);
default int commonDominatorOf(int[] nodes) {
if (nodes.length == 0) {
return -1;
}
int result = nodes[0];
for (int i = 1; i < nodes.length; ++i) {
result = commonDominatorOf(result, nodes[i]);
}
return result;
}
}

View File

@ -240,8 +240,7 @@ public final class GraphUtils {
int[] set = new int[items.length];
int sz = 0;
int last = -1;
for (int i = 0; i < items.length; ++i) {
int item = items[i];
for (int item : items) {
if (item != last) {
set[sz++] = item;
last = item;

View File

@ -22,14 +22,14 @@ import java.util.*;
* @author Alexey Andreev
*/
public class MutableGraphNode {
int tag;
Map<MutableGraphNode, MutableGraphEdge> edges = new HashMap<>();
private int tag;
final Map<MutableGraphNode, MutableGraphEdge> edges = new LinkedHashMap<>();
public MutableGraphNode(int tag) {
this.tag = tag;
}
public MutableGraphEdge connect(MutableGraphNode other) {
private MutableGraphEdge connect(MutableGraphNode other) {
MutableGraphEdge edge = edges.get(other);
if (edge == null) {
edge = new MutableGraphEdge();

View File

@ -26,10 +26,6 @@ import org.teavm.common.*;
import org.teavm.model.*;
import org.teavm.model.instructions.*;
/**
*
* @author Alexey Andreev
*/
public class DataFlowGraphBuilder implements InstructionReader {
private int lastIndex;
private GraphBuilder builder = new GraphBuilder();
@ -68,6 +64,11 @@ public class DataFlowGraphBuilder implements InstructionReader {
builder.addEdge(from, to);
}
}
for (TryCatchJointReader joint : block.readTryCatchJoints()) {
for (VariableReader sourceVar : joint.readSourceVariables()) {
builder.addEdge(sourceVar.getIndex(), joint.getReceiver().getIndex());
}
}
block.readAllInstructions(this);
}
Graph graph = builder.build();

View File

@ -44,6 +44,7 @@ import org.teavm.model.PhiReader;
import org.teavm.model.Program;
import org.teavm.model.RuntimeConstant;
import org.teavm.model.TryCatchBlockReader;
import org.teavm.model.TryCatchJointReader;
import org.teavm.model.ValueType;
import org.teavm.model.VariableReader;
import org.teavm.model.emit.ProgramEmitter;
@ -136,10 +137,22 @@ class DependencyGraphBuilder {
BasicBlockReader block = program.basicBlockAt(i);
currentExceptionConsumer = createExceptionConsumer(dep, block);
block.readAllInstructions(reader);
for (TryCatchJointReader joint : block.readTryCatchJoints()) {
DependencyNode receiverNode = nodes[joint.getReceiver().getIndex()];
if (receiverNode == null) {
continue;
}
for (VariableReader source : joint.readSourceVariables()) {
DependencyNode sourceNode = nodes[source.getIndex()];
if (sourceNode != null) {
sourceNode.connect(receiverNode);
}
}
}
for (PhiReader phi : block.readPhis()) {
DependencyNode receiverNode = nodes[phi.getReceiver().getIndex()];
for (IncomingReader incoming : phi.readIncomings()) {
DependencyNode incomingNode = nodes[incoming.getValue().getIndex()];
DependencyNode receiverNode = nodes[phi.getReceiver().getIndex()];
if (incomingNode != null && receiverNode != null) {
incomingNode.connect(receiverNode);
}

View File

@ -26,8 +26,8 @@ import org.teavm.model.MethodReference;
* @author Alexey Andreev
*/
class AsyncCallsFinder implements StatementVisitor, ExprVisitor {
Set<MethodReference> asyncCalls = new HashSet<>();
Set<MethodReference> allCalls = new HashSet<>();
final Set<MethodReference> asyncCalls = new HashSet<>();
final Set<MethodReference> allCalls = new HashSet<>();
private void visitList(List<Statement> statements) {
for (Statement stmt : statements) {
@ -178,7 +178,9 @@ class AsyncCallsFinder implements StatementVisitor, ExprVisitor {
@Override
public void visit(QualificationExpr expr) {
expr.getQualified().acceptVisitor(this);
if (expr.getQualified() != null) {
expr.getQualified().acceptVisitor(this);
}
}
@Override
@ -201,8 +203,4 @@ class AsyncCallsFinder implements StatementVisitor, ExprVisitor {
public void visit(InstanceOfExpr expr) {
expr.getExpr().acceptVisitor(this);
}
@Override
public void visit(StaticClassExpr expr) {
}
}

View File

@ -21,18 +21,14 @@ import org.teavm.codegen.NameFrequencyConsumer;
import org.teavm.javascript.ast.*;
import org.teavm.model.*;
/**
*
* @author Alexey Andreev
*/
public class NameFrequencyEstimator implements StatementVisitor, ExprVisitor, MethodNodeVisitor {
private NameFrequencyConsumer consumer;
private ClassReaderSource classSource;
class NameFrequencyEstimator implements StatementVisitor, ExprVisitor, MethodNodeVisitor {
private final NameFrequencyConsumer consumer;
private final ClassReaderSource classSource;
private boolean async;
private Set<MethodReference> injectedMethods;
private Set<MethodReference> asyncFamilyMethods;
private final Set<MethodReference> injectedMethods;
private final Set<MethodReference> asyncFamilyMethods;
public NameFrequencyEstimator(NameFrequencyConsumer consumer, ClassReaderSource classSource,
NameFrequencyEstimator(NameFrequencyConsumer consumer, ClassReaderSource classSource,
Set<MethodReference> injectedMethods, Set<MethodReference> asyncFamilyMethods) {
this.consumer = consumer;
this.classSource = classSource;
@ -309,7 +305,9 @@ public class NameFrequencyEstimator implements StatementVisitor, ExprVisitor, Me
@Override
public void visit(QualificationExpr expr) {
expr.getQualified().acceptVisitor(this);
if (expr.getQualified() != null) {
expr.getQualified().acceptVisitor(this);
}
consumer.consume(expr.getField());
}
@ -349,9 +347,4 @@ public class NameFrequencyEstimator implements StatementVisitor, ExprVisitor, Me
consumer.consumeFunction("$rt_isInstance");
}
}
@Override
public void visit(StaticClassExpr expr) {
visitType(expr.getType());
}
}

View File

@ -30,10 +30,6 @@ import org.teavm.model.util.LivenessAnalyzer;
import org.teavm.model.util.ProgramUtils;
import org.teavm.model.util.UsageExtractor;
/**
*
* @author Alexey Andreev
*/
public class Optimizer {
public void optimize(RegularMethodNode method, Program program) {
ReadWriteStatsBuilder stats = new ReadWriteStatsBuilder(method.getVariables().size());

View File

@ -16,20 +16,17 @@
package org.teavm.javascript;
import java.util.*;
import java.util.stream.Collectors;
import org.teavm.javascript.ast.*;
/**
*
* @author Alexey Andreev
*/
class OptimizingVisitor implements StatementVisitor, ExprVisitor {
public Expr resultExpr;
public Statement resultStmt;
private boolean[] preservedVars;
private int[] readFrequencies;
private Expr resultExpr;
Statement resultStmt;
private final boolean[] preservedVars;
private final int[] readFrequencies;
private List<Statement> resultSequence;
public OptimizingVisitor(boolean[] preservedVars, int[] readFreqencies) {
OptimizingVisitor(boolean[] preservedVars, int[] readFreqencies) {
this.preservedVars = preservedVars;
this.readFrequencies = readFreqencies;
}
@ -261,9 +258,11 @@ class OptimizingVisitor implements StatementVisitor, ExprVisitor {
@Override
public void visit(QualificationExpr expr) {
expr.getQualified().acceptVisitor(this);
Expr qualified = resultExpr;
expr.setQualified(qualified);
if (expr.getQualified() != null) {
expr.getQualified().acceptVisitor(this);
Expr qualified = resultExpr;
expr.setQualified(qualified);
}
resultExpr = expr;
}
@ -297,11 +296,6 @@ class OptimizingVisitor implements StatementVisitor, ExprVisitor {
resultExpr = expr;
}
@Override
public void visit(StaticClassExpr expr) {
resultExpr = expr;
}
@Override
public void visit(AssignmentStatement statement) {
if (statement.getLeftValue() == null) {
@ -331,19 +325,13 @@ class OptimizingVisitor implements StatementVisitor, ExprVisitor {
resultSequence = new ArrayList<>();
processSequenceImpl(statements);
wieldTryCatch(resultSequence);
List<Statement> result = new ArrayList<>();
for (Statement part : resultSequence) {
if (part != null) {
result.add(part);
}
}
List<Statement> result = resultSequence.stream().filter(part -> part != null).collect(Collectors.toList());
resultSequence = backup;
return result;
}
private boolean processSequenceImpl(List<Statement> statements) {
for (int i = 0; i < statements.size(); ++i) {
Statement part = statements.get(i);
for (Statement part : statements) {
if (part instanceof SequentialStatement) {
if (!processSequenceImpl(((SequentialStatement) part).getSequence())) {
return false;
@ -440,7 +428,6 @@ class OptimizingVisitor implements StatementVisitor, ExprVisitor {
List<Statement> remaining = statements.subList(i + 1, statements.size());
cond.getConsequent().addAll(remaining);
remaining.clear();
break check_conditional;
}
}
}

View File

@ -24,10 +24,6 @@ import org.teavm.model.util.DefinitionExtractor;
import org.teavm.model.util.ProgramUtils;
import org.teavm.model.util.UsageExtractor;
/**
*
* @author Alexey Andreev
*/
class ReadWriteStatsBuilder {
public int[] reads;
public int[] writes;
@ -67,6 +63,13 @@ class ReadWriteStatsBuilder {
reads[var.getIndex()]++;
}
}
for (TryCatchJoint joint : block.getTryCatchJoints()) {
writes[joint.getReceiver().getIndex()] += joint.getSourceVariables().size();
for (Variable var : joint.getSourceVariables()) {
reads[var.getIndex()]++;
}
}
for (Phi phi : block.getPhis()) {
writes[phi.getReceiver().getIndex()] += phi.getIncomings().size();
for (Incoming incoming : phi.getIncomings()) {

View File

@ -73,7 +73,6 @@ import org.teavm.javascript.ast.ReturnStatement;
import org.teavm.javascript.ast.SequentialStatement;
import org.teavm.javascript.ast.Statement;
import org.teavm.javascript.ast.StatementVisitor;
import org.teavm.javascript.ast.StaticClassExpr;
import org.teavm.javascript.ast.SubscriptExpr;
import org.teavm.javascript.ast.SwitchClause;
import org.teavm.javascript.ast.SwitchStatement;
@ -100,50 +99,46 @@ import org.teavm.model.MethodReader;
import org.teavm.model.MethodReference;
import org.teavm.model.ValueType;
/**
*
* @author Alexey Andreev
*/
public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext {
private static final String variableNames = "abcdefghijkmnopqrstuvwxyz";
private static final String variablePartNames = "abcdefghijkmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
private NamingStrategy naming;
private SourceWriter writer;
private ListableClassHolderSource classSource;
private ClassLoader classLoader;
private final NamingStrategy naming;
private final SourceWriter writer;
private final ListableClassHolderSource classSource;
private final ClassLoader classLoader;
private boolean minifying;
private Map<MethodReference, InjectorHolder> injectorMap = new HashMap<>();
private Map<String, Integer> stringPoolMap = new HashMap<>();
private List<String> stringPool = new ArrayList<>();
private Properties properties = new Properties();
private ServiceRepository services;
private final Map<MethodReference, InjectorHolder> injectorMap = new HashMap<>();
private final Map<String, Integer> stringPoolMap = new HashMap<>();
private final List<String> stringPool = new ArrayList<>();
private final Properties properties = new Properties();
private final ServiceRepository services;
private DebugInformationEmitter debugEmitter = new DummyDebugInformationEmitter();
private Deque<LocationStackEntry> locationStack = new ArrayDeque<>();
private final Deque<LocationStackEntry> locationStack = new ArrayDeque<>();
private DeferredCallSite lastCallSite;
private DeferredCallSite prevCallSite;
private Set<MethodReference> asyncMethods;
private Set<MethodReference> asyncFamilyMethods;
private Diagnostics diagnostics;
private final Set<MethodReference> asyncMethods;
private final Set<MethodReference> asyncFamilyMethods;
private final Diagnostics diagnostics;
private boolean async;
private Precedence precedence;
private Map<String, String> blockIdMap = new HashMap<>();
private List<Set<String>> debugNames = new ArrayList<>();
private List<String> cachedVariableNames = new ArrayList<>();
private final Map<String, String> blockIdMap = new HashMap<>();
private final List<Set<String>> debugNames = new ArrayList<>();
private final List<String> cachedVariableNames = new ArrayList<>();
private boolean end;
private int currentPart;
private static class InjectorHolder {
public final Injector injector;
public InjectorHolder(Injector injector) {
private InjectorHolder(Injector injector) {
this.injector = injector;
}
}
private static class LocationStackEntry {
NodeLocation location;
final NodeLocation location;
public LocationStackEntry(NodeLocation location) {
LocationStackEntry(NodeLocation location) {
this.location = location;
}
}
@ -395,6 +390,11 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
.append("=").ws().append(constantToString(value)).append(";").softNewLine();
debugEmitter.addField(field.getName(), naming.getNameFor(fieldRef));
}
if (cls.getName().equals("java.lang.Object")) {
writer.append("this.$id").ws().append('=').ws().append("0;").softNewLine();
}
writer.outdent().append("}").newLine();
for (FieldNode field : staticFields) {
@ -403,7 +403,7 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
value = getDefaultValue(field.getType());
}
FieldReference fieldRef = new FieldReference(cls.getName(), field.getName());
writer.appendClass(cls.getName()).append('.').appendField(fieldRef).ws().append("=").ws()
writer.append("var ").appendStaticField(fieldRef).ws().append("=").ws()
.append(constantToString(value)).append(";").softNewLine();
}
} catch (NamingException e) {
@ -431,9 +431,9 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
}
if (needsClinit) {
writer.append("function ").appendClass(cls.getName()).append("_$clinit()").ws()
writer.append("function ").appendClass(cls.getName()).append("_$callClinit()").ws()
.append("{").softNewLine().indent();
writer.appendClass(cls.getName()).append("_$clinit").ws().append("=").ws()
writer.appendClass(cls.getName()).append("_$callClinit").ws().append("=").ws()
.append("function(){};").newLine();
for (MethodNode method : clinitMethods) {
renderBody(method, true);
@ -498,7 +498,7 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
MethodHolder clinit = classSource.get(cls.getName()).getMethod(
new MethodDescriptor("<clinit>", ValueType.VOID));
if (clinit != null) {
writer.appendClass(cls.getName()).append("_$clinit");
writer.appendClass(cls.getName()).append("_$callClinit");
} else {
writer.append('0');
}
@ -624,13 +624,13 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
}
writer.appendMethodBody(ref).append("(");
writer.append("this");
for (int i = 0; i < args.size(); ++i) {
writer.append(",").ws().append(args.get(i));
for (String arg : args) {
writer.append(",").ws().append(arg);
}
writer.append(");").ws().append("}");
}
public void renderBody(MethodNode method, boolean inner) throws IOException {
private void renderBody(MethodNode method, boolean inner) throws IOException {
debugNames.clear();
cachedVariableNames.clear();
debugNames.addAll(method.getParameterDebugNames());
@ -1211,7 +1211,7 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
if (statement.getLocation() != null) {
pushLocation(statement.getLocation());
}
writer.appendClass(statement.getClassName()).append("_$clinit();").softNewLine();
writer.appendClass(statement.getClassName()).append("_$callClinit();").softNewLine();
if (statement.getLocation() != null) {
popLocation();
}
@ -1220,7 +1220,7 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
}
}
public String variableName(int index) {
private String variableName(int index) {
while (index >= cachedVariableNames.size()) {
cachedVariableNames.add(null);
}
@ -1250,12 +1250,21 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
List<String> nameList = new ArrayList<>(names);
Collections.sort(nameList);
for (String name : nameList) {
sb.append('_').append(name);
sb.append('_').append(escapeName(name));
}
}
return sb.toString();
}
private static String escapeName(String name) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < name.length(); ++i) {
char c = name.charAt(i);
sb.append(Character.isJavaIdentifierPart(c) ? c : '_');
}
return sb.toString();
}
private String pointerName() {
return minifying ? "$p" : "$ptr";
}
@ -1673,7 +1682,7 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
}
}
public String constantToString(Object cst) {
private String constantToString(Object cst) {
if (cst == null) {
return "null";
}
@ -1948,8 +1957,14 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
pushLocation(expr.getLocation());
}
precedence = Precedence.MEMBER_ACCESS;
expr.getQualified().acceptVisitor(this);
writer.append('.').appendField(expr.getField());
if (expr.getQualified() != null) {
expr.getQualified().acceptVisitor(this);
writer.append('.').appendField(expr.getField());
} else {
writer.appendStaticField(expr.getField());
}
if (expr.getLocation() != null) {
popLocation();
}
@ -2140,21 +2155,6 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
}
}
@Override
public void visit(StaticClassExpr expr) {
try {
if (expr.getLocation() != null) {
pushLocation(expr.getLocation());
}
writer.append(typeToClsString(naming, expr.getType()));
if (expr.getLocation() != null) {
popLocation();
}
} catch (IOException e) {
throw new RenderingException("IO error occured", e);
}
}
private void visitStatements(List<Statement> statements) {
if (statements.isEmpty()) {
return;
@ -2313,10 +2313,10 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
}
private class InjectorContextImpl implements InjectorContext {
private List<Expr> arguments;
private Precedence precedence = Renderer.this.precedence;
private final List<Expr> arguments;
private final Precedence precedence = Renderer.this.precedence;
public InjectorContextImpl(List<Expr> arguments) {
InjectorContextImpl(List<Expr> arguments) {
this.arguments = arguments;
}

View File

@ -23,13 +23,9 @@ import org.teavm.model.*;
import org.teavm.model.instructions.*;
import org.teavm.model.instructions.InvocationType;
/**
*
* @author Alexey Andreev
*/
class StatementGenerator implements InstructionVisitor {
private int lastSwitchId;
List<Statement> statements = new ArrayList<>();
final List<Statement> statements = new ArrayList<>();
GraphIndexer indexer;
BasicBlock nextBlock;
BasicBlock currentBlock;
@ -39,7 +35,7 @@ class StatementGenerator implements InstructionVisitor {
private NodeLocation currentLocation;
boolean async;
public void setCurrentLocation(NodeLocation currentLocation) {
void setCurrentLocation(NodeLocation currentLocation) {
this.currentLocation = currentLocation;
}
@ -478,8 +474,7 @@ class StatementGenerator implements InstructionVisitor {
stmt.setLocation(currentLocation);
statements.add(stmt);
} else {
Expr fieldExpr = Expr.qualify(Expr.staticClass(ValueType.object(insn.getField().getClassName())),
insn.getField());
Expr fieldExpr = Expr.qualify(null, insn.getField());
AssignmentStatement stmt = Statement.assign(Expr.var(insn.getReceiver().getIndex()), fieldExpr);
stmt.setLocation(currentLocation);
statements.add(stmt);
@ -493,7 +488,7 @@ class StatementGenerator implements InstructionVisitor {
if (insn.getInstance() != null) {
left = Expr.qualify(Expr.var(insn.getInstance().getIndex()), insn.getField());
} else {
left = Expr.qualify(Expr.staticClass(ValueType.object(insn.getField().getClassName())), insn.getField());
left = Expr.qualify(null, insn.getField());
}
AssignmentStatement stmt = Statement.assign(left, right);
stmt.setLocation(currentLocation);
@ -613,6 +608,9 @@ class StatementGenerator implements InstructionVisitor {
return null;
}
Decompiler.Block block = blockMap[target.getIndex()];
if (block == null) {
throw new IllegalStateException("Could not find block for basic block $" + target.getIndex());
}
if (target.getIndex() == indexer.nodeAt(block.end)) {
BreakStatement breakStmt = new BreakStatement();
breakStmt.setLocation(currentLocation);

View File

@ -19,16 +19,12 @@ import java.util.Arrays;
import java.util.List;
import org.teavm.javascript.ast.*;
/**
*
* @author Alexey Andreev
*/
class UnusedVariableEliminator implements ExprVisitor, StatementVisitor {
int[] variables;
int[] indexes;
private final int[] variables;
private final int[] indexes;
int lastIndex;
public UnusedVariableEliminator(int parameterCount, List<Integer> variables) {
UnusedVariableEliminator(int parameterCount, List<Integer> variables) {
this.variables = new int[variables.size()];
int variableCount = 0;
for (int i = 0; i < variables.size(); ++i) {
@ -176,7 +172,9 @@ class UnusedVariableEliminator implements ExprVisitor, StatementVisitor {
@Override
public void visit(QualificationExpr expr) {
expr.getQualified().acceptVisitor(this);
if (expr.getQualified() != null) {
expr.getQualified().acceptVisitor(this);
}
}
@Override
@ -200,10 +198,6 @@ class UnusedVariableEliminator implements ExprVisitor, StatementVisitor {
expr.getExpr().acceptVisitor(this);
}
@Override
public void visit(StaticClassExpr expr) {
}
@Override
public void visit(InitClassStatement statement) {
}

View File

@ -20,10 +20,6 @@ import java.util.HashMap;
import java.util.Map;
import org.teavm.model.*;
/**
*
* @author Alexey Andreev
*/
public abstract class Expr implements Cloneable {
private NodeLocation location;
@ -152,12 +148,6 @@ public abstract class Expr implements Cloneable {
return expr;
}
public static Expr staticClass(ValueType type) {
StaticClassExpr expr = new StaticClassExpr();
expr.setType(type);
return expr;
}
public NodeLocation getLocation() {
return location;
}

View File

@ -15,10 +15,6 @@
*/
package org.teavm.javascript.ast;
/**
*
* @author Alexey Andreev
*/
public interface ExprVisitor {
void visit(BinaryExpr expr);
@ -45,6 +41,4 @@ public interface ExprVisitor {
void visit(NewMultiArrayExpr expr);
void visit(InstanceOfExpr expr);
void visit(StaticClassExpr expr);
}

View File

@ -1,206 +0,0 @@
/*
* Copyright 2013 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.ast;
/**
*
* @author Alexey Andreev
*/
public class RenamingVisitor implements StatementVisitor, ExprVisitor {
private int[] varNames;
public RenamingVisitor(int[] varNames) {
this.varNames = varNames;
}
@Override
public void visit(BinaryExpr expr) {
expr.getFirstOperand().acceptVisitor(this);
expr.getSecondOperand().acceptVisitor(this);
}
@Override
public void visit(UnaryExpr expr) {
expr.getOperand().acceptVisitor(this);
}
@Override
public void visit(ConditionalExpr expr) {
expr.getCondition().acceptVisitor(this);
expr.getConsequent().acceptVisitor(this);
expr.getAlternative().acceptVisitor(this);
}
@Override
public void visit(ConstantExpr expr) {
}
@Override
public void visit(VariableExpr expr) {
expr.setIndex(varNames[expr.getIndex()]);
}
@Override
public void visit(SubscriptExpr expr) {
expr.getArray().acceptVisitor(this);
expr.getIndex().acceptVisitor(this);
}
@Override
public void visit(UnwrapArrayExpr expr) {
expr.getArray().acceptVisitor(this);
}
@Override
public void visit(InvocationExpr expr) {
for (Expr arg : expr.getArguments()) {
arg.acceptVisitor(this);
}
}
@Override
public void visit(QualificationExpr expr) {
expr.getQualified().acceptVisitor(this);
}
@Override
public void visit(NewExpr expr) {
}
@Override
public void visit(NewArrayExpr expr) {
expr.getLength().acceptVisitor(this);
}
@Override
public void visit(NewMultiArrayExpr expr) {
for (Expr dim : expr.getDimensions()) {
dim.acceptVisitor(this);
}
}
@Override
public void visit(InstanceOfExpr expr) {
expr.getExpr().acceptVisitor(this);
}
@Override
public void visit(StaticClassExpr expr) {
}
@Override
public void visit(AssignmentStatement statement) {
if (statement.getLeftValue() != null) {
statement.getLeftValue().acceptVisitor(this);
}
statement.getRightValue().acceptVisitor(this);
}
@Override
public void visit(SequentialStatement statement) {
for (Statement part : statement.getSequence()) {
part.acceptVisitor(this);
}
}
@Override
public void visit(ConditionalStatement statement) {
statement.getCondition().acceptVisitor(this);
for (Statement part : statement.getConsequent()) {
part.acceptVisitor(this);
}
for (Statement part : statement.getAlternative()) {
part.acceptVisitor(this);
}
}
@Override
public void visit(SwitchStatement statement) {
statement.getValue().acceptVisitor(this);
for (SwitchClause clause : statement.getClauses()) {
for (Statement part : clause.getBody()) {
part.acceptVisitor(this);
}
}
for (Statement part : statement.getDefaultClause()) {
part.acceptVisitor(this);
}
}
@Override
public void visit(WhileStatement statement) {
if (statement.getCondition() != null) {
statement.getCondition().acceptVisitor(this);
}
for (Statement part : statement.getBody()) {
part.acceptVisitor(this);
}
}
@Override
public void visit(BlockStatement statement) {
for (Statement part : statement.getBody()) {
part.acceptVisitor(this);
}
}
@Override
public void visit(BreakStatement statement) {
}
@Override
public void visit(ContinueStatement statement) {
}
@Override
public void visit(ReturnStatement statement) {
if (statement.getResult() != null) {
statement.getResult().acceptVisitor(this);
}
}
@Override
public void visit(ThrowStatement statement) {
statement.getException().acceptVisitor(this);
}
@Override
public void visit(InitClassStatement statement) {
}
@Override
public void visit(TryCatchStatement statement) {
for (Statement part : statement.getProtectedBody()) {
part.acceptVisitor(this);
}
for (Statement part : statement.getHandler()) {
part.acceptVisitor(this);
}
statement.setExceptionVariable(varNames[statement.getExceptionVariable()]);
}
@Override
public void visit(GotoPartStatement statement) {
}
@Override
public void visit(MonitorEnterStatement statement) {
}
@Override
public void visit(MonitorExitStatement statement) {
}
}

View File

@ -1,52 +0,0 @@
/*
* Copyright 2012 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.ast;
import java.util.Map;
import org.teavm.model.ValueType;
/**
*
* @author Alexey Andreev
*/
public class StaticClassExpr extends Expr {
private ValueType type;
public ValueType getType() {
return type;
}
public void setType(ValueType type) {
this.type = type;
}
@Override
public void acceptVisitor(ExprVisitor visitor) {
visitor.visit(this);
}
@Override
protected Expr clone(Map<Expr, Expr> cache) {
Expr known = cache.get(this);
if (known != null) {
return known;
}
StaticClassExpr copy = new StaticClassExpr();
cache.put(this, copy);
copy.setType(type);
return copy;
}
}

View File

@ -18,16 +18,14 @@ package org.teavm.model;
import java.util.*;
import org.teavm.model.instructions.InstructionReader;
/**
*
* @author Alexey Andreev
*/
public class BasicBlock implements BasicBlockReader {
private Program program;
private int index;
private List<Phi> phis = new ArrayList<>();
private List<Instruction> instructions = new ArrayList<>();
List<TryCatchBlock> tryCatchBlocks = new ArrayList<>();
private List<TryCatchBlock> tryCatchBlocks = new ArrayList<>();
private List<TryCatchJoint> joints = new ArrayList<>();
private List<TryCatchJointReader> immutableJoints;
BasicBlock(Program program, int index) {
this.program = program;
@ -199,6 +197,12 @@ public class BasicBlock implements BasicBlockReader {
}
}
}
for (int i = 0; i < joints.size(); ++i) {
TryCatchJoint joint = joints.get(i);
if (joint.getSource() == predecessor) {
joints.remove(i--);
}
}
}
private List<TryCatchBlock> immutableTryCatchBlocks = Collections.unmodifiableList(tryCatchBlocks);
@ -251,4 +255,16 @@ public class BasicBlock implements BasicBlockReader {
public List<TryCatchBlock> getTryCatchBlocks() {
return safeTryCatchBlocks;
}
public List<TryCatchJoint> getTryCatchJoints() {
return joints;
}
@Override
public List<TryCatchJointReader> readTryCatchJoints() {
if (immutableJoints == null) {
immutableJoints = Collections.unmodifiableList(joints);
}
return immutableJoints;
}
}

View File

@ -18,10 +18,6 @@ package org.teavm.model;
import java.util.List;
import org.teavm.model.instructions.InstructionReader;
/**
*
* @author Alexey Andreev
*/
public interface BasicBlockReader {
ProgramReader getProgram();
@ -36,4 +32,6 @@ public interface BasicBlockReader {
void readAllInstructions(InstructionReader reader);
List<? extends TryCatchBlockReader> readTryCatchBlocks();
List<TryCatchJointReader> readTryCatchJoints();
}

View File

@ -15,10 +15,6 @@
*/
package org.teavm.model;
/**
*
* @author Alexey Andreev
*/
public interface IncomingReader {
VariableReader getValue();

View File

@ -0,0 +1,35 @@
/*
* 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.model;
public class InterpretException extends Exception {
private final BasicBlockReader block;
private final int index;
public InterpretException(BasicBlockReader block, int index, Throwable cause) {
super(cause);
this.block = block;
this.index = index;
}
public BasicBlockReader getBlock() {
return block;
}
public int getIndex() {
return index;
}
}

View File

@ -0,0 +1,838 @@
/*
* 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.model;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.objenesis.Objenesis;
import org.objenesis.ObjenesisStd;
import org.teavm.model.instructions.ArrayElementType;
import org.teavm.model.instructions.BinaryBranchingCondition;
import org.teavm.model.instructions.BinaryOperation;
import org.teavm.model.instructions.BranchingCondition;
import org.teavm.model.instructions.CastIntegerDirection;
import org.teavm.model.instructions.InstructionReader;
import org.teavm.model.instructions.IntegerSubtype;
import org.teavm.model.instructions.InvocationType;
import org.teavm.model.instructions.NumericOperandType;
import org.teavm.model.instructions.SwitchTableEntryReader;
public class Interpreter {
private ClassLoader classLoader;
private BasicBlockReader currentBlock;
private List<List<IncomingReader>> outgoings;
private Object[] variables;
private Object result;
private State state;
public Interpreter(ClassLoader classLoader) {
this.classLoader = classLoader;
}
public Object interpret(ProgramReader program, Object[] parameters) throws InterpretException {
variables = new Object[program.variableCount()];
System.arraycopy(parameters, 0, variables, 0, parameters.length);
currentBlock = program.basicBlockAt(0);
state = State.EXECUTING;
outgoings = new ArrayList<>();
for (int i = 0; i < program.basicBlockCount(); ++i) {
outgoings.add(new ArrayList<>());
}
for (int i = 0; i < program.basicBlockCount(); ++i) {
BasicBlockReader block = program.basicBlockAt(i);
for (PhiReader phi : block.readPhis()) {
for (IncomingReader incoming : phi.readIncomings()) {
outgoings.get(incoming.getSource().getIndex()).add(incoming);
}
}
}
try {
while (true) {
int instructionIndex = 0;
try {
while (instructionIndex < currentBlock.instructionCount()) {
currentBlock.readInstruction(instructionIndex++, reader);
}
} catch (RuntimeException e) {
if (!pickExceptionHandler(e)) {
throw new InterpretException(currentBlock, instructionIndex, e);
}
}
switch (state) {
case EXITED: {
return result;
}
case THROWN: {
Throwable ex = (Throwable) result;
throw new InterpretException(currentBlock, currentBlock.instructionCount() - 1, ex);
}
case EXECUTING:
break;
}
}
} finally {
currentBlock = null;
variables = null;
outgoings = null;
result = null;
}
}
private boolean pickExceptionHandler(Throwable e) {
for (TryCatchBlockReader tryCatch : currentBlock.readTryCatchBlocks()) {
Class<?> exceptionType;
try {
exceptionType = tryCatch.getExceptionType() != null
? Class.forName(tryCatch.getExceptionType(), false, classLoader)
: null;
} catch (ClassNotFoundException cnfe) {
throw new RuntimeException("Can't find exception class " + tryCatch.getExceptionType());
}
if (exceptionType == null || exceptionType.isInstance(e)) {
currentBlock = tryCatch.getProtectedBlock();
return true;
}
}
return false;
}
private InstructionReader reader = new InstructionReader() {
private Objenesis objenesis = new ObjenesisStd();
@Override
public void location(InstructionLocation location) {
}
@Override
public void nop() {
}
@Override
public void classConstant(VariableReader receiver, ValueType cst) {
variables[receiver.getIndex()] = asJvmClass(cst);
}
@Override
public void nullConstant(VariableReader receiver) {
variables[receiver.getIndex()] = null;
}
@Override
public void integerConstant(VariableReader receiver, int cst) {
variables[receiver.getIndex()] = cst;
}
@Override
public void longConstant(VariableReader receiver, long cst) {
variables[receiver.getIndex()] = cst;
}
@Override
public void floatConstant(VariableReader receiver, float cst) {
variables[receiver.getIndex()] = cst;
}
@Override
public void doubleConstant(VariableReader receiver, double cst) {
variables[receiver.getIndex()] = cst;
}
@Override
public void stringConstant(VariableReader receiver, String cst) {
variables[receiver.getIndex()] = cst;
}
@Override
public void binary(BinaryOperation op, VariableReader receiver, VariableReader first, VariableReader second,
NumericOperandType type) {
switch (type) {
case INT: {
int a = (Integer) variables[first.getIndex()];
int b = (Integer) variables[second.getIndex()];
int result;
switch (op) {
case ADD:
result = a + b;
break;
case SUBTRACT:
result = a - b;
break;
case MULTIPLY:
result = a * b;
break;
case DIVIDE:
result = a * b;
break;
case MODULO:
result = a % b;
break;
case COMPARE:
result = Integer.compare(a, b);
break;
case AND:
result = a & b;
break;
case OR:
result = a | b;
break;
case XOR:
result = a ^ b;
break;
default:
throw new IllegalArgumentException("Unknown operation: " + op);
}
variables[receiver.getIndex()] = result;
break;
}
case LONG: {
long a = (Long) variables[first.getIndex()];
long b = (Long) variables[second.getIndex()];
long result;
switch (op) {
case ADD:
result = a + b;
break;
case SUBTRACT:
result = a - b;
break;
case MULTIPLY:
result = a * b;
break;
case DIVIDE:
result = a * b;
break;
case MODULO:
result = a % b;
break;
case COMPARE:
result = Long.compare(a, b);
break;
case AND:
result = a & b;
break;
case OR:
result = a | b;
break;
case XOR:
result = a ^ b;
break;
default:
throw new IllegalArgumentException("Unknown operation: " + op);
}
variables[receiver.getIndex()] = result;
break;
}
case FLOAT: {
float a = (Float) variables[first.getIndex()];
float b = (Float) variables[second.getIndex()];
float result;
switch (op) {
case ADD:
result = a + b;
break;
case SUBTRACT:
result = a - b;
break;
case MULTIPLY:
result = a * b;
break;
case DIVIDE:
result = a * b;
break;
case MODULO:
result = a % b;
break;
case COMPARE:
result = Float.compare(a, b);
break;
case AND:
case OR:
case XOR:
throw new IllegalArgumentException("Unsupported operation " + op
+ " for operands of type" + type);
default:
throw new IllegalArgumentException("Unknown operation: " + op);
}
variables[receiver.getIndex()] = result;
break;
}
case DOUBLE: {
double a = (Double) variables[first.getIndex()];
double b = (Double) variables[second.getIndex()];
double result;
switch (op) {
case ADD:
result = a + b;
break;
case SUBTRACT:
result = a - b;
break;
case MULTIPLY:
result = a * b;
break;
case DIVIDE:
result = a * b;
break;
case MODULO:
result = a % b;
break;
case COMPARE:
result = Double.compare(a, b);
break;
case AND:
case OR:
case XOR:
throw new IllegalArgumentException("Unsupported operation " + op
+ " for operands of type" + type);
default:
throw new IllegalArgumentException("Unknown operation: " + op);
}
variables[receiver.getIndex()] = result;
break;
}
}
}
@Override
public void negate(VariableReader receiver, VariableReader operand, NumericOperandType type) {
Object result;
Object a = variables[operand.getIndex()];
switch (type) {
case INT:
result = -(Integer) a;
break;
case LONG:
result = -(Long) a;
break;
case FLOAT:
result = -(Float) a;
break;
case DOUBLE:
result = -(Double) a;
break;
default:
throw new IllegalArgumentException("Unknown type: " + type);
}
variables[receiver.getIndex()] = result;
}
@Override
public void assign(VariableReader receiver, VariableReader assignee) {
variables[receiver.getIndex()] = variables[assignee.getIndex()];
}
@Override
public void cast(VariableReader receiver, VariableReader value, ValueType targetType) {
variables[receiver.getIndex()] = asJvmClass(targetType).cast(variables[value.getIndex()]);
}
@Override
public void cast(VariableReader receiver, VariableReader value, NumericOperandType sourceType,
NumericOperandType targetType) {
Object result;
switch (sourceType) {
case INT: {
int a = (Integer) variables[value.getIndex()];
switch (targetType) {
case INT:
result = a;
break;
case LONG:
result = (long) a;
break;
case FLOAT:
result = (float) a;
break;
case DOUBLE:
result = (double) a;
break;
default:
throw new IllegalArgumentException("Can't cast " + sourceType + " to " + targetType);
}
break;
}
case LONG: {
long a = (Long) variables[value.getIndex()];
switch (targetType) {
case INT:
result = (int) a;
break;
case LONG:
result = a;
break;
case FLOAT:
result = (float) a;
break;
case DOUBLE:
result = (double) a;
break;
default:
throw new IllegalArgumentException("Can't cast " + sourceType + " to " + targetType);
}
break;
}
case FLOAT: {
float a = (Float) variables[value.getIndex()];
switch (targetType) {
case INT:
result = (int) a;
break;
case LONG:
result = (long) a;
break;
case FLOAT:
result = a;
break;
case DOUBLE:
result = (double) a;
break;
default:
throw new IllegalArgumentException("Can't cast " + sourceType + " to " + targetType);
}
break;
}
case DOUBLE: {
double a = (Double) variables[value.getIndex()];
switch (targetType) {
case INT:
result = (int) a;
break;
case LONG:
result = (long) a;
break;
case FLOAT:
result = (float) a;
break;
case DOUBLE:
result = a;
break;
default:
throw new IllegalArgumentException("Can't cast " + sourceType + " to " + targetType);
}
break;
}
default:
throw new IllegalArgumentException("Can't cast " + sourceType + " to " + targetType);
}
variables[receiver.getIndex()] = result;
}
@Override
public void cast(VariableReader receiver, VariableReader value, IntegerSubtype type,
CastIntegerDirection direction) {
switch (direction) {
case FROM_INTEGER: {
int a = (Integer) variables[value.getIndex()];
Object result;
switch (type) {
case BYTE:
result = (byte) a;
break;
case SHORT:
result = (short) a;
break;
case CHARACTER:
result = (char) a;
break;
default:
throw new IllegalArgumentException("Unknown type: " + type);
}
variables[receiver.getIndex()] = result;
break;
}
case TO_INTEGER: {
Object a = variables[value.getIndex()];
int result;
switch (type) {
case BYTE:
result = (Byte) a;
break;
case SHORT:
result = (Short) a;
break;
case CHARACTER:
result = (Character) a;
break;
default:
throw new IllegalArgumentException("Unknown type: " + type);
}
variables[receiver.getIndex()] = result;
break;
}
}
}
@Override
public void jumpIf(BranchingCondition cond, VariableReader operand, BasicBlockReader consequent,
BasicBlockReader alternative) {
Object a = variables[operand.getIndex()];
boolean c;
switch (cond) {
case EQUAL:
c = (Integer) a == 0;
break;
case NOT_EQUAL:
c = (Integer) a != 0;
break;
case LESS:
c = (Integer) a < 0;
break;
case LESS_OR_EQUAL:
c = (Integer) a <= 0;
break;
case GREATER:
c = (Integer) a > 0;
break;
case GREATER_OR_EQUAL:
c = (Integer) a >= 0;
break;
case NULL:
c = a == null;
break;
case NOT_NULL:
c = a != null;
break;
default:
throw new IllegalArgumentException("Unknown condition: " + cond);
}
jump(c ? consequent : alternative);
}
@Override
public void jumpIf(BinaryBranchingCondition cond, VariableReader first, VariableReader second,
BasicBlockReader consequent, BasicBlockReader alternative) {
Object a = variables[first.getIndex()];
Object b = variables[second.getIndex()];
boolean c;
switch (cond) {
case EQUAL:
c = ((Integer) a).intValue() == (Integer) b;
break;
case NOT_EQUAL:
c = ((Integer) a).intValue() != (Integer) b;
break;
case REFERENCE_EQUAL:
c = a == b;
break;
case REFERENCE_NOT_EQUAL:
c = a != b;
break;
default:
throw new IllegalArgumentException("Unknown condition: " + cond);
}
jump(c ? consequent : alternative);
}
@Override
public void jump(BasicBlockReader target) {
Object[] newVariables = variables.clone();
for (IncomingReader outgoing : outgoings.get(currentBlock.getIndex())) {
if (outgoing.getPhi().getBasicBlock() != target) {
continue;
}
newVariables[outgoing.getPhi().getReceiver().getIndex()] = variables[outgoing.getValue().getIndex()];
}
variables = newVariables;
currentBlock = target;
}
@Override
public void choose(VariableReader condition, List<? extends SwitchTableEntryReader> table,
BasicBlockReader defaultTarget) {
int value = (Integer) variables[condition.getIndex()];
for (SwitchTableEntryReader entry : table) {
if (value == entry.getCondition()) {
jump(entry.getTarget());
return;
}
}
jump(defaultTarget);
}
@Override
public void exit(VariableReader valueToReturn) {
state = State.EXITED;
result = variables[valueToReturn.getIndex()];
}
@Override
public void raise(VariableReader exception) {
Throwable e = (Throwable) variables[exception.getIndex()];
if (!pickExceptionHandler(e)) {
state = State.EXITED;
result = e;
}
}
@Override
public void createArray(VariableReader receiver, ValueType itemType, VariableReader size) {
Class<?> itemJvmType = asJvmClass(itemType);
int sizeValue = (int) variables[size.getIndex()];
variables[receiver.getIndex()] = Array.newInstance(itemJvmType, sizeValue);
}
@Override
public void createArray(VariableReader receiver, ValueType itemType,
List<? extends VariableReader> dimensions) {
Class<?> itemJvmType = asJvmClass(itemType);
for (int i = 1; i < dimensions.size(); ++i) {
itemJvmType = Array.newInstance(itemJvmType, 0).getClass();
}
variables[receiver.getIndex()] = createArray(itemJvmType, dimensions, 0);
}
private Object createArray(Class<?> itemType, List<? extends VariableReader> dimensions, int dimensionIndex) {
int dimensionValue = (int) variables[dimensions.get(dimensionIndex).getIndex()];
Object result = Array.newInstance(itemType, dimensionValue);
if (dimensionIndex < dimensions.size() - 1) {
for (int i = 0; i < dimensionValue; ++i) {
Array.set(result, i, createArray(itemType.getComponentType(), dimensions, dimensionIndex + 1));
}
}
return result;
}
@Override
public void create(VariableReader receiver, String type) {
Class<?> cls;
try {
cls = Class.forName(type, false, classLoader);
} catch (ClassNotFoundException e) {
throw new RuntimeException("Class not found: " + type);
}
variables[receiver.getIndex()] = objenesis.newInstance(cls);
}
@Override
public void getField(VariableReader receiver, VariableReader instance, FieldReference field,
ValueType fieldType) {
Field jvmField = getJvmField(field);
Object jvmInstance = instance != null ? variables[instance.getIndex()] : null;
Object result;
try {
result = jvmField.get(jvmInstance);
} catch (IllegalAccessException e) {
throw new RuntimeException("Can't get field value: " + field);
}
variables[receiver.getIndex()] = result;
}
@Override
public void putField(VariableReader instance, FieldReference field, VariableReader value, ValueType fieldType) {
Field jvmField = getJvmField(field);
Object jvmInstance = instance != null ? variables[instance.getIndex()] : null;
try {
jvmField.set(jvmInstance, variables[value.getIndex()]);
} catch (IllegalAccessException e) {
throw new RuntimeException("Can't get field value: " + field);
}
}
private Field getJvmField(FieldReference field) {
Class<?> cls;
try {
cls = Class.forName(field.getClassName(), false, classLoader);
} catch (ClassNotFoundException e) {
throw new RuntimeException("Class not found: " + field.getClassName());
}
Field jvmField;
try {
jvmField = cls.getDeclaredField(field.getFieldName());
} catch (NoSuchFieldException e) {
throw new RuntimeException("Field not found: " + field);
}
jvmField.setAccessible(true);
return jvmField;
}
@Override
public void arrayLength(VariableReader receiver, VariableReader array) {
int value = Array.getLength(variables[array.getIndex()]);
variables[receiver.getIndex()] = value;
}
@Override
public void cloneArray(VariableReader receiver, VariableReader array) {
Object jvmArray = variables[array.getIndex()];
int length = Array.getLength(jvmArray);
Object copy = Array.newInstance(jvmArray.getClass().getComponentType(), length);
for (int i = 0; i < length; ++i) {
Array.set(copy, i, Array.get(array, i));
}
variables[receiver.getIndex()] = copy;
}
@Override
public void unwrapArray(VariableReader receiver, VariableReader array, ArrayElementType elementType) {
variables[receiver.getIndex()] = variables[array.getIndex()];
}
@Override
public void getElement(VariableReader receiver, VariableReader array, VariableReader index) {
Object jvmArray = variables[array.getIndex()];
int indexValue = (Integer) variables[index.getIndex()];
variables[receiver.getIndex()] = Array.get(jvmArray, indexValue);
}
@Override
public void putElement(VariableReader array, VariableReader index, VariableReader value) {
Object jvmArray = variables[array.getIndex()];
int indexValue = (Integer) variables[index.getIndex()];
Array.set(jvmArray, indexValue, variables[value.getIndex()]);
}
@Override
public void invoke(VariableReader receiver, VariableReader instance, MethodReference method,
List<? extends VariableReader> arguments, InvocationType type) {
Method jvmMethod = asJvmMethod(method);
Object[] jvmArgs = new Object[arguments.size()];
for (int i = 0; i < jvmArgs.length; ++i) {
jvmArgs[i] = variables[arguments.get(i).getIndex()];
}
Object jvmInstance = instance != null ? variables[instance.getIndex()] : null;
Object result;
try {
result = jvmMethod.invoke(jvmInstance, jvmArgs);
} catch (IllegalAccessException | InvocationTargetException e) {
throw new RuntimeException("Error calling method " + method, e);
}
if (receiver != null) {
variables[receiver.getIndex()] = result;
}
}
private Method asJvmMethod(MethodReference method) {
Class<?> cls;
try {
cls = Class.forName(method.getClassName(), false, classLoader);
} catch (ClassNotFoundException e) {
throw new RuntimeException("Can't find class " + method.getClassName());
}
Class<?>[] jvmParameters = new Class[method.parameterCount()];
for (int i = 0; i < method.parameterCount(); ++i) {
jvmParameters[i] = asJvmClass(method.parameterType(i));
}
Class<?> jvmReturnType = asJvmClass(method.getReturnType());
for (Method jvmMethod : cls.getDeclaredMethods()) {
if (Arrays.equals(jvmMethod.getParameterTypes(), jvmParameters)
&& jvmReturnType.equals(jvmMethod.getReturnType())) {
return jvmMethod;
}
}
throw new RuntimeException("Method not found: " + method);
}
@Override
public void invokeDynamic(VariableReader receiver, VariableReader instance, MethodDescriptor method,
List<? extends VariableReader> arguments, MethodHandle bootstrapMethod,
List<RuntimeConstant> bootstrapArguments) {
throw new RuntimeException("InvokeDynamic is not supported");
}
@Override
public void isInstance(VariableReader receiver, VariableReader value, ValueType type) {
Object jvmValue = variables[value.getIndex()];
Class<?> jvmType = asJvmClass(type);
variables[receiver.getIndex()] = jvmType.isInstance(jvmValue);
}
@Override
public void initClass(String className) {
try {
Class.forName(className);
} catch (ClassNotFoundException e) {
throw new RuntimeException("Class not found: " + className);
}
}
@Override
public void nullCheck(VariableReader receiver, VariableReader value) {
Object jvmValue = variables[value.getIndex()];
if (jvmValue == null) {
throw new NullPointerException();
}
variables[receiver.getIndex()] = jvmValue;
}
@Override
public void monitorEnter(VariableReader objectRef) {
}
@Override
public void monitorExit(VariableReader objectRef) {
}
private Class<?> asJvmClass(ValueType type) {
if (type instanceof ValueType.Primitive) {
switch (((ValueType.Primitive) type).getKind()) {
case BOOLEAN:
return boolean.class;
case BYTE:
return byte.class;
case SHORT:
return short.class;
case CHARACTER:
return char.class;
case INTEGER:
return int.class;
case LONG:
return long.class;
case FLOAT:
return float.class;
case DOUBLE:
return double.class;
default:
break;
}
} else if (type instanceof ValueType.Void) {
return void.class;
} else if (type instanceof ValueType.Array) {
Class<?> itemJvmClass = asJvmClass(((ValueType.Array) type).getItemType());
return Array.newInstance(itemJvmClass, 0).getClass();
} else if (type instanceof ValueType.Object) {
try {
Class.forName(((ValueType.Object) type).getClassName(), false, classLoader);
} catch (ClassNotFoundException e) {
throw new IllegalArgumentException("Class not found: " + type);
}
}
throw new IllegalArgumentException("Unknown type: " + type);
}
};
private enum State {
EXECUTING,
EXITED,
THROWN
}
}

View File

@ -20,10 +20,6 @@ import java.util.Map;
import org.teavm.optimization.GlobalValueNumbering;
import org.teavm.optimization.UnusedVariableElimination;
/**
*
* @author Alexey Andreev
*/
public class PreOptimizingClassHolderSource implements ClassHolderSource {
private ClassHolderSource innerClassSource;
private Map<String, ClassHolder> cache = new HashMap<>();

View File

@ -18,10 +18,6 @@ package org.teavm.model;
import java.util.ArrayList;
import java.util.List;
/**
*
* @author Alexey Andreev
*/
public class Program implements ProgramReader {
private List<BasicBlock> basicBlocks = new ArrayList<>();
private List<Variable> variables = new ArrayList<>();

View File

@ -15,10 +15,6 @@
*/
package org.teavm.model;
/**
*
* @author Alexey Andreev
*/
public class TryCatchBlock implements TryCatchBlockReader {
BasicBlock protectedBlock;
private BasicBlock handler;

View File

@ -15,10 +15,6 @@
*/
package org.teavm.model;
/**
*
* @author Alexey Andreev
*/
public interface TryCatchBlockReader {
BasicBlockReader getProtectedBlock();

View File

@ -0,0 +1,57 @@
/*
* 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.model;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class TryCatchJoint implements TryCatchJointReader {
private BasicBlock source;
private List<Variable> sourceVariables = new ArrayList<>();
private List<VariableReader> readonlySourceVariables;
private Variable receiver;
@Override
public List<VariableReader> readSourceVariables() {
if (readonlySourceVariables == null) {
readonlySourceVariables = Collections.unmodifiableList(sourceVariables);
}
return readonlySourceVariables;
}
public List<Variable> getSourceVariables() {
return sourceVariables;
}
@Override
public Variable getReceiver() {
return receiver;
}
public void setReceiver(Variable receiver) {
this.receiver = receiver;
}
@Override
public BasicBlock getSource() {
return source;
}
public void setSource(BasicBlock source) {
this.source = source;
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2014 Alexey Andreev.
* 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.
@ -13,15 +13,14 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.teavm.parsing;
package org.teavm.model;
import java.util.Map;
import org.teavm.model.Instruction;
import java.util.List;
/**
*
* @author Alexey Andreev
*/
public interface VariableDebugInformation {
Map<Integer, String> getDebugNames(Instruction insn);
public interface TryCatchJointReader {
List<VariableReader> readSourceVariables();
VariableReader getReceiver();
BasicBlockReader getSource();
}

View File

@ -15,15 +15,21 @@
*/
package org.teavm.model.util;
import java.util.function.IntUnaryOperator;
import org.teavm.model.*;
import org.teavm.model.instructions.*;
/**
*
* @author Alexey Andreev
*/
public abstract class BasicBlockMapper implements InstructionVisitor {
protected abstract BasicBlock map(BasicBlock block);
public class BasicBlockMapper implements InstructionVisitor {
private IntUnaryOperator mapFunction;
public BasicBlockMapper(IntUnaryOperator mapFunction) {
this.mapFunction = mapFunction;
}
private BasicBlock map(BasicBlock block) {
Program program = block.getProgram();
return program.basicBlockAt(mapFunction.applyAsInt(block.getIndex()));
}
public void transform(Program program) {
for (int i = 0; i < program.basicBlockCount(); ++i) {
@ -37,6 +43,9 @@ public abstract class BasicBlockMapper implements InstructionVisitor {
return;
}
lastInsn.acceptVisitor(this);
for (TryCatchJoint joint : block.getTryCatchJoints()) {
joint.setSource(map(joint.getSource()));
}
for (Phi phi : block.getPhis()) {
for (Incoming incoming : phi.getIncomings()) {
incoming.setSource(map(incoming.getSource()));

View File

@ -21,10 +21,6 @@ import org.teavm.common.IntegerArray;
import org.teavm.common.MutableGraphEdge;
import org.teavm.common.MutableGraphNode;
/**
*
* @author Alexey Andreev
*/
class GraphColorer {
public void colorize(List<MutableGraphNode> graph, int[] colors) {
colorize(graph, colors, new int[graph.size()]);

View File

@ -0,0 +1,482 @@
/*
* 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.model.util;
import java.util.List;
import java.util.stream.Collectors;
import org.teavm.model.BasicBlock;
import org.teavm.model.BasicBlockReader;
import org.teavm.model.FieldReference;
import org.teavm.model.Instruction;
import org.teavm.model.InstructionLocation;
import org.teavm.model.InvokeDynamicInstruction;
import org.teavm.model.MethodDescriptor;
import org.teavm.model.MethodHandle;
import org.teavm.model.MethodReference;
import org.teavm.model.Program;
import org.teavm.model.RuntimeConstant;
import org.teavm.model.ValueType;
import org.teavm.model.Variable;
import org.teavm.model.VariableReader;
import org.teavm.model.instructions.ArrayElementType;
import org.teavm.model.instructions.ArrayLengthInstruction;
import org.teavm.model.instructions.AssignInstruction;
import org.teavm.model.instructions.BinaryBranchingCondition;
import org.teavm.model.instructions.BinaryBranchingInstruction;
import org.teavm.model.instructions.BinaryInstruction;
import org.teavm.model.instructions.BinaryOperation;
import org.teavm.model.instructions.BranchingCondition;
import org.teavm.model.instructions.BranchingInstruction;
import org.teavm.model.instructions.CastInstruction;
import org.teavm.model.instructions.CastIntegerDirection;
import org.teavm.model.instructions.CastIntegerInstruction;
import org.teavm.model.instructions.CastNumberInstruction;
import org.teavm.model.instructions.ClassConstantInstruction;
import org.teavm.model.instructions.CloneArrayInstruction;
import org.teavm.model.instructions.ConstructArrayInstruction;
import org.teavm.model.instructions.ConstructInstruction;
import org.teavm.model.instructions.ConstructMultiArrayInstruction;
import org.teavm.model.instructions.DoubleConstantInstruction;
import org.teavm.model.instructions.EmptyInstruction;
import org.teavm.model.instructions.ExitInstruction;
import org.teavm.model.instructions.FloatConstantInstruction;
import org.teavm.model.instructions.GetElementInstruction;
import org.teavm.model.instructions.GetFieldInstruction;
import org.teavm.model.instructions.InitClassInstruction;
import org.teavm.model.instructions.InstructionReader;
import org.teavm.model.instructions.IntegerConstantInstruction;
import org.teavm.model.instructions.IntegerSubtype;
import org.teavm.model.instructions.InvocationType;
import org.teavm.model.instructions.InvokeInstruction;
import org.teavm.model.instructions.IsInstanceInstruction;
import org.teavm.model.instructions.JumpInstruction;
import org.teavm.model.instructions.LongConstantInstruction;
import org.teavm.model.instructions.MonitorEnterInstruction;
import org.teavm.model.instructions.MonitorExitInstruction;
import org.teavm.model.instructions.NegateInstruction;
import org.teavm.model.instructions.NullCheckInstruction;
import org.teavm.model.instructions.NullConstantInstruction;
import org.teavm.model.instructions.NumericOperandType;
import org.teavm.model.instructions.PutElementInstruction;
import org.teavm.model.instructions.PutFieldInstruction;
import org.teavm.model.instructions.RaiseInstruction;
import org.teavm.model.instructions.StringConstantInstruction;
import org.teavm.model.instructions.SwitchInstruction;
import org.teavm.model.instructions.SwitchTableEntry;
import org.teavm.model.instructions.SwitchTableEntryReader;
import org.teavm.model.instructions.UnwrapArrayInstruction;
public class InstructionCopyReader implements InstructionReader {
private Instruction copy;
private Program programCopy;
private InstructionLocation location;
public InstructionCopyReader(Program programCopy) {
this.programCopy = programCopy;
}
public Instruction getCopy() {
return copy;
}
public void resetLocation() {
location = null;
}
@Override
public void location(InstructionLocation location) {
this.location = location;
}
private Variable copyVar(VariableReader var) {
if (var == null) {
throw new NullPointerException();
}
return programCopy.variableAt(var.getIndex());
}
private BasicBlock copyBlock(BasicBlockReader block) {
return programCopy.basicBlockAt(block.getIndex());
}
@Override
public void nop() {
copy = new EmptyInstruction();
copy.setLocation(location);
}
@Override
public void classConstant(VariableReader receiver, ValueType cst) {
ClassConstantInstruction insnCopy = new ClassConstantInstruction();
insnCopy.setConstant(cst);
insnCopy.setReceiver(copyVar(receiver));
copy = insnCopy;
copy.setLocation(location);
}
@Override
public void nullConstant(VariableReader receiver) {
NullConstantInstruction insnCopy = new NullConstantInstruction();
insnCopy.setReceiver(copyVar(receiver));
copy = insnCopy;
copy.setLocation(location);
}
@Override
public void integerConstant(VariableReader receiver, int cst) {
IntegerConstantInstruction insnCopy = new IntegerConstantInstruction();
insnCopy.setConstant(cst);
insnCopy.setReceiver(copyVar(receiver));
copy = insnCopy;
copy.setLocation(location);
}
@Override
public void longConstant(VariableReader receiver, long cst) {
LongConstantInstruction insnCopy = new LongConstantInstruction();
insnCopy.setConstant(cst);
insnCopy.setReceiver(copyVar(receiver));
copy = insnCopy;
copy.setLocation(location);
}
@Override
public void floatConstant(VariableReader receiver, float cst) {
FloatConstantInstruction insnCopy = new FloatConstantInstruction();
insnCopy.setConstant(cst);
insnCopy.setReceiver(copyVar(receiver));
copy = insnCopy;
copy.setLocation(location);
}
@Override
public void doubleConstant(VariableReader receiver, double cst) {
DoubleConstantInstruction insnCopy = new DoubleConstantInstruction();
insnCopy.setConstant(cst);
insnCopy.setReceiver(copyVar(receiver));
copy = insnCopy;
copy.setLocation(location);
}
@Override
public void stringConstant(VariableReader receiver, String cst) {
StringConstantInstruction insnCopy = new StringConstantInstruction();
insnCopy.setConstant(cst);
insnCopy.setReceiver(copyVar(receiver));
copy = insnCopy;
copy.setLocation(location);
}
@Override
public void binary(BinaryOperation op, VariableReader receiver, VariableReader first, VariableReader second,
NumericOperandType type) {
BinaryInstruction insnCopy = new BinaryInstruction(op, type);
insnCopy.setFirstOperand(copyVar(first));
insnCopy.setSecondOperand(copyVar(second));
insnCopy.setReceiver(copyVar(receiver));
copy = insnCopy;
copy.setLocation(location);
}
@Override
public void negate(VariableReader receiver, VariableReader operand, NumericOperandType type) {
NegateInstruction insnCopy = new NegateInstruction(type);
insnCopy.setOperand(copyVar(operand));
insnCopy.setReceiver(copyVar(receiver));
copy = insnCopy;
copy.setLocation(location);
}
@Override
public void assign(VariableReader receiver, VariableReader assignee) {
AssignInstruction insnCopy = new AssignInstruction();
insnCopy.setAssignee(copyVar(assignee));
insnCopy.setReceiver(copyVar(receiver));
copy = insnCopy;
copy.setLocation(location);
}
@Override
public void cast(VariableReader receiver, VariableReader value, ValueType targetType) {
CastInstruction insnCopy = new CastInstruction();
insnCopy.setValue(copyVar(value));
insnCopy.setReceiver(copyVar(receiver));
insnCopy.setTargetType(targetType);
copy = insnCopy;
copy.setLocation(location);
}
@Override
public void cast(VariableReader receiver, VariableReader value, NumericOperandType sourceType,
NumericOperandType targetType) {
CastNumberInstruction insnCopy = new CastNumberInstruction(sourceType, targetType);
insnCopy.setValue(copyVar(value));
insnCopy.setReceiver(copyVar(receiver));
copy = insnCopy;
copy.setLocation(location);
}
@Override
public void cast(VariableReader receiver, VariableReader value, IntegerSubtype type,
CastIntegerDirection dir) {
CastIntegerInstruction insnCopy = new CastIntegerInstruction(type, dir);
insnCopy.setValue(copyVar(value));
insnCopy.setReceiver(copyVar(receiver));
copy = insnCopy;
copy.setLocation(location);
}
@Override
public void jumpIf(BranchingCondition cond, VariableReader operand, BasicBlockReader consequent,
BasicBlockReader alternative) {
BranchingInstruction insnCopy = new BranchingInstruction(cond);
insnCopy.setOperand(copyVar(operand));
insnCopy.setConsequent(copyBlock(consequent));
insnCopy.setAlternative(copyBlock(alternative));
copy = insnCopy;
copy.setLocation(location);
}
@Override
public void jumpIf(BinaryBranchingCondition cond, VariableReader first, VariableReader second,
BasicBlockReader consequent, BasicBlockReader alternative) {
BinaryBranchingInstruction insnCopy = new BinaryBranchingInstruction(cond);
insnCopy.setFirstOperand(copyVar(first));
insnCopy.setSecondOperand(copyVar(second));
insnCopy.setConsequent(copyBlock(consequent));
insnCopy.setAlternative(copyBlock(alternative));
copy = insnCopy;
copy.setLocation(location);
}
@Override
public void jump(BasicBlockReader target) {
JumpInstruction insnCopy = new JumpInstruction();
insnCopy.setTarget(copyBlock(target));
copy = insnCopy;
copy.setLocation(location);
}
@Override
public void choose(VariableReader condition, List<? extends SwitchTableEntryReader> table,
BasicBlockReader defaultTarget) {
SwitchInstruction insnCopy = new SwitchInstruction();
insnCopy.setCondition(copyVar(condition));
insnCopy.setDefaultTarget(copyBlock(defaultTarget));
for (SwitchTableEntryReader entry : table) {
SwitchTableEntry entryCopy = new SwitchTableEntry();
entryCopy.setCondition(entry.getCondition());
entryCopy.setTarget(copyBlock(entry.getTarget()));
insnCopy.getEntries().add(entryCopy);
}
copy = insnCopy;
copy.setLocation(location);
}
@Override
public void exit(VariableReader valueToReturn) {
ExitInstruction insnCopy = new ExitInstruction();
insnCopy.setValueToReturn(valueToReturn != null ? copyVar(valueToReturn) : null);
copy = insnCopy;
copy.setLocation(location);
}
@Override
public void raise(VariableReader exception) {
RaiseInstruction insnCopy = new RaiseInstruction();
insnCopy.setException(copyVar(exception));
copy = insnCopy;
copy.setLocation(location);
}
@Override
public void createArray(VariableReader receiver, ValueType itemType, VariableReader size) {
ConstructArrayInstruction insnCopy = new ConstructArrayInstruction();
insnCopy.setItemType(itemType);
insnCopy.setSize(copyVar(size));
insnCopy.setReceiver(copyVar(receiver));
copy = insnCopy;
copy.setLocation(location);
}
@Override
public void createArray(VariableReader receiver, ValueType itemType,
List<? extends VariableReader> dimensions) {
ConstructMultiArrayInstruction insnCopy = new ConstructMultiArrayInstruction();
insnCopy.setItemType(itemType);
insnCopy.setReceiver(copyVar(receiver));
for (VariableReader dim : dimensions) {
insnCopy.getDimensions().add(copyVar(dim));
}
copy = insnCopy;
copy.setLocation(location);
}
@Override
public void create(VariableReader receiver, String type) {
ConstructInstruction insnCopy = new ConstructInstruction();
insnCopy.setType(type);
insnCopy.setReceiver(copyVar(receiver));
copy = insnCopy;
copy.setLocation(location);
}
@Override
public void getField(VariableReader receiver, VariableReader instance, FieldReference field,
ValueType fieldType) {
GetFieldInstruction insnCopy = new GetFieldInstruction();
insnCopy.setField(field);
insnCopy.setFieldType(fieldType);
insnCopy.setInstance(instance != null ? copyVar(instance) : null);
insnCopy.setReceiver(copyVar(receiver));
copy = insnCopy;
copy.setLocation(location);
}
@Override
public void putField(VariableReader instance, FieldReference field, VariableReader value,
ValueType fieldType) {
PutFieldInstruction insnCopy = new PutFieldInstruction();
insnCopy.setField(field);
insnCopy.setInstance(instance != null ? copyVar(instance) : null);
insnCopy.setValue(copyVar(value));
insnCopy.setFieldType(fieldType);
copy = insnCopy;
copy.setLocation(location);
}
@Override
public void arrayLength(VariableReader receiver, VariableReader array) {
ArrayLengthInstruction insnCopy = new ArrayLengthInstruction();
insnCopy.setArray(copyVar(array));
insnCopy.setReceiver(copyVar(receiver));
copy = insnCopy;
copy.setLocation(location);
}
@Override
public void cloneArray(VariableReader receiver, VariableReader array) {
CloneArrayInstruction insnCopy = new CloneArrayInstruction();
insnCopy.setArray(copyVar(array));
insnCopy.setReceiver(copyVar(receiver));
copy = insnCopy;
copy.setLocation(location);
}
@Override
public void unwrapArray(VariableReader receiver, VariableReader array, ArrayElementType elementType) {
UnwrapArrayInstruction insnCopy = new UnwrapArrayInstruction(elementType);
insnCopy.setArray(copyVar(array));
insnCopy.setReceiver(copyVar(receiver));
copy = insnCopy;
copy.setLocation(location);
}
@Override
public void getElement(VariableReader receiver, VariableReader array, VariableReader index) {
GetElementInstruction insnCopy = new GetElementInstruction();
insnCopy.setArray(copyVar(array));
insnCopy.setReceiver(copyVar(receiver));
insnCopy.setIndex(copyVar(index));
copy = insnCopy;
copy.setLocation(location);
}
@Override
public void putElement(VariableReader array, VariableReader index, VariableReader value) {
PutElementInstruction insnCopy = new PutElementInstruction();
insnCopy.setArray(copyVar(array));
insnCopy.setValue(copyVar(value));
insnCopy.setIndex(copyVar(index));
copy = insnCopy;
copy.setLocation(location);
}
@Override
public void invoke(VariableReader receiver, VariableReader instance, MethodReference method,
List<? extends VariableReader> arguments, InvocationType type) {
InvokeInstruction insnCopy = new InvokeInstruction();
insnCopy.setMethod(method);
insnCopy.setType(type);
insnCopy.setInstance(instance != null ? copyVar(instance) : null);
insnCopy.setReceiver(receiver != null ? copyVar(receiver) : null);
for (VariableReader arg : arguments) {
insnCopy.getArguments().add(copyVar(arg));
}
copy = insnCopy;
copy.setLocation(location);
}
@Override
public void invokeDynamic(VariableReader receiver, VariableReader instance, MethodDescriptor method,
List<? extends VariableReader> arguments, MethodHandle bootstrapMethod,
List<RuntimeConstant> bootstrapArguments) {
InvokeDynamicInstruction insnCopy = new InvokeDynamicInstruction();
insnCopy.setMethod(method);
insnCopy.setBootstrapMethod(bootstrapMethod);
insnCopy.getBootstrapArguments().addAll(bootstrapArguments);
if (instance != null) {
insnCopy.setInstance(copyVar(instance));
}
insnCopy.getArguments().addAll(arguments.stream().map(this::copyVar).collect(Collectors.toList()));
insnCopy.setReceiver(receiver != null ? copyVar(receiver) : null);
copy = insnCopy;
copy.setLocation(location);
}
@Override
public void isInstance(VariableReader receiver, VariableReader value, ValueType type) {
IsInstanceInstruction insnCopy = new IsInstanceInstruction();
insnCopy.setValue(copyVar(value));
insnCopy.setReceiver(copyVar(receiver));
insnCopy.setType(type);
copy = insnCopy;
copy.setLocation(location);
}
@Override
public void initClass(String className) {
InitClassInstruction insnCopy = new InitClassInstruction();
insnCopy.setClassName(className);
copy = insnCopy;
copy.setLocation(location);
}
@Override
public void nullCheck(VariableReader receiver, VariableReader value) {
NullCheckInstruction insnCopy = new NullCheckInstruction();
insnCopy.setReceiver(copyVar(receiver));
insnCopy.setValue(copyVar(value));
copy = insnCopy;
copy.setLocation(location);
}
@Override
public void monitorEnter(VariableReader objectRef) {
MonitorEnterInstruction insnCopy = new MonitorEnterInstruction();
insnCopy.setObjectRef(copyVar(objectRef));
copy = insnCopy;
copy.setLocation(location);
}
@Override
public void monitorExit(VariableReader objectRef) {
MonitorExitInstruction insnCopy = new MonitorExitInstruction();
insnCopy.setObjectRef(copyVar(objectRef));
copy = insnCopy;
copy.setLocation(location);
}
}

View File

@ -15,16 +15,67 @@
*/
package org.teavm.model.util;
import java.util.function.Function;
import org.teavm.model.BasicBlock;
import org.teavm.model.Incoming;
import org.teavm.model.Instruction;
import org.teavm.model.InvokeDynamicInstruction;
import org.teavm.model.Phi;
import org.teavm.model.TryCatchBlock;
import org.teavm.model.TryCatchJoint;
import org.teavm.model.Variable;
import org.teavm.model.instructions.*;
/**
*
* @author Alexey Andreev
*/
public abstract class InstructionVariableMapper implements InstructionVisitor {
protected abstract Variable map(Variable var);
public class InstructionVariableMapper implements InstructionVisitor {
private final Function<Variable, Variable> f;
public InstructionVariableMapper(Function<Variable, Variable> f) {
this.f = f;
}
public void apply(BasicBlock block) {
applyToInstructions(block);
applyToPhis(block);
applyToTryCatchBlocks(block);
applyToTryCatchJoints(block);
}
public void applyToInstructions(BasicBlock block) {
for (Instruction insn : block.getInstructions()) {
insn.acceptVisitor(this);
}
}
public void applyToPhis(BasicBlock block) {
for (Phi phi : block.getPhis()) {
phi.setReceiver(map(phi.getReceiver()));
for (Incoming incoming : phi.getIncomings()) {
incoming.setValue(map(incoming.getValue()));
}
}
}
public void applyToTryCatchBlocks(BasicBlock block) {
for (TryCatchBlock tryCatch : block.getTryCatchBlocks()) {
if (tryCatch.getExceptionVariable() != null) {
tryCatch.setExceptionVariable(map(tryCatch.getExceptionVariable()));
}
}
}
public void applyToTryCatchJoints(BasicBlock block) {
for (TryCatchJoint joint : block.getTryCatchJoints()) {
joint.setReceiver(map(joint.getReceiver()));
for (int i = 0; i < joint.getSourceVariables().size(); ++i) {
Variable var = joint.getSourceVariables().get(i);
joint.getSourceVariables().set(i, map(var));
}
}
}
private Variable map(Variable var) {
return f.apply(var);
}
@Override
public void visit(EmptyInstruction insn) {
@ -252,8 +303,4 @@ public abstract class InstructionVariableMapper implements InstructionVisitor {
public void visit(MonitorExitInstruction insn) {
insn.setObjectRef(map(insn.getObjectRef()));
}
}

View File

@ -19,10 +19,6 @@ import java.util.*;
import org.teavm.common.MutableGraphNode;
import org.teavm.model.*;
/**
*
* @author Alexey Andreev
*/
class InterferenceGraphBuilder {
public List<MutableGraphNode> build(Program program, int paramCount, LivenessAnalyzer liveness) {
List<MutableGraphNode> nodes = new ArrayList<>();
@ -32,7 +28,8 @@ class InterferenceGraphBuilder {
UsageExtractor useExtractor = new UsageExtractor();
DefinitionExtractor defExtractor = new DefinitionExtractor();
InstructionTransitionExtractor succExtractor = new InstructionTransitionExtractor();
List<List<Incoming>> outgoings = getOutgoings(program);
List<List<Incoming>> outgoings = ProgramUtils.getPhiOutputs(program);
List<List<TryCatchJoint>> outputJoints = ProgramUtils.getOutputJoints(program);
Set<MutableGraphNode> live = new HashSet<>(128);
for (int i = 0; i < program.basicBlockCount(); ++i) {
BasicBlock block = program.basicBlockAt(i);
@ -50,6 +47,11 @@ class InterferenceGraphBuilder {
live.add(nodes.get(j));
}
}
for (TryCatchJoint joint : outputJoints.get(i)) {
for (Variable outputVar : joint.getSourceVariables()) {
live.add(nodes.get(outputVar.getIndex()));
}
}
for (Incoming outgoing : outgoings.get(i)) {
live.add(nodes.get(outgoing.getValue().getIndex()));
}
@ -89,29 +91,21 @@ class InterferenceGraphBuilder {
live.add(nodes.get(j));
}
}
for (TryCatchJoint joint : block.getTryCatchJoints()) {
live.add(nodes.get(joint.getReceiver().getIndex()));
}
for (Phi phi : block.getPhis()) {
live.add(nodes.get(phi.getReceiver().getIndex()));
}
for (TryCatchJoint joint : block.getTryCatchJoints()) {
nodes.get(joint.getReceiver().getIndex()).connectAll(live);
}
for (Phi phi : block.getPhis()) {
nodes.get(phi.getReceiver().getIndex()).connectAll(live);
}
}
return nodes;
}
private List<List<Incoming>> getOutgoings(Program program) {
List<List<Incoming>> outgoings = new ArrayList<>(program.basicBlockCount());
for (int i = 0; i < program.basicBlockCount(); ++i) {
outgoings.add(new ArrayList<Incoming>());
}
for (int i = 0; i < program.basicBlockCount(); ++i) {
BasicBlock block = program.basicBlockAt(i);
for (Phi phi : block.getPhis()) {
for (Incoming incoming : phi.getIncomings()) {
outgoings.get(incoming.getSource().getIndex()).add(incoming);
}
}
}
return outgoings;
}
}

View File

@ -17,12 +17,9 @@ package org.teavm.model.util;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
import org.teavm.model.*;
/**
*
* @author Alexey Andreev
*/
public class ListingBuilder {
public String buildListing(ProgramReader program, String prefix) {
StringBuilder sb = new StringBuilder();
@ -50,6 +47,13 @@ public class ListingBuilder {
if (block == null) {
continue;
}
for (TryCatchJointReader joint : block.readTryCatchJoints()) {
sb.append(" @").append(joint.getReceiver().getIndex()).append(" := e-phi(");
sb.append(joint.readSourceVariables().stream().map(sourceVar -> "@" + sourceVar.getIndex())
.collect(Collectors.joining(", ")));
sb.append(") from $").append(joint.getSource().getIndex()).append("\n");
}
for (PhiReader phi : block.readPhis()) {
sb.append(prefix).append(" ");
sb.append("@").append(phi.getReceiver().getIndex()).append(" := ");
@ -64,6 +68,7 @@ public class ListingBuilder {
}
sb.append("\n");
}
InstructionLocation location = null;
for (int j = 0; j < block.instructionCount(); ++j) {
insnSb.setLength(0);
@ -78,7 +83,8 @@ public class ListingBuilder {
for (TryCatchBlockReader tryCatch : block.readTryCatchBlocks()) {
sb.append(prefix).append(" catch ").append(tryCatch.getExceptionType()).append(" @")
.append(tryCatch.getExceptionVariable().getIndex())
.append(" -> $").append(tryCatch.getHandler().getIndex()).append("\n");
.append(" -> $").append(tryCatch.getHandler().getIndex());
sb.append("\n");
}
}
return sb.toString();

View File

@ -23,10 +23,6 @@ import java.util.Deque;
import org.teavm.common.Graph;
import org.teavm.model.*;
/**
*
* @author Alexey Andreev
*/
public class LivenessAnalyzer {
private BitSet[] liveVars;
@ -73,6 +69,16 @@ public class LivenessAnalyzer {
definitions[tryCatch.getExceptionVariable().getIndex()] = i;
}
}
for (TryCatchJoint joint : block.getTryCatchJoints()) {
definitions[joint.getReceiver().getIndex()] = i;
for (Variable sourceVar : joint.getSourceVariables()) {
Task task = new Task();
task.block = joint.getSource().getIndex();
task.var = sourceVar.getIndex();
stack.push(task);
}
}
for (Phi phi : block.getPhis()) {
definitions[phi.getReceiver().getIndex()] = i;
for (Incoming incoming : phi.getIncomings()) {

View File

@ -1,5 +1,5 @@
/*
* Copyright 2013 Alexey Andreev.
* 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.
@ -13,94 +13,133 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.teavm.parsing;
package org.teavm.model.util;
import java.util.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.teavm.common.DominatorTree;
import org.teavm.common.Graph;
import org.teavm.common.GraphUtils;
import org.teavm.model.*;
import org.teavm.model.instructions.*;
import org.teavm.model.util.DefinitionExtractor;
import org.teavm.model.util.ProgramUtils;
import org.teavm.model.BasicBlock;
import org.teavm.model.Incoming;
import org.teavm.model.Instruction;
import org.teavm.model.InvokeDynamicInstruction;
import org.teavm.model.Phi;
import org.teavm.model.Program;
import org.teavm.model.TryCatchBlock;
import org.teavm.model.TryCatchJoint;
import org.teavm.model.Variable;
import org.teavm.model.instructions.ArrayLengthInstruction;
import org.teavm.model.instructions.AssignInstruction;
import org.teavm.model.instructions.BinaryBranchingInstruction;
import org.teavm.model.instructions.BinaryInstruction;
import org.teavm.model.instructions.BranchingInstruction;
import org.teavm.model.instructions.CastInstruction;
import org.teavm.model.instructions.CastIntegerInstruction;
import org.teavm.model.instructions.CastNumberInstruction;
import org.teavm.model.instructions.ClassConstantInstruction;
import org.teavm.model.instructions.CloneArrayInstruction;
import org.teavm.model.instructions.ConstructArrayInstruction;
import org.teavm.model.instructions.ConstructInstruction;
import org.teavm.model.instructions.ConstructMultiArrayInstruction;
import org.teavm.model.instructions.DoubleConstantInstruction;
import org.teavm.model.instructions.EmptyInstruction;
import org.teavm.model.instructions.ExitInstruction;
import org.teavm.model.instructions.FloatConstantInstruction;
import org.teavm.model.instructions.GetElementInstruction;
import org.teavm.model.instructions.GetFieldInstruction;
import org.teavm.model.instructions.InitClassInstruction;
import org.teavm.model.instructions.InstructionVisitor;
import org.teavm.model.instructions.IntegerConstantInstruction;
import org.teavm.model.instructions.InvokeInstruction;
import org.teavm.model.instructions.IsInstanceInstruction;
import org.teavm.model.instructions.JumpInstruction;
import org.teavm.model.instructions.LongConstantInstruction;
import org.teavm.model.instructions.MonitorEnterInstruction;
import org.teavm.model.instructions.MonitorExitInstruction;
import org.teavm.model.instructions.NegateInstruction;
import org.teavm.model.instructions.NullCheckInstruction;
import org.teavm.model.instructions.NullConstantInstruction;
import org.teavm.model.instructions.PutElementInstruction;
import org.teavm.model.instructions.PutFieldInstruction;
import org.teavm.model.instructions.RaiseInstruction;
import org.teavm.model.instructions.StringConstantInstruction;
import org.teavm.model.instructions.SwitchInstruction;
import org.teavm.model.instructions.UnwrapArrayInstruction;
/**
*
* @author Alexey Andreev
*/
public class SSATransformer {
public class PhiUpdater {
private Program program;
private Graph cfg;
private DominatorTree domTree;
private int[][] domFrontiers;
private Variable[] variableMap;
private BasicBlock currentBlock;
private Phi[][] phiMap;
private int[][] phiIndexMap;
private ValueType[] arguments;
private VariableDebugInformation variableDebugInfo;
private Map<Integer, String> variableDebugMap = new HashMap<>();
private List<Map<BasicBlock, Map<Variable, TryCatchJoint>>> jointMap = new ArrayList<>();
private List<List<Phi>> synthesizedPhis = new ArrayList<>();
private List<List<TryCatchJoint>> synthesizedJoints = new ArrayList<>();
private boolean[] usedDefinitions;
public void transformToSSA(Program program, VariableDebugInformation variableDebugInfo, ValueType[] arguments) {
public void updatePhis(Program program, Variable[] arguments) {
if (program.basicBlockCount() == 0) {
return;
}
this.program = program;
this.variableDebugInfo = variableDebugInfo;
this.arguments = arguments;
variableDebugMap.clear();
cfg = ProgramUtils.buildControlFlowGraphWithTryCatch(program);
domTree = GraphUtils.buildDominatorTree(cfg);
cfg = ProgramUtils.buildControlFlowGraph(program);
DominatorTree domTree = GraphUtils.buildDominatorTree(cfg);
domFrontiers = new int[cfg.size()][];
variableMap = new Variable[program.variableCount()];
usedDefinitions = new boolean[program.variableCount()];
for (int i = 0; i < arguments.length; ++i) {
variableMap[i] = arguments[i];
usedDefinitions[i] = true;
}
phiMap = new Phi[program.basicBlockCount()][];
phiIndexMap = new int[program.basicBlockCount()][];
jointMap = new ArrayList<>();
for (int i = 0; i < phiMap.length; ++i) {
phiMap[i] = new Phi[program.variableCount()];
phiIndexMap[i] = new int[program.variableCount()];
jointMap.add(new HashMap<>());
}
applySignature();
domFrontiers = GraphUtils.findDominanceFrontiers(cfg, domTree);
synthesizedPhis.clear();
synthesizedJoints.clear();
for (int i = 0; i < program.basicBlockCount(); ++i) {
synthesizedPhis.add(new ArrayList<>());
synthesizedJoints.add(new ArrayList<>());
}
estimatePhis();
renameVariables();
}
private void applySignature() {
if (program.variableCount() == 0) {
return;
}
int index = 0;
variableMap[index] = program.variableAt(index);
++index;
for (int i = 0; i < arguments.length; ++i) {
variableMap[index] = program.variableAt(i + 1);
++index;
ValueType arg = arguments[i];
if (arg instanceof ValueType.Primitive) {
PrimitiveType kind = ((ValueType.Primitive) arg).getKind();
if (kind == PrimitiveType.LONG || kind == PrimitiveType.DOUBLE) {
variableMap[index] = variableMap[index - 1];
++index;
}
}
}
arguments = null;
}
private void estimatePhis() {
DefinitionExtractor definitionExtractor = new DefinitionExtractor();
for (int i = 0; i < program.basicBlockCount(); ++i) {
currentBlock = program.basicBlockAt(i);
for (Phi phi : currentBlock.getPhis()) {
markAssignment(phi.getReceiver());
}
for (TryCatchJoint joint : currentBlock.getTryCatchJoints()) {
markAssignment(joint.getReceiver());
}
for (Instruction insn : currentBlock.getInstructions()) {
insn.acceptVisitor(definitionExtractor);
for (Variable var : definitionExtractor.getDefinedVariables()) {
markAssignment(var);
}
}
for (TryCatchBlock tryCatch : currentBlock.getTryCatchBlocks()) {
markAssignment(tryCatch.getExceptionVariable());
}
}
}
static class Task {
private static class Task {
Variable[] variables;
BasicBlock block;
}
@ -119,63 +158,72 @@ public class SSATransformer {
}
}
List<List<TryCatchBlock>> caughtBlocks = new ArrayList<>();
List<List<Phi>> specialPhis = new ArrayList<>();
for (int i = 0; i < program.basicBlockCount(); ++i) {
caughtBlocks.add(new ArrayList<>());
specialPhis.add(new ArrayList<>());
}
for (int i = 0; i < program.basicBlockCount(); ++i) {
for (TryCatchBlock tryCatch : program.basicBlockAt(i).getTryCatchBlocks()) {
caughtBlocks.get(tryCatch.getHandler().getIndex()).add(tryCatch);
}
}
List<List<Incoming>> phiOutputs = ProgramUtils.getPhiOutputs(program);
List<List<TryCatchJoint>> existingOutputJoints = ProgramUtils.getOutputJoints(program);
boolean[] processed = new boolean[program.basicBlockCount()];
while (head > 0) {
Task task = stack[--head];
currentBlock = task.block;
if (processed[currentBlock.getIndex()]) {
int index = currentBlock.getIndex();
if (processed[index]) {
continue;
}
processed[currentBlock.getIndex()] = true;
processed[index] = true;
variableMap = Arrays.copyOf(task.variables, task.variables.length);
for (Phi phi : currentBlock.getPhis()) {
for (Phi phi : synthesizedPhis.get(index)) {
Variable var = program.createVariable();
var.getDebugNames().addAll(phi.getReceiver().getDebugNames());
variableMap[phi.getReceiver().getIndex()] = var;
phi.setReceiver(var);
}
if (!caughtBlocks.get(currentBlock.getIndex()).isEmpty()) {
Phi phi = new Phi();
phi.setReceiver(program.createVariable());
for (TryCatchBlock tryCatch : caughtBlocks.get(currentBlock.getIndex())) {
variableMap[tryCatch.getExceptionVariable().getIndex()] = phi.getReceiver();
Set<String> debugNames = tryCatch.getExceptionVariable().getDebugNames();
tryCatch.setExceptionVariable(program.createVariable());
tryCatch.getExceptionVariable().getDebugNames().addAll(debugNames);
Incoming incoming = new Incoming();
incoming.setSource(tryCatch.getProtectedBlock());
incoming.setValue(tryCatch.getExceptionVariable());
phi.getIncomings().add(incoming);
}
specialPhis.get(currentBlock.getIndex()).add(phi);
for (TryCatchJoint joint : synthesizedJoints.get(index)) {
Variable var = program.createVariable();
var.getDebugNames().addAll(joint.getReceiver().getDebugNames());
variableMap[joint.getReceiver().getIndex()] = var;
joint.setReceiver(var);
}
for (Phi phi : currentBlock.getPhis()) {
phi.setReceiver(define(phi.getReceiver()));
}
for (TryCatchJoint joint : currentBlock.getTryCatchJoints()) {
joint.setReceiver(define(joint.getReceiver()));
}
for (Instruction insn : currentBlock.getInstructions()) {
variableDebugMap.putAll(variableDebugInfo.getDebugNames(insn));
insn.acceptVisitor(consumer);
}
int[] successors = domGraph.outgoingEdges(currentBlock.getIndex());
for (int i = 0; i < successors.length; ++i) {
for (TryCatchBlock tryCatch : currentBlock.getTryCatchBlocks()) {
Variable var = tryCatch.getExceptionVariable();
if (var != null) {
Variable newVar = introduce(var, true);
tryCatch.setExceptionVariable(newVar);
}
}
for (Incoming output : phiOutputs.get(index)) {
output.setValue(use(output.getValue()));
}
for (TryCatchJoint joint : existingOutputJoints.get(index)) {
for (int i = 0; i < joint.getSourceVariables().size(); ++i) {
Variable var = joint.getSourceVariables().get(i);
joint.getSourceVariables().set(i, use(var));
}
}
int[] successors = domGraph.outgoingEdges(index);
for (int successor : successors) {
Task next = new Task();
next.variables = Arrays.copyOf(variableMap, variableMap.length);
next.block = program.basicBlockAt(successors[i]);
next.block = program.basicBlockAt(successor);
stack[head++] = next;
}
successors = cfg.outgoingEdges(currentBlock.getIndex());
for (int i = 0; i < successors.length; ++i) {
int successor = successors[i];
successors = cfg.outgoingEdges(index);
for (int successor : successors) {
int[] phiIndexes = phiIndexMap[successor];
List<Phi> phis = program.basicBlockAt(successor).getPhis();
List<Phi> phis = synthesizedPhis.get(successor);
for (int j = 0; j < phis.size(); ++j) {
Phi phi = phis.get(j);
Variable var = variableMap[phiIndexes[j]];
@ -189,8 +237,18 @@ public class SSATransformer {
}
}
}
for (int i = 0; i < specialPhis.size(); ++i) {
program.basicBlockAt(i).getPhis().addAll(specialPhis.get(i));
for (int i = 0; i < program.basicBlockCount(); ++i) {
for (Phi phi : synthesizedPhis.get(i)) {
if (!phi.getIncomings().isEmpty()) {
program.basicBlockAt(i).getPhis().add(phi);
}
}
for (TryCatchJoint joint : synthesizedJoints.get(i)) {
if (!joint.getSourceVariables().isEmpty()) {
program.basicBlockAt(i).getTryCatchJoints().add(joint);
}
}
}
}
@ -206,24 +264,98 @@ public class SSATransformer {
}
for (int frontier : frontiers) {
BasicBlock frontierBlock = program.basicBlockAt(frontier);
frontierBlock.getPhis();
if (isExceptionHandler(block, frontierBlock)) {
continue;
}
boolean exists = frontierBlock.getPhis().stream()
.flatMap(phi -> phi.getIncomings().stream())
.anyMatch(incoming -> incoming.getSource() == block && incoming.getValue() == var);
if (exists) {
continue;
}
Phi phi = phiMap[frontier][var.getIndex()];
if (phi == null) {
phi = new Phi();
phi.setReceiver(var);
phiIndexMap[frontier][frontierBlock.getPhis().size()] = var.getIndex();
frontierBlock.getPhis().add(phi);
phiIndexMap[frontier][synthesizedPhis.get(frontier).size()] = var.getIndex();
synthesizedPhis.get(frontier).add(phi);
phiMap[frontier][var.getIndex()] = phi;
worklist[head++] = frontierBlock;
}
}
for (TryCatchBlock tryCatch : block.getTryCatchBlocks()) {
BasicBlock frontierBlock = tryCatch.getHandler();
int frontier = frontierBlock.getIndex();
boolean jointExists = frontierBlock.getTryCatchJoints().stream()
.anyMatch(joint -> joint.getSourceVariables().contains(var) && joint.getSource() == block);
if (jointExists) {
continue;
}
Map<Variable, TryCatchJoint> jointSubmap = jointMap.get(frontier).get(block);
if (jointSubmap == null) {
jointSubmap = new HashMap<>();
jointMap.get(frontier).put(block, jointSubmap);
}
TryCatchJoint joint = jointSubmap.get(var);
if (joint == null) {
joint = new TryCatchJoint();
joint.setSource(block);
joint.setReceiver(var);
synthesizedJoints.get(frontier).add(joint);
jointSubmap.put(var, joint);
worklist[head++] = frontierBlock;
}
}
}
}
private boolean isExceptionHandler(BasicBlock source, BasicBlock target) {
return source.getTryCatchBlocks().stream().anyMatch(tryCatch -> tryCatch.getHandler() == target);
}
private Variable define(Variable var) {
Variable result = program.createVariable();
variableMap[var.getIndex()] = result;
return result;
Variable original = var;
var = introduce(var, false);
variableMap[original.getIndex()] = var;
return var;
}
private Variable introduce(Variable var, boolean clear) {
Variable original = var;
Variable old = variableMap[var.getIndex()];
if (old == null) {
old = var;
}
if (!usedDefinitions[var.getIndex()]) {
usedDefinitions[var.getIndex()] = true;
} else {
var = program.createVariable();
}
for (TryCatchBlock tryCatch : currentBlock.getTryCatchBlocks()) {
Map<Variable, TryCatchJoint> joints = jointMap.get(tryCatch.getHandler().getIndex()).get(currentBlock);
if (joints == null) {
continue;
}
TryCatchJoint joint = joints.get(original);
if (joint == null) {
continue;
}
if (joint.getSourceVariables().isEmpty()) {
joint.getSourceVariables().add(original);
}
if (clear) {
joint.getSourceVariables().clear();
}
joint.getSourceVariables().add(var);
}
return var;
}
private Variable use(Variable var) {
@ -231,10 +363,6 @@ public class SSATransformer {
if (mappedVar == null) {
throw new AssertionError();
}
String debugName = variableDebugMap.get(var.getIndex());
if (debugName != null) {
mappedVar.getDebugNames().add(debugName);
}
return mappedVar;
}
@ -440,9 +568,6 @@ public class SSATransformer {
@Override
public void visit(UnwrapArrayInstruction insn) {
insn.setArray(use(insn.getArray()));
for (String debugName : insn.getArray().getDebugNames()) {
variableDebugMap.put(insn.getReceiver().getIndex(), debugName + ".data");
}
insn.setReceiver(define(insn.getReceiver()));
}

View File

@ -45,7 +45,10 @@ public class ProgramNodeSplittingBackend implements GraphSplittingBackend {
copies[i] = blockCopy.getIndex();
map.put(nodes[i], copies[i] + 1);
}
CopyBlockMapper copyBlockMapper = new CopyBlockMapper(map);
BasicBlockMapper copyBlockMapper = new BasicBlockMapper(block -> {
int mappedIndex = map.get(block);
return mappedIndex == 0 ? block : mappedIndex - 1;
});
for (int i = 0; i < copies.length; ++i) {
copyBlockMapper.transform(program.basicBlockAt(copies[i]));
}
@ -54,21 +57,4 @@ public class ProgramNodeSplittingBackend implements GraphSplittingBackend {
}
return copies;
}
private static class CopyBlockMapper extends BasicBlockMapper {
private IntIntMap map;
public CopyBlockMapper(IntIntMap map) {
this.map = map;
}
@Override
protected BasicBlock map(BasicBlock block) {
int mappedIndex = map.get(block.getIndex());
if (mappedIndex == 0) {
return block;
}
return block.getProgram().basicBlockAt(mappedIndex - 1);
}
}
}

View File

@ -15,17 +15,28 @@
*/
package org.teavm.model.util;
import java.util.*;
import java.util.stream.Collectors;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.teavm.common.Graph;
import org.teavm.common.GraphBuilder;
import org.teavm.model.*;
import org.teavm.model.instructions.*;
import org.teavm.model.BasicBlock;
import org.teavm.model.BasicBlockReader;
import org.teavm.model.Incoming;
import org.teavm.model.IncomingReader;
import org.teavm.model.Instruction;
import org.teavm.model.InstructionLocation;
import org.teavm.model.Phi;
import org.teavm.model.PhiReader;
import org.teavm.model.Program;
import org.teavm.model.ProgramReader;
import org.teavm.model.TryCatchBlock;
import org.teavm.model.TryCatchBlockReader;
import org.teavm.model.TryCatchJoint;
import org.teavm.model.TryCatchJointReader;
import org.teavm.model.Variable;
import org.teavm.model.VariableReader;
/**
*
* @author Alexey Andreev
*/
public final class ProgramUtils {
private ProgramUtils() {
}
@ -51,38 +62,12 @@ public final class ProgramUtils {
return graphBuilder.build();
}
public static Graph buildControlFlowGraphWithTryCatch(Program program) {
GraphBuilder graphBuilder = new GraphBuilder(program.basicBlockCount());
InstructionTransitionExtractor transitionExtractor = new InstructionTransitionExtractor();
for (int i = 0; i < program.basicBlockCount(); ++i) {
BasicBlock block = program.basicBlockAt(i);
Instruction insn = block.getLastInstruction();
if (insn != null) {
insn.acceptVisitor(transitionExtractor);
if (transitionExtractor.getTargets() != null) {
for (BasicBlock successor : transitionExtractor.getTargets()) {
graphBuilder.addEdge(i, successor.getIndex());
for (TryCatchBlock succTryCatch : successor.getTryCatchBlocks()) {
graphBuilder.addEdge(i, succTryCatch.getHandler().getIndex());
}
}
}
}
for (TryCatchBlock tryCatch : block.getTryCatchBlocks()) {
graphBuilder.addEdge(i, tryCatch.getHandler().getIndex());
}
}
return graphBuilder.build();
}
public static Map<InstructionLocation, InstructionLocation[]> getLocationCFG(Program program) {
return new LocationGraphBuilder().build(program);
}
public static Program copy(ProgramReader program) {
Program copy = new Program();
InstructionCopyReader insnCopier = new InstructionCopyReader();
insnCopier.programCopy = copy;
for (int i = 0; i < program.variableCount(); ++i) {
Variable var = copy.createVariable();
var.getDebugNames().addAll(program.variableAt(i).readDebugNames());
@ -95,25 +80,18 @@ public final class ProgramUtils {
BasicBlock blockCopy = copy.basicBlockAt(i);
blockCopy.getInstructions().addAll(copyInstructions(block, 0, block.instructionCount(), copy));
blockCopy.getPhis().addAll(copyPhis(block, copy));
for (TryCatchBlockReader tryCatch : block.readTryCatchBlocks()) {
TryCatchBlock tryCatchCopy = new TryCatchBlock();
tryCatchCopy.setExceptionType(tryCatch.getExceptionType());
tryCatchCopy.setExceptionVariable(copy.variableAt(tryCatch.getExceptionVariable().getIndex()));
tryCatchCopy.setHandler(copy.basicBlockAt(tryCatch.getHandler().getIndex()));
blockCopy.getTryCatchBlocks().add(tryCatchCopy);
}
blockCopy.getTryCatchBlocks().addAll(copyTryCatches(block, copy));
blockCopy.getTryCatchJoints().addAll(copyTryCatchJoints(block, copy));
}
return copy;
}
public static List<Instruction> copyInstructions(BasicBlockReader block, int from, int to, Program target) {
List<Instruction> result = new ArrayList<>();
InstructionCopyReader copyReader = new InstructionCopyReader();
copyReader.programCopy = target;
InstructionCopyReader copyReader = new InstructionCopyReader(target);
for (int i = from; i < to; ++i) {
block.readInstruction(i, copyReader);
copyReader.copy.setLocation(copyReader.location);
result.add(copyReader.copy);
result.add(copyReader.getCopy());
}
return result;
}
@ -146,393 +124,51 @@ public final class ProgramUtils {
return result;
}
private static class InstructionCopyReader implements InstructionReader {
Instruction copy;
Program programCopy;
InstructionLocation location;
@Override
public void location(InstructionLocation location) {
this.location = location;
}
private Variable copyVar(VariableReader var) {
if (var == null) {
throw new NullPointerException();
public static List<TryCatchJoint> copyTryCatchJoints(BasicBlockReader block, Program target) {
List<TryCatchJoint> result = new ArrayList<>();
for (TryCatchJointReader joint : block.readTryCatchJoints()) {
TryCatchJoint jointCopy = new TryCatchJoint();
jointCopy.setSource(target.basicBlockAt(joint.getSource().getIndex()));
jointCopy.setReceiver(target.variableAt(joint.getReceiver().getIndex()));
for (VariableReader sourceVar : joint.readSourceVariables()) {
jointCopy.getSourceVariables().add(target.variableAt(sourceVar.getIndex()));
}
return programCopy.variableAt(var.getIndex());
result.add(jointCopy);
}
return result;
}
public static List<List<Incoming>> getPhiOutputs(Program program) {
List<List<Incoming>> outputs = new ArrayList<>(program.basicBlockCount());
for (int i = 0; i < program.basicBlockCount(); ++i) {
outputs.add(new ArrayList<>());
}
private BasicBlock copyBlock(BasicBlockReader block) {
return programCopy.basicBlockAt(block.getIndex());
}
@Override
public void nop() {
copy = new EmptyInstruction();
copy.setLocation(location);
}
@Override
public void classConstant(VariableReader receiver, ValueType cst) {
ClassConstantInstruction insnCopy = new ClassConstantInstruction();
insnCopy.setConstant(cst);
insnCopy.setReceiver(copyVar(receiver));
copy = insnCopy;
copy.setLocation(location);
}
@Override
public void nullConstant(VariableReader receiver) {
NullConstantInstruction insnCopy = new NullConstantInstruction();
insnCopy.setReceiver(copyVar(receiver));
copy = insnCopy;
copy.setLocation(location);
}
@Override
public void integerConstant(VariableReader receiver, int cst) {
IntegerConstantInstruction insnCopy = new IntegerConstantInstruction();
insnCopy.setConstant(cst);
insnCopy.setReceiver(copyVar(receiver));
copy = insnCopy;
copy.setLocation(location);
}
@Override
public void longConstant(VariableReader receiver, long cst) {
LongConstantInstruction insnCopy = new LongConstantInstruction();
insnCopy.setConstant(cst);
insnCopy.setReceiver(copyVar(receiver));
copy = insnCopy;
copy.setLocation(location);
}
@Override
public void floatConstant(VariableReader receiver, float cst) {
FloatConstantInstruction insnCopy = new FloatConstantInstruction();
insnCopy.setConstant(cst);
insnCopy.setReceiver(copyVar(receiver));
copy = insnCopy;
copy.setLocation(location);
}
@Override
public void doubleConstant(VariableReader receiver, double cst) {
DoubleConstantInstruction insnCopy = new DoubleConstantInstruction();
insnCopy.setConstant(cst);
insnCopy.setReceiver(copyVar(receiver));
copy = insnCopy;
copy.setLocation(location);
}
@Override
public void stringConstant(VariableReader receiver, String cst) {
StringConstantInstruction insnCopy = new StringConstantInstruction();
insnCopy.setConstant(cst);
insnCopy.setReceiver(copyVar(receiver));
copy = insnCopy;
copy.setLocation(location);
}
@Override
public void binary(BinaryOperation op, VariableReader receiver, VariableReader first, VariableReader second,
NumericOperandType type) {
BinaryInstruction insnCopy = new BinaryInstruction(op, type);
insnCopy.setFirstOperand(copyVar(first));
insnCopy.setSecondOperand(copyVar(second));
insnCopy.setReceiver(copyVar(receiver));
copy = insnCopy;
copy.setLocation(location);
}
@Override
public void negate(VariableReader receiver, VariableReader operand, NumericOperandType type) {
NegateInstruction insnCopy = new NegateInstruction(type);
insnCopy.setOperand(copyVar(operand));
insnCopy.setReceiver(copyVar(receiver));
copy = insnCopy;
copy.setLocation(location);
}
@Override
public void assign(VariableReader receiver, VariableReader assignee) {
AssignInstruction insnCopy = new AssignInstruction();
insnCopy.setAssignee(copyVar(assignee));
insnCopy.setReceiver(copyVar(receiver));
copy = insnCopy;
copy.setLocation(location);
}
@Override
public void cast(VariableReader receiver, VariableReader value, ValueType targetType) {
CastInstruction insnCopy = new CastInstruction();
insnCopy.setValue(copyVar(value));
insnCopy.setReceiver(copyVar(receiver));
insnCopy.setTargetType(targetType);
copy = insnCopy;
copy.setLocation(location);
}
@Override
public void cast(VariableReader receiver, VariableReader value, NumericOperandType sourceType,
NumericOperandType targetType) {
CastNumberInstruction insnCopy = new CastNumberInstruction(sourceType, targetType);
insnCopy.setValue(copyVar(value));
insnCopy.setReceiver(copyVar(receiver));
copy = insnCopy;
copy.setLocation(location);
}
@Override
public void cast(VariableReader receiver, VariableReader value, IntegerSubtype type,
CastIntegerDirection dir) {
CastIntegerInstruction insnCopy = new CastIntegerInstruction(type, dir);
insnCopy.setValue(copyVar(value));
insnCopy.setReceiver(copyVar(receiver));
copy = insnCopy;
copy.setLocation(location);
}
@Override
public void jumpIf(BranchingCondition cond, VariableReader operand, BasicBlockReader consequent,
BasicBlockReader alternative) {
BranchingInstruction insnCopy = new BranchingInstruction(cond);
insnCopy.setOperand(copyVar(operand));
insnCopy.setConsequent(copyBlock(consequent));
insnCopy.setAlternative(copyBlock(alternative));
copy = insnCopy;
copy.setLocation(location);
}
@Override
public void jumpIf(BinaryBranchingCondition cond, VariableReader first, VariableReader second,
BasicBlockReader consequent, BasicBlockReader alternative) {
BinaryBranchingInstruction insnCopy = new BinaryBranchingInstruction(cond);
insnCopy.setFirstOperand(copyVar(first));
insnCopy.setSecondOperand(copyVar(second));
insnCopy.setConsequent(copyBlock(consequent));
insnCopy.setAlternative(copyBlock(alternative));
copy = insnCopy;
copy.setLocation(location);
}
@Override
public void jump(BasicBlockReader target) {
JumpInstruction insnCopy = new JumpInstruction();
insnCopy.setTarget(copyBlock(target));
copy = insnCopy;
copy.setLocation(location);
}
@Override
public void choose(VariableReader condition, List<? extends SwitchTableEntryReader> table,
BasicBlockReader defaultTarget) {
SwitchInstruction insnCopy = new SwitchInstruction();
insnCopy.setCondition(copyVar(condition));
insnCopy.setDefaultTarget(copyBlock(defaultTarget));
for (SwitchTableEntryReader entry : table) {
SwitchTableEntry entryCopy = new SwitchTableEntry();
entryCopy.setCondition(entry.getCondition());
entryCopy.setTarget(copyBlock(entry.getTarget()));
insnCopy.getEntries().add(entryCopy);
for (int i = 0; i < program.basicBlockCount(); ++i) {
BasicBlock block = program.basicBlockAt(i);
for (Phi phi : block.getPhis()) {
for (Incoming incoming : phi.getIncomings()) {
outputs.get(incoming.getSource().getIndex()).add(incoming);
}
}
copy = insnCopy;
copy.setLocation(location);
}
@Override
public void exit(VariableReader valueToReturn) {
ExitInstruction insnCopy = new ExitInstruction();
insnCopy.setValueToReturn(valueToReturn != null ? copyVar(valueToReturn) : null);
copy = insnCopy;
copy.setLocation(location);
return outputs;
}
public static List<List<TryCatchJoint>> getOutputJoints(Program program) {
List<List<TryCatchJoint>> outputs = new ArrayList<>(program.basicBlockCount());
for (int i = 0; i < program.basicBlockCount(); ++i) {
outputs.add(new ArrayList<>());
}
@Override
public void raise(VariableReader exception) {
RaiseInstruction insnCopy = new RaiseInstruction();
insnCopy.setException(copyVar(exception));
copy = insnCopy;
copy.setLocation(location);
}
@Override
public void createArray(VariableReader receiver, ValueType itemType, VariableReader size) {
ConstructArrayInstruction insnCopy = new ConstructArrayInstruction();
insnCopy.setItemType(itemType);
insnCopy.setSize(copyVar(size));
insnCopy.setReceiver(copyVar(receiver));
copy = insnCopy;
copy.setLocation(location);
}
@Override
public void createArray(VariableReader receiver, ValueType itemType,
List<? extends VariableReader> dimensions) {
ConstructMultiArrayInstruction insnCopy = new ConstructMultiArrayInstruction();
insnCopy.setItemType(itemType);
insnCopy.setReceiver(copyVar(receiver));
for (VariableReader dim : dimensions) {
insnCopy.getDimensions().add(copyVar(dim));
for (int i = 0; i < program.basicBlockCount(); ++i) {
BasicBlock block = program.basicBlockAt(i);
for (TryCatchJoint joint : block.getTryCatchJoints()) {
outputs.get(joint.getSource().getIndex()).add(joint);
}
copy = insnCopy;
copy.setLocation(location);
}
@Override
public void create(VariableReader receiver, String type) {
ConstructInstruction insnCopy = new ConstructInstruction();
insnCopy.setType(type);
insnCopy.setReceiver(copyVar(receiver));
copy = insnCopy;
copy.setLocation(location);
}
@Override
public void getField(VariableReader receiver, VariableReader instance, FieldReference field,
ValueType fieldType) {
GetFieldInstruction insnCopy = new GetFieldInstruction();
insnCopy.setField(field);
insnCopy.setFieldType(fieldType);
insnCopy.setInstance(instance != null ? copyVar(instance) : null);
insnCopy.setReceiver(copyVar(receiver));
copy = insnCopy;
copy.setLocation(location);
}
@Override
public void putField(VariableReader instance, FieldReference field, VariableReader value,
ValueType fieldType) {
PutFieldInstruction insnCopy = new PutFieldInstruction();
insnCopy.setField(field);
insnCopy.setInstance(instance != null ? copyVar(instance) : null);
insnCopy.setValue(copyVar(value));
insnCopy.setFieldType(fieldType);
copy = insnCopy;
copy.setLocation(location);
}
@Override
public void arrayLength(VariableReader receiver, VariableReader array) {
ArrayLengthInstruction insnCopy = new ArrayLengthInstruction();
insnCopy.setArray(copyVar(array));
insnCopy.setReceiver(copyVar(receiver));
copy = insnCopy;
copy.setLocation(location);
}
@Override
public void cloneArray(VariableReader receiver, VariableReader array) {
CloneArrayInstruction insnCopy = new CloneArrayInstruction();
insnCopy.setArray(copyVar(array));
insnCopy.setReceiver(copyVar(receiver));
copy = insnCopy;
copy.setLocation(location);
}
@Override
public void unwrapArray(VariableReader receiver, VariableReader array, ArrayElementType elementType) {
UnwrapArrayInstruction insnCopy = new UnwrapArrayInstruction(elementType);
insnCopy.setArray(copyVar(array));
insnCopy.setReceiver(copyVar(receiver));
copy = insnCopy;
copy.setLocation(location);
}
@Override
public void getElement(VariableReader receiver, VariableReader array, VariableReader index) {
GetElementInstruction insnCopy = new GetElementInstruction();
insnCopy.setArray(copyVar(array));
insnCopy.setReceiver(copyVar(receiver));
insnCopy.setIndex(copyVar(index));
copy = insnCopy;
copy.setLocation(location);
}
@Override
public void putElement(VariableReader array, VariableReader index, VariableReader value) {
PutElementInstruction insnCopy = new PutElementInstruction();
insnCopy.setArray(copyVar(array));
insnCopy.setValue(copyVar(value));
insnCopy.setIndex(copyVar(index));
copy = insnCopy;
copy.setLocation(location);
}
@Override
public void invoke(VariableReader receiver, VariableReader instance, MethodReference method,
List<? extends VariableReader> arguments, InvocationType type) {
InvokeInstruction insnCopy = new InvokeInstruction();
insnCopy.setMethod(method);
insnCopy.setType(type);
insnCopy.setInstance(instance != null ? copyVar(instance) : null);
insnCopy.setReceiver(receiver != null ? copyVar(receiver) : null);
for (VariableReader arg : arguments) {
insnCopy.getArguments().add(copyVar(arg));
}
copy = insnCopy;
copy.setLocation(location);
}
@Override
public void invokeDynamic(VariableReader receiver, VariableReader instance, MethodDescriptor method,
List<? extends VariableReader> arguments, MethodHandle bootstrapMethod,
List<RuntimeConstant> bootstrapArguments) {
InvokeDynamicInstruction insnCopy = new InvokeDynamicInstruction();
insnCopy.setMethod(method);
insnCopy.setBootstrapMethod(bootstrapMethod);
insnCopy.getBootstrapArguments().addAll(bootstrapArguments);
if (instance != null) {
insnCopy.setInstance(copyVar(instance));
}
insnCopy.getArguments().addAll(arguments.stream().map(this::copyVar).collect(Collectors.toList()));
insnCopy.setReceiver(receiver != null ? copyVar(receiver) : null);
copy = insnCopy;
copy.setLocation(location);
}
@Override
public void isInstance(VariableReader receiver, VariableReader value, ValueType type) {
IsInstanceInstruction insnCopy = new IsInstanceInstruction();
insnCopy.setValue(copyVar(value));
insnCopy.setReceiver(copyVar(receiver));
insnCopy.setType(type);
copy = insnCopy;
copy.setLocation(location);
}
@Override
public void initClass(String className) {
InitClassInstruction insnCopy = new InitClassInstruction();
insnCopy.setClassName(className);
copy = insnCopy;
copy.setLocation(location);
}
@Override
public void nullCheck(VariableReader receiver, VariableReader value) {
NullCheckInstruction insnCopy = new NullCheckInstruction();
insnCopy.setReceiver(copyVar(receiver));
insnCopy.setValue(copyVar(value));
copy = insnCopy;
copy.setLocation(location);
}
@Override
public void monitorEnter(VariableReader objectRef) {
MonitorEnterInstruction insnCopy = new MonitorEnterInstruction();
insnCopy.setObjectRef(copyVar(objectRef));
copy = insnCopy;
copy.setLocation(location);
}
@Override
public void monitorExit(VariableReader objectRef) {
MonitorExitInstruction insnCopy = new MonitorExitInstruction();
insnCopy.setObjectRef(copyVar(objectRef));
copy = insnCopy;
copy.setLocation(location);
}
return outputs;
}
}

View File

@ -15,19 +15,33 @@
*/
package org.teavm.model.util;
import java.util.*;
import org.teavm.common.*;
import org.teavm.model.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.teavm.common.DisjointSet;
import org.teavm.common.MutableGraphEdge;
import org.teavm.common.MutableGraphNode;
import org.teavm.model.BasicBlock;
import org.teavm.model.Incoming;
import org.teavm.model.Instruction;
import org.teavm.model.MethodReader;
import org.teavm.model.MethodReference;
import org.teavm.model.Phi;
import org.teavm.model.Program;
import org.teavm.model.ProgramReader;
import org.teavm.model.TryCatchJoint;
import org.teavm.model.Variable;
import org.teavm.model.instructions.AssignInstruction;
import org.teavm.model.instructions.EmptyInstruction;
import org.teavm.model.instructions.JumpInstruction;
/**
*
* @author Alexey Andreev
*/
public class RegisterAllocator {
public void allocateRegisters(MethodReader method, Program program) {
insertJointArgumentsCopies(program);
insertPhiArgumentsCopies(program);
InterferenceGraphBuilder interferenceBuilder = new InterferenceGraphBuilder();
LivenessAnalyzer liveness = new LivenessAnalyzer();
@ -63,6 +77,7 @@ public class RegisterAllocator {
for (int i = 0; i < program.basicBlockCount(); ++i) {
program.basicBlockAt(i).getPhis().clear();
program.basicBlockAt(i).getTryCatchJoints().clear();
}
}
@ -98,6 +113,39 @@ public class RegisterAllocator {
}
}
private void insertJointArgumentsCopies(Program program) {
for (int i = 0; i < program.basicBlockCount(); ++i) {
BasicBlock block = program.basicBlockAt(i);
block.getTryCatchJoints().forEach(this::insertCopy);
}
}
private void insertCopy(TryCatchJoint joint) {
Set<Variable> variableSet = new HashSet<>(joint.getSourceVariables());
BasicBlock block = joint.getSource();
DefinitionExtractor defExtractor = new DefinitionExtractor();
for (int i = block.getInstructions().size() - 1; i >= 0; --i) {
Instruction insn = block.getInstructions().get(i);
insn.acceptVisitor(defExtractor);
for (Variable definedVar : defExtractor.getDefinedVariables()) {
if (variableSet.remove(definedVar)) {
AssignInstruction copyInsn = new AssignInstruction();
copyInsn.setReceiver(joint.getReceiver());
copyInsn.setAssignee(definedVar);
block.getInstructions().add(i, copyInsn);
}
}
}
for (Variable enteringVar : variableSet) {
AssignInstruction copyInsn = new AssignInstruction();
copyInsn.setReceiver(joint.getReceiver());
copyInsn.setAssignee(enteringVar);
block.getInstructions().add(0, copyInsn);
}
}
private void insertPhiArgumentsCopies(Program program) {
for (int i = 0; i < program.basicBlockCount(); ++i) {
Map<BasicBlock, BasicBlock> blockMap = new HashMap<>();
@ -136,15 +184,8 @@ public class RegisterAllocator {
JumpInstruction jumpInstruction = new JumpInstruction();
jumpInstruction.setTarget(phi.getBasicBlock());
copyBlock.getInstructions().add(jumpInstruction);
incoming.getSource().getLastInstruction().acceptVisitor(new BasicBlockMapper() {
@Override protected BasicBlock map(BasicBlock block) {
if (block == phi.getBasicBlock()) {
return copyBlock;
} else {
return block;
}
}
});
incoming.getSource().getLastInstruction().acceptVisitor(new BasicBlockMapper(block ->
block == phi.getBasicBlock().getIndex() ? copyBlock.getIndex() : block));
blockMap.put(source, copyBlock);
incoming.setSource(copyBlock);
source = copyBlock;
@ -154,12 +195,8 @@ public class RegisterAllocator {
}
private boolean isExceptionHandler(Incoming incoming) {
for (TryCatchBlock tryCatch : incoming.getSource().getTryCatchBlocks()) {
if (tryCatch.getExceptionVariable() == incoming.getValue()) {
return true;
}
}
return false;
return incoming.getSource().getTryCatchJoints().stream().anyMatch(
joint -> joint.getReceiver() == incoming.getValue());
}
private void removeRedundantCopies(Program program, List<MutableGraphNode> interferenceGraph,
@ -218,26 +255,11 @@ public class RegisterAllocator {
}
private void renameVariables(final Program program, final int[] varMap) {
InstructionVariableMapper mapper = new InstructionVariableMapper() {
@Override protected Variable map(Variable var) {
return program.variableAt(varMap[var.getIndex()]);
}
};
InstructionVariableMapper mapper = new InstructionVariableMapper(var ->
program.variableAt(varMap[var.getIndex()]));
for (int i = 0; i < program.basicBlockCount(); ++i) {
BasicBlock block = program.basicBlockAt(i);
for (Instruction insn : block.getInstructions()) {
insn.acceptVisitor(mapper);
}
for (Phi phi : block.getPhis()) {
phi.setReceiver(program.variableAt(varMap[phi.getReceiver().getIndex()]));
for (Incoming incoming : phi.getIncomings()) {
incoming.setValue(program.variableAt(varMap[incoming.getValue().getIndex()]));
}
}
for (TryCatchBlock tryCatch : block.getTryCatchBlocks()) {
tryCatch.setExceptionVariable(program.variableAt(
varMap[tryCatch.getExceptionVariable().getIndex()]));
}
mapper.apply(block);
}
String[][] originalNames = new String[program.variableCount()][];
for (int i = 0; i < program.variableCount(); ++i) {
@ -279,6 +301,11 @@ public class RegisterAllocator {
classes.union(phi.getReceiver().getIndex(), incoming.getValue().getIndex());
}
}
for (TryCatchJoint joint : block.getTryCatchJoints()) {
for (Variable sourceVar : joint.getSourceVariables()) {
classes.union(sourceVar.getIndex(), joint.getReceiver().getIndex());
}
}
}
return classes;
}

View File

@ -51,6 +51,11 @@ public class TypeInferer {
builder.addEdge(incoming.getValue().getIndex(), phi.getReceiver().getIndex());
}
}
for (TryCatchJointReader joint : block.readTryCatchJoints()) {
for (VariableReader sourceVar : joint.readSourceVariables()) {
builder.addEdge(sourceVar.getIndex(), joint.getReceiver().getIndex());
}
}
for (TryCatchBlockReader tryCatch : block.readTryCatchBlocks()) {
if (tryCatch.getExceptionVariable() != null) {
types[tryCatch.getExceptionVariable().getIndex()] = VariableType.OBJECT;

View File

@ -1,50 +0,0 @@
/*
* Copyright 2013 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.optimization;
import java.util.Arrays;
import java.util.List;
import org.teavm.model.ClassHolder;
import org.teavm.model.ListableClassHolderSource;
import org.teavm.model.MethodHolder;
import org.teavm.model.Program;
import org.teavm.model.util.ProgramUtils;
/**
*
* @author Alexey Andreev
*/
public class ClassSetOptimizer {
private List<MethodOptimization> getOptimizations() {
return Arrays.asList(new ArrayUnwrapMotion(), new LoopInvariantMotion(),
new GlobalValueNumbering(), new UnusedVariableElimination());
}
public void optimizeAll(ListableClassHolderSource classSource) {
for (String className : classSource.getClassNames()) {
ClassHolder cls = classSource.get(className);
for (MethodHolder method : cls.getMethods()) {
if (method.getProgram() != null && method.getProgram().basicBlockCount() > 0) {
Program program = ProgramUtils.copy(method.getProgram());
for (MethodOptimization optimization : getOptimizations()) {
optimization.optimize(method, program);
}
method.setProgram(program);
}
}
}
}
}

View File

@ -35,8 +35,8 @@ public class EmptyBlockElimination implements MethodOptimization {
int lastNonEmpty = program.basicBlockCount() - 1;
for (int i = program.basicBlockCount() - 2; i > 0; --i) {
BasicBlock block = program.basicBlockAt(i);
if (block.getPhis().isEmpty() && block.getInstructions().size() == 1
&& block.getLastInstruction() instanceof JumpInstruction) {
if (block.getPhis().isEmpty() && block.getTryCatchJoints().isEmpty()
&& block.getInstructions().size() == 1 && block.getLastInstruction() instanceof JumpInstruction) {
JumpInstruction insn = (JumpInstruction) block.getLastInstruction();
if (insn.getTarget().getIndex() == i + 1) {
blockMapping[i] = lastNonEmpty;
@ -44,11 +44,7 @@ public class EmptyBlockElimination implements MethodOptimization {
}
lastNonEmpty = blockMapping[i];
}
new BasicBlockMapper() {
@Override protected BasicBlock map(BasicBlock block) {
return program.basicBlockAt(blockMapping[block.getIndex()]);
}
}.transform(program);
new BasicBlockMapper(block -> blockMapping[block]).transform(program);
for (int i = 0; i < program.basicBlockCount(); ++i) {
if (blockMapping[i] != i) {
program.deleteBasicBlock(i);

View File

@ -24,10 +24,6 @@ import org.teavm.model.*;
import org.teavm.model.instructions.*;
import org.teavm.model.util.ProgramUtils;
/**
*
* @author Alexey Andreev
*/
public class GlobalValueNumbering implements MethodOptimization {
private Map<String, KnownValue> knownValues = new HashMap<>();
private boolean eliminate;
@ -52,7 +48,8 @@ public class GlobalValueNumbering implements MethodOptimization {
for (int i = 0; i < map.length; ++i) {
map[i] = i;
}
List<List<Incoming>> outgoings = findOutgoings(program);
List<List<Incoming>> outgoings = ProgramUtils.getPhiOutputs(program);
List<List<TryCatchJoint>> outputJoints = ProgramUtils.getOutputJoints(program);
int[] stack = new int[cfg.size() * 2];
int top = 0;
@ -95,13 +92,21 @@ public class GlobalValueNumbering implements MethodOptimization {
eliminate = false;
}
}
for (TryCatchJoint joint : outputJoints.get(v)) {
for (int i = 0; i < joint.getSourceVariables().size(); ++i) {
int sourceVar = map[joint.getSourceVariables().get(i).getIndex()];
joint.getSourceVariables().set(i, program.variableAt(sourceVar));
}
}
for (Incoming incoming : outgoings.get(v)) {
int value = map[incoming.getValue().getIndex()];
incoming.setValue(program.variableAt(value));
}
for (TryCatchBlock tryCatch : block.getTryCatchBlocks()) {
int var = map[tryCatch.getExceptionVariable().getIndex()];
tryCatch.setExceptionVariable(program.variableAt(var));
if (tryCatch.getExceptionVariable() != null) {
int var = map[tryCatch.getExceptionVariable().getIndex()];
tryCatch.setExceptionVariable(program.variableAt(var));
}
}
for (int succ : dom.outgoingEdges(v)) {
stack[top++] = succ;
@ -121,21 +126,6 @@ public class GlobalValueNumbering implements MethodOptimization {
this.program = null;
}
private List<List<Incoming>> findOutgoings(Program program) {
List<List<Incoming>> outgoings = new ArrayList<>();
for (int i = 0; i < program.basicBlockCount(); ++i) {
outgoings.add(new ArrayList<>());
}
for (int i = 0; i < program.basicBlockCount(); ++i) {
for (Phi phi : program.basicBlockAt(i).getPhis()) {
for (Incoming incoming : phi.getIncomings()) {
outgoings.get(incoming.getSource().getIndex()).add(incoming);
}
}
}
return outgoings;
}
private void bind(int var, String value) {
KnownValue known = knownValues.get(value);
if (known != null && domTree.dominates(known.location, currentBlockIndex) && known.value != var) {

View File

@ -29,7 +29,6 @@ import org.teavm.model.util.*;
*/
public class LoopInvariantMotion implements MethodOptimization {
private int[] preheaders;
private Instruction[] constantInstructions;
private LoopGraph graph;
private DominatorTree dom;
private Program program;
@ -45,7 +44,7 @@ public class LoopInvariantMotion implements MethodOptimization {
IntegerStack stack = new IntegerStack(graph.size());
int[] defLocation = new int[program.variableCount()];
Arrays.fill(defLocation, -1);
constantInstructions = new Instruction[program.variableCount()];
Instruction[] constantInstructions = new Instruction[program.variableCount()];
for (int i = 0; i <= method.parameterCount(); ++i) {
defLocation[i] = 0;
}
@ -126,7 +125,8 @@ public class LoopInvariantMotion implements MethodOptimization {
}
}
if (variableMap != null) {
insn.acceptVisitor(new VariableMapperImpl(variableMap));
Variable[] currentVariableMap = variableMap;
insn.acceptVisitor(new InstructionVariableMapper(var -> currentVariableMap[var.getIndex()]));
}
newInstructions.add(insn);
preheaderInstructions.addAll(preheaderInstructions.size() - 1, newInstructions);
@ -165,18 +165,18 @@ public class LoopInvariantMotion implements MethodOptimization {
}
private int insertPreheader(int headerIndex) {
final BasicBlock preheader = program.createBasicBlock();
BasicBlock preheader = program.createBasicBlock();
JumpInstruction escapeInsn = new JumpInstruction();
final BasicBlock header = program.basicBlockAt(headerIndex);
BasicBlock header = program.basicBlockAt(headerIndex);
escapeInsn.setTarget(header);
preheader.getInstructions().add(escapeInsn);
for (int i = 0; i < header.getPhis().size(); ++i) {
Phi phi = header.getPhis().get(i);
for (Phi phi : header.getPhis()) {
Phi preheaderPhi = null;
for (int j = 0; j < phi.getIncomings().size(); ++j) {
Incoming incoming = phi.getIncomings().get(j);
for (int i = 0; i < phi.getIncomings().size(); ++i) {
Incoming incoming = phi.getIncomings().get(i);
if (!dom.dominates(headerIndex, incoming.getSource().getIndex())) {
phi.getIncomings().remove(j--);
phi.getIncomings().remove(i--);
if (preheaderPhi == null) {
preheaderPhi = new Phi();
preheaderPhi.setReceiver(program.createVariable());
@ -192,37 +192,20 @@ public class LoopInvariantMotion implements MethodOptimization {
phi.getIncomings().add(incoming);
}
}
for (int predIndex : graph.incomingEdges(headerIndex)) {
if (!dom.dominates(headerIndex, predIndex)) {
BasicBlock pred = program.basicBlockAt(predIndex);
pred.getLastInstruction().acceptVisitor(new BasicBlockMapper() {
@Override protected BasicBlock map(BasicBlock block) {
if (block == header) {
block = preheader;
}
return block;
}
});
pred.getLastInstruction().acceptVisitor(new BasicBlockMapper(
block -> block == header.getIndex() ? preheader.getIndex() : block));
}
}
return preheader.getIndex();
}
private static class VariableMapperImpl extends InstructionVariableMapper {
private Variable[] map;
public VariableMapperImpl(Variable[] map) {
this.map = map;
}
@Override
protected Variable map(Variable var) {
return map[var.getIndex()];
}
}
private static class InstructionAnalyzer implements InstructionVisitor {
public boolean canMove;
boolean canMove;
public boolean constant;
@Override

View File

@ -0,0 +1,26 @@
/*
* 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.optimization;
import org.teavm.model.MethodReader;
import org.teavm.model.Program;
public class LoopInversion implements MethodOptimization {
@Override
public void optimize(MethodReader method, Program program) {
new LoopInversionImpl(program, method.parameterCount() + 1).apply();
}
}

View File

@ -0,0 +1,357 @@
/*
* 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.optimization;
import com.carrotsearch.hppc.IntIntMap;
import com.carrotsearch.hppc.IntIntOpenHashMap;
import com.carrotsearch.hppc.IntOpenHashSet;
import com.carrotsearch.hppc.IntSet;
import java.util.ArrayList;
import java.util.Arrays;
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.common.DominatorTree;
import org.teavm.common.Graph;
import org.teavm.common.GraphUtils;
import org.teavm.common.Loop;
import org.teavm.common.LoopGraph;
import org.teavm.model.BasicBlock;
import org.teavm.model.Incoming;
import org.teavm.model.Instruction;
import org.teavm.model.Phi;
import org.teavm.model.Program;
import org.teavm.model.TryCatchBlock;
import org.teavm.model.TryCatchJoint;
import org.teavm.model.Variable;
import org.teavm.model.util.BasicBlockMapper;
import org.teavm.model.util.InstructionCopyReader;
import org.teavm.model.util.PhiUpdater;
import org.teavm.model.util.ProgramUtils;
/**
* Transforms loop in form:
*
* ```
* while (true) {
* condition;
* body;
* }
* ```
*
* to form:
*
* ```
* if (condition) {
* while (true) {
* body;
* condition; // copy
* }
* }
* ```
*
* where `condition` is a part of loop that has exits and `body` has no exits.
* More formally, we define *body start candidate* as a node which 1) dominates all of the "tails" (i.e. nodes
* that have edges to loop header), 2) does not dominate loop exits. *Body start* is a body start candidate
* that is not dominated by some other body start candidate. If body start does not exits, loop is
* not invertible.
*
* Therefore, *body* is a set of nodes of the loop that are dominated by body start and
* all remaining nodes are *condition*.
*/
class LoopInversionImpl {
private final Program program;
private final int parameterCount;
private Graph cfg;
private DominatorTree dom;
private boolean postponed;
private boolean changed;
LoopInversionImpl(Program program, int parameterCount) {
this.program = program;
this.parameterCount = parameterCount;
}
void apply() {
do {
cfg = ProgramUtils.buildControlFlowGraph(program);
LoopGraph loopGraph = new LoopGraph(cfg);
dom = GraphUtils.buildDominatorTree(cfg);
List<LoopWithExits> loops = getLoopsWithExits(loopGraph);
postponed = false;
if (!loops.isEmpty()) {
for (LoopWithExits loop : loops) {
loop.invert();
}
if (changed) {
Variable[] inputs = new Variable[parameterCount];
for (int i = 0; i < inputs.length; ++i) {
inputs[i] = program.variableAt(i);
}
new PhiUpdater().updatePhis(program, inputs);
}
}
} while (postponed);
}
private List<LoopWithExits> getLoopsWithExits(LoopGraph cfg) {
Map<Loop, LoopWithExits> loops = new HashMap<>();
for (int node = 0; node < cfg.size(); ++node) {
Loop loop = cfg.loopAt(node);
while (loop != null) {
LoopWithExits loopWithExits = getLoopWithExits(loops, loop);
loopWithExits.nodes.add(node);
for (int successor : cfg.outgoingEdges(node)) {
Loop successorLoop = cfg.loopAt(successor);
if (successorLoop == null || !successorLoop.isChildOf(loop)) {
loopWithExits.exits.add(node);
break;
}
}
loop = loop.getParent();
}
}
List<LoopWithExits> resultList = new ArrayList<>();
Set<LoopWithExits> visited = new HashSet<>();
for (LoopWithExits loop : loops.values()) {
sortLoops(loop, visited, resultList);
}
Collections.reverse(resultList);
return resultList;
}
private LoopWithExits getLoopWithExits(Map<Loop, LoopWithExits> cache, Loop loop) {
return cache.computeIfAbsent(loop, key ->
new LoopWithExits(key.getHead(), key.getParent() != null
? getLoopWithExits(cache, key.getParent())
: null));
}
private void sortLoops(LoopWithExits loop, Set<LoopWithExits> visited, List<LoopWithExits> target) {
if (!visited.add(loop)) {
return;
}
if (loop.parent != null) {
sortLoops(loop.parent, visited, target);
}
target.add(loop);
}
private class LoopWithExits {
final int head;
final LoopWithExits parent;
final IntSet nodes = new IntOpenHashSet();
final IntSet nodesAndCopies = new IntOpenHashSet();
final IntSet exits = new IntOpenHashSet();
int bodyStart;
int copyStart;
int headCopy;
final IntIntMap copiedNodes = new IntIntOpenHashMap();
boolean shouldSkip;
LoopWithExits(int head, LoopWithExits parent) {
this.head = head;
this.parent = parent;
}
void invert() {
if (tryInvert()) {
LoopWithExits ancestor = parent;
while (ancestor != null) {
ancestor.shouldSkip = true;
ancestor = ancestor.parent;
}
}
}
private boolean tryInvert() {
if (shouldSkip) {
postponed = true;
return false;
}
if (!findCondition() || bodyStart < 0) {
return false;
}
collectNodesToCopy();
copyCondition();
moveBackEdges();
removeInternalPhiInputsFromCondition();
removeExternalPhiInputsFromConditionCopy();
changed = true;
return true;
}
private boolean findCondition() {
IntSet tailNodes = new IntOpenHashSet(program.basicBlockCount());
for (int tailCandidate : cfg.incomingEdges(head)) {
if (nodes.contains(tailCandidate)) {
tailNodes.add(tailCandidate);
}
}
bodyStart = dom.commonDominatorOf(tailNodes.toArray());
int candidate = bodyStart;
while (bodyStart != head) {
int currentCandidate = candidate;
if (Arrays.stream(exits.toArray()).anyMatch(exit -> dom.dominates(currentCandidate, exit))) {
break;
}
bodyStart = candidate;
candidate = dom.immediateDominatorOf(candidate);
}
return candidate != bodyStart;
}
private void collectNodesToCopy() {
int[] nodes = this.nodes.toArray();
Arrays.sort(nodes);
for (int node : nodes) {
nodesAndCopies.add(node);
if (node == head || (node != bodyStart && !dom.dominates(bodyStart, node))) {
int copy = program.createBasicBlock().getIndex();
if (head == node) {
headCopy = copy;
}
copiedNodes.put(node, copy);
nodesAndCopies.add(copy);
}
}
}
private void copyCondition() {
BasicBlockMapper blockMapper = new BasicBlockMapper(block -> copiedNodes.getOrDefault(block, block));
InstructionCopyReader copier = new InstructionCopyReader(program);
for (int node : copiedNodes.keys().toArray()) {
BasicBlock sourceBlock = program.basicBlockAt(node);
BasicBlock targetBlock = program.basicBlockAt(copiedNodes.get(node));
copier.resetLocation();
for (int i = 0; i < sourceBlock.instructionCount(); ++i) {
sourceBlock.readInstruction(i, copier);
Instruction insn = copier.getCopy();
insn.acceptVisitor(blockMapper);
targetBlock.getInstructions().add(insn);
}
for (Phi phi : sourceBlock.getPhis()) {
Phi phiCopy = new Phi();
phiCopy.setReceiver(phi.getReceiver());
for (Incoming incoming : phi.getIncomings()) {
Incoming incomingCopy = new Incoming();
int source = incoming.getSource().getIndex();
incomingCopy.setSource(program.basicBlockAt(copiedNodes.getOrDefault(source, source)));
incomingCopy.setValue(incoming.getValue());
phiCopy.getIncomings().add(incomingCopy);
}
targetBlock.getPhis().add(phiCopy);
}
for (TryCatchBlock tryCatch : sourceBlock.getTryCatchBlocks()) {
TryCatchBlock tryCatchCopy = new TryCatchBlock();
int handler = tryCatch.getHandler().getIndex();
tryCatchCopy.setExceptionType(tryCatch.getExceptionType());
tryCatchCopy.setExceptionVariable(tryCatch.getExceptionVariable());
tryCatchCopy.setHandler(program.basicBlockAt(copiedNodes.getOrDefault(handler, handler)));
targetBlock.getTryCatchBlocks().add(tryCatchCopy);
}
for (TryCatchJoint joint : sourceBlock.getTryCatchJoints()) {
TryCatchJoint jointCopy = new TryCatchJoint();
jointCopy.setReceiver(joint.getReceiver());
jointCopy.getSourceVariables().addAll(joint.getSourceVariables());
int source = joint.getSource().getIndex();
jointCopy.setSource(program.basicBlockAt(copiedNodes.getOrDefault(source, source)));
targetBlock.getTryCatchJoints().add(joint);
}
}
for (int node = 0; node < cfg.size(); ++node) {
BasicBlock block = program.basicBlockAt(node);
for (Phi phi : block.getPhis()) {
for (Incoming incoming : phi.getIncomings().toArray(new Incoming[0])) {
int source = incoming.getSource().getIndex();
if (copiedNodes.containsKey(source)) {
Incoming incomingCopy = new Incoming();
incomingCopy.setValue(incoming.getValue());
incomingCopy.setSource(program.basicBlockAt(copiedNodes.get(source)));
phi.getIncomings().add(incomingCopy);
}
}
}
}
}
/**
* Back edges from body are not back edges anymore, instead they point to a copied condition.
*/
private void moveBackEdges() {
BasicBlockMapper mapper = new BasicBlockMapper(block -> block == head ? headCopy : block);
for (int node : nodes.toArray()) {
BasicBlock block = program.basicBlockAt(node);
Instruction last = block.getLastInstruction();
if (last != null) {
last.acceptVisitor(mapper);
}
}
}
/**
* Original head becomes start of `if (condition)`, it's not loop head anymore.
* Hence we don't need phi inputs that come from back edges.
*/
private void removeInternalPhiInputsFromCondition() {
BasicBlock block = program.basicBlockAt(head);
for (Phi phi : block.getPhis()) {
List<Incoming> incomings = phi.getIncomings();
for (int i = 0; i < incomings.size(); ++i) {
Incoming incoming = incomings.get(i);
if (nodes.contains(incoming.getSource().getIndex())) {
incomings.remove(i--);
}
}
}
}
/**
* Head copy is not a loop head anymore and there aren't transition from outside of former loop,
* therefore delete all external phi inputs.
*/
private void removeExternalPhiInputsFromConditionCopy() {
BasicBlock block = program.basicBlockAt(headCopy);
for (Phi phi : block.getPhis()) {
List<Incoming> incomings = phi.getIncomings();
for (int i = 0; i < incomings.size(); ++i) {
Incoming incoming = incomings.get(i);
if (!nodesAndCopies.contains(incoming.getSource().getIndex())) {
incomings.remove(i--);
}
}
}
}
}
}

View File

@ -19,10 +19,6 @@ import org.teavm.common.Graph;
import org.teavm.model.*;
import org.teavm.model.instructions.*;
/**
*
* @author Alexey Andreev
*/
public class UnusedVariableElimination implements MethodOptimization {
@Override
public void optimize(MethodReader method, Program program) {
@ -64,6 +60,12 @@ public class UnusedVariableElimination implements MethodOptimization {
block.getInstructions().remove(j--);
}
}
for (int j = 0; j < block.getTryCatchJoints().size(); ++j) {
TryCatchJoint joint = block.getTryCatchJoints().get(j);
if (!used[joint.getReceiver().getIndex()]) {
block.getTryCatchJoints().remove(j--);
}
}
for (int j = 0; j < block.getPhis().size(); ++j) {
Phi phi = block.getPhis().get(j);
if (!used[phi.getReceiver().getIndex()]) {
@ -258,12 +260,10 @@ public class UnusedVariableElimination implements MethodOptimization {
@Override
public void visit(MonitorEnterInstruction insn) {
}
@Override
public void visit(MonitorExitInstruction insn) {
}
}
}

View File

@ -20,10 +20,6 @@ import org.teavm.common.GraphBuilder;
import org.teavm.model.*;
import org.teavm.model.instructions.*;
/**
*
* @author Alexey Andreev
*/
public final class VariableUsageGraphBuilder {
private VariableUsageGraphBuilder() {
}
@ -41,6 +37,11 @@ public final class VariableUsageGraphBuilder {
builder.addEdge(incoming.getValue().getIndex(), phi.getReceiver().getIndex());
}
}
for (TryCatchJoint joint : block.getTryCatchJoints()) {
for (Variable sourceVar : joint.getSourceVariables()) {
builder.addEdge(sourceVar.getIndex(), joint.getReceiver().getIndex());
}
}
}
return builder.build();
}

View File

@ -17,12 +17,14 @@ package org.teavm.parsing;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
import org.objectweb.asm.commons.JSRInlinerAdapter;
import org.objectweb.asm.tree.*;
import org.teavm.model.*;
import org.teavm.model.util.PhiUpdater;
import org.teavm.optimization.UnreachableBasicBlockEliminator;
/**
@ -47,8 +49,8 @@ public final class Parser {
programParser.setFileName(fileName);
Program program = programParser.parse(node, className);
new UnreachableBasicBlockEliminator().optimize(program);
SSATransformer ssaProducer = new SSATransformer();
ssaProducer.transformToSSA(program, programParser, method.getParameterTypes());
PhiUpdater phiUpdater = new PhiUpdater();
phiUpdater.updatePhis(program, applySignature(program, method.getParameterTypes()));
method.setProgram(program);
parseAnnotations(method.getAnnotations(), node.visibleAnnotations, node.invisibleAnnotations);
while (program.variableCount() <= method.parameterCount()) {
@ -65,6 +67,31 @@ public final class Parser {
return method;
}
private static Variable[] applySignature(Program program, ValueType[] arguments) {
if (program.variableCount() == 0) {
return new Variable[0];
}
Variable[] variableMap = new Variable[program.variableCount()];
int index = 0;
variableMap[index] = program.variableAt(index);
++index;
for (int i = 0; i < arguments.length; ++i) {
variableMap[index] = program.variableAt(i + 1);
++index;
ValueType arg = arguments[i];
if (arg instanceof ValueType.Primitive) {
PrimitiveType kind = ((ValueType.Primitive) arg).getKind();
if (kind == PrimitiveType.LONG || kind == PrimitiveType.DOUBLE) {
variableMap[index] = variableMap[index - 1];
++index;
}
}
}
return Arrays.copyOf(variableMap, index);
}
public static ClassHolder parseClass(ClassNode node) {
ClassHolder cls = new ClassHolder(node.name.replace('/', '.'));
parseModifiers(node.access, cls);

View File

@ -27,11 +27,11 @@ import org.teavm.model.util.ProgramUtils;
*
* @author Alexey Andreev
*/
public class ProgramParser implements VariableDebugInformation {
static final byte ROOT = 0;
static final byte SINGLE = 1;
static final byte DOUBLE_FIRST_HALF = 2;
static final byte DOUBLE_SECOND_HALF = 3;
public class ProgramParser {
private static final byte ROOT = 0;
private static final byte SINGLE = 1;
private static final byte DOUBLE_FIRST_HALF = 2;
private static final byte DOUBLE_SECOND_HALF = 3;
private String fileName;
private StackFrame[] stackBefore;
private StackFrame[] stackAfter;
@ -60,17 +60,17 @@ public class ProgramParser implements VariableDebugInformation {
}
private static class StackFrame {
public final StackFrame next;
public final byte type;
public final int depth;
final StackFrame next;
final byte type;
final int depth;
public StackFrame(int depth) {
StackFrame(int depth) {
this.next = null;
this.type = ROOT;
this.depth = depth;
}
public StackFrame(StackFrame next, byte type) {
StackFrame(StackFrame next, byte type) {
this.next = next;
this.type = type;
this.depth = next != null ? next.depth + 1 : 0;
@ -148,21 +148,20 @@ public class ProgramParser implements VariableDebugInformation {
private int popDouble() {
if (stack == null || stack.type != DOUBLE_SECOND_HALF) {
throw new AssertionError("Illegal stack state at " + index);
throw new AssertionError("***Illegal stack state at " + index);
}
stack = stack.next;
if (stack == null || stack.type != DOUBLE_FIRST_HALF) {
throw new AssertionError("Illegal stack state at " + index);
throw new AssertionError("***Illegal stack state at " + index);
}
int depth = stack.depth;
stack = stack.next;
return depth;
}
@Override
public Map<Integer, String> getDebugNames(Instruction insn) {
Map<Integer, String> map = variableDebugNames.get(insn);
return map != null ? Collections.unmodifiableMap(map) : Collections.<Integer, String>emptyMap();
return map != null ? Collections.unmodifiableMap(map) : Collections.emptyMap();
}
private void prepare(MethodNode method) {
@ -513,8 +512,8 @@ public class ProgramParser implements VariableDebugInformation {
}
insn.setMethod(new MethodDescriptor(name, MethodDescriptor.parseSignature(desc)));
for (int i = 0; i < bsmArgs.length; ++i) {
insn.getBootstrapArguments().add(convertConstant(bsmArgs[i]));
for (Object bsmArg : bsmArgs) {
insn.getBootstrapArguments().add(convertConstant(bsmArg));
}
addInstruction(insn);
@ -1047,6 +1046,7 @@ public class ProgramParser implements VariableDebugInformation {
case Opcodes.POP2:
if (stack.type == SINGLE) {
popSingle();
popSingle();
} else {
popDouble();
}
@ -1199,8 +1199,9 @@ public class ProgramParser implements VariableDebugInformation {
case Opcodes.SWAP: {
int b = popSingle();
int a = popSingle();
int tmp = pushSingle();
pushSingle();
pushSingle();
int tmp = b + 1;
emitAssignInsn(a, tmp);
emitAssignInsn(b, a);
emitAssignInsn(tmp, b);
@ -1725,7 +1726,7 @@ public class ProgramParser implements VariableDebugInformation {
}
};
static MethodHandle parseHandle(Handle handle) {
private static MethodHandle parseHandle(Handle handle) {
switch (handle.getTag()) {
case Opcodes.H_GETFIELD:
return MethodHandle.fieldGetter(handle.getOwner().replace('/', '.'), handle.getName(),

View File

@ -15,26 +15,88 @@
*/
package org.teavm.vm;
import java.io.*;
import java.util.*;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.ServiceLoader;
import java.util.Set;
import org.teavm.cache.NoCache;
import org.teavm.codegen.*;
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.common.ServiceRepository;
import org.teavm.debugging.information.DebugInformationEmitter;
import org.teavm.debugging.information.SourceLocation;
import org.teavm.dependency.*;
import org.teavm.dependency.BootstrapMethodSubstitutor;
import org.teavm.dependency.DependencyChecker;
import org.teavm.dependency.DependencyInfo;
import org.teavm.dependency.DependencyListener;
import org.teavm.dependency.Linker;
import org.teavm.dependency.MethodDependency;
import org.teavm.diagnostics.AccumulationDiagnostics;
import org.teavm.diagnostics.ProblemProvider;
import org.teavm.javascript.*;
import org.teavm.javascript.Decompiler;
import org.teavm.javascript.EmptyRegularMethodNodeCache;
import org.teavm.javascript.MethodNodeCache;
import org.teavm.javascript.Renderer;
import org.teavm.javascript.RenderingException;
import org.teavm.javascript.ast.ClassNode;
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.*;
import org.teavm.model.instructions.*;
import org.teavm.model.util.*;
import org.teavm.optimization.*;
import org.teavm.model.BasicBlock;
import org.teavm.model.CallLocation;
import org.teavm.model.ClassHolder;
import org.teavm.model.ClassHolderSource;
import org.teavm.model.ClassHolderTransformer;
import org.teavm.model.ClassReader;
import org.teavm.model.ClassReaderSource;
import org.teavm.model.ElementHolder;
import org.teavm.model.ElementModifier;
import org.teavm.model.InstructionLocation;
import org.teavm.model.ListableClassHolderSource;
import org.teavm.model.ListableClassReaderSource;
import org.teavm.model.MethodHolder;
import org.teavm.model.MethodReference;
import org.teavm.model.MutableClassHolderSource;
import org.teavm.model.Program;
import org.teavm.model.ProgramCache;
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.ListingBuilder;
import org.teavm.model.util.MissingItemsProcessor;
import org.teavm.model.util.ModelUtils;
import org.teavm.model.util.ProgramUtils;
import org.teavm.model.util.RegisterAllocator;
import org.teavm.optimization.ArrayUnwrapMotion;
import org.teavm.optimization.Devirtualization;
import org.teavm.optimization.GlobalValueNumbering;
import org.teavm.optimization.LoopInvariantMotion;
import org.teavm.optimization.MethodOptimization;
import org.teavm.optimization.UnusedVariableElimination;
import org.teavm.vm.spi.RendererListener;
import org.teavm.vm.spi.TeaVMHost;
import org.teavm.vm.spi.TeaVMPlugin;
@ -69,20 +131,20 @@ import org.teavm.vm.spi.TeaVMPlugin;
* @author Alexey Andreev
*/
public class TeaVM implements TeaVMHost, ServiceRepository {
private ClassReaderSource classSource;
private DependencyChecker dependencyChecker;
private AccumulationDiagnostics diagnostics = new AccumulationDiagnostics();
private ClassLoader classLoader;
private final ClassReaderSource classSource;
private final DependencyChecker dependencyChecker;
private final AccumulationDiagnostics diagnostics = new AccumulationDiagnostics();
private final ClassLoader classLoader;
private boolean minifying = true;
private boolean bytecodeLogging;
private OutputStream logStream = System.out;
private Map<String, TeaVMEntryPoint> entryPoints = new HashMap<>();
private Map<String, String> exportedClasses = new HashMap<>();
private Map<MethodReference, Generator> methodGenerators = new HashMap<>();
private Map<MethodReference, Injector> methodInjectors = new HashMap<>();
private List<RendererListener> rendererListeners = new ArrayList<>();
private Map<Class<?>, Object> services = new HashMap<>();
private Properties properties = new Properties();
private final OutputStream logStream = System.out;
private final Map<String, TeaVMEntryPoint> entryPoints = new HashMap<>();
private final Map<String, String> exportedClasses = new HashMap<>();
private final Map<MethodReference, Generator> methodGenerators = new HashMap<>();
private final Map<MethodReference, Injector> methodInjectors = new HashMap<>();
private final List<RendererListener> rendererListeners = new ArrayList<>();
private final Map<Class<?>, Object> services = new HashMap<>();
private final Properties properties = new Properties();
private DebugInformationEmitter debugEmitter;
private ProgramCache programCache;
private MethodNodeCache astCache = new EmptyRegularMethodNodeCache();
@ -90,8 +152,8 @@ public class TeaVM implements TeaVMHost, ServiceRepository {
private TeaVMProgressListener progressListener;
private boolean cancelled;
private ListableClassHolderSource writtenClasses;
private Set<MethodReference> asyncMethods = new HashSet<>();
private Set<MethodReference> asyncFamilyMethods = new HashSet<>();
private final Set<MethodReference> asyncMethods = new HashSet<>();
private final Set<MethodReference> asyncFamilyMethods = new HashSet<>();
TeaVM(ClassReaderSource classSource, ClassLoader classLoader) {
this.classSource = classSource;
@ -288,10 +350,6 @@ public class TeaVM implements TeaVMHost, ServiceRepository {
exportedClasses.put(name, className);
}
public void linkType(String className) {
dependencyChecker.linkClass(className, null).initClass(null);
}
/**
* Gets a {@link ClassReaderSource} which is used by this TeaVM instance. It is exactly what was
* passed to {@link TeaVMBuilder#setClassSource(ClassHolderSource)}.
@ -420,7 +478,6 @@ public class TeaVM implements TeaVMHost, ServiceRepository {
return;
}
DefaultNamingStrategy naming = new DefaultNamingStrategy(aliasProvider, dependencyChecker.getClassSource());
naming.setMinifying(minifying);
SourceWriterBuilder builder = new SourceWriterBuilder(naming);
builder.setMinified(minifying);
SourceWriter sourceWriter = builder.build(writer);
@ -654,7 +711,7 @@ public class TeaVM implements TeaVMHost, ServiceRepository {
}
private List<MethodOptimization> getOptimizations() {
return Arrays.asList(new ArrayUnwrapMotion(), new LoopInvariantMotion(),
return Arrays.asList(new ArrayUnwrapMotion(), /*new LoopInversion(),*/ new LoopInvariantMotion(),
new GlobalValueNumbering(), new UnusedVariableElimination());
}

View File

@ -14,9 +14,15 @@
* limitations under the License.
*/
"use strict";
var $rt_lastObjectId = 0;
var $rt_lastObjectId = 1;
function $rt_nextId() {
return $rt_lastObjectId++;
var current = $rt_lastObjectId;
var next = (current + 1) | 0;
if (next === 0) {
next = (next + 1) | 0;
}
$rt_lastObjectId = next;
return current;
}
function $rt_compare(a, b) {
return a > b ? 1 : a < b ? -1 : 0;
@ -39,14 +45,17 @@ function $rt_isAssignable(from, to) {
function $rt_createArray(cls, sz) {
var data = new Array(sz);
var arr = new ($rt_arraycls(cls))(data);
for (var i = 0; i < sz; i = (i + 1) | 0) {
data[i] = null;
if (sz > 0) {
var i = 0;
do {
data[i] = null;
i = (i + 1) | 0;
} while (i < sz);
}
return arr;
}
function $rt_wrapArray(cls, data) {
var arr = new ($rt_arraycls(cls))(data);
return arr;
return new ($rt_arraycls(cls))(data);
}
function $rt_createUnfilledArray(cls, sz) {
return new ($rt_arraycls(cls))(new Array(sz));
@ -67,7 +76,7 @@ var $rt_createIntArray;
var $rt_createBooleanArray;
var $rt_createFloatArray;
var $rt_createDoubleArray;
if (ArrayBuffer) {
if (typeof 'ArrayBuffer' !== 'undefined') {
$rt_createNumericArray = function(cls, nativeArray) {
return new ($rt_arraycls(cls))(nativeArray);
};
@ -110,10 +119,11 @@ if (ArrayBuffer) {
$rt_createCharArray = function(sz) { return $rt_createNumericArray($rt_charcls(), sz); }
}
function $rt_arraycls(cls) {
if (typeof cls.$array === 'undefined') {
var result = cls.$array;
if (result === null) {
var arraycls = function(data) {
this.data = data;
this.$id = $rt_nextId();
this.$id = 0;
};
arraycls.prototype = new ($rt_objcls())();
arraycls.prototype.constructor = arraycls;
@ -132,12 +142,15 @@ function $rt_arraycls(cls) {
arraycls.$meta = { item : cls, supertypes : [$rt_objcls()], primitive : false, superclass : $rt_objcls(),
name : name, binaryName : name, enum : false };
arraycls.classObject = null;
arraycls.$array = null;
result = arraycls;
cls.$array = arraycls;
}
return cls.$array;
return result;
}
function $rt_createcls() {
return {
$array : null,
classObject : null,
$meta : {
supertypes : [],
@ -228,7 +241,7 @@ function $rt_throw(ex) {
function $rt_exception(ex) {
var err = ex.$jsException;
if (!err) {
var err = new Error("Java exception thrown");
err = new Error("Java exception thrown");
err.$javaException = ex;
ex.$jsException = err;
}
@ -363,7 +376,7 @@ function $rt_putStderr(ch) {
}
function $rt_metadata(data) {
for (var i = 0; i < data.length; i += 8) {
var cls = data[i + 0];
var cls = data[i];
cls.$meta = {};
var m = cls.$meta;
m.name = data[i + 1];
@ -402,8 +415,8 @@ function $rt_metadata(data) {
}
var virtualMethods = data[i + 7];
for (var j = 0; j < virtualMethods.length; j += 2) {
var name = virtualMethods[j + 0];
for (j = 0; j < virtualMethods.length; j += 2) {
var name = virtualMethods[j];
var func = virtualMethods[j + 1];
if (typeof name === 'string') {
name = [name];
@ -412,6 +425,8 @@ function $rt_metadata(data) {
cls.prototype[name[k]] = func;
}
}
cls.$array = null;
}
}
function $rt_threadStarter(f) {
@ -681,7 +696,7 @@ function Long_compare(a, b) {
if (r !== 0) {
return r;
}
var r = (a.lo >>> 1) - (b.lo >>> 1);
r = (a.lo >>> 1) - (b.lo >>> 1);
if (r !== 0) {
return r;
}
@ -895,15 +910,15 @@ function LongInt_ucompare(a, b) {
if (r != 0) {
return r;
}
var r = (a.hi >>> 1) - (b.hi >>> 1);
r = (a.hi >>> 1) - (b.hi >>> 1);
if (r != 0) {
return r;
}
var r = (a.hi & 1) - (b.hi & 1);
r = (a.hi & 1) - (b.hi & 1);
if (r != 0) {
return r;
}
var r = (a.lo >>> 1) - (b.lo >>> 1);
r = (a.lo >>> 1) - (b.lo >>> 1);
if (r != 0) {
return r;
}
@ -924,7 +939,8 @@ function LongInt_numOfLeadingZeroBits(a) {
function LongInt_shl(a, b) {
if (b == 0) {
return;
} else if (b < 32) {
}
if (b < 32) {
a.sup = ((a.hi >>> (32 - b)) | (a.sup << b)) & 0xFFFF;
a.hi = (a.lo >>> (32 - b)) | (a.hi << b);
a.lo <<= b;
@ -949,7 +965,8 @@ function LongInt_shl(a, b) {
function LongInt_shr(a, b) {
if (b == 0) {
return;
} else if (b == 32) {
}
if (b == 32) {
a.lo = a.hi;
a.hi = a.sup;
a.sup = 0;

View File

@ -32,5 +32,6 @@
<orderEntry type="library" name="Maven: org.ow2.asm:asm-debug-all:5.0.4" level="project" />
<orderEntry type="library" name="Maven: com.carrotsearch:hppc:0.6.1" level="project" />
<orderEntry type="library" name="Maven: com.fasterxml.jackson.core:jackson-annotations:2.6.2" level="project" />
<orderEntry type="library" name="Maven: org.objenesis:objenesis:2.4" level="project" />
</component>
</module>

View File

@ -15,6 +15,7 @@
<orderEntry type="library" scope="PROVIDED" name="Maven: commons-io:commons-io:2.4" level="project" />
<orderEntry type="library" scope="PROVIDED" name="Maven: org.ow2.asm:asm-debug-all:5.0.4" level="project" />
<orderEntry type="library" scope="PROVIDED" name="Maven: com.carrotsearch:hppc:0.6.1" level="project" />
<orderEntry type="library" scope="PROVIDED" name="Maven: org.objenesis:objenesis:2.4" level="project" />
<orderEntry type="module" module-name="teavm-jso" />
<orderEntry type="library" scope="PROVIDED" name="Maven: org.slf4j:slf4j-api:1.7.7" level="project" />
</component>

View File

@ -24,6 +24,7 @@
<orderEntry type="library" name="Maven: commons-io:commons-io:2.4" level="project" />
<orderEntry type="library" name="Maven: org.ow2.asm:asm-debug-all:5.0.4" level="project" />
<orderEntry type="library" name="Maven: com.carrotsearch:hppc:0.6.1" level="project" />
<orderEntry type="library" name="Maven: org.objenesis:objenesis:2.4" level="project" />
<orderEntry type="module" module-name="teavm-classlib" />
<orderEntry type="module" module-name="teavm-platform" />
<orderEntry type="module" module-name="teavm-jso" />

View File

@ -0,0 +1,36 @@
/*
* 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.jso.dom.events;
import org.teavm.jso.JSProperty;
public interface WheelEvent extends MouseEvent {
int DOM_DELTA_PIXEL = 0;
int DOM_DELTA_LINE = 1;
int DOM_DELTA_PAGE = 2;
@JSProperty
double getDeltaX();
@JSProperty
double getDeltaY();
@JSProperty
double getDeltaZ();
@JSProperty
int getDeltaMode();
}

View File

@ -0,0 +1,26 @@
/*
* 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.jso.dom.events;
public interface WheelEventTarget extends EventTarget {
default void listenWheel(EventListener<WheelEvent> listener) {
addEventListener("wheel", listener);
}
default void neglectWheel(EventListener<WheelEvent> listener) {
removeEventListener("wheel", listener);
}
}

View File

@ -23,6 +23,7 @@ import org.teavm.jso.dom.events.FocusEventTarget;
import org.teavm.jso.dom.events.KeyboardEventTarget;
import org.teavm.jso.dom.events.LoadEventTarget;
import org.teavm.jso.dom.events.MouseEventTarget;
import org.teavm.jso.dom.events.WheelEventTarget;
import org.teavm.jso.dom.xml.Element;
import org.teavm.jso.dom.xml.Node;
import org.teavm.jso.dom.xml.NodeList;
@ -32,7 +33,7 @@ import org.teavm.jso.dom.xml.NodeList;
* @author Alexey Andreev
*/
public interface HTMLElement extends Element, ElementCSSInlineStyle, EventTarget, FocusEventTarget, MouseEventTarget,
KeyboardEventTarget, LoadEventTarget {
WheelEventTarget, KeyboardEventTarget, LoadEventTarget {
@Override
NodeList<? extends HTMLElement> getElementsByTagName(String name);
@ -110,7 +111,7 @@ public interface HTMLElement extends Element, ElementCSSInlineStyle, EventTarget
HTMLDocument getOwnerDocument();
@JSProperty
int getInnerHTML();
String getInnerHTML();
@JSProperty
void setInnerHTML(String content);

View File

@ -0,0 +1,111 @@
/*
* 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.jso.typedarrays;
import org.teavm.jso.JSBody;
import org.teavm.jso.JSMethod;
public abstract class DataView extends ArrayBufferView {
@JSMethod
public abstract byte getInt8(int byteOffset);
@JSMethod
public abstract short getUInt8(int byteOffset);
@JSMethod
public abstract short getInt16(int byteOffset);
@JSMethod
public abstract short getInt16(int byteOffset, boolean littleEndian);
@JSMethod
public abstract int getUInt16(int byteOffset);
@JSMethod
public abstract int getUInt16(int byteOffset, boolean littleEndian);
@JSMethod
public abstract int getInt32(int byteOffset);
@JSMethod
public abstract int getInt32(int byteOffset, boolean littleEndian);
@JSMethod
public abstract int getUInt32(int byteOffset);
@JSMethod
public abstract int getUInt32(int byteOffset, boolean littleEndian);
@JSMethod
public abstract float getFloat32(int byteOffset);
@JSMethod
public abstract float getFloat32(int byteOffset, boolean littleEndian);
@JSMethod
public abstract double getFloat64(int byteOffset);
@JSMethod
public abstract double getFloat64(int byteOffset, boolean littleEndian);
@JSMethod
public abstract void setInt8(int byteOffset, int value);
@JSMethod
public abstract void setUInt8(int byteOffset, int value);
@JSMethod
public abstract void setInt16(int byteOffset, int value);
@JSMethod
public abstract void setInt16(int byteOffset, int value, boolean littleEndian);
@JSMethod
public abstract void setUInt16(int byteOffset, int value);
@JSMethod
public abstract void setUInt16(int byteOffset, int value, boolean littleEndian);
@JSMethod
public abstract void setInt32(int byteOffset, int value);
@JSMethod
public abstract void setInt32(int byteOffset, int value, boolean littleEndian);
@JSMethod
public abstract void setUInt32(int byteOffset, int value);
@JSMethod
public abstract void setUInt32(int byteOffset, int value, boolean littleEndian);
@JSMethod
public abstract void setFloat32(int byteOffset, float value);
@JSMethod
public abstract void setFloat32(int byteOffset, float value, boolean littleEndian);
@JSMethod
public abstract void setFloat64(int byteOffset, double value);
@JSMethod
public abstract void setFloat64(int byteOffset, double value, boolean littleEndian);
@JSBody(params = "buffer", script = "return new DataView(buffer);")
public static native DataView create(ArrayBuffer buffer);
@JSBody(params = {"buffer", "offset", "length"}, script = "return new DataView(buffer, offset, length);")
public static native DataView create(ArrayBuffer buffer, int offset, int length);
}

View File

@ -0,0 +1,63 @@
/*
* Copyright 2015 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.webaudio;
import org.teavm.jso.JSMethod;
import org.teavm.jso.JSProperty;
import org.teavm.jso.typedarrays.Float32Array;
import org.teavm.jso.typedarrays.Uint8Array;
public interface AnalyserNode extends AudioNode {
@JSProperty
void setFftSize(int size);
@JSProperty
int getFftSize();
@JSProperty
int getFrequencyBinCount();
@JSProperty
void setMinDecibels(float value);
@JSProperty
float getMinDecibels();
@JSProperty
void setMaxDecibels(float value);
@JSProperty
float getMaxDecibels();
@JSProperty
void setSmoothingTimeConstant(float value);
@JSProperty
float getSmoothingTimeConstant();
@JSMethod
void getFloatFrequencyData(Float32Array array);
@JSMethod
void getByteFrequencyData(Uint8Array array);
@JSMethod
void getFloatTimeDomainData(Float32Array array);
@JSMethod
void getByteTimeDomainData(Uint8Array array);
}

View File

@ -0,0 +1,50 @@
/*
* 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.jso.webaudio;
import org.teavm.jso.JSMethod;
import org.teavm.jso.JSObject;
import org.teavm.jso.JSProperty;
import org.teavm.jso.typedarrays.Float32Array;
public interface AudioBuffer extends JSObject {
@JSProperty
float getSampleRate();
@JSProperty
int getLength();
@JSProperty
double getDuration();
@JSProperty
int getNumberOfChannels();
@JSMethod
Float32Array getChannelData(int channel);
@JSMethod
void copyFromChannel(Float32Array destination, int channelNumber);
@JSMethod
void copyFromChannel(Float32Array destination, int channelNumber, int startInChannel);
@JSMethod
void copyToChannel(Float32Array source, int channelNumber);
@JSMethod
void copyToChannel(Float32Array source, int channelNumber, int startInChannel);
}

View File

@ -0,0 +1,77 @@
/*
* 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.jso.webaudio;
import org.teavm.jso.JSMethod;
import org.teavm.jso.JSProperty;
import org.teavm.jso.dom.events.EventListener;
public interface AudioBufferSourceNode extends AudioNode {
@JSProperty
AudioBuffer getBuffer();
@JSProperty
void setBuffer(AudioBuffer buffer);
@JSProperty
AudioParam getPlaybackRate();
@JSProperty
AudioParam getDetune();
@JSProperty
boolean getLoop();
@JSProperty
void setLoop(boolean loop);
@JSProperty
double getLoopStart();
@JSProperty
void setLoopStart(double start);
@JSProperty
double getLoopEnd();
@JSProperty
void setLoopEnd(double end);
@JSProperty("onended")
void setOnEnded(EventListener<MediaEvent> ent);
@JSProperty("onended")
EventListener<MediaEvent> getOnEnded();
@JSMethod
void start(double when, double offset, double duration);
@JSMethod
void start(double when, double offset);
@JSMethod
void start(double when);
@JSMethod
void start();
@JSMethod
void stop(double when);
@JSMethod
void stop();
}

View File

@ -0,0 +1,161 @@
/*
* 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.jso.webaudio;
import org.teavm.jso.JSBody;
import org.teavm.jso.JSMethod;
import org.teavm.jso.JSObject;
import org.teavm.jso.JSProperty;
import org.teavm.jso.dom.events.EventListener;
import org.teavm.jso.dom.html.HTMLMediaElement;
import org.teavm.jso.typedarrays.ArrayBuffer;
import org.teavm.jso.typedarrays.Float32Array;
public abstract class AudioContext implements JSObject {
public static final String STATE_SUSPENDED = "suspended";
public static final String STATE_RUNNING = "running";
public static final String STATE_CLOSE = "close";
@JSProperty
public abstract AudioDestinationNode getDestination();
@JSProperty
public abstract float getSampleRate();
@JSProperty
public abstract double getCurrentTime();
@JSProperty
public abstract AudioListener getListener();
@JSProperty
public abstract String getState();
@JSProperty("onstatechange")
public abstract void setOnStateChange(EventListener<MediaEvent> listener);
@JSProperty("onstatechange")
public abstract EventListener<MediaEvent> getOnStateChange();
@JSMethod
public abstract void suspend();
@JSMethod
public abstract void resume();
@JSMethod
public abstract void close();
@JSMethod
public abstract AudioBuffer createBuffer(int numberOfChannels, int length, float sampleRate);
@JSMethod
public abstract AudioBuffer decodeAudioData(ArrayBuffer audioData, DecodeSuccessCallback successCallback,
DecodeErrorCallback errorCallback);
@JSMethod
public abstract AudioBuffer decodeAudioData(ArrayBuffer audioData, DecodeSuccessCallback successCallback);
@JSMethod
public abstract AudioBuffer decodeAudioData(ArrayBuffer audioData);
@JSMethod
public abstract AudioBufferSourceNode createBufferSource();
@JSMethod
public abstract MediaElementAudioSourceNode createMediaElementSource(HTMLMediaElement mediaElement);
@JSMethod
public abstract MediaStreamAudioSourceNode createMediaStreamSource(MediaStream mediaStream);
@JSMethod
public abstract MediaStreamAudioDestinationNode createMediaStreamDestination();
@JSMethod
public abstract AudioWorker createAudioWorker();
@JSMethod
public abstract ScriptProcessorNode createScriptProcessor(int bufferSize, int numberOfInputChannels,
int numberOfOutputChannels);
@JSMethod
public abstract ScriptProcessorNode createScriptProcessor(int bufferSize, int numberOfInputChannels);
@JSMethod
public abstract ScriptProcessorNode createScriptProcessor(int bufferSize);
@JSMethod
public abstract ScriptProcessorNode createScriptProcessor();
@JSMethod
public abstract AnalyserNode createAnalyser();
@JSMethod
public abstract GainNode createGain();
@JSMethod
public abstract DelayNode createDelay(double maxDelayTime);
@JSMethod
public abstract DelayNode createDelay();
@JSMethod
public abstract BiquadFilterNode createBiquadFilter();
@JSMethod
public abstract IIRFilterNode createIIRFilter(Float32Array feedforward, Float32Array feedback);
@JSMethod
public abstract WaveShaperNode createWaveShaper();
@JSMethod
public abstract PannerNode createPanner();
@JSMethod
public abstract StereoPannerNode createStereoPanner();
@JSMethod
public abstract ConvolverNode createConvolver();
@JSMethod
public abstract ChannelSplitterNode createChannelSplitter(int numberOfOutputs);
@JSMethod
public abstract ChannelSplitterNode createChannelSplitter();
@JSMethod
public abstract ChannelMergerNode createChannelMerger(int numberOfInputs);
@JSMethod
public abstract ChannelMergerNode createChannelMerger();
@JSMethod
public abstract DynamicsCompressorNode createDynamicsCompressor();
@JSMethod
public abstract OscillatorNode createOscillator();
@JSMethod
public abstract PeriodicWave createPeriodicWave(Float32Array real, Float32Array image,
PeriodicWaveConstraints constraints);
@JSMethod
public abstract PeriodicWave createPeriodicWave(Float32Array real, Float32Array image);
@JSBody(params = {},
script = "var Context = window.AudioContext || window.webkitAudioContext; return new Context();")
public static native AudioContext create();
}

View File

@ -0,0 +1,24 @@
/*
* 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.jso.webaudio;
import org.teavm.jso.JSProperty;
public interface AudioDestinationNode extends AudioNode {
@JSProperty
int getMaxChannelCount();
}

View File

@ -0,0 +1,44 @@
/*
* 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.jso.webaudio;
import org.teavm.jso.JSMethod;
import org.teavm.jso.JSObject;
import org.teavm.jso.JSProperty;
public interface AudioListener extends JSObject {
@JSProperty
void setDopplerFactor(float value);
@JSProperty
float getDopplerFactor();
@JSProperty
void setSpeedOfSound(float value);
@JSProperty
float getSpeedOfSound();
@JSMethod
void setPosition(float x, float y, float z);
@JSMethod
void setOrientation(float x, float y, float z, float xUp, float yUp, float zUp);
@JSMethod
void setVelocity(float x, float y, float z);
}

View File

@ -0,0 +1,83 @@
/*
* 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.jso.webaudio;
import org.teavm.jso.JSMethod;
import org.teavm.jso.JSObject;
import org.teavm.jso.JSProperty;
public interface AudioNode extends JSObject {
String CHANNEL_COUNT_MODE_MAX = "max";
String CHANNEL_COUNT_MODE_CLAMPED_MAX = "clamped-max";
String CHANNEL_COUNT_MODE_EXPLICIT = "explicit";
String CHANNEL_INTERPRETATION_SPEAKERS = "speakers";
String CHANNEL_INTERPRETATION_DISCRETE = "discrete";
@JSMethod
void connect(AudioNode destination, int output, int input);
@JSMethod
void connect(AudioNode destination, int output);
@JSMethod
void connect(AudioNode destination);
@JSMethod
void connect(AudioParam destination, int output);
@JSMethod
void connect(AudioParam destination);
@JSMethod
void disconnect();
@JSMethod
void disconnect(int output);
@JSMethod
void disconnect(AudioNode destination);
@JSMethod
void disconnect(AudioNode destination, int output);
@JSMethod
void disconnect(AudioNode destination, int output, int input);
@JSMethod
void disconnect(AudioParam destination);
@JSMethod
void disconnect(AudioParam destination, int output);
@JSProperty
AudioContext getContext();
@JSProperty
int getNumberOfInputs();
@JSProperty
int getNumberOfOutputs();
@JSProperty
int getChannelCount();
@JSProperty
String getChannelCountMode();
@JSProperty
String getChannelInterpretation();
}

View File

@ -0,0 +1,50 @@
/*
* 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.jso.webaudio;
import org.teavm.jso.JSMethod;
import org.teavm.jso.JSObject;
import org.teavm.jso.JSProperty;
import org.teavm.jso.typedarrays.Float32Array;
public interface AudioParam extends JSObject {
@JSProperty
float getValue();
@JSProperty
void setValue(float value);
@JSProperty
float getDefaultValue();
@JSMethod
void setValueAtTime(float value, double startTime);
@JSMethod
void linearRampToValueAtTime(float value, double endTime);
@JSMethod
void exponentialRampToValueAtTime(float value, double endTime);
@JSMethod
void setTargetAtTime(float target, double startTime, float timeConstant);
@JSMethod
void setValueCurveAtTime(Float32Array values, double startTime, double duration);
@JSMethod
void cancelScheduledValues(double startTime);
}

View File

@ -0,0 +1,38 @@
/*
* 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.jso.webaudio;
import org.teavm.jso.JSObject;
import org.teavm.jso.JSProperty;
import org.teavm.jso.dom.events.Event;
import org.teavm.jso.typedarrays.Float32Array;
public interface AudioProcessEvent extends Event {
@JSProperty
double getPlaybackTime();
@JSProperty
AudioWorkerNodeProcessor getNode();
@JSProperty
Float32Array[][] getInputs();
@JSProperty
Float32Array[][] getOutputs();
@JSProperty
JSObject getParameters();
}

View File

@ -0,0 +1,29 @@
/*
* 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.jso.webaudio;
import org.teavm.jso.JSProperty;
public interface AudioProcessingEvent extends MediaEvent {
@JSProperty
double getPlaybackTime();
@JSProperty
AudioBuffer getInputBuffer();
@JSProperty
AudioBuffer getOutputBuffer();
}

View File

@ -0,0 +1,59 @@
/*
* 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.jso.webaudio;
import org.teavm.jso.JSMethod;
import org.teavm.jso.JSObject;
import org.teavm.jso.JSProperty;
import org.teavm.jso.dom.events.EventListener;
public interface AudioWorker extends JSObject {
@JSProperty
AudioWorkerParamDescriptor[] getParameters();
@JSProperty(value = "onmessage")
void setOnMessage(EventListener<MediaEvent> event);
@JSProperty(value = "onmessage")
EventListener<MediaEvent> getOnMessage();
@JSProperty(value = "onloaded")
void setOnLoaded(EventListener<MediaEvent> event);
@JSProperty(value = "onloaded")
EventListener<MediaEvent> getOnLoaded();
@JSMethod
void terminate();
@JSMethod
void postMessage(JSObject message, JSObject[] transfer);
@JSMethod
void postMessage(JSObject message, JSObject transfer);
@JSMethod
void postMessage(JSObject message);
@JSMethod
AudioWorkerNode createNode(int numberOfInputs, int numberOfOutputs);
@JSMethod
AudioParam addParameter(String name, float defaultValue);
@JSMethod
void removeParameter(String name);
}

View File

@ -0,0 +1,47 @@
/*
* 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.jso.webaudio;
import org.teavm.jso.JSMethod;
import org.teavm.jso.JSObject;
import org.teavm.jso.JSProperty;
import org.teavm.jso.dom.events.EventListener;
public interface AudioWorkerGlobalScope extends JSObject {
@JSProperty
float getSampleRate();
@JSProperty("onaudioprocess")
void setOnAudioProcess(EventListener<MediaEvent> event);
@JSProperty("onaudioprocess")
EventListener<MediaEvent> getOnAudioProcess();
@JSProperty("onnodecreate")
void setOnNodeCreate(EventListener<MediaEvent> event);
@JSProperty("onnodecreate")
EventListener<MediaEvent> getOnNodeCreate();
@JSProperty
AudioWorkerParamDescriptor[] getParameters();
@JSMethod
AudioParam addParameter(String name, float defaultValue);
@JSMethod
void removeParameter(String name);
}

View File

@ -0,0 +1,39 @@
/*
* 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.jso.webaudio;
import org.teavm.jso.JSMethod;
import org.teavm.jso.JSObject;
import org.teavm.jso.JSProperty;
import org.teavm.jso.dom.events.EventListener;
public interface AudioWorkerNode extends AudioNode {
@JSProperty("onmessage")
void setOnMessage(EventListener<MediaEvent> event);
@JSProperty("onmessage")
EventListener<MediaEvent> getOnMessage();
@JSMethod
void postMessage(JSObject message, JSObject[] transfer);
@JSMethod
void postMessage(JSObject message, JSObject transfer);
@JSMethod
void postMessage(JSObject message);
}

View File

@ -0,0 +1,31 @@
/*
* 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.jso.webaudio;
import org.teavm.jso.JSProperty;
import org.teavm.jso.core.JSArray;
public interface AudioWorkerNodeCreationEvent extends MediaEvent {
@JSProperty
AudioWorkerNodeProcessor getNode();
@JSProperty
JSArray getInputs();
@JSProperty
JSArray getOutputs();
}

View File

@ -0,0 +1,40 @@
/*
* 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.jso.webaudio;
import org.teavm.jso.JSMethod;
import org.teavm.jso.JSObject;
import org.teavm.jso.JSProperty;
import org.teavm.jso.dom.events.EventListener;
import org.teavm.jso.dom.events.EventTarget;
public interface AudioWorkerNodeProcessor extends EventTarget {
@JSProperty("onmessage")
void setOnMessage(EventListener<MediaEvent> event);
@JSProperty("onmessage")
EventListener<MediaEvent> getOnMessage();
@JSMethod
void postMessage(JSObject message, JSObject[] transfer);
@JSMethod
void postMessage(JSObject message, JSObject transfer);
@JSMethod
void postMessage(JSObject message);
}

View File

@ -0,0 +1,27 @@
/*
* 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.jso.webaudio;
import org.teavm.jso.JSObject;
import org.teavm.jso.JSProperty;
public interface AudioWorkerParamDescriptor extends JSObject {
@JSProperty
String getName();
@JSProperty
float getDefaultValue();
}

View File

@ -0,0 +1,52 @@
/*
* 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.jso.webaudio;
import org.teavm.jso.JSMethod;
import org.teavm.jso.JSProperty;
import org.teavm.jso.typedarrays.Float32Array;
public interface BiquadFilterNode extends AudioNode {
String TYPE_LOW_PASS = "lowpass";
String TYPE_LOW_SHELF = "lowshelf";
String TYPE_HIGH_SHELF = "highshelf";
String TYPE_HIGH_PASS = "highpass";
String TYPE_BAND_PASS = "bandpass";
String TYPE_PEAKING = "peaking";
String TYPE_NOTCH = "notch";
String TYPE_ALL_PASS = "allpass";
@JSProperty
void setType(String type);
@JSProperty
String getType();
@JSProperty
AudioParam getFrequency();
@JSProperty
AudioParam getDetune();
@JSProperty("Q")
AudioParam getQ();
@JSProperty
AudioParam getGain();
@JSMethod
void getFrequencyResponse(Float32Array frequencyHz, Float32Array magResponse, Float32Array phaseResponse);
}

View File

@ -0,0 +1,19 @@
/*
* 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.jso.webaudio;
public interface ChannelMergerNode extends AudioNode {
}

View File

@ -0,0 +1,19 @@
/*
* 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.jso.webaudio;
public interface ChannelSplitterNode extends AudioNode {
}

View File

@ -0,0 +1,33 @@
/*
* 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.jso.webaudio;
import org.teavm.jso.JSProperty;
public interface ConvolverNode extends AudioNode {
@JSProperty
void setBuffer(AudioBuffer buffer);
@JSProperty
AudioBuffer getBuffer();
@JSProperty
void setNormalize(boolean normalised);
@JSProperty
boolean getNormalize();
}

View File

@ -0,0 +1,26 @@
/*
* 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.jso.webaudio;
import org.teavm.jso.JSFunctor;
import org.teavm.jso.JSMethod;
import org.teavm.jso.JSObject;
@JSFunctor
public interface DecodeErrorCallback extends JSObject {
@JSMethod
void onError(JSObject error);
}

View File

@ -0,0 +1,26 @@
/*
* 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.jso.webaudio;
import org.teavm.jso.JSFunctor;
import org.teavm.jso.JSMethod;
import org.teavm.jso.JSObject;
@JSFunctor
public interface DecodeSuccessCallback extends JSObject {
@JSMethod
void onSuccess(AudioBuffer decodedData);
}

View File

@ -0,0 +1,23 @@
/*
* 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.jso.webaudio;
import org.teavm.jso.JSProperty;
public interface DelayNode extends AudioNode {
@JSProperty
AudioParam getDelayTime();
}

View File

@ -0,0 +1,38 @@
/*
* 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.jso.webaudio;
import org.teavm.jso.JSProperty;
public interface DynamicsCompressorNode extends AudioNode {
@JSProperty
AudioParam getThreshold();
@JSProperty
AudioParam getKnee();
@JSProperty
AudioParam getRatio();
@JSProperty
float getReduction();
@JSProperty
AudioParam getAttack();
@JSProperty
AudioParam getRelease();
}

Some files were not shown because too many files have changed in this diff Show More