Adds implementation of some JCL methods/classes

This commit is contained in:
konsoletyper 2014-03-06 13:47:24 +04:00
parent da314bf6f2
commit 688d6191fd
13 changed files with 285 additions and 12 deletions

View File

@ -89,6 +89,7 @@ public class JCLComparisonBuilder {
copyResource("html/package_obj.png");
copyResource("html/int_obj.png");
copyResource("html/enum_obj.png");
copyResource("html/annotation_obj.png");
try (Writer out = new OutputStreamWriter(new FileOutputStream(new File(
outputDirectory, "jcl.html")), "UTF-8")) {
generateHtml(out, packages);

View File

@ -57,10 +57,10 @@ class JCLComparisonVisitor implements ClassVisitor {
jclClass = new JCLClass(simpleName);
jclClass.status = classReader != null ? JCLStatus.FOUND : JCLStatus.MISSING;
jclClass.visibility = (access & Opcodes.ACC_PROTECTED) != 0 ? JCLVisibility.PROTECTED : JCLVisibility.PUBLIC;
if ((access & Opcodes.ACC_INTERFACE) != 0) {
jclClass.type = JCLClassType.INTERFACE;
} else if ((access & Opcodes.ACC_ANNOTATION) != 0) {
if ((access & Opcodes.ACC_ANNOTATION) != 0) {
jclClass.type = JCLClassType.ANNOTATION;
} else if ((access & Opcodes.ACC_INTERFACE) != 0) {
jclClass.type = JCLClassType.INTERFACE;
} else if ((access & Opcodes.ACC_ENUM) != 0) {
jclClass.type = JCLClassType.ENUM;
} else {

View File

@ -86,6 +86,12 @@ public class ClassNativeGenerator implements Generator, Injector, DependencyPlug
case "charClass":
context.getWriter().append("$rt_cls($rt_charcls())");
break;
case "byteClass":
context.getWriter().append("$rt_cls($rt_bytecls())");
break;
case "doubleClass":
context.getWriter().append("$rt_cls($rt_doublecls())");
break;
case "wrap":
context.writeExpr(context.getArgument(0));
break;
@ -176,6 +182,9 @@ public class ClassNativeGenerator implements Generator, Injector, DependencyPlug
case "booleanClass":
case "intClass":
case "charClass":
case "byteClass":
case "voidClass":
case "doubleClass":
case "wrap":
case "getSuperclass":
case "getComponentType0":

View File

@ -19,13 +19,15 @@ import java.io.IOException;
import org.teavm.codegen.SourceWriter;
import org.teavm.javascript.ni.Generator;
import org.teavm.javascript.ni.GeneratorContext;
import org.teavm.javascript.ni.Injector;
import org.teavm.javascript.ni.InjectorContext;
import org.teavm.model.MethodReference;
/**
*
* @author Alexey Andreev
*/
public class DoubleNativeGenerator implements Generator {
public class DoubleNativeGenerator implements Generator, Injector {
@Override
public void generate(GeneratorContext context, SourceWriter writer, MethodReference methodRef) throws IOException {
switch (methodRef.getName()) {
@ -38,6 +40,15 @@ public class DoubleNativeGenerator implements Generator {
}
}
@Override
public void generate(InjectorContext context, MethodReference methodRef) throws IOException {
switch (methodRef.getName()) {
case "getNaN":
context.getWriter().append("NaN");
break;
}
}
private void generateIsNaN(GeneratorContext context, SourceWriter writer) throws IOException {
writer.append("return (isNaN(").append(context.getParameterName(1)).append(")").ws().append("?")
.ws().append("1").ws().append(":").ws().append("0").ws().append(");").softNewLine();

View File

@ -29,4 +29,8 @@ public class TArrayIndexOutOfBoundsException extends TIndexOutOfBoundsException
public TArrayIndexOutOfBoundsException(TString message) {
super(message);
}
public TArrayIndexOutOfBoundsException(int index) {
super(TInteger.toString(index));
}
}

View File

@ -22,12 +22,20 @@ import org.teavm.javascript.ni.Rename;
* @author Alexey Andreev
*/
public class TByte extends TNumber implements TComparable<TByte> {
public static final byte MIN_VALUE = -128;
public static final byte MAX_VALUE = 127;
public static final TClass<TByte> TYPE = TClass.byteClass();
public static final int SIZE = 8;
private byte value;
public TByte(byte value) {
this.value = value;
}
public TByte(TString value) {
this.value = parseByte(value, 10);
}
@Override
public int intValue() {
return value;
@ -54,6 +62,7 @@ public class TByte extends TNumber implements TComparable<TByte> {
}
public static TByte valueOf(byte value) {
// TODO: add caching
return new TByte(value);
}
@ -85,4 +94,32 @@ public class TByte extends TNumber implements TComparable<TByte> {
public int compareTo(TByte other) {
return compare(value, other.value);
}
public static byte parseByte(TString s) throws TNumberFormatException {
return parseByte(s, 10);
}
public static byte parseByte(TString s, int radix) throws TNumberFormatException {
int value = TInteger.parseInt(s, radix);
if (value < MIN_VALUE || value >= MAX_VALUE) {
throw new TNumberFormatException();
}
return (byte)value;
}
public static TByte valueOf(TString s, int radix) throws TNumberFormatException {
return valueOf(parseByte(s, radix));
}
public static TByte valueOf(TString s) throws TNumberFormatException {
return valueOf(parseByte(s));
}
public static TByte decode(TString nm) throws TNumberFormatException {
TInteger value = TInteger.decode(nm);
if (value.intValue() < MIN_VALUE || value.intValue() >= MAX_VALUE) {
throw new TNumberFormatException();
}
return TByte.valueOf((byte)value.intValue());
}
}

View File

@ -558,6 +558,10 @@ public class TCharacter extends TObject implements TComparable<TCharacter> {
}
}
public static boolean isUnicodeIdentifierPart(char ch) {
return isUnicodeIdentifierPart((int)ch);
}
public static boolean isUnicodeIdentifierPart(int codePoint) {
switch (getType(codePoint)) {
case UPPERCASE_LETTER:

View File

@ -85,6 +85,14 @@ public class TClass<T> extends TObject {
@PluggableDependency(ClassNativeGenerator.class)
static native TClass<TVoid> voidClass();
@InjectedBy(ClassNativeGenerator.class)
@PluggableDependency(ClassNativeGenerator.class)
static native TClass<TByte> byteClass();
@InjectedBy(ClassNativeGenerator.class)
@PluggableDependency(ClassNativeGenerator.class)
static native TClass<TDouble> doubleClass();
@InjectedBy(ClassNativeGenerator.class)
@PluggableDependency(ClassNativeGenerator.class)
public static native <S extends TObject> TClass<S> wrap(Class<S> cls);

View File

@ -33,4 +33,8 @@ public class TClassNotFoundException extends TReflectiveOperationException {
public TClassNotFoundException(TString message) {
super(message);
}
public TThrowable getException() {
return getCause();
}
}

View File

@ -16,6 +16,7 @@
package org.teavm.classlib.java.lang;
import org.teavm.javascript.ni.GeneratedBy;
import org.teavm.javascript.ni.InjectedBy;
import org.teavm.javascript.ni.Rename;
/**
@ -23,14 +24,26 @@ import org.teavm.javascript.ni.Rename;
* @author Alexey Andreev
*/
public class TDouble extends TNumber implements TComparable<TDouble> {
public static double POSITIVE_INFINITY = 1 / 0.0;
public static double NEGATIVE_INFINITY = -POSITIVE_INFINITY;
public static final double POSITIVE_INFINITY = 1 / 0.0;
public static final double NEGATIVE_INFINITY = -POSITIVE_INFINITY;
public static final double NaN = getNaN();
public static final double MAX_VALUE = 0x1.FFFFFFFFFFFFFP+1023;
public static final double MIN_NORMAL = -0x1.0P+1022;
public static final double MIN_VALUE = 0x0.0000000000001P-1022;
public static final int MAX_EXPONENT = 1023;
public static final int MIN_EXPONENT = -1022;
public static final int SIZE = 64;
public static final TClass<TDouble> TYPE = TClass.doubleClass();
private double value;
public TDouble(double value) {
this.value = value;
}
public TDouble(TString value) throws TNumberFormatException {
this.value = parseDouble(value);
}
@Override
public double doubleValue() {
return value;
@ -199,9 +212,151 @@ public class TDouble extends TNumber implements TComparable<TDouble> {
return compare(value, other.value);
}
public boolean isNaN() {
return isNaN(value);
}
public boolean isInfinite() {
return isInfinite(value);
}
@GeneratedBy(DoubleNativeGenerator.class)
public static native boolean isNaN(double v);
@InjectedBy(DoubleNativeGenerator.class)
private static native double getNaN();
@GeneratedBy(DoubleNativeGenerator.class)
public static native boolean isInfinite(double v);
public static long doubleToRawLongBits(double value) {
return doubleToLongBits(value);
}
public static long doubleToLongBits(double value) {
if (value == POSITIVE_INFINITY) {
return 0x7FF0000000000000L;
} else if (value == NEGATIVE_INFINITY) {
return 0xFFF0000000000000L;
} else if (isNaN(value)) {
return 0x7FF8000000000000L;
}
double abs = TMath.abs(value);
int exp = TMath.getExponent(abs);
if (exp < -1022) {
exp = -1023;
}
long mantissa = (long)(abs * binaryExponent(exp + 52)) & 0xFFFFFFFFFFFFFL;
return mantissa | ((exp + 1023L) << 52) | (value < 0 ? (1L << 63) : 0);
}
public static double longBitsToDouble(long bits) {
if ((bits & 0x7FF0000000000000L) == 0x7FF0000000000000L) {
if (bits == 0x7FF0000000000000L) {
return POSITIVE_INFINITY;
} else if (bits == 0xFFF0000000000000L) {
return NEGATIVE_INFINITY;
} else {
return NaN;
}
}
boolean negative = (bits & (1 << 63)) != 0;
int rawExp = (int)((bits >> 52) & 0x7FFL) - 1023;
long mantissa = bits & 0xFFFFFFFFFFFFFL;
if (rawExp == 0) {
mantissa <<= 1;
} else {
mantissa |= (1L << 52);
}
double value = mantissa * binaryExponent(rawExp - 1023 - 52);
return !negative ? value : -value;
}
public static TString toHexString(double d) {
if (isNaN(d)) {
return TString.wrap("NaN");
} else if (isInfinite(d)) {
return d > 0 ? TString.wrap("Infinity") : TString.wrap("-Infinity");
}
char[] buffer = new char[30];
int sz = 0;
long bits = doubleToLongBits(d);
long mantissa = bits & 0xFFFFFFFFFFFFFL;
for (int i = 0; i < 13; ++i) {
int digit = (int)(mantissa & 0xF);
if (digit > 0 || sz > 0) {
buffer[sz++] = TCharacter.forDigit(digit, 16);
}
mantissa >>>= 4;
}
if (sz == 0) {
buffer[sz++] = '0';
}
buffer[sz++] = '.';
int exp = (int)((bits >>> 52) & 0x7FF);
if (exp == -1023) {
buffer[sz++] = '0';
++exp;
} else {
buffer[sz++] = '1';
}
buffer[sz++] = 'x';
buffer[sz++] = '0';
if ((bits & (1L << 63)) == 0) {
buffer[sz++] = '-';
}
int half = sz / 2;
for (int i = 0; i < half; ++i) {
char tmp = buffer[i];
buffer[i] = buffer[sz - i - 1];
buffer[sz - i - 1] = tmp;
}
buffer[sz++] = 'p';
if (exp < 0) {
exp = -exp;
buffer[sz++] = '-';
}
int pos = 1000;
boolean first = true;
for (int i = 0; i < 4; ++i) {
int digit = exp / pos;
if (digit > 0 || !first) {
buffer[sz++] = TCharacter.forDigit(digit, 10);
first = false;
}
digit *= 10;
pos /= 10;
}
if (first) {
buffer[sz++] = '0';
}
return new TString(buffer, 0, sz);
}
public static double binaryExponent(int n) {
double result = 1;
if (n >= 0) {
double d = 2;
while (n != 0) {
if (n % 2 != 0) {
result *= d;
}
n /= 2;
d *= d;
}
} else {
n = -n;
double d = 0.5;
while (n != 0) {
if (n % 2 != 0) {
result *= d;
}
n /= 2;
d *= d;
}
}
return result;
}
}

View File

@ -224,6 +224,11 @@ public final class TMath extends TObject {
}
} else if (d < 1) {
int expBit = 1 << (negativeExponents.length - 1);
int offset = 0;
if (d < 0x1P-1024) {
d *= 0x1P52;
offset = 52;
}
for (int i = negativeExponents.length - 1; i >= 0; --i) {
if (d < negativeExponents[i]) {
d *= exponents[i];
@ -231,7 +236,7 @@ public final class TMath extends TObject {
}
expBit >>>= 1;
}
exp = -exp;
exp = -(exp + offset);
}
return exp;
}
@ -263,7 +268,9 @@ public final class TMath extends TObject {
}
private static class ExponentConstants {
public static double[] exponents = { 1E1, 1E2, 1E4, 1E8, 1E16, 1E32, 1E64, 1E128, 1E256 };
public static double[] negativeExponents = { 1E-1, 1E-2, 1E-4, 1E-8, 1E-16, 1E-32, 1E-64, 1E-128, 1E-256 };
public static double[] exponents = { 0x1P1, 0x1P2, 0x1P4, 0x1P8, 0x1P16, 0x1P32, 0x1P64, 0x1P128, 0x1P256,
0x1P256, 0x1P512 };
public static double[] negativeExponents = { 0x1P-1, 0x1P-2, 0x1P-4, 0x1P-8, 0x1P-16, 0x1P-32, 0x1P-64,
0x1P-128, 0x1P-256, 0x1P-256, 0x1P-512 };
}
}

View File

@ -48,4 +48,37 @@ public class DoubleTest {
assertEquals(0, Double.parseDouble("00000"), 1E-12);
assertEquals(0, Double.parseDouble("00000.0000"), 1E-12);
}
@Test
public void longBitsExtracted() {
assertEquals(0x41E23456789ABCDEL, Double.doubleToLongBits(0x1.23456789ABCDEP+31));
}
@Test
public void subNormalLongBitsExtracted() {
assertEquals(0x00000056789ABCDEL, Double.doubleToLongBits(0x0.00056789ABCDEP-1022));
}
@Test
public void longBitsPacked() {
assertEquals(0x1.23456789ABCDEP+31, Double.longBitsToDouble(0x41E23456789ABCDEL), 0x1.0P-19);
}
@Test
public void subNormalLongBitsPacked() {
assertEquals(0x0.00056789ABCDEP-1022, Double.longBitsToDouble(0x00000056789ABCDEL), 0x1.0P-19);
}
@Test
public void hexStringBuilt() {
assertEquals("0x1.23456789abcdep31", Double.toHexString(0x1.23456789ABCDEP+31));
assertEquals("0x1.0p0", Double.toHexString(1));
assertEquals("-0x1.0p0", Double.toHexString(-1));
assertEquals("0x1.0p1", Double.toHexString(2));
assertEquals("0x1.8p1", Double.toHexString(3));
assertEquals("0x1.0p-1", Double.toHexString(0.5));
assertEquals("0x1.0p-2", Double.toHexString(0.25));
assertEquals("0x1.0p-1022", Double.toHexString(Double.MIN_NORMAL));
assertEquals("0x0.0000000000001p-1022", Double.toHexString(Double.MIN_VALUE));
}
}

View File

@ -817,19 +817,19 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
visitBinary(expr, "<<");
break;
case LEFT_SHIFT_LONG:
visitBinaryFunction(expr, "Long_lsh");
visitBinaryFunction(expr, "Long_shr");
break;
case RIGHT_SHIFT:
visitBinary(expr, ">>");
break;
case RIGHT_SHIFT_LONG:
visitBinaryFunction(expr, "Long_rsh");
visitBinaryFunction(expr, "Long_shr");
break;
case UNSIGNED_RIGHT_SHIFT:
visitBinary(expr, ">>>");
break;
case UNSIGNED_RIGHT_SHIFT_LONG:
visitBinaryFunction(expr, "Long_rshu");
visitBinaryFunction(expr, "Long_shru");
break;
}
}