diff --git a/core/src/main/java/org/teavm/common/GraphUtils.java b/core/src/main/java/org/teavm/common/GraphUtils.java index 365d1fd11..31731e9fa 100644 --- a/core/src/main/java/org/teavm/common/GraphUtils.java +++ b/core/src/main/java/org/teavm/common/GraphUtils.java @@ -21,10 +21,6 @@ import java.util.List; import java.util.function.IntPredicate; import java.util.stream.Collectors; -/** - * - * @author Alexey Andreev - */ public final class GraphUtils { static final byte NONE = 0; static final byte VISITING = 1; @@ -233,12 +229,6 @@ public final class GraphUtils { return components.toArray(new int[0][]); } - private static class SCCFinder { - int[] index; - int[] lowlink; - boolean[] onStack; - } - public static DominatorTree buildDominatorTree(Graph graph) { DominatorTreeBuilder builder = new DominatorTreeBuilder(graph); builder.build(); diff --git a/core/src/main/java/org/teavm/model/MethodHandle.java b/core/src/main/java/org/teavm/model/MethodHandle.java index 4c5859042..139d20cb2 100644 --- a/core/src/main/java/org/teavm/model/MethodHandle.java +++ b/core/src/main/java/org/teavm/model/MethodHandle.java @@ -17,10 +17,6 @@ package org.teavm.model; import java.util.Arrays; -/** - * - * @author Alexey Andreev - */ public class MethodHandle { private MethodHandleType kind; private String className; diff --git a/core/src/main/java/org/teavm/model/util/InstructionStringifier.java b/core/src/main/java/org/teavm/model/util/InstructionStringifier.java index cbfbabc54..4c64687b4 100644 --- a/core/src/main/java/org/teavm/model/util/InstructionStringifier.java +++ b/core/src/main/java/org/teavm/model/util/InstructionStringifier.java @@ -21,10 +21,6 @@ import java.util.stream.Collectors; import org.teavm.model.*; import org.teavm.model.instructions.*; -/** - * - * @author Alexey Andreev - */ public class InstructionStringifier implements InstructionReader { private TextLocation location; private StringBuilder sb; @@ -64,12 +60,12 @@ public class InstructionStringifier implements InstructionReader { @Override public void longConstant(VariableReader receiver, long cst) { - sb.append("@").append(receiver.getIndex()).append(" := ").append(cst); + sb.append("@").append(receiver.getIndex()).append(" := ").append(cst).append("L"); } @Override public void floatConstant(VariableReader receiver, float cst) { - sb.append("@").append(receiver.getIndex()).append(" := ").append(cst); + sb.append("@").append(receiver.getIndex()).append(" := ").append(cst).append('F'); } @Override @@ -267,38 +263,35 @@ public class InstructionStringifier implements InstructionReader { @Override public void create(VariableReader receiver, String type) { - sb.append("@").append(receiver.getIndex()).append(" = new ").append(type).append("()"); + sb.append("@").append(receiver.getIndex()).append(" = new ").append(type).append(""); } @Override public void getField(VariableReader receiver, VariableReader instance, FieldReference field, ValueType fieldType) { - sb.append("@").append(receiver.getIndex()).append(" := "); + sb.append("@").append(receiver.getIndex()).append(" := field " + field); + sb.append(field); if (instance != null) { - sb.append("@").append(instance.getIndex()); - } else { - sb.append(field.getClassName()); + sb.append(" @").append(instance.getIndex()); } - sb.append(".").append(field.getFieldName()); } @Override public void putField(VariableReader instance, FieldReference field, VariableReader value, ValueType fieldType) { + sb.append("field " + field); if (instance != null) { - sb.append("@").append(instance.getIndex()); - } else { - sb.append(field.getClassName()); + sb.append(" @").append(instance.getIndex()); } - sb.append(".").append(field.getFieldName()).append(" := @").append(value.getIndex()); + sb.append(" := @").append(value.getIndex()); } @Override public void arrayLength(VariableReader receiver, VariableReader array) { - sb.append("@").append(receiver.getIndex()).append(" := @").append(array.getIndex()).append(".length"); + sb.append("@").append(receiver.getIndex()).append(" := lengthOf @").append(array.getIndex()); } @Override public void cloneArray(VariableReader receiver, VariableReader array) { - sb.append("@").append(receiver.getIndex()).append(" := @").append(array.getIndex()).append(".clone()"); + sb.append("@").append(receiver.getIndex()).append(" := clone @").append(array.getIndex()).append(""); } @Override @@ -325,19 +318,25 @@ public class InstructionStringifier implements InstructionReader { if (receiver != null) { sb.append("@").append(receiver.getIndex()).append(" := "); } + switch (type) { + case SPECIAL: + sb.append("invoke "); + break; + case VIRTUAL: + sb.append("invokeVirtual "); + break; + } + if (instance != null) { sb.append("@").append(instance.getIndex()); - } else { - sb.append(method.getClassName()); } - sb.append(".").append(method.getName()).append("("); + for (int i = 0; i < arguments.size(); ++i) { - if (i > 0) { + if (instance != null || i > 0) { sb.append(", "); } sb.append("@").append(arguments.get(i).getIndex()); } - sb.append(")"); } @Override @@ -410,12 +409,12 @@ public class InstructionStringifier implements InstructionReader { @Override public void isInstance(VariableReader receiver, VariableReader value, ValueType type) { sb.append("@").append(receiver.getIndex()).append(" := @").append(value.getIndex()) - .append(" instanceof ").append(type); + .append(" instanceOf ").append(type); } @Override public void initClass(String className) { - sb.append("initclass ").append(className); + sb.append("initClass ").append(className); } @Override @@ -425,11 +424,11 @@ public class InstructionStringifier implements InstructionReader { @Override public void monitorEnter(VariableReader objectRef) { - sb.append("monitorenter @").append(objectRef.getIndex()); + sb.append("monitorEnter @").append(objectRef.getIndex()); } @Override public void monitorExit(VariableReader objectRef) { - sb.append("monitorexit @").append(objectRef.getIndex()); + sb.append("monitorExit @").append(objectRef.getIndex()); } } diff --git a/core/src/main/java/org/teavm/model/util/ListingBuilder.java b/core/src/main/java/org/teavm/model/util/ListingBuilder.java index f4dc79071..ff2b431e1 100644 --- a/core/src/main/java/org/teavm/model/util/ListingBuilder.java +++ b/core/src/main/java/org/teavm/model/util/ListingBuilder.java @@ -46,7 +46,7 @@ public class ListingBuilder { for (PhiReader phi : block.readPhis()) { sb.append(prefix).append(" "); - sb.append("@").append(phi.getReceiver().getIndex()).append(" := "); + sb.append("@").append(phi.getReceiver().getIndex()).append(" := phi "); List incomings = phi.readIncomings(); for (int j = 0; j < incomings.size(); ++j) { if (j > 0) { diff --git a/core/src/main/java/org/teavm/model/util/ListingLexer.java b/core/src/main/java/org/teavm/model/util/ListingLexer.java new file mode 100644 index 000000000..4382a6f8b --- /dev/null +++ b/core/src/main/java/org/teavm/model/util/ListingLexer.java @@ -0,0 +1,424 @@ +/* + * 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.io.IOException; +import java.io.Reader; + +class ListingLexer { + private Reader reader; + private int c; + private ListingToken token; + private Object tokenValue; + private int index = -1; + private int tokenStart; + + public ListingLexer(Reader reader) { + this.reader = reader; + } + + public ListingToken getToken() { + return token; + } + + public Object getTokenValue() { + return tokenValue; + } + + public int getIndex() { + return index; + } + + public int getTokenStart() { + return tokenStart; + } + + public void nextToken() throws IOException, ListingParseException { + if (token == ListingToken.EOF) { + return; + } + + tokenStart = index; + if (index < 0) { + tokenStart = 0; + nextChar(); + } + skipWhiteSpace(); + + do { + switch (c) { + case -1: + token = ListingToken.EOF; + break; + case '@': + nextChar(); + readVariable(); + break; + case '$': + readLabel(); + break; + case '\'': + readString(); + break; + case ':': + nextChar(); + if (c == '=') { + nextChar(); + token = ListingToken.ASSIGN; + } else { + token = ListingToken.COLON; + } + break; + case '=': + nextChar(); + expect('='); + token = ListingToken.EQUAL; + break; + case '!': + nextChar(); + expect('='); + token = ListingToken.NOT_EQUAL; + break; + case '<': + nextChar(); + if (c == '=') { + nextChar(); + token = ListingToken.LESS_OR_EQUAL; + } else if (c == '<') { + nextChar(); + token = ListingToken.SHIFT_LEFT; + } else { + token = ListingToken.LESS; + } + break; + case '>': + nextChar(); + if (c == '=') { + nextChar(); + token = ListingToken.GREATER_OR_EQUAL; + } else if (c == '>') { + nextChar(); + if (c == '>') { + nextChar(); + token = ListingToken.SHIFT_RIGHT_UNSIGNED; + } else { + token = ListingToken.SHIFT_RIGHT; + } + } else { + token = ListingToken.GREATER; + } + break; + case '+': + nextChar(); + token = ListingToken.ADD; + break; + case '-': + nextChar(); + token = ListingToken.SUBTRACT; + break; + case '*': + nextChar(); + token = ListingToken.SUBTRACT; + break; + case '/': + nextChar(); + if (c == '/') { + if (skipComment()) { + continue; + } else { + token = ListingToken.EOF; + } + } else { + token = ListingToken.DIVIDE; + } + break; + case '%': + nextChar(); + token = ListingToken.REMAINDER; + break; + case '&': + nextChar(); + token = ListingToken.AND; + break; + case '|': + nextChar(); + token = ListingToken.OR; + break; + case '^': + nextChar(); + token = ListingToken.XOR; + break; + case '.': + nextChar(); + token = ListingToken.DOT; + break; + case ',': + nextChar(); + token = ListingToken.COMMA; + break; + case '[': + nextChar(); + token = ListingToken.LEFT_SQUARE_BRACKET; + break; + case ']': + nextChar(); + token = ListingToken.RIGHT_SQUARE_BRACKET; + break; + default: + if (isIdentifierStart()) { + readIdentifier(); + } else if (c >= '0' && c <= '9') { + readNumber(); + } else { + unexpected(); + } + break; + } + } while (false); + } + + private void readVariable() throws IOException { + nextChar(); + token = ListingToken.VARIABLE; + readIdentifierLike(); + } + + private void readLabel() throws IOException { + readIdentifierLike(); + token = ListingToken.LABEL; + readIdentifierLike(); + } + + private void readIdentifierLike() throws IOException { + StringBuilder sb = new StringBuilder(); + while (isIdentifierPart()) { + sb.append(c); + nextChar(); + } + tokenValue = sb.toString(); + } + + private void readIdentifier() throws IOException { + token = ListingToken.IDENTIFIER; + StringBuilder sb = new StringBuilder(); + sb.append(c); + while (isIdentifierPart()) { + sb.append(c); + nextChar(); + } + tokenValue = sb.toString(); + } + + private boolean isIdentifierStart() { + if (c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z') { + return true; + } + switch (c) { + case '_': + return true; + default: + return false; + } + } + + private boolean isIdentifierPart() { + if (isIdentifierStart() || c >= '0' && c <= '9') { + return true; + } + switch (c) { + case '<': + case '>': + case '(': + case ')': + case '.': + case '$': + case '#': + return true; + default: + return false; + } + } + + private void readString() throws IOException, ListingParseException { + nextChar(); + token = ListingToken.STRING; + StringBuilder sb = new StringBuilder(); + + while (true) { + switch (c) { + case '\'': + nextChar(); + tokenValue = sb.toString(); + return; + case '\\': + switch (c) { + case 'n': + sb.append('\n'); + break; + case 't': + sb.append('\t'); + break; + case '\'': + case '\\': + sb.append(c); + break; + case 'u': + int codePoint = 0; + for (int i = 0; i < 4; ++i) { + if (c == -1) { + throw new ListingParseException("Wrong escape sequence", index); + } + int digit = Character.digit((char) c, 16); + if (digit < 0) { + throw new ListingParseException("Wrong escape sequence", index); + } + codePoint = codePoint * 16 + digit; + } + sb.appendCodePoint(codePoint); + break; + default: + throw new ListingParseException("Wrong escape sequence", index); + } + break; + default: + if (c < ' ') { + throw new ListingParseException("Unexpected character in string literal: " + c, index); + } + sb.append(c); + nextChar(); + break; + } + } + } + + private void readNumber() throws IOException, ListingParseException { + StringBuilder sb = new StringBuilder(); + sb.append(c); + + nextChar(); + token = ListingToken.INTEGER; + + while (c >= '0' && c <= '9') { + sb.append(c); + nextChar(); + } + + if (c == '.') { + sb.append('.'); + token = ListingToken.DOUBLE; + nextChar(); + + if (c < '0' || c > '9') { + throw new ListingParseException("Wrong number", index); + } + + while (c >= '0' && c <= '9') { + sb.append(c); + nextChar(); + } + } + + if (c == 'E' || c == 'e') { + sb.append('e'); + nextChar(); + if (c == '+' || c == '-') { + sb.append(c); + nextChar(); + } + + if (c < '0' || c > '9') { + throw new ListingParseException("Wrong number", index); + } + + while (c >= '0' && c <= '9') { + sb.append(c); + nextChar(); + } + } + + if (c == 'F' || c == 'f') { + nextChar(); + token = ListingToken.FLOAT; + } else if (c == 'l' || c == 'L') { + nextChar(); + token = ListingToken.LONG; + } else if (isIdentifierStart()) { + throw new ListingParseException("Wrong number", index); + } + + switch (token) { + case INTEGER: + tokenValue = Integer.parseInt(sb.toString()); + break; + case LONG: + tokenValue = Long.parseLong(sb.toString()); + break; + case FLOAT: + tokenValue = Float.parseFloat(sb.toString()); + break; + case DOUBLE: + tokenValue = Double.parseDouble(sb.toString()); + break; + default: + break; + } + } + + private void expect(char expected) throws IOException, ListingParseException { + if (c != expected) { + unexpected(); + } + nextChar(); + } + + private void unexpected() throws ListingParseException { + throw new ListingParseException("Unexpected character: " + c, index); + } + + private void skipWhiteSpace() throws IOException { + while (true) { + switch (c) { + case ' ': + case '\n': + case '\t': + nextChar(); + break; + default: + return; + } + } + } + + private boolean skipComment() throws IOException { + while (true) { + switch (c) { + case '\n': + nextChar(); + return true; + case -1: + return false; + default: + nextChar(); + break; + } + } + } + + private void nextChar() throws IOException { + c = reader.read(); + ++index; + } +} diff --git a/core/src/main/java/org/teavm/model/util/ListingParseException.java b/core/src/main/java/org/teavm/model/util/ListingParseException.java new file mode 100644 index 000000000..561b52ecc --- /dev/null +++ b/core/src/main/java/org/teavm/model/util/ListingParseException.java @@ -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.model.util; + +public class ListingParseException extends Exception { + private final int index; + + public ListingParseException(String message, int index) { + super(message); + this.index = index; + } + + public int getIndex() { + return index; + } +} diff --git a/core/src/main/java/org/teavm/model/util/ListingParser.java b/core/src/main/java/org/teavm/model/util/ListingParser.java new file mode 100644 index 000000000..a95489610 --- /dev/null +++ b/core/src/main/java/org/teavm/model/util/ListingParser.java @@ -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.model.util; + +public class ListingParser { +} diff --git a/core/src/main/java/org/teavm/model/util/ListingToken.java b/core/src/main/java/org/teavm/model/util/ListingToken.java new file mode 100644 index 000000000..b4ecc12f5 --- /dev/null +++ b/core/src/main/java/org/teavm/model/util/ListingToken.java @@ -0,0 +1,51 @@ +/* + * 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; + +enum ListingToken { + IDENTIFIER, + INTEGER, + LONG, + FLOAT, + DOUBLE, + STRING, + VARIABLE, + LABEL, + ASSIGN, + EQUAL, + NOT_EQUAL, + LESS, + LESS_OR_EQUAL, + GREATER, + GREATER_OR_EQUAL, + ADD, + SUBTRACT, + MULTIPLY, + DIVIDE, + REMAINDER, + AND, + OR, + XOR, + SHIFT_LEFT, + SHIFT_RIGHT, + SHIFT_RIGHT_UNSIGNED, + DOT, + LEFT_SQUARE_BRACKET, + RIGHT_SQUARE_BRACKET, + COMMA, + COLON, + EOF +}