diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/CharacterNativeGenerator.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/CharacterNativeGenerator.java new file mode 100644 index 000000000..bb17ca6ae --- /dev/null +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/CharacterNativeGenerator.java @@ -0,0 +1,52 @@ +/* + * 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; + +import java.io.IOException; +import org.teavm.codegen.SourceWriter; +import org.teavm.javascript.ni.Generator; +import org.teavm.javascript.ni.GeneratorContext; +import org.teavm.model.MethodReference; +import org.teavm.model.ValueType; + +/** + * + * @author Alexey Andreev + */ +public class CharacterNativeGenerator implements Generator { + @Override + public void generate(GeneratorContext context, SourceWriter writer, MethodReference methodRef) throws IOException { + switch (methodRef.getName()) { + case "toLowerCase": + if (methodRef.getDescriptor().parameterType(0) == ValueType.CHARACTER) { + generateToLowerCase(context, writer); + } else { + generateToLowerCaseInt(context, writer); + } + break; + } + } + + private void generateToLowerCase(GeneratorContext context, SourceWriter writer) throws IOException{ + writer.append("return String.fromCharCode(").append(context.getParameterName(1)) + .append(").toLowerCase().charCodeAt(0)|0;").softNewLine(); + } + + private void generateToLowerCaseInt(GeneratorContext context, SourceWriter writer) throws IOException{ + writer.append("return String.fromCharCode(").append(context.getParameterName(1)) + .append(").toLowerCase().charCodeAt(0);").softNewLine(); + } +} diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TBoolean.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TBoolean.java new file mode 100644 index 000000000..967644e7e --- /dev/null +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TBoolean.java @@ -0,0 +1,101 @@ +/* + * 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; + +import org.teavm.classlib.java.io.TSerializable; +import org.teavm.javascript.ni.GeneratedBy; +import org.teavm.javascript.ni.Rename; + +/** + * + * @author Alexey Andreev + */ +public class TBoolean extends TObject implements TSerializable, TComparable { + public static final TBoolean TRUE = new TBoolean(true); + public static final TBoolean FALSE = new TBoolean(false); + public static final Class TYPE = boolean.class; + private boolean value; + + public TBoolean(boolean value) { + this.value = value; + } + + public TBoolean(TString value) { + this.value = parseBoolean(value); + } + + @Override + public int compareTo(TBoolean other) { + return compare(value, other.value); + } + + public static int compare(boolean x, boolean y) { + if (x) { + if (!y) { + return 1; + } + } else { + if (y) { + return -1; + } + } + return 0; + } + + public static boolean parseBoolean(TString s) { + return s != null && s.toLowerCase().equals("true"); + } + + public boolean booleanValue() { + return value; + } + + public static TBoolean valueOf(boolean value) { + return value ? TRUE : FALSE; + } + + public static TBoolean valueOf(TString value) { + return valueOf(parseBoolean(value)); + } + + public static TString toString(boolean value) { + return value ? TString.wrap("true") : TString.wrap("false"); + } + + @Override + @Rename("toString") + public TString toString0() { + return toString(value); + } + + @Override + @GeneratedBy(ObjectNativeGenerator.class) + public int hashCode() { + return value ? 1231 : 1237; + } + + @Override + public boolean equals(TObject obj) { + if (this == obj) { + return true; + } + return obj instanceof TBoolean && ((TBoolean)obj).value == value; + } + + public boolean getBoolean(TString key) { + return valueOf(TSystem.getProperty(key)).booleanValue(); + } +} diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TCharacter.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TCharacter.java new file mode 100644 index 000000000..551e4b8df --- /dev/null +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TCharacter.java @@ -0,0 +1,30 @@ +/* + * 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; + +import org.teavm.javascript.ni.GeneratedBy; + +/** + * + * @author Alexey Andreev + */ +public class TCharacter { + @GeneratedBy(CharacterNativeGenerator.class) + public static native char toLowerCase(char ch); + + @GeneratedBy(CharacterNativeGenerator.class) + public static native int toLowerCase(int ch); +} diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TString.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TString.java index 3f0514e8d..e1350c903 100644 --- a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TString.java +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TString.java @@ -72,6 +72,23 @@ public class TString extends TObject implements TSerializable, TComparable= UTF16Helper.SUPPLEMENTARY_PLANE) { + characters[charCount++] = UTF16Helper.highSurrogate(codePoint); + characters[charCount++] = UTF16Helper.lowSurrogate(codePoint); + } else { + characters[charCount++] = (char)codePoint; + } + } + if (charCount < characters.length) { + characters = TArrays.copyOf(characters, charCount); + } + } + private void initWithBytes(byte[] bytes, int offset, int length, Charset charset) { TStringBuilder sb = new TStringBuilder(bytes.length * 2); this.characters = new char[sb.length()]; @@ -533,4 +550,23 @@ public class TString extends TObject implements TSerializable, TComparable edges = new HashMap<>(); + + public MutableGraphNode(int tag) { + this.tag = tag; + } + + public MutableGraphEdge connect(MutableGraphNode other) { + MutableGraphEdge edge = edges.get(other); + if (edge == null) { + edge = new MutableGraphEdge(); + edge.first = this; + edge.second = other; + edges.put(other, edge); + MutableGraphEdge back = new MutableGraphEdge(); + back.first = other; + back.second = this; + back.back = edge; + edge.back = back; + other.edges.put(this, back); + } + return edge; + } + + public Collection getEdges() { + return edges.values(); + } + + public int getTag() { + return tag; + } +} diff --git a/teavm-core/src/main/java/org/teavm/model/util/RegisterAllocator.java b/teavm-core/src/main/java/org/teavm/model/util/RegisterAllocator.java index 59c54a43e..c991cfeb8 100644 --- a/teavm-core/src/main/java/org/teavm/model/util/RegisterAllocator.java +++ b/teavm-core/src/main/java/org/teavm/model/util/RegisterAllocator.java @@ -35,7 +35,8 @@ public class RegisterAllocator { liveness.analyze(program); Graph interferenceGraph = interferenceBuilder.build(program, method.parameterCount(), liveness); DisjointSet congruenceClasses = buildPhiCongruenceClasses(program); - removeRedundantCopies(program, phiArgsCopies, interferenceGraph, congruenceClasses); + List classInterferenceGraph = makeMutableGraph(interferenceGraph, congruenceClasses); + removeRedundantCopies(program, phiArgsCopies, classInterferenceGraph, congruenceClasses); int[] classArray = congruenceClasses.pack(program.variableCount()); int[] colors = new int[program.variableCount()]; Arrays.fill(colors, -1); @@ -57,6 +58,25 @@ public class RegisterAllocator { int var; } + private static List makeMutableGraph(Graph graph, DisjointSet classes) { + List mutableGraph = new ArrayList<>(); + for (int i = 0; i < graph.size(); ++i) { + int cls = classes.find(i); + while (cls >= mutableGraph.size()) { + mutableGraph.add(new MutableGraphNode(mutableGraph.size())); + } + MutableGraphNode node = mutableGraph.get(cls); + for (int j : graph.outgoingEdges(i)) { + int otherCls = classes.find(j); + while (otherCls >= mutableGraph.size()) { + mutableGraph.add(new MutableGraphNode(mutableGraph.size())); + } + node.connect(mutableGraph.get(otherCls)); + } + } + return mutableGraph; + } + private List insertPhiArgumentsCopies(Program program) { List copies = new ArrayList<>(); for (int i = 0; i < program.basicBlockCount(); ++i) { @@ -108,24 +128,34 @@ public class RegisterAllocator { return copies; } - private void removeRedundantCopies(Program program, List copies, Graph inteferenceGraph, - DisjointSet congruenceClasses) { + private void removeRedundantCopies(Program program, List copies, + List interferenceGraph, DisjointSet congruenceClasses) { for (PhiArgumentCopy copy : copies) { boolean interfere = false; - for (int neighbour : inteferenceGraph.outgoingEdges(copy.original)) { - if (neighbour == copy.var || neighbour == copy.original) { + int varClass = congruenceClasses.find(copy.var); + int origClass = congruenceClasses.find(copy.original); + for (MutableGraphEdge edge : interferenceGraph.get(copy.original).getEdges()) { + if (edge.getFirst() == edge.getSecond()) { continue; } - if (congruenceClasses.find(neighbour) == congruenceClasses.find(copy.var) || - congruenceClasses.find(neighbour) == congruenceClasses.find(copy.original)) { + int neighbour = congruenceClasses.find(edge.getSecond().getTag()); + if (neighbour == varClass || neighbour == origClass) { interfere = true; break; } } if (!interfere) { - congruenceClasses.union(copy.var, copy.original); + int newClass = congruenceClasses.union(varClass, origClass); copy.block.getInstructions().set(copy.index, new EmptyInstruction()); copy.incoming.setValue(program.variableAt(copy.original)); + for (MutableGraphEdge edge : interferenceGraph.get(varClass).getEdges() + .toArray(new MutableGraphEdge[0])) { + edge.setFirst(interferenceGraph.get(newClass)); + } + for (MutableGraphEdge edge : interferenceGraph.get(origClass).getEdges() + .toArray(new MutableGraphEdge[0])) { + edge.setFirst(interferenceGraph.get(newClass)); + } } } }