Fixes bugs. Adds JCL implementation

This commit is contained in:
konsoletyper 2014-02-21 15:07:37 +04:00
parent 59e6095fef
commit 31b9525309
14 changed files with 591 additions and 32 deletions

View File

@ -54,6 +54,9 @@
<configuration>
<minifying>false</minifying>
<numThreads>1</numThreads>
<wildcards>
<param>**.ArraysTest</param>
</wildcards>
</configuration>
</execution>
</executions>

View File

@ -128,10 +128,10 @@ public class TArrayList<E> extends TAbstractList<E> implements TCloneable, TSeri
}
ensureCapacity(size + c.size());
int gap = c.size();
size += gap;
for (int i = gap - 1; i > index; --i) {
array[i] = array[i - gap];
for (int i = size - 1; i >= index; --i) {
array[i + gap] = array[i];
}
size += gap;
TIterator<? extends E> iter = c.iterator();
for (int i = 0; i < gap; ++i) {
array[index++] = iter.next();

View File

@ -182,4 +182,99 @@ public class TArrays extends TObject {
public static void fill(TObject[] a, TObject val) {
fill(a, 0, a.length, val);
}
public static void sort(Object[] a) {
sort(a, new NaturalOrder());
}
public static void sort(Object[] a, int fromIndex, int toIndex) {
sort(a, fromIndex, toIndex, new NaturalOrder());
}
private static class NaturalOrder implements TComparator<Object> {
@SuppressWarnings({ "rawtypes", "unchecked" })
@Override public int compare(Object o1, Object o2) {
if (o1 != null) {
return ((TComparable)o1).compareTo((TComparable)o2);
} else if (o2 != null) {
return ((TComparable)o2).compareTo((TComparable)o1);
} else {
return 0;
}
}
}
public static <T> void sort(T[] a, int fromIndex, int toIndex, TComparator<? super T> c) {
@SuppressWarnings("unchecked")
T[] subarray = (T[])new Object[toIndex - fromIndex];
for (int i = fromIndex; i < toIndex; ++i) {
subarray[i - fromIndex] = a[i];
}
sort(subarray, c);
for (int i = fromIndex; i < toIndex; ++i) {
a[i] = subarray[i - fromIndex];
}
}
@SuppressWarnings("unchecked")
public static <T> void sort(T[] a, TComparator<? super T> c) {
Object[] first = a;
Object[] second = new Object[a.length];
int chunkSize = 1;
while (chunkSize < a.length) {
for (int i = 0; i < first.length; i += chunkSize * 2) {
merge(first, second, i, Math.min(first.length, i + chunkSize),
Math.min(first.length, i + 2 * chunkSize), (TComparator<Object>)c);
}
Object[] tmp = first;
first = second;
second = tmp;
chunkSize *= 2;
}
if (first != a) {
for (int i = 0; i < first.length; ++i) {
second[i] = first[i];
}
}
}
private static void merge(Object[] a, Object[] b, int from, int split, int to, TComparator<Object> comp) {
int index = from;
int from2 = split;
while (true) {
if (from == split) {
while (from2 < to) {
b[index++] = a[from2++];
}
break;
} else if (from2 == to) {
while (from < split) {
b[index++] = a[from++];
}
break;
}
Object p = a[from];
Object q = a[from2];
if (comp.compare(p, q) <= 0) {
b[index++] = p;
++from;
} else {
b[index++] = q;
++from2;
}
}
}
@SafeVarargs
public static <T> TList<T> asList(final T... a) {
return new TAbstractList<T>() {
@Override public T get(int index) {
return a[index];
}
@Override public int size() {
return a.length;
}
};
}
}

View File

@ -0,0 +1,135 @@
/*
* Copyright 2014 Alexey Andreev.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.teavm.classlib.java.util;
import org.teavm.classlib.java.lang.*;
/**
*
* @author Alexey Andreev
*/
public class TCollections extends TObject {
public static <T> TIterator<T> emptyIterator() {
return new TIterator<T>() {
@Override public boolean hasNext() {
return false;
}
@Override public T next() {
throw new TNoSuchElementException();
}
@Override public void remove() {
throw new TIllegalStateException();
}
};
}
public static <T> TListIterator<T> emptyListIterator() {
return new TListIterator<T>() {
@Override public boolean hasNext() {
return false;
}
@Override public T next() {
throw new TNoSuchElementException();
}
@Override public void remove() {
throw new TIllegalStateException();
}
@Override public boolean hasPrevious() {
return false;
}
@Override public T previous() {
throw new TNoSuchElementException();
}
@Override public int nextIndex() {
return 0;
}
@Override public int previousIndex() {
return -1;
}
@Override public void set(T e) {
throw new TUnsupportedOperationException();
}
@Override public void add(T e) {
throw new TUnsupportedOperationException();
}
};
}
public static final <T> TList<T> emptyList() {
return new TAbstractList<T>() {
@Override public T get(int index) {
throw new TIndexOutOfBoundsException();
}
@Override public int size() {
return 0;
}
};
}
public static <T> TList<T> singletonList(final T o) {
return new TAbstractList<T>() {
@Override public T get(int index) {
if (index != 0) {
throw new TIndexOutOfBoundsException();
}
return o;
}
@Override public int size() {
return 1;
}
};
}
public static <T> TList<T> nCopies(final int n, final T o) {
return new TAbstractList<T>() {
@Override public T get(int index) {
if (index < 0 || index >= n) {
throw new TIndexOutOfBoundsException();
}
return o;
}
@Override public int size() {
return n;
}
};
}
public static void swap(TList<?> list, int i, int j) {
@SuppressWarnings("unchecked")
TList<Object> objList = (TList<Object>)list;
Object tmp = objList.get(i);
objList.set(i, objList.get(j));
objList.set(j, tmp);
}
public static <T> void sort(TList<T> list, TComparator<? super T> c) {
@SuppressWarnings("unchecked")
T[] array = (T[])new Object[list.size()];
list.toArray(array);
TArrays.sort(array, c);
for (int i = 0; i < array.length; ++i) {
list.set(i, array[i]);
}
}
public static <T extends TComparable<? super T>> void sort(TList<T> list) {
sort(list, new TComparator<T>() {
@Override public int compare(T o1, T o2) {
return o1 != null ? o1.compareTo(o2) : -o2.compareTo(o1);
}
});
}
}

View File

@ -15,14 +15,10 @@
*/
package org.teavm.classlib.java.util;
import org.teavm.classlib.java.lang.TObject;
/**
*
* @author Alexey Andreev <konsoletyper@gmail.com>
*/
public interface TComparator<T extends TObject> {
public interface TComparator<T> {
int compare(T o1, T o2);
boolean equals(TObject obj);
}

View File

@ -78,6 +78,35 @@ public class ArrayListTest {
}
}
@Test
public void manyElementsAdded() {
List<Integer> list = fillFromZeroToNine();
list.addAll(3, fillFromZeroToNine());
assertEquals(20, list.size());
assertEquals(Integer.valueOf(2), list.get(2));
assertEquals(Integer.valueOf(0), list.get(3));
assertEquals(Integer.valueOf(9), list.get(12));
assertEquals(Integer.valueOf(3), list.get(13));
assertEquals(Integer.valueOf(9), list.get(19));
}
@Test
public void manyElementsRemoved() {
List<Integer> list = fillFromZeroToNine();
list.subList(2, 4).clear();
assertEquals(8, list.size());
assertEquals(Integer.valueOf(1), list.get(1));
assertEquals(Integer.valueOf(4), list.get(2));
assertEquals(Integer.valueOf(9), list.get(7));
}
@Test
public void elementIndexFound() {
List<Integer> list = fillFromZeroToNine();
assertEquals(3, list.indexOf(3));
assertEquals(-1, list.indexOf(100));
}
private List<Integer> fillFromZeroToNine() {
List<Integer> list = new ArrayList<>();
for (int i = 0; i < 10; ++i) {

View File

@ -0,0 +1,47 @@
/*
* Copyright 2014 Alexey Andreev.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.teavm.classlib.java.lang.util;
import static org.junit.Assert.*;
import java.util.Arrays;
import java.util.List;
import org.junit.Test;
/**
*
* @author Alexey Andreev
*/
public class ArraysTest {
@Test
public void arraySorted() {
Integer[] array = { 2, 5, 7, 3, 5, 6 };
Arrays.sort(array);
assertEquals(Integer.valueOf(2), array[0]);
assertEquals(Integer.valueOf(3), array[1]);
assertEquals(Integer.valueOf(5), array[2]);
assertEquals(Integer.valueOf(5), array[3]);
assertEquals(Integer.valueOf(6), array[4]);
assertEquals(Integer.valueOf(7), array[5]);
}
@Test
public void arrayExposedAsList() {
Integer[] array = { 2, 3, 4 };
List<Integer> list = Arrays.asList(array);
assertEquals(3, list.size());
assertEquals(Integer.valueOf(4), list.get(2));
}
}

View File

@ -43,8 +43,8 @@ public class GraphBuilder {
}
public void addEdge(int from, int to) {
if (to < 0) {
throw new IllegalArgumentException("To is negative: " + to);
if (to < 0 || from < 0) {
throw new IllegalArgumentException();
}
sz = Math.max(sz, Math.max(from, to) + 1);
builtGraph = null;

View File

@ -141,7 +141,6 @@ public class DependencyChecker implements DependencyInfo {
}
public void schedulePropagation(final DependencyConsumer consumer, final String type) {
System.out.print("");
executor.executeFast(new Runnable() {
@Override public void run() {
consumer.consume(type);

View File

@ -41,8 +41,8 @@ class DependencyNodeToNodeTransition implements DependencyConsumer {
}
if (!destination.hasType(type)) {
destination.propagate(type);
source.getArrayItem().connect(destination.getArrayItem());
destination.getArrayItem().connect(source.getArrayItem());
}
source.getArrayItem().connect(destination.getArrayItem());
destination.getArrayItem().connect(source.getArrayItem());
}
}

View File

@ -0,0 +1,226 @@
/*
* Copyright 2014 Alexey Andreev.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.teavm.model.util;
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);
@Override
public void visit(EmptyInstruction insn) {
}
@Override
public void visit(ClassConstantInstruction insn) {
insn.setReceiver(map(insn.getReceiver()));
}
@Override
public void visit(NullConstantInstruction insn) {
insn.setReceiver(map(insn.getReceiver()));
}
@Override
public void visit(IntegerConstantInstruction insn) {
insn.setReceiver(map(insn.getReceiver()));
}
@Override
public void visit(LongConstantInstruction insn) {
insn.setReceiver(map(insn.getReceiver()));
}
@Override
public void visit(FloatConstantInstruction insn) {
insn.setReceiver(map(insn.getReceiver()));
}
@Override
public void visit(DoubleConstantInstruction insn) {
insn.setReceiver(map(insn.getReceiver()));
}
@Override
public void visit(StringConstantInstruction insn) {
insn.setReceiver(map(insn.getReceiver()));
}
@Override
public void visit(BinaryInstruction insn) {
insn.setReceiver(map(insn.getReceiver()));
insn.setFirstOperand(map(insn.getFirstOperand()));
insn.setSecondOperand(map(insn.getSecondOperand()));
}
@Override
public void visit(NegateInstruction insn) {
insn.setReceiver(map(insn.getReceiver()));
insn.setOperand(map(insn.getOperand()));
}
@Override
public void visit(AssignInstruction insn) {
insn.setReceiver(map(insn.getReceiver()));
insn.setAssignee(map(insn.getAssignee()));
}
@Override
public void visit(CastInstruction insn) {
insn.setReceiver(map(insn.getReceiver()));
insn.setValue(map(insn.getValue()));
}
@Override
public void visit(CastNumberInstruction insn) {
insn.setReceiver(map(insn.getReceiver()));
insn.setValue(map(insn.getValue()));
}
@Override
public void visit(CastIntegerInstruction insn) {
insn.setReceiver(map(insn.getReceiver()));
insn.setValue(map(insn.getValue()));
}
@Override
public void visit(BranchingInstruction insn) {
insn.setOperand(map(insn.getOperand()));
}
@Override
public void visit(BinaryBranchingInstruction insn) {
insn.setFirstOperand(map(insn.getFirstOperand()));
insn.setSecondOperand(map(insn.getSecondOperand()));
}
@Override
public void visit(JumpInstruction insn) {
}
@Override
public void visit(SwitchInstruction insn) {
insn.setCondition(insn.getCondition());
}
@Override
public void visit(ExitInstruction insn) {
if (insn.getValueToReturn() != null) {
insn.setValueToReturn(map(insn.getValueToReturn()));
}
}
@Override
public void visit(RaiseInstruction insn) {
insn.setException(map(insn.getException()));
}
@Override
public void visit(ConstructArrayInstruction insn) {
insn.setReceiver(map(insn.getReceiver()));
insn.setSize(map(insn.getSize()));
}
@Override
public void visit(ConstructInstruction insn) {
insn.setReceiver(map(insn.getReceiver()));
}
@Override
public void visit(ConstructMultiArrayInstruction insn) {
insn.setReceiver(map(insn.getReceiver()));
for (int i = 0; i < insn.getDimensions().size(); ++i) {
insn.getDimensions().set(i, map(insn.getDimensions().get(i)));
}
}
@Override
public void visit(GetFieldInstruction insn) {
if (insn.getInstance() != null) {
insn.setInstance(map(insn.getInstance()));
}
insn.setReceiver(map(insn.getReceiver()));
}
@Override
public void visit(PutFieldInstruction insn) {
if (insn.getInstance() != null) {
insn.setInstance(map(insn.getInstance()));
}
insn.setValue(map(insn.getValue()));
}
@Override
public void visit(ArrayLengthInstruction insn) {
insn.setReceiver(map(insn.getReceiver()));
insn.setArray(map(insn.getArray()));
}
@Override
public void visit(CloneArrayInstruction insn) {
insn.setReceiver(map(insn.getReceiver()));
insn.setArray(map(insn.getArray()));
}
@Override
public void visit(UnwrapArrayInstruction insn) {
insn.setReceiver(map(insn.getReceiver()));
insn.setArray(map(insn.getArray()));
}
@Override
public void visit(GetElementInstruction insn) {
insn.setReceiver(map(insn.getReceiver()));
insn.setArray(map(insn.getArray()));
insn.setIndex(map(insn.getIndex()));
}
@Override
public void visit(PutElementInstruction insn) {
insn.setValue(map(insn.getValue()));
insn.setArray(map(insn.getArray()));
insn.setIndex(map(insn.getIndex()));
}
@Override
public void visit(InvokeInstruction insn) {
if (insn.getReceiver() != null) {
insn.setReceiver(map(insn.getReceiver()));
}
if (insn.getInstance() != null) {
insn.setInstance(map(insn.getInstance()));
}
for (int i = 0; i < insn.getArguments().size(); ++i) {
insn.getArguments().set(i, map(insn.getArguments().get(i)));
}
}
@Override
public void visit(IsInstanceInstruction insn) {
insn.setReceiver(map(insn.getReceiver()));
insn.setValue(map(insn.getValue()));
}
@Override
public void visit(InitClassInstruction insn) {
}
}

View File

@ -150,11 +150,15 @@ public class RegisterAllocator {
copy.incoming.setValue(program.variableAt(copy.original));
for (MutableGraphEdge edge : interferenceGraph.get(varClass).getEdges()
.toArray(new MutableGraphEdge[0])) {
edge.setFirst(interferenceGraph.get(newClass));
if (edge.getFirst() != null) {
edge.setFirst(interferenceGraph.get(newClass));
}
}
for (MutableGraphEdge edge : interferenceGraph.get(origClass).getEdges()
.toArray(new MutableGraphEdge[0])) {
edge.setFirst(interferenceGraph.get(newClass));
if (edge.getFirst() != null) {
edge.setFirst(interferenceGraph.get(newClass));
}
}
}
}

View File

@ -36,7 +36,7 @@ public class ClassSetOptimizer {
}
private List<MethodOptimization> getOptimizations() {
return Arrays.<MethodOptimization>asList(new CommonSubexpressionElimination(), new UnusedVariableElimination());
return Arrays.<MethodOptimization>asList(new UnusedVariableElimination());
}
public void optimizeAll(ListableClassHolderSource classSource) {

View File

@ -15,7 +15,9 @@
*/
package org.teavm.optimization;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.teavm.common.DominatorTree;
import org.teavm.common.Graph;
@ -52,6 +54,7 @@ public class CommonSubexpressionElimination implements MethodOptimization {
for (int i = 0; i < map.length; ++i) {
map[i] = i;
}
List<List<Incoming>> outgoings = findOutgoings(program);
int[] stack = new int[cfg.size() * 2];
int top = 0;
@ -64,7 +67,7 @@ public class CommonSubexpressionElimination implements MethodOptimization {
int v = stack[--top];
currentBlockIndex = v;
BasicBlock block = program.basicBlockAt(v);
for (int i = 0; i < block.getPhis().size(); ++i) {
/*for (int i = 0; i < block.getPhis().size(); ++i) {
Phi phi = block.getPhis().get(i);
int sharedValue = -2;
for (Incoming incoming : phi.getIncomings()) {
@ -77,32 +80,31 @@ public class CommonSubexpressionElimination implements MethodOptimization {
}
}
if (sharedValue != -1) {
map[phi.getReceiver().getIndex()] = sharedValue;
if (sharedValue != -2) {
AssignInstruction assignInsn = new AssignInstruction();
assignInsn.setReceiver(phi.getReceiver());
assignInsn.setAssignee(program.variableAt(sharedValue));
block.getInstructions().add(0, assignInsn);
}
block.getPhis().remove(i--);
}
}
}*/
for (int i = 0; i < block.getInstructions().size(); ++i) {
Instruction currentInsn = block.getInstructions().get(i);
currentInsn.acceptVisitor(optimizer);
if (eliminate) {
block.getInstructions().remove(i--);
block.getInstructions().set(i, new EmptyInstruction());
eliminate = false;
}
}
for (Incoming incoming : outgoings.get(v)) {
int value = map[incoming.getValue().getIndex()];
incoming.setValue(program.variableAt(value));
}
for (int succ : dom.outgoingEdges(v)) {
stack[top++] = succ;
}
}
for (int v = 0; v < program.basicBlockCount(); ++v) {
BasicBlock block = program.basicBlockAt(v);
for (int i = 0; i < block.getPhis().size(); ++i) {
Phi phi = block.getPhis().get(i);
for (Incoming incoming : phi.getIncomings()) {
int value = map[incoming.getValue().getIndex()];
incoming.setValue(program.variableAt(value));
}
}
}
for (int i = 0; i < map.length; ++i) {
if (map[i] != i) {
@ -114,6 +116,21 @@ public class CommonSubexpressionElimination implements MethodOptimization {
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<Incoming>());
}
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)) {
@ -166,16 +183,19 @@ public class CommonSubexpressionElimination implements MethodOptimization {
int b = map[insn.getSecondOperand().getIndex()];
insn.setFirstOperand(program.variableAt(a));
insn.setSecondOperand(program.variableAt(b));
boolean commutative = false;
String value;
switch (insn.getOperation()) {
case ADD:
value = "+";
commutative = true;
break;
case SUBTRACT:
value = "-";
break;
case MULTIPLY:
value = "*";
commutative = true;
break;
case DIVIDE:
value = "/";
@ -188,12 +208,15 @@ public class CommonSubexpressionElimination implements MethodOptimization {
break;
case AND:
value = "&";
commutative = true;
break;
case OR:
value = "|";
commutative = true;
break;
case XOR:
value = "^";
commutative = true;
break;
case SHIFT_LEFT:
value = "<<";
@ -207,8 +230,10 @@ public class CommonSubexpressionElimination implements MethodOptimization {
default:
return;
}
value = "@" + a + value + "@" + b;
bind(insn.getReceiver().getIndex(), value);
bind(insn.getReceiver().getIndex(), "@" + a + value + "@" + b);
if (commutative) {
bind(insn.getReceiver().getIndex(), "@" + b + value + "@" + a);
}
}
@Override