Reduce minimum runtime size
|
@ -90,6 +90,7 @@ public class JCLPlugin implements TeaVMPlugin {
|
||||||
}
|
}
|
||||||
|
|
||||||
host.add(new NumericClassTransformer());
|
host.add(new NumericClassTransformer());
|
||||||
|
host.add(new SystemClassTransformer());
|
||||||
|
|
||||||
if (!isBootstrap()) {
|
if (!isBootstrap()) {
|
||||||
List<ReflectionSupplier> reflectionSuppliers = new ArrayList<>();
|
List<ReflectionSupplier> reflectionSuppliers = new ArrayList<>();
|
||||||
|
|
|
@ -0,0 +1,70 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2018 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.impl;
|
||||||
|
|
||||||
|
import org.teavm.diagnostics.Diagnostics;
|
||||||
|
import org.teavm.model.BasicBlock;
|
||||||
|
import org.teavm.model.ClassHolder;
|
||||||
|
import org.teavm.model.ClassHolderTransformer;
|
||||||
|
import org.teavm.model.ClassReaderSource;
|
||||||
|
import org.teavm.model.FieldReference;
|
||||||
|
import org.teavm.model.Instruction;
|
||||||
|
import org.teavm.model.MethodHolder;
|
||||||
|
import org.teavm.model.MethodReference;
|
||||||
|
import org.teavm.model.Program;
|
||||||
|
import org.teavm.model.instructions.GetFieldInstruction;
|
||||||
|
import org.teavm.model.instructions.InvocationType;
|
||||||
|
import org.teavm.model.instructions.InvokeInstruction;
|
||||||
|
|
||||||
|
public class SystemClassTransformer implements ClassHolderTransformer {
|
||||||
|
@Override
|
||||||
|
public void transformClass(ClassHolder cls, ClassReaderSource innerSource, Diagnostics diagnostics) {
|
||||||
|
for (MethodHolder method : cls.getMethods()) {
|
||||||
|
if (method.getProgram() != null) {
|
||||||
|
transformProgram(method.getProgram());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void transformProgram(Program program) {
|
||||||
|
for (BasicBlock block : program.getBasicBlocks()) {
|
||||||
|
for (Instruction insn : block) {
|
||||||
|
if (!(insn instanceof GetFieldInstruction)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
GetFieldInstruction getField = (GetFieldInstruction) insn;
|
||||||
|
FieldReference field = getField.getField();
|
||||||
|
if (field.getClassName().equals("java.lang.System")) {
|
||||||
|
switch (field.getFieldName()) {
|
||||||
|
case "err":
|
||||||
|
case "out":
|
||||||
|
case "in": {
|
||||||
|
InvokeInstruction invoke = new InvokeInstruction();
|
||||||
|
invoke.setType(InvocationType.SPECIAL);
|
||||||
|
invoke.setMethod(new MethodReference("java.lang.System", field.getFieldName(),
|
||||||
|
getField.getFieldType()));
|
||||||
|
invoke.setReceiver(getField.getReceiver());
|
||||||
|
invoke.setLocation(insn.getLocation());
|
||||||
|
insn.replace(invoke);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -22,10 +22,8 @@ import org.teavm.backend.javascript.spi.GeneratorContext;
|
||||||
import org.teavm.dependency.DependencyAgent;
|
import org.teavm.dependency.DependencyAgent;
|
||||||
import org.teavm.dependency.DependencyNode;
|
import org.teavm.dependency.DependencyNode;
|
||||||
import org.teavm.dependency.DependencyPlugin;
|
import org.teavm.dependency.DependencyPlugin;
|
||||||
import org.teavm.dependency.FieldDependency;
|
|
||||||
import org.teavm.dependency.MethodDependency;
|
import org.teavm.dependency.MethodDependency;
|
||||||
import org.teavm.model.CallLocation;
|
import org.teavm.model.CallLocation;
|
||||||
import org.teavm.model.FieldReference;
|
|
||||||
import org.teavm.model.MethodReference;
|
import org.teavm.model.MethodReference;
|
||||||
|
|
||||||
public class SystemNativeGenerator implements Generator, DependencyPlugin {
|
public class SystemNativeGenerator implements Generator, DependencyPlugin {
|
||||||
|
@ -38,14 +36,6 @@ public class SystemNativeGenerator implements Generator, DependencyPlugin {
|
||||||
case "currentTimeMillis":
|
case "currentTimeMillis":
|
||||||
generateCurrentTimeMillis(writer);
|
generateCurrentTimeMillis(writer);
|
||||||
break;
|
break;
|
||||||
case "setOut":
|
|
||||||
writer.appendStaticField(new FieldReference("java.lang.System", "out"))
|
|
||||||
.ws().append('=').ws().append(context.getParameterName(1)).append(";").softNewLine();
|
|
||||||
break;
|
|
||||||
case "setErr":
|
|
||||||
writer.appendStaticField(new FieldReference("java.lang.System", "err"))
|
|
||||||
.ws().append('=').ws().append(context.getParameterName(1)).append(";").softNewLine();
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -53,13 +43,7 @@ public class SystemNativeGenerator implements Generator, DependencyPlugin {
|
||||||
public void methodReached(DependencyAgent agent, MethodDependency method, CallLocation location) {
|
public void methodReached(DependencyAgent agent, MethodDependency method, CallLocation location) {
|
||||||
switch (method.getReference().getName()) {
|
switch (method.getReference().getName()) {
|
||||||
case "doArrayCopy":
|
case "doArrayCopy":
|
||||||
achieveArrayCopy(method);
|
reachArrayCopy(method);
|
||||||
break;
|
|
||||||
case "setOut":
|
|
||||||
achieveSetOut(agent, method);
|
|
||||||
break;
|
|
||||||
case "setErr":
|
|
||||||
achieveSetErr(agent, method);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -84,23 +68,12 @@ public class SystemNativeGenerator implements Generator, DependencyPlugin {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void generateCurrentTimeMillis(SourceWriter writer) throws IOException {
|
private void generateCurrentTimeMillis(SourceWriter writer) throws IOException {
|
||||||
writer.append(writer.getNaming().getNameForClassInit("java.lang.System")).append("();").softNewLine();
|
|
||||||
writer.append("return Long_fromNumber(new Date().getTime());").softNewLine();
|
writer.append("return Long_fromNumber(new Date().getTime());").softNewLine();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void achieveArrayCopy(MethodDependency method) {
|
private void reachArrayCopy(MethodDependency method) {
|
||||||
DependencyNode src = method.getVariable(1);
|
DependencyNode src = method.getVariable(1);
|
||||||
DependencyNode dest = method.getVariable(3);
|
DependencyNode dest = method.getVariable(3);
|
||||||
src.getArrayItem().connect(dest.getArrayItem());
|
src.getArrayItem().connect(dest.getArrayItem());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void achieveSetErr(DependencyAgent agent, MethodDependency method) {
|
|
||||||
FieldDependency fieldDep = agent.linkField(new FieldReference("java.lang.System", "err"), null);
|
|
||||||
method.getVariable(1).connect(fieldDep.getValue());
|
|
||||||
}
|
|
||||||
|
|
||||||
private void achieveSetOut(DependencyAgent agent, MethodDependency method) {
|
|
||||||
FieldDependency fieldDep = agent.linkField(new FieldReference("java.lang.System", "out"), null);
|
|
||||||
method.getVariable(1).connect(fieldDep.getValue());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,7 @@ import org.teavm.classlib.java.io.TSerializable;
|
||||||
import org.teavm.classlib.java.util.TArrays;
|
import org.teavm.classlib.java.util.TArrays;
|
||||||
|
|
||||||
class TAbstractStringBuilder extends TObject implements TSerializable, TCharSequence {
|
class TAbstractStringBuilder extends TObject implements TSerializable, TCharSequence {
|
||||||
|
static class Constants {
|
||||||
private static float[] powersOfTen = { 1E1f, 1E2f, 1E4f, 1E8f, 1E16f, 1E32f };
|
private static float[] powersOfTen = { 1E1f, 1E2f, 1E4f, 1E8f, 1E16f, 1E32f };
|
||||||
private static double[] doublePowersOfTen = { 1E1, 1E2, 1E4, 1E8, 1E16, 1E32, 1E64, 1E128, 1E256 };
|
private static double[] doublePowersOfTen = { 1E1, 1E2, 1E4, 1E8, 1E16, 1E32, 1E64, 1E128, 1E256 };
|
||||||
private static float[] negPowersOfTen = { 1E-1f, 1E-2f, 1E-4f, 1E-8f, 1E-16f, 1E-32f };
|
private static float[] negPowersOfTen = { 1E-1f, 1E-2f, 1E-4f, 1E-8f, 1E-16f, 1E-32f };
|
||||||
|
@ -30,6 +31,7 @@ class TAbstractStringBuilder extends TObject implements TSerializable, TCharSequ
|
||||||
1000000000, 10000000000L, 100000000000L, 1000000000000L, 10000000000000L, 100000000000000L,
|
1000000000, 10000000000L, 100000000000L, 1000000000000L, 10000000000000L, 100000000000000L,
|
||||||
1000000000000000L, 10000000000000000L, 100000000000000000L, 1000000000000000000L };
|
1000000000000000L, 10000000000000000L, 100000000000000000L, 1000000000000000000L };
|
||||||
private static final long[] longLogPowersOfTen = { 1, 10, 100, 10000, 100000000, 10000000000000000L, };
|
private static final long[] longLogPowersOfTen = { 1, 10, 100, 10000, 100000000, 10000000000000000L, };
|
||||||
|
|
||||||
private static final int FLOAT_DECIMAL_PRECISION = 7;
|
private static final int FLOAT_DECIMAL_PRECISION = 7;
|
||||||
private static final int DOUBLE_DECIMAL_PRECISION = 16;
|
private static final int DOUBLE_DECIMAL_PRECISION = 16;
|
||||||
private static final float FLOAT_DECIMAL_FACTOR = 1E6f;
|
private static final float FLOAT_DECIMAL_FACTOR = 1E6f;
|
||||||
|
@ -38,6 +40,8 @@ class TAbstractStringBuilder extends TObject implements TSerializable, TCharSequ
|
||||||
private static final int DOUBLE_MAX_EXPONENT = 308;
|
private static final int DOUBLE_MAX_EXPONENT = 308;
|
||||||
private static final int FLOAT_MAX_POS = 1000000;
|
private static final int FLOAT_MAX_POS = 1000000;
|
||||||
private static final long DOUBLE_MAX_POS = 1000000000000000L;
|
private static final long DOUBLE_MAX_POS = 1000000000000000L;
|
||||||
|
}
|
||||||
|
|
||||||
char[] buffer;
|
char[] buffer;
|
||||||
private int length;
|
private int length;
|
||||||
|
|
||||||
|
@ -243,27 +247,27 @@ class TAbstractStringBuilder extends TObject implements TSerializable, TCharSequ
|
||||||
int bit = 32;
|
int bit = 32;
|
||||||
exp = 0;
|
exp = 0;
|
||||||
float digit = 1;
|
float digit = 1;
|
||||||
for (int i = powersOfTen.length - 1; i >= 0; --i) {
|
for (int i = Constants.powersOfTen.length - 1; i >= 0; --i) {
|
||||||
if ((exp | bit) <= FLOAT_MAX_EXPONENT && powersOfTen[i] * digit <= value) {
|
if ((exp | bit) <= Constants.FLOAT_MAX_EXPONENT && Constants.powersOfTen[i] * digit <= value) {
|
||||||
digit *= powersOfTen[i];
|
digit *= Constants.powersOfTen[i];
|
||||||
exp |= bit;
|
exp |= bit;
|
||||||
}
|
}
|
||||||
bit >>= 1;
|
bit >>= 1;
|
||||||
}
|
}
|
||||||
mantissa = (int) ((value / (digit / FLOAT_DECIMAL_FACTOR)) + 0.5f);
|
mantissa = (int) ((value / (digit / Constants.FLOAT_DECIMAL_FACTOR)) + 0.5f);
|
||||||
} else {
|
} else {
|
||||||
int bit = 32;
|
int bit = 32;
|
||||||
exp = 0;
|
exp = 0;
|
||||||
float digit = 1;
|
float digit = 1;
|
||||||
for (int i = negPowersOfTen.length - 1; i >= 0; --i) {
|
for (int i = Constants.negPowersOfTen.length - 1; i >= 0; --i) {
|
||||||
if ((exp | bit) <= 38 && negPowersOfTen[i] * digit * 10 > value) {
|
if ((exp | bit) <= 38 && Constants.negPowersOfTen[i] * digit * 10 > value) {
|
||||||
digit *= negPowersOfTen[i];
|
digit *= Constants.negPowersOfTen[i];
|
||||||
exp |= bit;
|
exp |= bit;
|
||||||
}
|
}
|
||||||
bit >>= 1;
|
bit >>= 1;
|
||||||
}
|
}
|
||||||
exp = -exp;
|
exp = -exp;
|
||||||
mantissa = (int) (((value * FLOAT_MAX_POS) / digit) + 0.5f);
|
mantissa = (int) (((value * Constants.FLOAT_MAX_POS) / digit) + 0.5f);
|
||||||
|
|
||||||
while (mantissa >= 10000000) {
|
while (mantissa >= 10000000) {
|
||||||
mantissa /= 10;
|
mantissa /= 10;
|
||||||
|
@ -272,7 +276,7 @@ class TAbstractStringBuilder extends TObject implements TSerializable, TCharSequ
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove trailing zeros
|
// Remove trailing zeros
|
||||||
digits = FLOAT_DECIMAL_PRECISION;
|
digits = Constants.FLOAT_DECIMAL_PRECISION;
|
||||||
int zeros = trailingDecimalZeros(mantissa);
|
int zeros = trailingDecimalZeros(mantissa);
|
||||||
if (zeros > 0) {
|
if (zeros > 0) {
|
||||||
digits -= zeros;
|
digits -= zeros;
|
||||||
|
@ -285,7 +289,7 @@ class TAbstractStringBuilder extends TObject implements TSerializable, TCharSequ
|
||||||
digits = Math.max(digits, intPart + 1);
|
digits = Math.max(digits, intPart + 1);
|
||||||
exp = 0;
|
exp = 0;
|
||||||
} else if (exp < 0) {
|
} else if (exp < 0) {
|
||||||
mantissa /= intPowersOfTen[-exp];
|
mantissa /= Constants.intPowersOfTen[-exp];
|
||||||
digits -= exp;
|
digits -= exp;
|
||||||
exp = 0;
|
exp = 0;
|
||||||
}
|
}
|
||||||
|
@ -312,7 +316,7 @@ class TAbstractStringBuilder extends TObject implements TSerializable, TCharSequ
|
||||||
if (negative) {
|
if (negative) {
|
||||||
buffer[target++] = '-';
|
buffer[target++] = '-';
|
||||||
}
|
}
|
||||||
int pos = FLOAT_MAX_POS;
|
int pos = Constants.FLOAT_MAX_POS;
|
||||||
for (int i = 0; i < digits; ++i) {
|
for (int i = 0; i < digits; ++i) {
|
||||||
int intDigit;
|
int intDigit;
|
||||||
if (pos > 0) {
|
if (pos > 0) {
|
||||||
|
@ -402,31 +406,31 @@ class TAbstractStringBuilder extends TObject implements TSerializable, TCharSequ
|
||||||
int bit = 256;
|
int bit = 256;
|
||||||
exp = 0;
|
exp = 0;
|
||||||
double digit = 1;
|
double digit = 1;
|
||||||
for (int i = doublePowersOfTen.length - 1; i >= 0; --i) {
|
for (int i = Constants.doublePowersOfTen.length - 1; i >= 0; --i) {
|
||||||
if ((exp | bit) <= DOUBLE_MAX_EXPONENT && doublePowersOfTen[i] * digit <= value) {
|
if ((exp | bit) <= Constants.DOUBLE_MAX_EXPONENT && Constants.doublePowersOfTen[i] * digit <= value) {
|
||||||
digit *= doublePowersOfTen[i];
|
digit *= Constants.doublePowersOfTen[i];
|
||||||
exp |= bit;
|
exp |= bit;
|
||||||
}
|
}
|
||||||
bit >>= 1;
|
bit >>= 1;
|
||||||
}
|
}
|
||||||
mantissa = (long) (((value / digit) * DOUBLE_DECIMAL_FACTOR) + 0.5);
|
mantissa = (long) (((value / digit) * Constants.DOUBLE_DECIMAL_FACTOR) + 0.5);
|
||||||
} else {
|
} else {
|
||||||
int bit = 256;
|
int bit = 256;
|
||||||
exp = 0;
|
exp = 0;
|
||||||
double digit = 1;
|
double digit = 1;
|
||||||
for (int i = negDoublePowersOfTen.length - 1; i >= 0; --i) {
|
for (int i = Constants.negDoublePowersOfTen.length - 1; i >= 0; --i) {
|
||||||
if ((exp | bit) <= 324 && negDoublePowersOfTen[i] * digit * 10 > value) {
|
if ((exp | bit) <= 324 && Constants.negDoublePowersOfTen[i] * digit * 10 > value) {
|
||||||
exp |= bit;
|
exp |= bit;
|
||||||
if (exp == 324) {
|
if (exp == 324) {
|
||||||
value /= negDoublePowersOfTen[i];
|
value /= Constants.negDoublePowersOfTen[i];
|
||||||
} else {
|
} else {
|
||||||
digit *= negDoublePowersOfTen[i];
|
digit *= Constants.negDoublePowersOfTen[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
bit >>= 1;
|
bit >>= 1;
|
||||||
}
|
}
|
||||||
exp = -exp;
|
exp = -exp;
|
||||||
mantissa = (long) (((value * DOUBLE_MAX_POS) / digit) + 0.5);
|
mantissa = (long) (((value * Constants.DOUBLE_MAX_POS) / digit) + 0.5);
|
||||||
|
|
||||||
while (mantissa >= 10000000000000000L) {
|
while (mantissa >= 10000000000000000L) {
|
||||||
mantissa /= 10;
|
mantissa /= 10;
|
||||||
|
@ -435,7 +439,7 @@ class TAbstractStringBuilder extends TObject implements TSerializable, TCharSequ
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove trailing zeros
|
// Remove trailing zeros
|
||||||
digits = DOUBLE_DECIMAL_PRECISION;
|
digits = Constants.DOUBLE_DECIMAL_PRECISION;
|
||||||
int zeros = trailingDecimalZeros(mantissa);
|
int zeros = trailingDecimalZeros(mantissa);
|
||||||
if (zeros > 0) {
|
if (zeros > 0) {
|
||||||
digits -= zeros;
|
digits -= zeros;
|
||||||
|
@ -448,7 +452,7 @@ class TAbstractStringBuilder extends TObject implements TSerializable, TCharSequ
|
||||||
digits = Math.max(digits, intPart + 1);
|
digits = Math.max(digits, intPart + 1);
|
||||||
exp = 0;
|
exp = 0;
|
||||||
} else if (exp < 0) {
|
} else if (exp < 0) {
|
||||||
mantissa /= longPowersOfTen[-exp];
|
mantissa /= Constants.longPowersOfTen[-exp];
|
||||||
digits -= exp;
|
digits -= exp;
|
||||||
exp = 0;
|
exp = 0;
|
||||||
}
|
}
|
||||||
|
@ -478,7 +482,7 @@ class TAbstractStringBuilder extends TObject implements TSerializable, TCharSequ
|
||||||
if (negative) {
|
if (negative) {
|
||||||
buffer[target++] = '-';
|
buffer[target++] = '-';
|
||||||
}
|
}
|
||||||
long pos = DOUBLE_MAX_POS;
|
long pos = Constants.DOUBLE_MAX_POS;
|
||||||
for (int i = 0; i < digits; ++i) {
|
for (int i = 0; i < digits; ++i) {
|
||||||
int intDigit;
|
int intDigit;
|
||||||
if (pos > 0) {
|
if (pos > 0) {
|
||||||
|
@ -541,10 +545,10 @@ class TAbstractStringBuilder extends TObject implements TSerializable, TCharSequ
|
||||||
long zeros = 1;
|
long zeros = 1;
|
||||||
int result = 0;
|
int result = 0;
|
||||||
int bit = 16;
|
int bit = 16;
|
||||||
for (int i = longLogPowersOfTen.length - 1; i >= 0; --i) {
|
for (int i = Constants.longLogPowersOfTen.length - 1; i >= 0; --i) {
|
||||||
if (n % (zeros * longLogPowersOfTen[i]) == 0) {
|
if (n % (zeros * Constants.longLogPowersOfTen[i]) == 0) {
|
||||||
result |= bit;
|
result |= bit;
|
||||||
zeros *= longLogPowersOfTen[i];
|
zeros *= Constants.longLogPowersOfTen[i];
|
||||||
}
|
}
|
||||||
bit >>>= 1;
|
bit >>>= 1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,7 +36,6 @@ public class TString extends TObject implements TSerializable, TComparable<TStri
|
||||||
public static final TComparator<TString> CASE_INSENSITIVE_ORDER = (o1, o2) -> o1.compareToIgnoreCase(o2);
|
public static final TComparator<TString> CASE_INSENSITIVE_ORDER = (o1, o2) -> o1.compareToIgnoreCase(o2);
|
||||||
private char[] characters;
|
private char[] characters;
|
||||||
private transient int hashCode;
|
private transient int hashCode;
|
||||||
private static TMap<TString, TString> pool = new THashMap<>();
|
|
||||||
|
|
||||||
public TString() {
|
public TString() {
|
||||||
this.characters = new char[0];
|
this.characters = new char[0];
|
||||||
|
@ -633,10 +632,10 @@ public class TString extends TObject implements TSerializable, TComparable<TStri
|
||||||
}
|
}
|
||||||
|
|
||||||
public TString intern() {
|
public TString intern() {
|
||||||
TString interned = pool.get(this);
|
TString interned = PoolHolder.pool.get(this);
|
||||||
if (interned == null) {
|
if (interned == null) {
|
||||||
interned = this;
|
interned = this;
|
||||||
pool.put(interned, interned);
|
PoolHolder.pool.put(interned, interned);
|
||||||
}
|
}
|
||||||
return interned;
|
return interned;
|
||||||
}
|
}
|
||||||
|
@ -712,4 +711,8 @@ public class TString extends TObject implements TSerializable, TComparable<TStri
|
||||||
}
|
}
|
||||||
return sb.toString();
|
return sb.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static class PoolHolder {
|
||||||
|
static TMap<TString, TString> pool = new THashMap<>();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,7 +23,6 @@ import org.teavm.classlib.java.io.TConsole;
|
||||||
import org.teavm.classlib.java.io.TInputStream;
|
import org.teavm.classlib.java.io.TInputStream;
|
||||||
import org.teavm.classlib.java.io.TPrintStream;
|
import org.teavm.classlib.java.io.TPrintStream;
|
||||||
import org.teavm.classlib.java.lang.reflect.TArray;
|
import org.teavm.classlib.java.lang.reflect.TArray;
|
||||||
import org.teavm.dependency.PluggableDependency;
|
|
||||||
import org.teavm.interop.Address;
|
import org.teavm.interop.Address;
|
||||||
import org.teavm.interop.DelegateTo;
|
import org.teavm.interop.DelegateTo;
|
||||||
import org.teavm.interop.Import;
|
import org.teavm.interop.Import;
|
||||||
|
@ -34,14 +33,35 @@ import org.teavm.runtime.RuntimeArray;
|
||||||
import org.teavm.runtime.RuntimeClass;
|
import org.teavm.runtime.RuntimeClass;
|
||||||
|
|
||||||
public final class TSystem extends TObject {
|
public final class TSystem extends TObject {
|
||||||
public static final TPrintStream out = new TPrintStream(new TConsoleOutputStreamStdout(), false);
|
private static TPrintStream outCache;
|
||||||
public static final TPrintStream err = new TPrintStream(new TConsoleOutputStreamStderr(), false);
|
private static TPrintStream errCache;
|
||||||
public static final TInputStream in = new TConsoleInputStream();
|
private static TInputStream inCache;
|
||||||
private static Properties properties;
|
private static Properties properties;
|
||||||
|
|
||||||
private TSystem() {
|
private TSystem() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static TPrintStream out() {
|
||||||
|
if (outCache == null) {
|
||||||
|
new TPrintStream(new TConsoleOutputStreamStdout(), false);
|
||||||
|
}
|
||||||
|
return outCache;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TPrintStream err() {
|
||||||
|
if (errCache == null) {
|
||||||
|
errCache = new TPrintStream(new TConsoleOutputStreamStderr(), false);
|
||||||
|
}
|
||||||
|
return errCache;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TInputStream in() {
|
||||||
|
if (inCache == null) {
|
||||||
|
inCache = new TConsoleInputStream();
|
||||||
|
}
|
||||||
|
return inCache;
|
||||||
|
}
|
||||||
|
|
||||||
public static TConsole console() {
|
public static TConsole console() {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -177,13 +197,13 @@ public final class TSystem extends TObject {
|
||||||
return (String) properties.remove(key);
|
return (String) properties.remove(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
@GeneratedBy(SystemNativeGenerator.class)
|
public static void setErr(TPrintStream err) {
|
||||||
@PluggableDependency(SystemNativeGenerator.class)
|
errCache = err;
|
||||||
public static native void setErr(TPrintStream err);
|
}
|
||||||
|
|
||||||
@GeneratedBy(SystemNativeGenerator.class)
|
public static void setOut(TPrintStream out) {
|
||||||
@PluggableDependency(SystemNativeGenerator.class)
|
outCache = out;
|
||||||
public static native void setOut(TPrintStream err);
|
}
|
||||||
|
|
||||||
@DelegateTo("gcLowLevel")
|
@DelegateTo("gcLowLevel")
|
||||||
public static void gc() {
|
public static void gc() {
|
||||||
|
|
|
@ -150,7 +150,7 @@ public class TThrowable extends RuntimeException {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void printStackTrace() {
|
public void printStackTrace() {
|
||||||
printStackTrace(TSystem.err);
|
printStackTrace(TSystem.err());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void printStackTrace(TPrintStream stream) {
|
public void printStackTrace(TPrintStream stream) {
|
||||||
|
|
|
@ -24,11 +24,6 @@ public abstract class TCharset implements Comparable<TCharset> {
|
||||||
private String canonicalName;
|
private String canonicalName;
|
||||||
private String[] aliases;
|
private String[] aliases;
|
||||||
private Set<String> aliasSet;
|
private Set<String> aliasSet;
|
||||||
private static final Map<String, TCharset> charsets = new HashMap<>();
|
|
||||||
|
|
||||||
static {
|
|
||||||
charsets.put("UTF-8", new TUTF8Charset());
|
|
||||||
}
|
|
||||||
|
|
||||||
protected TCharset(String canonicalName, String[] aliases) {
|
protected TCharset(String canonicalName, String[] aliases) {
|
||||||
checkCanonicalName(canonicalName);
|
checkCanonicalName(canonicalName);
|
||||||
|
@ -73,7 +68,7 @@ public abstract class TCharset implements Comparable<TCharset> {
|
||||||
throw new IllegalArgumentException("charsetName is null");
|
throw new IllegalArgumentException("charsetName is null");
|
||||||
}
|
}
|
||||||
checkCanonicalName(charsetName);
|
checkCanonicalName(charsetName);
|
||||||
TCharset charset = charsets.get(charsetName.toUpperCase());
|
TCharset charset = Charsets.value.get(charsetName.toUpperCase());
|
||||||
if (charset == null) {
|
if (charset == null) {
|
||||||
throw new TUnsupportedCharsetException(charsetName);
|
throw new TUnsupportedCharsetException(charsetName);
|
||||||
}
|
}
|
||||||
|
@ -81,10 +76,9 @@ public abstract class TCharset implements Comparable<TCharset> {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static TCharset defaultCharset() {
|
public static TCharset defaultCharset() {
|
||||||
return charsets.get("UTF-8");
|
return Charsets.value.get("UTF-8");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public final String name() {
|
public final String name() {
|
||||||
return canonicalName;
|
return canonicalName;
|
||||||
}
|
}
|
||||||
|
@ -144,4 +138,12 @@ public abstract class TCharset implements Comparable<TCharset> {
|
||||||
public final int compareTo(TCharset that) {
|
public final int compareTo(TCharset that) {
|
||||||
return canonicalName.compareToIgnoreCase(that.canonicalName);
|
return canonicalName.compareToIgnoreCase(that.canonicalName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static class Charsets {
|
||||||
|
private static final Map<String, TCharset> value = new HashMap<>();
|
||||||
|
|
||||||
|
static {
|
||||||
|
value.put("UTF-8", new TUTF8Charset());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,7 @@ import java.io.IOException;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.io.OutputStreamWriter;
|
import java.io.OutputStreamWriter;
|
||||||
import java.io.Writer;
|
import java.io.Writer;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.text.DecimalFormat;
|
import java.text.DecimalFormat;
|
||||||
import java.text.NumberFormat;
|
import java.text.NumberFormat;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
@ -67,6 +68,7 @@ import org.teavm.model.ClassHolder;
|
||||||
import org.teavm.model.ClassHolderTransformer;
|
import org.teavm.model.ClassHolderTransformer;
|
||||||
import org.teavm.model.ClassReaderSource;
|
import org.teavm.model.ClassReaderSource;
|
||||||
import org.teavm.model.ElementModifier;
|
import org.teavm.model.ElementModifier;
|
||||||
|
import org.teavm.model.FieldReference;
|
||||||
import org.teavm.model.ListableClassHolderSource;
|
import org.teavm.model.ListableClassHolderSource;
|
||||||
import org.teavm.model.ListableClassReaderSource;
|
import org.teavm.model.ListableClassReaderSource;
|
||||||
import org.teavm.model.MethodHolder;
|
import org.teavm.model.MethodHolder;
|
||||||
|
@ -215,26 +217,9 @@ public class JavaScriptTarget implements TeaVMTarget, TeaVMJavaScriptHost {
|
||||||
dep.getVariable(1).propagate(dependencyAnalyzer.getType("[C"));
|
dep.getVariable(1).propagate(dependencyAnalyzer.getType("[C"));
|
||||||
dep.use();
|
dep.use();
|
||||||
|
|
||||||
dep = dependencyAnalyzer.linkMethod(new MethodReference(String.class, "getChars", int.class, int.class,
|
dependencyAnalyzer.linkField(new FieldReference(String.class.getName(), "characters"), null);
|
||||||
char[].class, int.class, void.class), null);
|
|
||||||
dep.getVariable(0).propagate(stringType);
|
|
||||||
dep.getVariable(3).propagate(dependencyAnalyzer.getType("[C"));
|
|
||||||
dep.use();
|
|
||||||
|
|
||||||
MethodDependency internDep = dependencyAnalyzer.linkMethod(new MethodReference(String.class, "intern",
|
|
||||||
String.class), null);
|
|
||||||
internDep.getVariable(0).propagate(stringType);
|
|
||||||
internDep.use();
|
|
||||||
|
|
||||||
dep = dependencyAnalyzer.linkMethod(new MethodReference(String.class, "length", int.class), null);
|
|
||||||
dep.getVariable(0).propagate(stringType);
|
|
||||||
dep.use();
|
|
||||||
|
|
||||||
dependencyAnalyzer.linkMethod(new MethodReference(Object.class, "clone", Object.class), null).use();
|
dependencyAnalyzer.linkMethod(new MethodReference(Object.class, "clone", Object.class), null).use();
|
||||||
dependencyAnalyzer.linkMethod(new MethodReference(Thread.class, "currentThread", Thread.class), null).use();
|
|
||||||
dependencyAnalyzer.linkMethod(new MethodReference(Thread.class, "getMainThread", Thread.class), null).use();
|
|
||||||
dependencyAnalyzer.linkMethod(
|
|
||||||
new MethodReference(Thread.class, "setCurrentThread", Thread.class, void.class), null).use();
|
|
||||||
MethodDependency exceptionCons = dependencyAnalyzer.linkMethod(new MethodReference(
|
MethodDependency exceptionCons = dependencyAnalyzer.linkMethod(new MethodReference(
|
||||||
NoClassDefFoundError.class, "<init>", String.class, void.class), null);
|
NoClassDefFoundError.class, "<init>", String.class, void.class), null);
|
||||||
|
|
||||||
|
@ -281,7 +266,7 @@ public class JavaScriptTarget implements TeaVMTarget, TeaVMJavaScriptHost {
|
||||||
@Override
|
@Override
|
||||||
public void emit(ListableClassHolderSource classes, BuildTarget target, String outputName) {
|
public void emit(ListableClassHolderSource classes, BuildTarget target, String outputName) {
|
||||||
try (OutputStream output = target.createResource(outputName);
|
try (OutputStream output = target.createResource(outputName);
|
||||||
Writer writer = new OutputStreamWriter(output, "UTF-8")) {
|
Writer writer = new OutputStreamWriter(output, StandardCharsets.UTF_8)) {
|
||||||
emit(classes, writer, target);
|
emit(classes, writer, target);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new RenderingException(e);
|
throw new RenderingException(e);
|
||||||
|
@ -322,7 +307,7 @@ public class JavaScriptTarget implements TeaVMTarget, TeaVMJavaScriptHost {
|
||||||
renderingContext.setMinifying(minifying);
|
renderingContext.setMinifying(minifying);
|
||||||
Renderer renderer = new Renderer(sourceWriter, asyncMethods, asyncFamilyMethods,
|
Renderer renderer = new Renderer(sourceWriter, asyncMethods, asyncFamilyMethods,
|
||||||
controller.getDiagnostics(), renderingContext);
|
controller.getDiagnostics(), renderingContext);
|
||||||
RuntimeRenderer runtimeRenderer = new RuntimeRenderer(naming, sourceWriter);
|
RuntimeRenderer runtimeRenderer = new RuntimeRenderer(classes, naming, sourceWriter);
|
||||||
renderer.setProperties(controller.getProperties());
|
renderer.setProperties(controller.getProperties());
|
||||||
renderer.setMinifying(minifying);
|
renderer.setMinifying(minifying);
|
||||||
if (debugEmitter != null) {
|
if (debugEmitter != null) {
|
||||||
|
@ -358,6 +343,15 @@ public class JavaScriptTarget implements TeaVMTarget, TeaVMJavaScriptHost {
|
||||||
renderer.renderStringConstants();
|
renderer.renderStringConstants();
|
||||||
renderer.renderCompatibilityStubs();
|
renderer.renderCompatibilityStubs();
|
||||||
|
|
||||||
|
if (renderer.isLongLibraryUsed()) {
|
||||||
|
runtimeRenderer.renderHandWrittenRuntime("long.js");
|
||||||
|
}
|
||||||
|
if (renderer.isThreadLibraryUsed()) {
|
||||||
|
runtimeRenderer.renderHandWrittenRuntime("thread.js");
|
||||||
|
} else {
|
||||||
|
runtimeRenderer.renderHandWrittenRuntime("simpleThread.js");
|
||||||
|
}
|
||||||
|
|
||||||
for (Map.Entry<? extends String, ? extends TeaVMEntryPoint> entry
|
for (Map.Entry<? extends String, ? extends TeaVMEntryPoint> entry
|
||||||
: controller.getEntryPoints().entrySet()) {
|
: controller.getEntryPoints().entrySet()) {
|
||||||
sourceWriter.append("").append(entry.getKey()).ws().append("=").ws();
|
sourceWriter.append("").append(entry.getKey()).ws().append("=").ws();
|
||||||
|
|
|
@ -77,6 +77,9 @@ public class Renderer implements RenderingManager {
|
||||||
private int stringPoolSize;
|
private int stringPoolSize;
|
||||||
private int metadataSize;
|
private int metadataSize;
|
||||||
|
|
||||||
|
private boolean longLibraryUsed;
|
||||||
|
private boolean threadLibraryUsed;
|
||||||
|
|
||||||
public Renderer(SourceWriter writer, Set<MethodReference> asyncMethods, Set<MethodReference> asyncFamilyMethods,
|
public Renderer(SourceWriter writer, Set<MethodReference> asyncMethods, Set<MethodReference> asyncFamilyMethods,
|
||||||
Diagnostics diagnostics, RenderingContext context) {
|
Diagnostics diagnostics, RenderingContext context) {
|
||||||
this.naming = context.getNaming();
|
this.naming = context.getNaming();
|
||||||
|
@ -90,6 +93,14 @@ public class Renderer implements RenderingManager {
|
||||||
this.context = context;
|
this.context = context;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isLongLibraryUsed() {
|
||||||
|
return longLibraryUsed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isThreadLibraryUsed() {
|
||||||
|
return threadLibraryUsed;
|
||||||
|
}
|
||||||
|
|
||||||
public int getStringPoolSize() {
|
public int getStringPoolSize() {
|
||||||
return stringPoolSize;
|
return stringPoolSize;
|
||||||
}
|
}
|
||||||
|
@ -752,6 +763,8 @@ public class Renderer implements RenderingManager {
|
||||||
|
|
||||||
writer.newLine();
|
writer.newLine();
|
||||||
debugEmitter.emitMethod(null);
|
debugEmitter.emitMethod(null);
|
||||||
|
|
||||||
|
longLibraryUsed |= statementRenderer.isLongLibraryUsed();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void renderAsyncPrologue() throws IOException {
|
private void renderAsyncPrologue() throws IOException {
|
||||||
|
@ -831,6 +844,7 @@ public class Renderer implements RenderingManager {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(AsyncMethodNode methodNode) {
|
public void visit(AsyncMethodNode methodNode) {
|
||||||
|
threadLibraryUsed = true;
|
||||||
try {
|
try {
|
||||||
statementRenderer.setAsync(true);
|
statementRenderer.setAsync(true);
|
||||||
this.async = true;
|
this.async = true;
|
||||||
|
|
|
@ -26,22 +26,38 @@ import org.mozilla.javascript.ast.AstRoot;
|
||||||
import org.teavm.backend.javascript.codegen.NamingException;
|
import org.teavm.backend.javascript.codegen.NamingException;
|
||||||
import org.teavm.backend.javascript.codegen.NamingStrategy;
|
import org.teavm.backend.javascript.codegen.NamingStrategy;
|
||||||
import org.teavm.backend.javascript.codegen.SourceWriter;
|
import org.teavm.backend.javascript.codegen.SourceWriter;
|
||||||
|
import org.teavm.model.ClassReader;
|
||||||
|
import org.teavm.model.ClassReaderSource;
|
||||||
|
import org.teavm.model.FieldReference;
|
||||||
|
import org.teavm.model.MethodDescriptor;
|
||||||
import org.teavm.model.MethodReference;
|
import org.teavm.model.MethodReference;
|
||||||
import org.teavm.model.ValueType;
|
import org.teavm.model.ValueType;
|
||||||
import org.teavm.vm.RenderingException;
|
import org.teavm.vm.RenderingException;
|
||||||
|
|
||||||
public class RuntimeRenderer {
|
public class RuntimeRenderer {
|
||||||
|
private static final String STRING_CLASS = String.class.getName();
|
||||||
|
private static final String THREAD_CLASS = Thread.class.getName();
|
||||||
|
|
||||||
|
private static final MethodReference NPE_INIT_METHOD = new MethodReference(NullPointerException.class,
|
||||||
|
"<init>", void.class);
|
||||||
|
private static final MethodDescriptor STRING_INTERN_METHOD = new MethodDescriptor("intern",
|
||||||
|
String.class, String.class);
|
||||||
|
private static final MethodDescriptor CURRENT_THREAD_METHOD = new MethodDescriptor("currentThread",
|
||||||
|
Thread.class);
|
||||||
|
|
||||||
|
private final ClassReaderSource classSource;
|
||||||
private final NamingStrategy naming;
|
private final NamingStrategy naming;
|
||||||
private final SourceWriter writer;
|
private final SourceWriter writer;
|
||||||
|
|
||||||
public RuntimeRenderer(NamingStrategy naming, SourceWriter writer) {
|
public RuntimeRenderer(ClassReaderSource classSource, NamingStrategy naming, SourceWriter writer) {
|
||||||
|
this.classSource = classSource;
|
||||||
this.naming = naming;
|
this.naming = naming;
|
||||||
this.writer = writer;
|
this.writer = writer;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void renderRuntime() throws RenderingException {
|
public void renderRuntime() throws RenderingException {
|
||||||
try {
|
try {
|
||||||
renderHandWrittenRuntime();
|
renderHandWrittenRuntime("runtime.js");
|
||||||
renderSetCloneMethod();
|
renderSetCloneMethod();
|
||||||
renderRuntimeCls();
|
renderRuntimeCls();
|
||||||
renderRuntimeString();
|
renderRuntimeString();
|
||||||
|
@ -60,22 +76,22 @@ public class RuntimeRenderer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void renderHandWrittenRuntime() throws IOException {
|
public void renderHandWrittenRuntime(String name) throws IOException {
|
||||||
AstRoot ast = parseRuntime();
|
AstRoot ast = parseRuntime(name);
|
||||||
ast.visit(new StringConstantElimination());
|
ast.visit(new StringConstantElimination());
|
||||||
AstWriter astWriter = new AstWriter(writer);
|
AstWriter astWriter = new AstWriter(writer);
|
||||||
astWriter.hoist(ast);
|
astWriter.hoist(ast);
|
||||||
astWriter.print(ast);
|
astWriter.print(ast);
|
||||||
}
|
}
|
||||||
|
|
||||||
private AstRoot parseRuntime() throws IOException {
|
private AstRoot parseRuntime(String name) throws IOException {
|
||||||
CompilerEnvirons env = new CompilerEnvirons();
|
CompilerEnvirons env = new CompilerEnvirons();
|
||||||
env.setRecoverFromErrors(true);
|
env.setRecoverFromErrors(true);
|
||||||
env.setLanguageVersion(Context.VERSION_1_8);
|
env.setLanguageVersion(Context.VERSION_1_8);
|
||||||
JSParser factory = new JSParser(env);
|
JSParser factory = new JSParser(env);
|
||||||
|
|
||||||
ClassLoader loader = RuntimeRenderer.class.getClassLoader();
|
ClassLoader loader = RuntimeRenderer.class.getClassLoader();
|
||||||
try (InputStream input = loader.getResourceAsStream("org/teavm/backend/javascript/runtime.js");
|
try (InputStream input = loader.getResourceAsStream("org/teavm/backend/javascript/" + name);
|
||||||
Reader reader = new InputStreamReader(input, StandardCharsets.UTF_8)) {
|
Reader reader = new InputStreamReader(input, StandardCharsets.UTF_8)) {
|
||||||
return factory.parse(reader, null, 0);
|
return factory.parse(reader, null, 0);
|
||||||
}
|
}
|
||||||
|
@ -113,29 +129,21 @@ public class RuntimeRenderer {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void renderRuntimeUnwrapString() throws IOException {
|
private void renderRuntimeUnwrapString() throws IOException {
|
||||||
MethodReference stringLen = new MethodReference(String.class, "length", int.class);
|
FieldReference stringChars = new FieldReference(STRING_CLASS, "characters");
|
||||||
MethodReference getChars = new MethodReference(String.class, "getChars", int.class, int.class,
|
|
||||||
char[].class, int.class, void.class);
|
|
||||||
writer.append("function $rt_ustr(str) {").indent().softNewLine();
|
writer.append("function $rt_ustr(str) {").indent().softNewLine();
|
||||||
writer.append("if (str === null) {").indent().softNewLine();
|
writer.append("if (str === null) {").indent().softNewLine();
|
||||||
writer.append("return null;").softNewLine();
|
writer.append("return null;").softNewLine();
|
||||||
writer.outdent().append("}").softNewLine();
|
writer.outdent().append("}").softNewLine();
|
||||||
writer.append("var result = \"\";").softNewLine();
|
|
||||||
writer.append("var sz = ").appendMethodBody(stringLen).append("(str);").softNewLine();
|
writer.append("return String.fromCharCode.apply(null, str.").appendField(stringChars)
|
||||||
writer.append("var array = $rt_createCharArray(sz);").softNewLine();
|
.append(".data);").softNewLine();
|
||||||
writer.appendMethodBody(getChars).append("(str, 0, sz, array, 0);").softNewLine();
|
|
||||||
writer.append("for (var i = 0; i < sz; i = (i + 1) | 0) {").indent().softNewLine();
|
|
||||||
writer.append("result += String.fromCharCode(array.data[i]);").softNewLine();
|
|
||||||
writer.outdent().append("}").softNewLine();
|
|
||||||
writer.append("return result;").softNewLine();
|
|
||||||
writer.outdent().append("}").newLine();
|
writer.outdent().append("}").newLine();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void renderRuntimeNullCheck() throws IOException {
|
private void renderRuntimeNullCheck() throws IOException {
|
||||||
writer.append("function $rt_nullCheck(val) {").indent().softNewLine();
|
writer.append("function $rt_nullCheck(val) {").indent().softNewLine();
|
||||||
writer.append("if (val === null) {").indent().softNewLine();
|
writer.append("if (val === null) {").indent().softNewLine();
|
||||||
writer.append("$rt_throw(").append(naming.getNameForInit(new MethodReference(NullPointerException.class,
|
writer.append("$rt_throw(").append(naming.getNameForInit(NPE_INIT_METHOD)).append("());").softNewLine();
|
||||||
"<init>", void.class))).append("());").softNewLine();
|
|
||||||
writer.outdent().append("}").softNewLine();
|
writer.outdent().append("}").softNewLine();
|
||||||
writer.append("return val;").softNewLine();
|
writer.append("return val;").softNewLine();
|
||||||
writer.outdent().append("}").newLine();
|
writer.outdent().append("}").newLine();
|
||||||
|
@ -143,8 +151,14 @@ public class RuntimeRenderer {
|
||||||
|
|
||||||
private void renderRuntimeIntern() throws IOException {
|
private void renderRuntimeIntern() throws IOException {
|
||||||
writer.append("function $rt_intern(str) {").indent().softNewLine();
|
writer.append("function $rt_intern(str) {").indent().softNewLine();
|
||||||
|
ClassReader stringCls = classSource.get(STRING_CLASS);
|
||||||
|
if (stringCls != null && stringCls.getMethod(STRING_INTERN_METHOD) != null) {
|
||||||
writer.append("return ").appendMethodBody(new MethodReference(String.class, "intern", String.class))
|
writer.append("return ").appendMethodBody(new MethodReference(String.class, "intern", String.class))
|
||||||
.append("(str);").softNewLine();
|
.append("(str);").softNewLine();
|
||||||
|
} else {
|
||||||
|
writer.append("return str;").softNewLine();
|
||||||
|
}
|
||||||
|
|
||||||
writer.outdent().append("}").newLine();
|
writer.outdent().append("}").newLine();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -153,14 +167,23 @@ public class RuntimeRenderer {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void renderRuntimeThreads() throws IOException {
|
private void renderRuntimeThreads() throws IOException {
|
||||||
|
ClassReader threadCls = classSource.get(THREAD_CLASS);
|
||||||
|
boolean threadUsed = threadCls != null && threadCls.getMethod(CURRENT_THREAD_METHOD) != null;
|
||||||
|
|
||||||
writer.append("function $rt_getThread()").ws().append("{").indent().softNewLine();
|
writer.append("function $rt_getThread()").ws().append("{").indent().softNewLine();
|
||||||
|
if (threadUsed) {
|
||||||
writer.append("return ").appendMethodBody(Thread.class, "currentThread", Thread.class).append("();")
|
writer.append("return ").appendMethodBody(Thread.class, "currentThread", Thread.class).append("();")
|
||||||
.softNewLine();
|
.softNewLine();
|
||||||
|
} else {
|
||||||
|
writer.append("return null;").softNewLine();
|
||||||
|
}
|
||||||
writer.outdent().append("}").newLine();
|
writer.outdent().append("}").newLine();
|
||||||
|
|
||||||
writer.append("function $rt_setThread(t)").ws().append("{").indent().softNewLine();
|
writer.append("function $rt_setThread(t)").ws().append("{").indent().softNewLine();
|
||||||
|
if (threadUsed) {
|
||||||
writer.append("return ").appendMethodBody(Thread.class, "setCurrentThread", Thread.class, void.class)
|
writer.append("return ").appendMethodBody(Thread.class, "setCurrentThread", Thread.class, void.class)
|
||||||
.append("(t);").softNewLine();
|
.append("(t);").softNewLine();
|
||||||
|
}
|
||||||
writer.outdent().append("}").newLine();
|
writer.outdent().append("}").newLine();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -102,6 +102,7 @@ public class StatementRenderer implements ExprVisitor, StatementVisitor {
|
||||||
private int currentPart;
|
private int currentPart;
|
||||||
private List<String> blockIds = new ArrayList<>();
|
private List<String> blockIds = new ArrayList<>();
|
||||||
private IntIndexedContainer blockIndexMap = new IntArrayList();
|
private IntIndexedContainer blockIndexMap = new IntArrayList();
|
||||||
|
private boolean longLibraryUsed;
|
||||||
|
|
||||||
public StatementRenderer(RenderingContext context, SourceWriter writer) {
|
public StatementRenderer(RenderingContext context, SourceWriter writer) {
|
||||||
this.context = context;
|
this.context = context;
|
||||||
|
@ -112,6 +113,10 @@ public class StatementRenderer implements ExprVisitor, StatementVisitor {
|
||||||
this.debugEmitter = context.getDebugEmitter();
|
this.debugEmitter = context.getDebugEmitter();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isLongLibraryUsed() {
|
||||||
|
return longLibraryUsed;
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isAsync() {
|
public boolean isAsync() {
|
||||||
return async;
|
return async;
|
||||||
}
|
}
|
||||||
|
@ -621,6 +626,7 @@ public class StatementRenderer implements ExprVisitor, StatementVisitor {
|
||||||
@Override
|
@Override
|
||||||
public void visit(BinaryExpr expr) {
|
public void visit(BinaryExpr expr) {
|
||||||
if (expr.getType() == OperationType.LONG) {
|
if (expr.getType() == OperationType.LONG) {
|
||||||
|
longLibraryUsed = true;
|
||||||
switch (expr.getOperation()) {
|
switch (expr.getOperation()) {
|
||||||
case ADD:
|
case ADD:
|
||||||
visitBinaryFunction(expr, "Long_add");
|
visitBinaryFunction(expr, "Long_add");
|
||||||
|
@ -763,6 +769,7 @@ public class StatementRenderer implements ExprVisitor, StatementVisitor {
|
||||||
switch (expr.getOperation()) {
|
switch (expr.getOperation()) {
|
||||||
case NOT: {
|
case NOT: {
|
||||||
if (expr.getType() == OperationType.LONG) {
|
if (expr.getType() == OperationType.LONG) {
|
||||||
|
longLibraryUsed = true;
|
||||||
writer.append("Long_not(");
|
writer.append("Long_not(");
|
||||||
precedence = Precedence.min();
|
precedence = Precedence.min();
|
||||||
expr.getOperand().acceptVisitor(this);
|
expr.getOperand().acceptVisitor(this);
|
||||||
|
@ -782,6 +789,7 @@ public class StatementRenderer implements ExprVisitor, StatementVisitor {
|
||||||
}
|
}
|
||||||
case NEGATE:
|
case NEGATE:
|
||||||
if (expr.getType() == OperationType.LONG) {
|
if (expr.getType() == OperationType.LONG) {
|
||||||
|
longLibraryUsed = true;
|
||||||
writer.append("Long_neg(");
|
writer.append("Long_neg(");
|
||||||
precedence = Precedence.min();
|
precedence = Precedence.min();
|
||||||
expr.getOperand().acceptVisitor(this);
|
expr.getOperand().acceptVisitor(this);
|
||||||
|
|
478
core/src/main/resources/org/teavm/backend/javascript/long.js
Normal file
|
@ -0,0 +1,478 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2018 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.
|
||||||
|
*/
|
||||||
|
"use strict";
|
||||||
|
function Long_eq(a, b) {
|
||||||
|
return a.hi === b.hi && a.lo === b.lo;
|
||||||
|
}
|
||||||
|
function Long_ne(a, b) {
|
||||||
|
return a.hi !== b.hi || a.lo !== b.lo;
|
||||||
|
}
|
||||||
|
function Long_gt(a, b) {
|
||||||
|
if (a.hi < b.hi) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (a.hi > b.hi) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
var x = a.lo >>> 1;
|
||||||
|
var y = b.lo >>> 1;
|
||||||
|
if (x !== y) {
|
||||||
|
return x > y;
|
||||||
|
}
|
||||||
|
return (a.lo & 1) > (b.lo & 1);
|
||||||
|
}
|
||||||
|
function Long_ge(a, b) {
|
||||||
|
if (a.hi < b.hi) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (a.hi > b.hi) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
var x = a.lo >>> 1;
|
||||||
|
var y = b.lo >>> 1;
|
||||||
|
if (x !== y) {
|
||||||
|
return x >= y;
|
||||||
|
}
|
||||||
|
return (a.lo & 1) >= (b.lo & 1);
|
||||||
|
}
|
||||||
|
function Long_lt(a, b) {
|
||||||
|
if (a.hi > b.hi) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (a.hi < b.hi) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
var x = a.lo >>> 1;
|
||||||
|
var y = b.lo >>> 1;
|
||||||
|
if (x !== y) {
|
||||||
|
return x < y;
|
||||||
|
}
|
||||||
|
return (a.lo & 1) < (b.lo & 1);
|
||||||
|
}
|
||||||
|
function Long_le(a, b) {
|
||||||
|
if (a.hi > b.hi) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (a.hi < b.hi) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
var x = a.lo >>> 1;
|
||||||
|
var y = b.lo >>> 1;
|
||||||
|
if (x !== y) {
|
||||||
|
return x <= y;
|
||||||
|
}
|
||||||
|
return (a.lo & 1) <= (b.lo & 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
function Long_add(a, b) {
|
||||||
|
if (a.hi === (a.lo >> 31) && b.hi === (b.lo >> 31)) {
|
||||||
|
return Long_fromNumber(a.lo + b.lo);
|
||||||
|
} else if (Math.abs(a.hi) < Long_MAX_NORMAL && Math.abs(b.hi) < Long_MAX_NORMAL) {
|
||||||
|
return Long_fromNumber(Long_toNumber(a) + Long_toNumber(b));
|
||||||
|
}
|
||||||
|
var a_lolo = a.lo & 0xFFFF;
|
||||||
|
var a_lohi = a.lo >>> 16;
|
||||||
|
var a_hilo = a.hi & 0xFFFF;
|
||||||
|
var a_hihi = a.hi >>> 16;
|
||||||
|
var b_lolo = b.lo & 0xFFFF;
|
||||||
|
var b_lohi = b.lo >>> 16;
|
||||||
|
var b_hilo = b.hi & 0xFFFF;
|
||||||
|
var b_hihi = b.hi >>> 16;
|
||||||
|
|
||||||
|
var lolo = (a_lolo + b_lolo) | 0;
|
||||||
|
var lohi = (a_lohi + b_lohi + (lolo >> 16)) | 0;
|
||||||
|
var hilo = (a_hilo + b_hilo + (lohi >> 16)) | 0;
|
||||||
|
var hihi = (a_hihi + b_hihi + (hilo >> 16)) | 0;
|
||||||
|
return new Long((lolo & 0xFFFF) | ((lohi & 0xFFFF) << 16), (hilo & 0xFFFF) | ((hihi & 0xFFFF) << 16));
|
||||||
|
}
|
||||||
|
function Long_inc(a) {
|
||||||
|
var lo = (a.lo + 1) | 0;
|
||||||
|
var hi = a.hi;
|
||||||
|
if (lo === 0) {
|
||||||
|
hi = (hi + 1) | 0;
|
||||||
|
}
|
||||||
|
return new Long(lo, hi);
|
||||||
|
}
|
||||||
|
function Long_dec(a) {
|
||||||
|
var lo = (a.lo - 1) | 0;
|
||||||
|
var hi = a.hi;
|
||||||
|
if (lo === -1) {
|
||||||
|
hi = (hi - 1) | 0;
|
||||||
|
}
|
||||||
|
return new Long(lo, hi);
|
||||||
|
}
|
||||||
|
function Long_neg(a) {
|
||||||
|
return Long_inc(new Long(a.lo ^ 0xFFFFFFFF, a.hi ^ 0xFFFFFFFF));
|
||||||
|
}
|
||||||
|
function Long_sub(a, b) {
|
||||||
|
if (a.hi === (a.lo >> 31) && b.hi === (b.lo >> 31)) {
|
||||||
|
return Long_fromNumber(a.lo - b.lo);
|
||||||
|
}
|
||||||
|
var a_lolo = a.lo & 0xFFFF;
|
||||||
|
var a_lohi = a.lo >>> 16;
|
||||||
|
var a_hilo = a.hi & 0xFFFF;
|
||||||
|
var a_hihi = a.hi >>> 16;
|
||||||
|
var b_lolo = b.lo & 0xFFFF;
|
||||||
|
var b_lohi = b.lo >>> 16;
|
||||||
|
var b_hilo = b.hi & 0xFFFF;
|
||||||
|
var b_hihi = b.hi >>> 16;
|
||||||
|
|
||||||
|
var lolo = (a_lolo - b_lolo) | 0;
|
||||||
|
var lohi = (a_lohi - b_lohi + (lolo >> 16)) | 0;
|
||||||
|
var hilo = (a_hilo - b_hilo + (lohi >> 16)) | 0;
|
||||||
|
var hihi = (a_hihi - b_hihi + (hilo >> 16)) | 0;
|
||||||
|
return new Long((lolo & 0xFFFF) | ((lohi & 0xFFFF) << 16), (hilo & 0xFFFF) | ((hihi & 0xFFFF) << 16));
|
||||||
|
}
|
||||||
|
function Long_compare(a, b) {
|
||||||
|
var r = a.hi - b.hi;
|
||||||
|
if (r !== 0) {
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
r = (a.lo >>> 1) - (b.lo >>> 1);
|
||||||
|
if (r !== 0) {
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
return (a.lo & 1) - (b.lo & 1);
|
||||||
|
}
|
||||||
|
function Long_isPositive(a) {
|
||||||
|
return (a.hi & 0x80000000) === 0;
|
||||||
|
}
|
||||||
|
function Long_isNegative(a) {
|
||||||
|
return (a.hi & 0x80000000) !== 0;
|
||||||
|
}
|
||||||
|
function Long_mul(a, b) {
|
||||||
|
var positive = Long_isNegative(a) === Long_isNegative(b);
|
||||||
|
if (Long_isNegative(a)) {
|
||||||
|
a = Long_neg(a);
|
||||||
|
}
|
||||||
|
if (Long_isNegative(b)) {
|
||||||
|
b = Long_neg(b);
|
||||||
|
}
|
||||||
|
var a_lolo = a.lo & 0xFFFF;
|
||||||
|
var a_lohi = a.lo >>> 16;
|
||||||
|
var a_hilo = a.hi & 0xFFFF;
|
||||||
|
var a_hihi = a.hi >>> 16;
|
||||||
|
var b_lolo = b.lo & 0xFFFF;
|
||||||
|
var b_lohi = b.lo >>> 16;
|
||||||
|
var b_hilo = b.hi & 0xFFFF;
|
||||||
|
var b_hihi = b.hi >>> 16;
|
||||||
|
|
||||||
|
var lolo = 0;
|
||||||
|
var lohi = 0;
|
||||||
|
var hilo = 0;
|
||||||
|
var hihi = 0;
|
||||||
|
lolo = (a_lolo * b_lolo) | 0;
|
||||||
|
lohi = lolo >>> 16;
|
||||||
|
lohi = ((lohi & 0xFFFF) + a_lohi * b_lolo) | 0;
|
||||||
|
hilo = (hilo + (lohi >>> 16)) | 0;
|
||||||
|
lohi = ((lohi & 0xFFFF) + a_lolo * b_lohi) | 0;
|
||||||
|
hilo = (hilo + (lohi >>> 16)) | 0;
|
||||||
|
hihi = hilo >>> 16;
|
||||||
|
hilo = ((hilo & 0xFFFF) + a_hilo * b_lolo) | 0;
|
||||||
|
hihi = (hihi + (hilo >>> 16)) | 0;
|
||||||
|
hilo = ((hilo & 0xFFFF) + a_lohi * b_lohi) | 0;
|
||||||
|
hihi = (hihi + (hilo >>> 16)) | 0;
|
||||||
|
hilo = ((hilo & 0xFFFF) + a_lolo * b_hilo) | 0;
|
||||||
|
hihi = (hihi + (hilo >>> 16)) | 0;
|
||||||
|
hihi = (hihi + a_hihi * b_lolo + a_hilo * b_lohi + a_lohi * b_hilo + a_lolo * b_hihi) | 0;
|
||||||
|
var result = new Long((lolo & 0xFFFF) | (lohi << 16), (hilo & 0xFFFF) | (hihi << 16));
|
||||||
|
return positive ? result : Long_neg(result);
|
||||||
|
}
|
||||||
|
function Long_div(a, b) {
|
||||||
|
if (Math.abs(a.hi) < Long_MAX_NORMAL && Math.abs(b.hi) < Long_MAX_NORMAL) {
|
||||||
|
return Long_fromNumber(Long_toNumber(a) / Long_toNumber(b));
|
||||||
|
}
|
||||||
|
return Long_divRem(a, b)[0];
|
||||||
|
}
|
||||||
|
function Long_rem(a, b) {
|
||||||
|
if (Math.abs(a.hi) < Long_MAX_NORMAL && Math.abs(b.hi) < Long_MAX_NORMAL) {
|
||||||
|
return Long_fromNumber(Long_toNumber(a) % Long_toNumber(b));
|
||||||
|
}
|
||||||
|
return Long_divRem(a, b)[1];
|
||||||
|
}
|
||||||
|
function Long_divRem(a, b) {
|
||||||
|
if (b.lo === 0 && b.hi === 0) {
|
||||||
|
throw new Error("Division by zero");
|
||||||
|
}
|
||||||
|
var positive = Long_isNegative(a) === Long_isNegative(b);
|
||||||
|
if (Long_isNegative(a)) {
|
||||||
|
a = Long_neg(a);
|
||||||
|
}
|
||||||
|
if (Long_isNegative(b)) {
|
||||||
|
b = Long_neg(b);
|
||||||
|
}
|
||||||
|
a = new LongInt(a.lo, a.hi, 0);
|
||||||
|
b = new LongInt(b.lo, b.hi, 0);
|
||||||
|
var q = LongInt_div(a, b);
|
||||||
|
a = new Long(a.lo, a.hi);
|
||||||
|
q = new Long(q.lo, q.hi);
|
||||||
|
return positive ? [q, a] : [Long_neg(q), Long_neg(a)];
|
||||||
|
}
|
||||||
|
function Long_shiftLeft16(a) {
|
||||||
|
return new Long(a.lo << 16, (a.lo >>> 16) | (a.hi << 16));
|
||||||
|
}
|
||||||
|
function Long_shiftRight16(a) {
|
||||||
|
return new Long((a.lo >>> 16) | (a.hi << 16), a.hi >>> 16);
|
||||||
|
}
|
||||||
|
function Long_and(a, b) {
|
||||||
|
return new Long(a.lo & b.lo, a.hi & b.hi);
|
||||||
|
}
|
||||||
|
function Long_or(a, b) {
|
||||||
|
return new Long(a.lo | b.lo, a.hi | b.hi);
|
||||||
|
}
|
||||||
|
function Long_xor(a, b) {
|
||||||
|
return new Long(a.lo ^ b.lo, a.hi ^ b.hi);
|
||||||
|
}
|
||||||
|
function Long_shl(a, b) {
|
||||||
|
b &= 63;
|
||||||
|
if (b === 0) {
|
||||||
|
return a;
|
||||||
|
} else if (b < 32) {
|
||||||
|
return new Long(a.lo << b, (a.lo >>> (32 - b)) | (a.hi << b));
|
||||||
|
} else if (b === 32) {
|
||||||
|
return new Long(0, a.lo);
|
||||||
|
} else {
|
||||||
|
return new Long(0, a.lo << (b - 32));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function Long_shr(a, b) {
|
||||||
|
b &= 63;
|
||||||
|
if (b === 0) {
|
||||||
|
return a;
|
||||||
|
} else if (b < 32) {
|
||||||
|
return new Long((a.lo >>> b) | (a.hi << (32 - b)), a.hi >> b);
|
||||||
|
} else if (b === 32) {
|
||||||
|
return new Long(a.hi, a.hi >> 31);
|
||||||
|
} else {
|
||||||
|
return new Long((a.hi >> (b - 32)), a.hi >> 31);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function Long_shru(a, b) {
|
||||||
|
b &= 63;
|
||||||
|
if (b === 0) {
|
||||||
|
return a;
|
||||||
|
} else if (b < 32) {
|
||||||
|
return new Long((a.lo >>> b) | (a.hi << (32 - b)), a.hi >>> b);
|
||||||
|
} else if (b === 32) {
|
||||||
|
return new Long(a.hi, 0);
|
||||||
|
} else {
|
||||||
|
return new Long((a.hi >>> (b - 32)), 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Represents a mutable 80-bit unsigned integer
|
||||||
|
function LongInt(lo, hi, sup) {
|
||||||
|
this.lo = lo;
|
||||||
|
this.hi = hi;
|
||||||
|
this.sup = sup;
|
||||||
|
}
|
||||||
|
function LongInt_mul(a, b) {
|
||||||
|
var a_lolo = ((a.lo & 0xFFFF) * b) | 0;
|
||||||
|
var a_lohi = ((a.lo >>> 16) * b) | 0;
|
||||||
|
var a_hilo = ((a.hi & 0xFFFF) * b) | 0;
|
||||||
|
var a_hihi = ((a.hi >>> 16) * b) | 0;
|
||||||
|
var sup = (a.sup * b) | 0;
|
||||||
|
|
||||||
|
a_lohi = (a_lohi + (a_lolo >>> 16)) | 0;
|
||||||
|
a_hilo = (a_hilo + (a_lohi >>> 16)) | 0;
|
||||||
|
a_hihi = (a_hihi + (a_hilo >>> 16)) | 0;
|
||||||
|
sup = (sup + (a_hihi >>> 16)) | 0;
|
||||||
|
a.lo = (a_lolo & 0xFFFF) | (a_lohi << 16);
|
||||||
|
a.hi = (a_hilo & 0xFFFF) | (a_hihi << 16);
|
||||||
|
a.sup = sup & 0xFFFF;
|
||||||
|
}
|
||||||
|
function LongInt_sub(a, b) {
|
||||||
|
var a_lolo = a.lo & 0xFFFF;
|
||||||
|
var a_lohi = a.lo >>> 16;
|
||||||
|
var a_hilo = a.hi & 0xFFFF;
|
||||||
|
var a_hihi = a.hi >>> 16;
|
||||||
|
var b_lolo = b.lo & 0xFFFF;
|
||||||
|
var b_lohi = b.lo >>> 16;
|
||||||
|
var b_hilo = b.hi & 0xFFFF;
|
||||||
|
var b_hihi = b.hi >>> 16;
|
||||||
|
|
||||||
|
a_lolo = (a_lolo - b_lolo) | 0;
|
||||||
|
a_lohi = (a_lohi - b_lohi + (a_lolo >> 16)) | 0;
|
||||||
|
a_hilo = (a_hilo - b_hilo + (a_lohi >> 16)) | 0;
|
||||||
|
a_hihi = (a_hihi - b_hihi + (a_hilo >> 16)) | 0;
|
||||||
|
var sup = (a.sup - b.sup + (a_hihi >> 16)) | 0;
|
||||||
|
a.lo = (a_lolo & 0xFFFF) | (a_lohi << 16);
|
||||||
|
a.hi = (a_hilo & 0xFFFF) | (a_hihi << 16);
|
||||||
|
a.sup = sup;
|
||||||
|
}
|
||||||
|
function LongInt_add(a, b) {
|
||||||
|
var a_lolo = a.lo & 0xFFFF;
|
||||||
|
var a_lohi = a.lo >>> 16;
|
||||||
|
var a_hilo = a.hi & 0xFFFF;
|
||||||
|
var a_hihi = a.hi >>> 16;
|
||||||
|
var b_lolo = b.lo & 0xFFFF;
|
||||||
|
var b_lohi = b.lo >>> 16;
|
||||||
|
var b_hilo = b.hi & 0xFFFF;
|
||||||
|
var b_hihi = b.hi >>> 16;
|
||||||
|
|
||||||
|
a_lolo = (a_lolo + b_lolo) | 0;
|
||||||
|
a_lohi = (a_lohi + b_lohi + (a_lolo >> 16)) | 0;
|
||||||
|
a_hilo = (a_hilo + b_hilo + (a_lohi >> 16)) | 0;
|
||||||
|
a_hihi = (a_hihi + b_hihi + (a_hilo >> 16)) | 0;
|
||||||
|
var sup = (a.sup + b.sup + (a_hihi >> 16)) | 0;
|
||||||
|
a.lo = (a_lolo & 0xFFFF) | (a_lohi << 16);
|
||||||
|
a.hi = (a_hilo & 0xFFFF) | (a_hihi << 16);
|
||||||
|
a.sup = sup;
|
||||||
|
}
|
||||||
|
function LongInt_inc(a) {
|
||||||
|
a.lo = (a.lo + 1) | 0;
|
||||||
|
if (a.lo === 0) {
|
||||||
|
a.hi = (a.hi + 1) | 0;
|
||||||
|
if (a.hi === 0) {
|
||||||
|
a.sup = (a.sup + 1) & 0xFFFF;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function LongInt_dec(a) {
|
||||||
|
a.lo = (a.lo - 1) | 0;
|
||||||
|
if (a.lo === -1) {
|
||||||
|
a.hi = (a.hi - 1) | 0;
|
||||||
|
if (a.hi === -1) {
|
||||||
|
a.sup = (a.sup - 1) & 0xFFFF;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function LongInt_ucompare(a, b) {
|
||||||
|
var r = (a.sup - b.sup);
|
||||||
|
if (r !== 0) {
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
r = (a.hi >>> 1) - (b.hi >>> 1);
|
||||||
|
if (r !== 0) {
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
r = (a.hi & 1) - (b.hi & 1);
|
||||||
|
if (r !== 0) {
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
r = (a.lo >>> 1) - (b.lo >>> 1);
|
||||||
|
if (r !== 0) {
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
return (a.lo & 1) - (b.lo & 1);
|
||||||
|
}
|
||||||
|
function LongInt_numOfLeadingZeroBits(a) {
|
||||||
|
var n = 0;
|
||||||
|
var d = 16;
|
||||||
|
while (d > 0) {
|
||||||
|
if ((a >>> d) !== 0) {
|
||||||
|
a >>>= d;
|
||||||
|
n = (n + d) | 0;
|
||||||
|
}
|
||||||
|
d = (d / 2) | 0;
|
||||||
|
}
|
||||||
|
return 31 - n;
|
||||||
|
}
|
||||||
|
function LongInt_shl(a, b) {
|
||||||
|
if (b === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
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;
|
||||||
|
} else if (b === 32) {
|
||||||
|
a.sup = a.hi & 0xFFFF;
|
||||||
|
a.hi = a.lo;
|
||||||
|
a.lo = 0;
|
||||||
|
} else if (b < 64) {
|
||||||
|
a.sup = ((a.lo >>> (64 - b)) | (a.hi << (b - 32))) & 0xFFFF;
|
||||||
|
a.hi = a.lo << b;
|
||||||
|
a.lo = 0;
|
||||||
|
} else if (b === 64) {
|
||||||
|
a.sup = a.lo & 0xFFFF;
|
||||||
|
a.hi = 0;
|
||||||
|
a.lo = 0;
|
||||||
|
} else {
|
||||||
|
a.sup = (a.lo << (b - 64)) & 0xFFFF;
|
||||||
|
a.hi = 0;
|
||||||
|
a.lo = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function LongInt_shr(a, b) {
|
||||||
|
if (b === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (b === 32) {
|
||||||
|
a.lo = a.hi;
|
||||||
|
a.hi = a.sup;
|
||||||
|
a.sup = 0;
|
||||||
|
} else if (b < 32) {
|
||||||
|
a.lo = (a.lo >>> b) | (a.hi << (32 - b));
|
||||||
|
a.hi = (a.hi >>> b) | (a.sup << (32 - b));
|
||||||
|
a.sup >>>= b;
|
||||||
|
} else if (b === 64) {
|
||||||
|
a.lo = a.sup;
|
||||||
|
a.hi = 0;
|
||||||
|
a.sup = 0;
|
||||||
|
} else if (b < 64) {
|
||||||
|
a.lo = (a.hi >>> (b - 32)) | (a.sup << (64 - b));
|
||||||
|
a.hi = a.sup >>> (b - 32);
|
||||||
|
a.sup = 0;
|
||||||
|
} else {
|
||||||
|
a.lo = a.sup >>> (b - 64);
|
||||||
|
a.hi = 0;
|
||||||
|
a.sup = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function LongInt_copy(a) {
|
||||||
|
return new LongInt(a.lo, a.hi, a.sup);
|
||||||
|
}
|
||||||
|
function LongInt_div(a, b) {
|
||||||
|
// Normalize divisor
|
||||||
|
var bits = b.hi !== 0 ? LongInt_numOfLeadingZeroBits(b.hi) : LongInt_numOfLeadingZeroBits(b.lo) + 32;
|
||||||
|
var sz = 1 + ((bits / 16) | 0);
|
||||||
|
var dividentBits = bits % 16;
|
||||||
|
LongInt_shl(b, bits);
|
||||||
|
LongInt_shl(a, dividentBits);
|
||||||
|
var q = new LongInt(0, 0, 0);
|
||||||
|
while (sz-- > 0) {
|
||||||
|
LongInt_shl(q, 16);
|
||||||
|
// Calculate approximate q
|
||||||
|
var digitA = (a.hi >>> 16) + (0x10000 * a.sup);
|
||||||
|
var digitB = b.hi >>> 16;
|
||||||
|
var digit = (digitA / digitB) | 0;
|
||||||
|
var t = LongInt_copy(b);
|
||||||
|
LongInt_mul(t, digit);
|
||||||
|
// Adjust q either down or up
|
||||||
|
if (LongInt_ucompare(t, a) >= 0) {
|
||||||
|
while (LongInt_ucompare(t, a) > 0) {
|
||||||
|
LongInt_sub(t, b);
|
||||||
|
--digit;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
while (true) {
|
||||||
|
var nextT = LongInt_copy(t);
|
||||||
|
LongInt_add(nextT, b);
|
||||||
|
if (LongInt_ucompare(nextT, a) > 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
t = nextT;
|
||||||
|
++digit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
LongInt_sub(a, t);
|
||||||
|
q.lo |= digit;
|
||||||
|
LongInt_shl(a, 16);
|
||||||
|
}
|
||||||
|
LongInt_shr(a, bits + 16);
|
||||||
|
return q;
|
||||||
|
}
|
|
@ -507,99 +507,6 @@ function $rt_s(index) {
|
||||||
function $rt_eraseClinit(target) {
|
function $rt_eraseClinit(target) {
|
||||||
return target.$clinit = function() {};
|
return target.$clinit = function() {};
|
||||||
}
|
}
|
||||||
function TeaVMThread(runner) {
|
|
||||||
this.status = 3;
|
|
||||||
this.stack = [];
|
|
||||||
this.suspendCallback = null;
|
|
||||||
this.runner = runner;
|
|
||||||
this.attribute = null;
|
|
||||||
this.completeCallback = null;
|
|
||||||
}
|
|
||||||
TeaVMThread.prototype.push = function() {
|
|
||||||
for (var i = 0; i < arguments.length; ++i) {
|
|
||||||
this.stack.push(arguments[i]);
|
|
||||||
}
|
|
||||||
return this;
|
|
||||||
};
|
|
||||||
TeaVMThread.prototype.s = TeaVMThread.prototype.push;
|
|
||||||
TeaVMThread.prototype.pop = function() {
|
|
||||||
return this.stack.pop();
|
|
||||||
};
|
|
||||||
TeaVMThread.prototype.l = TeaVMThread.prototype.pop;
|
|
||||||
TeaVMThread.prototype.isResuming = function() {
|
|
||||||
return this.status === 2;
|
|
||||||
};
|
|
||||||
TeaVMThread.prototype.isSuspending = function() {
|
|
||||||
return this.status === 1;
|
|
||||||
};
|
|
||||||
TeaVMThread.prototype.suspend = function(callback) {
|
|
||||||
this.suspendCallback = callback;
|
|
||||||
this.status = 1;
|
|
||||||
};
|
|
||||||
TeaVMThread.prototype.start = function(callback) {
|
|
||||||
if (this.status !== 3) {
|
|
||||||
throw new Error("Thread already started");
|
|
||||||
}
|
|
||||||
if ($rt_currentNativeThread !== null) {
|
|
||||||
throw new Error("Another thread is running");
|
|
||||||
}
|
|
||||||
this.status = 0;
|
|
||||||
this.completeCallback = callback ? callback : function(result) {
|
|
||||||
if (result instanceof Error) {
|
|
||||||
throw result;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
this.run();
|
|
||||||
};
|
|
||||||
TeaVMThread.prototype.resume = function() {
|
|
||||||
if ($rt_currentNativeThread !== null) {
|
|
||||||
throw new Error("Another thread is running");
|
|
||||||
}
|
|
||||||
this.status = 2;
|
|
||||||
this.run();
|
|
||||||
};
|
|
||||||
TeaVMThread.prototype.run = function() {
|
|
||||||
$rt_currentNativeThread = this;
|
|
||||||
var result;
|
|
||||||
try {
|
|
||||||
result = this.runner();
|
|
||||||
} catch (e) {
|
|
||||||
result = e;
|
|
||||||
} finally {
|
|
||||||
$rt_currentNativeThread = null;
|
|
||||||
}
|
|
||||||
if (this.suspendCallback !== null) {
|
|
||||||
var self = this;
|
|
||||||
var callback = this.suspendCallback;
|
|
||||||
this.suspendCallback = null;
|
|
||||||
callback(function() {
|
|
||||||
self.resume();
|
|
||||||
});
|
|
||||||
} else if (this.status === 0) {
|
|
||||||
this.completeCallback(result);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
function $rt_suspending() {
|
|
||||||
var thread = $rt_nativeThread();
|
|
||||||
return thread != null && thread.isSuspending();
|
|
||||||
}
|
|
||||||
function $rt_resuming() {
|
|
||||||
var thread = $rt_nativeThread();
|
|
||||||
return thread != null && thread.isResuming();
|
|
||||||
}
|
|
||||||
function $rt_suspend(callback) {
|
|
||||||
return $rt_nativeThread().suspend(callback);
|
|
||||||
}
|
|
||||||
function $rt_startThread(runner, callback) {
|
|
||||||
new TeaVMThread(runner).start(callback);
|
|
||||||
}
|
|
||||||
var $rt_currentNativeThread = null;
|
|
||||||
function $rt_nativeThread() {
|
|
||||||
return $rt_currentNativeThread;
|
|
||||||
}
|
|
||||||
function $rt_invalidPointer() {
|
|
||||||
throw new Error("Invalid recorded state");
|
|
||||||
}
|
|
||||||
|
|
||||||
var $rt_numberConversionView = new DataView(new ArrayBuffer(8));
|
var $rt_numberConversionView = new DataView(new ArrayBuffer(8));
|
||||||
|
|
||||||
|
@ -716,465 +623,3 @@ function Long_toNumber(val) {
|
||||||
}
|
}
|
||||||
return 0x100000000 * hi + lo;
|
return 0x100000000 * hi + lo;
|
||||||
}
|
}
|
||||||
function Long_eq(a, b) {
|
|
||||||
return a.hi === b.hi && a.lo === b.lo;
|
|
||||||
}
|
|
||||||
function Long_ne(a, b) {
|
|
||||||
return a.hi !== b.hi || a.lo !== b.lo;
|
|
||||||
}
|
|
||||||
function Long_gt(a, b) {
|
|
||||||
if (a.hi < b.hi) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (a.hi > b.hi) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
var x = a.lo >>> 1;
|
|
||||||
var y = b.lo >>> 1;
|
|
||||||
if (x !== y) {
|
|
||||||
return x > y;
|
|
||||||
}
|
|
||||||
return (a.lo & 1) > (b.lo & 1);
|
|
||||||
}
|
|
||||||
function Long_ge(a, b) {
|
|
||||||
if (a.hi < b.hi) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (a.hi > b.hi) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
var x = a.lo >>> 1;
|
|
||||||
var y = b.lo >>> 1;
|
|
||||||
if (x !== y) {
|
|
||||||
return x >= y;
|
|
||||||
}
|
|
||||||
return (a.lo & 1) >= (b.lo & 1);
|
|
||||||
}
|
|
||||||
function Long_lt(a, b) {
|
|
||||||
if (a.hi > b.hi) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (a.hi < b.hi) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
var x = a.lo >>> 1;
|
|
||||||
var y = b.lo >>> 1;
|
|
||||||
if (x !== y) {
|
|
||||||
return x < y;
|
|
||||||
}
|
|
||||||
return (a.lo & 1) < (b.lo & 1);
|
|
||||||
}
|
|
||||||
function Long_le(a, b) {
|
|
||||||
if (a.hi > b.hi) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (a.hi < b.hi) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
var x = a.lo >>> 1;
|
|
||||||
var y = b.lo >>> 1;
|
|
||||||
if (x !== y) {
|
|
||||||
return x <= y;
|
|
||||||
}
|
|
||||||
return (a.lo & 1) <= (b.lo & 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
function Long_add(a, b) {
|
|
||||||
if (a.hi === (a.lo >> 31) && b.hi === (b.lo >> 31)) {
|
|
||||||
return Long_fromNumber(a.lo + b.lo);
|
|
||||||
} else if (Math.abs(a.hi) < Long_MAX_NORMAL && Math.abs(b.hi) < Long_MAX_NORMAL) {
|
|
||||||
return Long_fromNumber(Long_toNumber(a) + Long_toNumber(b));
|
|
||||||
}
|
|
||||||
var a_lolo = a.lo & 0xFFFF;
|
|
||||||
var a_lohi = a.lo >>> 16;
|
|
||||||
var a_hilo = a.hi & 0xFFFF;
|
|
||||||
var a_hihi = a.hi >>> 16;
|
|
||||||
var b_lolo = b.lo & 0xFFFF;
|
|
||||||
var b_lohi = b.lo >>> 16;
|
|
||||||
var b_hilo = b.hi & 0xFFFF;
|
|
||||||
var b_hihi = b.hi >>> 16;
|
|
||||||
|
|
||||||
var lolo = (a_lolo + b_lolo) | 0;
|
|
||||||
var lohi = (a_lohi + b_lohi + (lolo >> 16)) | 0;
|
|
||||||
var hilo = (a_hilo + b_hilo + (lohi >> 16)) | 0;
|
|
||||||
var hihi = (a_hihi + b_hihi + (hilo >> 16)) | 0;
|
|
||||||
return new Long((lolo & 0xFFFF) | ((lohi & 0xFFFF) << 16), (hilo & 0xFFFF) | ((hihi & 0xFFFF) << 16));
|
|
||||||
}
|
|
||||||
function Long_inc(a) {
|
|
||||||
var lo = (a.lo + 1) | 0;
|
|
||||||
var hi = a.hi;
|
|
||||||
if (lo === 0) {
|
|
||||||
hi = (hi + 1) | 0;
|
|
||||||
}
|
|
||||||
return new Long(lo, hi);
|
|
||||||
}
|
|
||||||
function Long_dec(a) {
|
|
||||||
var lo = (a.lo - 1) | 0;
|
|
||||||
var hi = a.hi;
|
|
||||||
if (lo === -1) {
|
|
||||||
hi = (hi - 1) | 0;
|
|
||||||
}
|
|
||||||
return new Long(lo, hi);
|
|
||||||
}
|
|
||||||
function Long_neg(a) {
|
|
||||||
return Long_inc(new Long(a.lo ^ 0xFFFFFFFF, a.hi ^ 0xFFFFFFFF));
|
|
||||||
}
|
|
||||||
function Long_sub(a, b) {
|
|
||||||
if (a.hi === (a.lo >> 31) && b.hi === (b.lo >> 31)) {
|
|
||||||
return Long_fromNumber(a.lo - b.lo);
|
|
||||||
}
|
|
||||||
var a_lolo = a.lo & 0xFFFF;
|
|
||||||
var a_lohi = a.lo >>> 16;
|
|
||||||
var a_hilo = a.hi & 0xFFFF;
|
|
||||||
var a_hihi = a.hi >>> 16;
|
|
||||||
var b_lolo = b.lo & 0xFFFF;
|
|
||||||
var b_lohi = b.lo >>> 16;
|
|
||||||
var b_hilo = b.hi & 0xFFFF;
|
|
||||||
var b_hihi = b.hi >>> 16;
|
|
||||||
|
|
||||||
var lolo = (a_lolo - b_lolo) | 0;
|
|
||||||
var lohi = (a_lohi - b_lohi + (lolo >> 16)) | 0;
|
|
||||||
var hilo = (a_hilo - b_hilo + (lohi >> 16)) | 0;
|
|
||||||
var hihi = (a_hihi - b_hihi + (hilo >> 16)) | 0;
|
|
||||||
return new Long((lolo & 0xFFFF) | ((lohi & 0xFFFF) << 16), (hilo & 0xFFFF) | ((hihi & 0xFFFF) << 16));
|
|
||||||
}
|
|
||||||
function Long_compare(a, b) {
|
|
||||||
var r = a.hi - b.hi;
|
|
||||||
if (r !== 0) {
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
r = (a.lo >>> 1) - (b.lo >>> 1);
|
|
||||||
if (r !== 0) {
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
return (a.lo & 1) - (b.lo & 1);
|
|
||||||
}
|
|
||||||
function Long_isPositive(a) {
|
|
||||||
return (a.hi & 0x80000000) === 0;
|
|
||||||
}
|
|
||||||
function Long_isNegative(a) {
|
|
||||||
return (a.hi & 0x80000000) !== 0;
|
|
||||||
}
|
|
||||||
function Long_mul(a, b) {
|
|
||||||
var positive = Long_isNegative(a) === Long_isNegative(b);
|
|
||||||
if (Long_isNegative(a)) {
|
|
||||||
a = Long_neg(a);
|
|
||||||
}
|
|
||||||
if (Long_isNegative(b)) {
|
|
||||||
b = Long_neg(b);
|
|
||||||
}
|
|
||||||
var a_lolo = a.lo & 0xFFFF;
|
|
||||||
var a_lohi = a.lo >>> 16;
|
|
||||||
var a_hilo = a.hi & 0xFFFF;
|
|
||||||
var a_hihi = a.hi >>> 16;
|
|
||||||
var b_lolo = b.lo & 0xFFFF;
|
|
||||||
var b_lohi = b.lo >>> 16;
|
|
||||||
var b_hilo = b.hi & 0xFFFF;
|
|
||||||
var b_hihi = b.hi >>> 16;
|
|
||||||
|
|
||||||
var lolo = 0;
|
|
||||||
var lohi = 0;
|
|
||||||
var hilo = 0;
|
|
||||||
var hihi = 0;
|
|
||||||
lolo = (a_lolo * b_lolo) | 0;
|
|
||||||
lohi = lolo >>> 16;
|
|
||||||
lohi = ((lohi & 0xFFFF) + a_lohi * b_lolo) | 0;
|
|
||||||
hilo = (hilo + (lohi >>> 16)) | 0;
|
|
||||||
lohi = ((lohi & 0xFFFF) + a_lolo * b_lohi) | 0;
|
|
||||||
hilo = (hilo + (lohi >>> 16)) | 0;
|
|
||||||
hihi = hilo >>> 16;
|
|
||||||
hilo = ((hilo & 0xFFFF) + a_hilo * b_lolo) | 0;
|
|
||||||
hihi = (hihi + (hilo >>> 16)) | 0;
|
|
||||||
hilo = ((hilo & 0xFFFF) + a_lohi * b_lohi) | 0;
|
|
||||||
hihi = (hihi + (hilo >>> 16)) | 0;
|
|
||||||
hilo = ((hilo & 0xFFFF) + a_lolo * b_hilo) | 0;
|
|
||||||
hihi = (hihi + (hilo >>> 16)) | 0;
|
|
||||||
hihi = (hihi + a_hihi * b_lolo + a_hilo * b_lohi + a_lohi * b_hilo + a_lolo * b_hihi) | 0;
|
|
||||||
var result = new Long((lolo & 0xFFFF) | (lohi << 16), (hilo & 0xFFFF) | (hihi << 16));
|
|
||||||
return positive ? result : Long_neg(result);
|
|
||||||
}
|
|
||||||
function Long_div(a, b) {
|
|
||||||
if (Math.abs(a.hi) < Long_MAX_NORMAL && Math.abs(b.hi) < Long_MAX_NORMAL) {
|
|
||||||
return Long_fromNumber(Long_toNumber(a) / Long_toNumber(b));
|
|
||||||
}
|
|
||||||
return Long_divRem(a, b)[0];
|
|
||||||
}
|
|
||||||
function Long_rem(a, b) {
|
|
||||||
if (Math.abs(a.hi) < Long_MAX_NORMAL && Math.abs(b.hi) < Long_MAX_NORMAL) {
|
|
||||||
return Long_fromNumber(Long_toNumber(a) % Long_toNumber(b));
|
|
||||||
}
|
|
||||||
return Long_divRem(a, b)[1];
|
|
||||||
}
|
|
||||||
function Long_divRem(a, b) {
|
|
||||||
if (b.lo === 0 && b.hi === 0) {
|
|
||||||
throw new Error("Division by zero");
|
|
||||||
}
|
|
||||||
var positive = Long_isNegative(a) === Long_isNegative(b);
|
|
||||||
if (Long_isNegative(a)) {
|
|
||||||
a = Long_neg(a);
|
|
||||||
}
|
|
||||||
if (Long_isNegative(b)) {
|
|
||||||
b = Long_neg(b);
|
|
||||||
}
|
|
||||||
a = new LongInt(a.lo, a.hi, 0);
|
|
||||||
b = new LongInt(b.lo, b.hi, 0);
|
|
||||||
var q = LongInt_div(a, b);
|
|
||||||
a = new Long(a.lo, a.hi);
|
|
||||||
q = new Long(q.lo, q.hi);
|
|
||||||
return positive ? [q, a] : [Long_neg(q), Long_neg(a)];
|
|
||||||
}
|
|
||||||
function Long_shiftLeft16(a) {
|
|
||||||
return new Long(a.lo << 16, (a.lo >>> 16) | (a.hi << 16));
|
|
||||||
}
|
|
||||||
function Long_shiftRight16(a) {
|
|
||||||
return new Long((a.lo >>> 16) | (a.hi << 16), a.hi >>> 16);
|
|
||||||
}
|
|
||||||
function Long_and(a, b) {
|
|
||||||
return new Long(a.lo & b.lo, a.hi & b.hi);
|
|
||||||
}
|
|
||||||
function Long_or(a, b) {
|
|
||||||
return new Long(a.lo | b.lo, a.hi | b.hi);
|
|
||||||
}
|
|
||||||
function Long_xor(a, b) {
|
|
||||||
return new Long(a.lo ^ b.lo, a.hi ^ b.hi);
|
|
||||||
}
|
|
||||||
function Long_shl(a, b) {
|
|
||||||
b &= 63;
|
|
||||||
if (b === 0) {
|
|
||||||
return a;
|
|
||||||
} else if (b < 32) {
|
|
||||||
return new Long(a.lo << b, (a.lo >>> (32 - b)) | (a.hi << b));
|
|
||||||
} else if (b === 32) {
|
|
||||||
return new Long(0, a.lo);
|
|
||||||
} else {
|
|
||||||
return new Long(0, a.lo << (b - 32));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
function Long_shr(a, b) {
|
|
||||||
b &= 63;
|
|
||||||
if (b === 0) {
|
|
||||||
return a;
|
|
||||||
} else if (b < 32) {
|
|
||||||
return new Long((a.lo >>> b) | (a.hi << (32 - b)), a.hi >> b);
|
|
||||||
} else if (b === 32) {
|
|
||||||
return new Long(a.hi, a.hi >> 31);
|
|
||||||
} else {
|
|
||||||
return new Long((a.hi >> (b - 32)), a.hi >> 31);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
function Long_shru(a, b) {
|
|
||||||
b &= 63;
|
|
||||||
if (b === 0) {
|
|
||||||
return a;
|
|
||||||
} else if (b < 32) {
|
|
||||||
return new Long((a.lo >>> b) | (a.hi << (32 - b)), a.hi >>> b);
|
|
||||||
} else if (b === 32) {
|
|
||||||
return new Long(a.hi, 0);
|
|
||||||
} else {
|
|
||||||
return new Long((a.hi >>> (b - 32)), 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Represents a mutable 80-bit unsigned integer
|
|
||||||
function LongInt(lo, hi, sup) {
|
|
||||||
this.lo = lo;
|
|
||||||
this.hi = hi;
|
|
||||||
this.sup = sup;
|
|
||||||
}
|
|
||||||
function LongInt_mul(a, b) {
|
|
||||||
var a_lolo = ((a.lo & 0xFFFF) * b) | 0;
|
|
||||||
var a_lohi = ((a.lo >>> 16) * b) | 0;
|
|
||||||
var a_hilo = ((a.hi & 0xFFFF) * b) | 0;
|
|
||||||
var a_hihi = ((a.hi >>> 16) * b) | 0;
|
|
||||||
var sup = (a.sup * b) | 0;
|
|
||||||
|
|
||||||
a_lohi = (a_lohi + (a_lolo >>> 16)) | 0;
|
|
||||||
a_hilo = (a_hilo + (a_lohi >>> 16)) | 0;
|
|
||||||
a_hihi = (a_hihi + (a_hilo >>> 16)) | 0;
|
|
||||||
sup = (sup + (a_hihi >>> 16)) | 0;
|
|
||||||
a.lo = (a_lolo & 0xFFFF) | (a_lohi << 16);
|
|
||||||
a.hi = (a_hilo & 0xFFFF) | (a_hihi << 16);
|
|
||||||
a.sup = sup & 0xFFFF;
|
|
||||||
}
|
|
||||||
function LongInt_sub(a, b) {
|
|
||||||
var a_lolo = a.lo & 0xFFFF;
|
|
||||||
var a_lohi = a.lo >>> 16;
|
|
||||||
var a_hilo = a.hi & 0xFFFF;
|
|
||||||
var a_hihi = a.hi >>> 16;
|
|
||||||
var b_lolo = b.lo & 0xFFFF;
|
|
||||||
var b_lohi = b.lo >>> 16;
|
|
||||||
var b_hilo = b.hi & 0xFFFF;
|
|
||||||
var b_hihi = b.hi >>> 16;
|
|
||||||
|
|
||||||
a_lolo = (a_lolo - b_lolo) | 0;
|
|
||||||
a_lohi = (a_lohi - b_lohi + (a_lolo >> 16)) | 0;
|
|
||||||
a_hilo = (a_hilo - b_hilo + (a_lohi >> 16)) | 0;
|
|
||||||
a_hihi = (a_hihi - b_hihi + (a_hilo >> 16)) | 0;
|
|
||||||
var sup = (a.sup - b.sup + (a_hihi >> 16)) | 0;
|
|
||||||
a.lo = (a_lolo & 0xFFFF) | (a_lohi << 16);
|
|
||||||
a.hi = (a_hilo & 0xFFFF) | (a_hihi << 16);
|
|
||||||
a.sup = sup;
|
|
||||||
}
|
|
||||||
function LongInt_add(a, b) {
|
|
||||||
var a_lolo = a.lo & 0xFFFF;
|
|
||||||
var a_lohi = a.lo >>> 16;
|
|
||||||
var a_hilo = a.hi & 0xFFFF;
|
|
||||||
var a_hihi = a.hi >>> 16;
|
|
||||||
var b_lolo = b.lo & 0xFFFF;
|
|
||||||
var b_lohi = b.lo >>> 16;
|
|
||||||
var b_hilo = b.hi & 0xFFFF;
|
|
||||||
var b_hihi = b.hi >>> 16;
|
|
||||||
|
|
||||||
a_lolo = (a_lolo + b_lolo) | 0;
|
|
||||||
a_lohi = (a_lohi + b_lohi + (a_lolo >> 16)) | 0;
|
|
||||||
a_hilo = (a_hilo + b_hilo + (a_lohi >> 16)) | 0;
|
|
||||||
a_hihi = (a_hihi + b_hihi + (a_hilo >> 16)) | 0;
|
|
||||||
var sup = (a.sup + b.sup + (a_hihi >> 16)) | 0;
|
|
||||||
a.lo = (a_lolo & 0xFFFF) | (a_lohi << 16);
|
|
||||||
a.hi = (a_hilo & 0xFFFF) | (a_hihi << 16);
|
|
||||||
a.sup = sup;
|
|
||||||
}
|
|
||||||
function LongInt_inc(a) {
|
|
||||||
a.lo = (a.lo + 1) | 0;
|
|
||||||
if (a.lo === 0) {
|
|
||||||
a.hi = (a.hi + 1) | 0;
|
|
||||||
if (a.hi === 0) {
|
|
||||||
a.sup = (a.sup + 1) & 0xFFFF;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
function LongInt_dec(a) {
|
|
||||||
a.lo = (a.lo - 1) | 0;
|
|
||||||
if (a.lo === -1) {
|
|
||||||
a.hi = (a.hi - 1) | 0;
|
|
||||||
if (a.hi === -1) {
|
|
||||||
a.sup = (a.sup - 1) & 0xFFFF;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
function LongInt_ucompare(a, b) {
|
|
||||||
var r = (a.sup - b.sup);
|
|
||||||
if (r !== 0) {
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
r = (a.hi >>> 1) - (b.hi >>> 1);
|
|
||||||
if (r !== 0) {
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
r = (a.hi & 1) - (b.hi & 1);
|
|
||||||
if (r !== 0) {
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
r = (a.lo >>> 1) - (b.lo >>> 1);
|
|
||||||
if (r !== 0) {
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
return (a.lo & 1) - (b.lo & 1);
|
|
||||||
}
|
|
||||||
function LongInt_numOfLeadingZeroBits(a) {
|
|
||||||
var n = 0;
|
|
||||||
var d = 16;
|
|
||||||
while (d > 0) {
|
|
||||||
if ((a >>> d) !== 0) {
|
|
||||||
a >>>= d;
|
|
||||||
n = (n + d) | 0;
|
|
||||||
}
|
|
||||||
d = (d / 2) | 0;
|
|
||||||
}
|
|
||||||
return 31 - n;
|
|
||||||
}
|
|
||||||
function LongInt_shl(a, b) {
|
|
||||||
if (b === 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
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;
|
|
||||||
} else if (b === 32) {
|
|
||||||
a.sup = a.hi & 0xFFFF;
|
|
||||||
a.hi = a.lo;
|
|
||||||
a.lo = 0;
|
|
||||||
} else if (b < 64) {
|
|
||||||
a.sup = ((a.lo >>> (64 - b)) | (a.hi << (b - 32))) & 0xFFFF;
|
|
||||||
a.hi = a.lo << b;
|
|
||||||
a.lo = 0;
|
|
||||||
} else if (b === 64) {
|
|
||||||
a.sup = a.lo & 0xFFFF;
|
|
||||||
a.hi = 0;
|
|
||||||
a.lo = 0;
|
|
||||||
} else {
|
|
||||||
a.sup = (a.lo << (b - 64)) & 0xFFFF;
|
|
||||||
a.hi = 0;
|
|
||||||
a.lo = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
function LongInt_shr(a, b) {
|
|
||||||
if (b === 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (b === 32) {
|
|
||||||
a.lo = a.hi;
|
|
||||||
a.hi = a.sup;
|
|
||||||
a.sup = 0;
|
|
||||||
} else if (b < 32) {
|
|
||||||
a.lo = (a.lo >>> b) | (a.hi << (32 - b));
|
|
||||||
a.hi = (a.hi >>> b) | (a.sup << (32 - b));
|
|
||||||
a.sup >>>= b;
|
|
||||||
} else if (b === 64) {
|
|
||||||
a.lo = a.sup;
|
|
||||||
a.hi = 0;
|
|
||||||
a.sup = 0;
|
|
||||||
} else if (b < 64) {
|
|
||||||
a.lo = (a.hi >>> (b - 32)) | (a.sup << (64 - b));
|
|
||||||
a.hi = a.sup >>> (b - 32);
|
|
||||||
a.sup = 0;
|
|
||||||
} else {
|
|
||||||
a.lo = a.sup >>> (b - 64);
|
|
||||||
a.hi = 0;
|
|
||||||
a.sup = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
function LongInt_copy(a) {
|
|
||||||
return new LongInt(a.lo, a.hi, a.sup);
|
|
||||||
}
|
|
||||||
function LongInt_div(a, b) {
|
|
||||||
// Normalize divisor
|
|
||||||
var bits = b.hi !== 0 ? LongInt_numOfLeadingZeroBits(b.hi) : LongInt_numOfLeadingZeroBits(b.lo) + 32;
|
|
||||||
var sz = 1 + ((bits / 16) | 0);
|
|
||||||
var dividentBits = bits % 16;
|
|
||||||
LongInt_shl(b, bits);
|
|
||||||
LongInt_shl(a, dividentBits);
|
|
||||||
var q = new LongInt(0, 0, 0);
|
|
||||||
while (sz-- > 0) {
|
|
||||||
LongInt_shl(q, 16);
|
|
||||||
// Calculate approximate q
|
|
||||||
var digitA = (a.hi >>> 16) + (0x10000 * a.sup);
|
|
||||||
var digitB = b.hi >>> 16;
|
|
||||||
var digit = (digitA / digitB) | 0;
|
|
||||||
var t = LongInt_copy(b);
|
|
||||||
LongInt_mul(t, digit);
|
|
||||||
// Adjust q either down or up
|
|
||||||
if (LongInt_ucompare(t, a) >= 0) {
|
|
||||||
while (LongInt_ucompare(t, a) > 0) {
|
|
||||||
LongInt_sub(t, b);
|
|
||||||
--digit;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
while (true) {
|
|
||||||
var nextT = LongInt_copy(t);
|
|
||||||
LongInt_add(nextT, b);
|
|
||||||
if (LongInt_ucompare(nextT, a) > 0) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
t = nextT;
|
|
||||||
++digit;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
LongInt_sub(a, t);
|
|
||||||
q.lo |= digit;
|
|
||||||
LongInt_shl(a, 16);
|
|
||||||
}
|
|
||||||
LongInt_shr(a, bits + 16);
|
|
||||||
return q;
|
|
||||||
}
|
|
||||||
|
|
|
@ -0,0 +1,41 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2018 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.
|
||||||
|
*/
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
function $rt_startThread(runner, callback) {
|
||||||
|
var result;
|
||||||
|
try {
|
||||||
|
result = runner();
|
||||||
|
} catch (e) {
|
||||||
|
result = e;
|
||||||
|
}
|
||||||
|
if (typeof callback !== 'undefined') {
|
||||||
|
callback(result);
|
||||||
|
} else if (e instanceof Error) {
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function $rt_suspending() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
function $rt_resuming() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
function $rt_nativeThread() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
function $rt_invalidPointer() {
|
||||||
|
}
|
111
core/src/main/resources/org/teavm/backend/javascript/thread.js
Normal file
|
@ -0,0 +1,111 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2018 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.
|
||||||
|
*/
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
function TeaVMThread(runner) {
|
||||||
|
this.status = 3;
|
||||||
|
this.stack = [];
|
||||||
|
this.suspendCallback = null;
|
||||||
|
this.runner = runner;
|
||||||
|
this.attribute = null;
|
||||||
|
this.completeCallback = null;
|
||||||
|
}
|
||||||
|
TeaVMThread.prototype.push = function() {
|
||||||
|
for (var i = 0; i < arguments.length; ++i) {
|
||||||
|
this.stack.push(arguments[i]);
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
TeaVMThread.prototype.s = TeaVMThread.prototype.push;
|
||||||
|
TeaVMThread.prototype.pop = function() {
|
||||||
|
return this.stack.pop();
|
||||||
|
};
|
||||||
|
TeaVMThread.prototype.l = TeaVMThread.prototype.pop;
|
||||||
|
TeaVMThread.prototype.isResuming = function() {
|
||||||
|
return this.status === 2;
|
||||||
|
};
|
||||||
|
TeaVMThread.prototype.isSuspending = function() {
|
||||||
|
return this.status === 1;
|
||||||
|
};
|
||||||
|
TeaVMThread.prototype.suspend = function(callback) {
|
||||||
|
this.suspendCallback = callback;
|
||||||
|
this.status = 1;
|
||||||
|
};
|
||||||
|
TeaVMThread.prototype.start = function(callback) {
|
||||||
|
if (this.status !== 3) {
|
||||||
|
throw new Error("Thread already started");
|
||||||
|
}
|
||||||
|
if ($rt_currentNativeThread !== null) {
|
||||||
|
throw new Error("Another thread is running");
|
||||||
|
}
|
||||||
|
this.status = 0;
|
||||||
|
this.completeCallback = callback ? callback : function(result) {
|
||||||
|
if (result instanceof Error) {
|
||||||
|
throw result;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
this.run();
|
||||||
|
};
|
||||||
|
TeaVMThread.prototype.resume = function() {
|
||||||
|
if ($rt_currentNativeThread !== null) {
|
||||||
|
throw new Error("Another thread is running");
|
||||||
|
}
|
||||||
|
this.status = 2;
|
||||||
|
this.run();
|
||||||
|
};
|
||||||
|
TeaVMThread.prototype.run = function() {
|
||||||
|
$rt_currentNativeThread = this;
|
||||||
|
var result;
|
||||||
|
try {
|
||||||
|
result = this.runner();
|
||||||
|
} catch (e) {
|
||||||
|
result = e;
|
||||||
|
} finally {
|
||||||
|
$rt_currentNativeThread = null;
|
||||||
|
}
|
||||||
|
if (this.suspendCallback !== null) {
|
||||||
|
var self = this;
|
||||||
|
var callback = this.suspendCallback;
|
||||||
|
this.suspendCallback = null;
|
||||||
|
callback(function() {
|
||||||
|
self.resume();
|
||||||
|
});
|
||||||
|
} else if (this.status === 0) {
|
||||||
|
this.completeCallback(result);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
function $rt_suspending() {
|
||||||
|
var thread = $rt_nativeThread();
|
||||||
|
return thread != null && thread.isSuspending();
|
||||||
|
}
|
||||||
|
function $rt_resuming() {
|
||||||
|
var thread = $rt_nativeThread();
|
||||||
|
return thread != null && thread.isResuming();
|
||||||
|
}
|
||||||
|
function $rt_suspend(callback) {
|
||||||
|
return $rt_nativeThread().suspend(callback);
|
||||||
|
}
|
||||||
|
function $rt_startThread(runner, callback) {
|
||||||
|
new TeaVMThread(runner).start(callback);
|
||||||
|
}
|
||||||
|
var $rt_currentNativeThread = null;
|
||||||
|
function $rt_nativeThread() {
|
||||||
|
return $rt_currentNativeThread;
|
||||||
|
}
|
||||||
|
function $rt_invalidPointer() {
|
||||||
|
throw new Error("Invalid recorded state");
|
||||||
|
}
|
|
@ -103,10 +103,14 @@ class UsageGenerator {
|
||||||
|
|
||||||
MethodDependency hashCodeDep = agent.linkMethod(new MethodReference(String.class, "hashCode", int.class),
|
MethodDependency hashCodeDep = agent.linkMethod(new MethodReference(String.class, "hashCode", int.class),
|
||||||
location);
|
location);
|
||||||
|
hashCodeDep.getVariable(0).propagate(agent.getType("java.lang.String"));
|
||||||
nameDep.getResult().connect(hashCodeDep.getVariable(0));
|
nameDep.getResult().connect(hashCodeDep.getVariable(0));
|
||||||
hashCodeDep.getThrown().connect(methodDep.getThrown());
|
hashCodeDep.getThrown().connect(methodDep.getThrown());
|
||||||
hashCodeDep.use();
|
hashCodeDep.use();
|
||||||
|
|
||||||
|
agent.linkMethod(new MethodReference(Object.class, "hashCode", int.class), null);
|
||||||
|
agent.linkMethod(new MethodReference(Object.class, "equals", Object.class, boolean.class), null);
|
||||||
|
|
||||||
return nameDep;
|
return nameDep;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
12
pom.xml
|
@ -68,7 +68,6 @@
|
||||||
<html4j.version>1.5</html4j.version>
|
<html4j.version>1.5</html4j.version>
|
||||||
<jetty.version>9.2.1.v20140609</jetty.version>
|
<jetty.version>9.2.1.v20140609</jetty.version>
|
||||||
<slf4j.version>1.7.7</slf4j.version>
|
<slf4j.version>1.7.7</slf4j.version>
|
||||||
<selenium.version>2.47.2</selenium.version>
|
|
||||||
<jackson.version>2.6.2</jackson.version>
|
<jackson.version>2.6.2</jackson.version>
|
||||||
<idea.version>2017.3.5</idea.version>
|
<idea.version>2017.3.5</idea.version>
|
||||||
<asm.version>7.0</asm.version>
|
<asm.version>7.0</asm.version>
|
||||||
|
@ -77,7 +76,6 @@
|
||||||
|
|
||||||
<teavm.test.incremental>false</teavm.test.incremental>
|
<teavm.test.incremental>false</teavm.test.incremental>
|
||||||
<teavm.test.threads>1</teavm.test.threads>
|
<teavm.test.threads>1</teavm.test.threads>
|
||||||
<teavm.test.selenium/>
|
|
||||||
<teavm.test.skip>true</teavm.test.skip>
|
<teavm.test.skip>true</teavm.test.skip>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
|
@ -183,16 +181,6 @@
|
||||||
<artifactId>slf4j-api</artifactId>
|
<artifactId>slf4j-api</artifactId>
|
||||||
<version>${slf4j.version}</version>
|
<version>${slf4j.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
|
||||||
<groupId>org.seleniumhq.selenium</groupId>
|
|
||||||
<artifactId>selenium-java</artifactId>
|
|
||||||
<version>${selenium.version}</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.seleniumhq.selenium</groupId>
|
|
||||||
<artifactId>selenium-remote-driver</artifactId>
|
|
||||||
<version>${selenium.version}</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.fasterxml.jackson.core</groupId>
|
<groupId>com.fasterxml.jackson.core</groupId>
|
||||||
<artifactId>jackson-annotations</artifactId>
|
<artifactId>jackson-annotations</artifactId>
|
||||||
|
|
|
@ -276,34 +276,27 @@ class TestRunner {
|
||||||
|
|
||||||
function runTeaVM() {
|
function runTeaVM() {
|
||||||
return new Promise(resolve => {
|
return new Promise(resolve => {
|
||||||
$rt_startThread(() => {
|
main([], result => {
|
||||||
const thread = $rt_nativeThread();
|
const message = {};
|
||||||
let instance;
|
if (result instanceof Error) {
|
||||||
if (thread.isResuming()) {
|
makeErrorMessage(message, result);
|
||||||
instance = thread.pop();
|
} else {
|
||||||
|
message.status = "OK";
|
||||||
}
|
}
|
||||||
try {
|
resolve(message);
|
||||||
runTest();
|
|
||||||
} catch (e) {
|
|
||||||
resolve({ status: "failed", errorMessage: buildErrorMessage(e) });
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (thread.isSuspending()) {
|
|
||||||
thread.push(instance);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
resolve({ status: "OK" });
|
|
||||||
});
|
});
|
||||||
|
|
||||||
function buildErrorMessage(e) {
|
function makeErrorMessage(message, e) {
|
||||||
let stack = e.stack;
|
message.status = "failed";
|
||||||
if (e.$javaException && e.$javaException.constructor.$meta) {
|
if (e.$javaException) {
|
||||||
stack = e.$javaException.constructor.$meta.name + ": ";
|
message.className = e.$javaException.constructor.name;
|
||||||
const exceptionMessage = extractException(e.$javaException);
|
message.message = e.$javaException.getMessage();
|
||||||
stack += exceptionMessage ? $rt_ustr(exceptionMessage) : "";
|
} else {
|
||||||
|
message.className = Object.getPrototypeOf(e).name;
|
||||||
|
message.message = e.message;
|
||||||
}
|
}
|
||||||
stack += "\n" + stack;
|
message.exception = e;
|
||||||
return stack;
|
message.stack = e.stack;
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,25 +0,0 @@
|
||||||
<!--
|
|
||||||
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.
|
|
||||||
-->
|
|
||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<script type="text/javascript" src="res/junit-client.js"></script>
|
|
||||||
<script type="text/javascript" src="res/runtime.js"></script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
|
@ -1,52 +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.
|
|
||||||
-->
|
|
||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<title>TeaVM JUnit tests</title>
|
|
||||||
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/>
|
|
||||||
<link rel="stylesheet" href="res/junit.css" type="text/css"/>
|
|
||||||
<script type="text/javascript" src="res/junit-support.js"></script>
|
|
||||||
<script type="text/javascript" src="tests/all.js"></script>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<script type="text/javascript">
|
|
||||||
function runTests() {
|
|
||||||
document.getElementById("start-button").disabled = true;
|
|
||||||
server.runAllTests(function() {
|
|
||||||
document.getElementById("start-button").disabled = false;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
<div class="test-header">
|
|
||||||
<div class="test-count">Total tests:
|
|
||||||
<span id="test-count"></span><span id="total-time" class="time-indicator"></span>
|
|
||||||
</div>
|
|
||||||
<div class="failed-test-count">Failed: <span id="failed-test-count"></span></div>
|
|
||||||
<div class="progress-bar">
|
|
||||||
<div id="progress-bar-content"></div>
|
|
||||||
</div>
|
|
||||||
<button id="start-button" onclick="runTests()">Run</button>
|
|
||||||
</div>
|
|
||||||
<div id="test-tree">
|
|
||||||
</div>
|
|
||||||
<div id="test-trace">
|
|
||||||
</div>
|
|
||||||
<script>
|
|
||||||
server = prepare();
|
|
||||||
</script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
Before Width: | Height: | Size: 774 B |
Before Width: | Height: | Size: 297 B |
|
@ -1,78 +0,0 @@
|
||||||
"use strict";
|
|
||||||
var JUnitClient = {};
|
|
||||||
JUnitClient.run = function() {
|
|
||||||
var handler = function(event) {
|
|
||||||
switch (event.data.command) {
|
|
||||||
case "runTest":
|
|
||||||
window.removeEventListener("message", handler);
|
|
||||||
$rt_startThread(function() {
|
|
||||||
JUnitClient.runTest();
|
|
||||||
});
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
window.addEventListener("message", handler);
|
|
||||||
window.parent.postMessage("ready", "*");
|
|
||||||
};
|
|
||||||
JUnitClient.runTest = function() {
|
|
||||||
var thread = $rt_nativeThread();
|
|
||||||
var instance;
|
|
||||||
var ptr = 0;
|
|
||||||
var message;
|
|
||||||
if (thread.isResuming()) {
|
|
||||||
ptr = thread.pop();
|
|
||||||
instance = thread.pop();
|
|
||||||
}
|
|
||||||
loop: while (true) { switch (ptr) {
|
|
||||||
case 0:
|
|
||||||
try {
|
|
||||||
runTest();
|
|
||||||
} catch (e) {
|
|
||||||
message = {};
|
|
||||||
JUnitClient.makeErrorMessage(message, e);
|
|
||||||
break loop;
|
|
||||||
}
|
|
||||||
if (thread.isSuspending()) {
|
|
||||||
thread.push(instance);
|
|
||||||
thread.push(ptr);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
message = {};
|
|
||||||
message.status = "ok";
|
|
||||||
break loop;
|
|
||||||
}}
|
|
||||||
window.parent.postMessage(message, "*");
|
|
||||||
};
|
|
||||||
JUnitClient.makeErrorMessage = function(message, e) {
|
|
||||||
message.status = "exception";
|
|
||||||
var stack = e.stack;
|
|
||||||
if (e.$javaException && e.$javaException.constructor.$meta) {
|
|
||||||
message.exception = e.$javaException.constructor.$meta.name;
|
|
||||||
message.stack = e.$javaException.constructor.$meta.name + ": ";
|
|
||||||
var exceptionMessage = extractException(e.$javaException);
|
|
||||||
message.stack += exceptionMessage ? $rt_ustr(exceptionMessage) : "";
|
|
||||||
}
|
|
||||||
message.stack += "\n" + stack;
|
|
||||||
};
|
|
||||||
JUnitClient.reportError = function(error) {
|
|
||||||
var handler = function() {
|
|
||||||
window.removeEventListener("message", handler);
|
|
||||||
var message = { status : "exception", stack : error };
|
|
||||||
window.parent.postMessage(message, "*");
|
|
||||||
};
|
|
||||||
window.addEventListener("message", handler);
|
|
||||||
};
|
|
||||||
JUnitClient.loadScript = function(scriptPath) {
|
|
||||||
var script = document.createElement("script");
|
|
||||||
script.src = scriptPath;
|
|
||||||
document.body.appendChild(script);
|
|
||||||
};
|
|
||||||
window.addEventListener("message", function(event) {
|
|
||||||
var data = event.data;
|
|
||||||
switch (data.command) {
|
|
||||||
case "loadScript":
|
|
||||||
JUnitClient.loadScript(data.script);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
window.parent.postMessage("loaded", "*");
|
|
|
@ -1,362 +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.
|
|
||||||
*/
|
|
||||||
"use strict";
|
|
||||||
function JUnitServer() {
|
|
||||||
this.tree = new Tree(document.getElementById("test-tree"));
|
|
||||||
this.totalTimeSpent = 0;
|
|
||||||
this.expectedExceptions = [];
|
|
||||||
this.frame = null;
|
|
||||||
this.tests = [];
|
|
||||||
this.currentTestNode = null;
|
|
||||||
this.testCaseCount = 0;
|
|
||||||
this.progressElem = document.getElementById("progress-bar-content");
|
|
||||||
this.runCount = 0;
|
|
||||||
this.failCount = 0;
|
|
||||||
this.traceElem = document.getElementById("test-trace");
|
|
||||||
this.failedElem = document.getElementById("failed-test-count");
|
|
||||||
this.totalTimeElem = document.getElementById("total-time");
|
|
||||||
var self = this;
|
|
||||||
this.tree.addSelectionListener(function(node) {
|
|
||||||
while (self.traceElem.firstChild) {
|
|
||||||
self.traceElem.removeChild(self.traceElem.firstChild);
|
|
||||||
}
|
|
||||||
if (node.error) {
|
|
||||||
var pre = document.createElement("pre");
|
|
||||||
pre.appendChild(document.createTextNode(node.error));
|
|
||||||
self.traceElem.appendChild(pre);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
JUnitServer.prototype = {};
|
|
||||||
JUnitServer.prototype.handleEvent = function(message, callback) {
|
|
||||||
if (message.status === "ok") {
|
|
||||||
if (this.expectedExceptions.length > 0) {
|
|
||||||
this.currentTestNode.success = false;
|
|
||||||
this.currentTestNode.error = "Expected exception not thrown";
|
|
||||||
this.failCount++;
|
|
||||||
} else {
|
|
||||||
this.currentTestNode.success = true;
|
|
||||||
}
|
|
||||||
} else if (message.status === "exception") {
|
|
||||||
if (message.exception && this.isExpectedException(message.exception)) {
|
|
||||||
this.currentTestNode.success = true;
|
|
||||||
} else {
|
|
||||||
this.currentTestNode.success = false;
|
|
||||||
this.currentTestNode.error = message.stack;
|
|
||||||
this.failCount++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.currentTestNode.indicator.className = "complete-indicator " +
|
|
||||||
(this.currentTestNode.success ? "successfull" : "failed");
|
|
||||||
this.runCount++;
|
|
||||||
this.progressElem.style.width = (100 * this.runCount / this.testCaseCount).toFixed(2) + "%";
|
|
||||||
document.body.removeChild(this.frame);
|
|
||||||
self.frame = null;
|
|
||||||
callback();
|
|
||||||
};
|
|
||||||
JUnitServer.prototype.isExpectedException = function(ex) {
|
|
||||||
for (var i = 0; i < this.expectedExceptions.length; ++i) {
|
|
||||||
if (this.expectedExceptions[i] === ex) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
JUnitServer.prototype.loadCode = function(path, additionalScripts, callback) {
|
|
||||||
this.frame = document.createElement("iframe");
|
|
||||||
this.frame.src = "junit-client.html";
|
|
||||||
document.body.appendChild(this.frame);
|
|
||||||
var sequence = [];
|
|
||||||
sequence.push(path);
|
|
||||||
for (var i = 0; i < additionalScripts.length; ++i) {
|
|
||||||
sequence.push(additionalScripts[i]);
|
|
||||||
}
|
|
||||||
var self = this;
|
|
||||||
var handler = function() {
|
|
||||||
window.removeEventListener("message", handler);
|
|
||||||
self.loadScripts(sequence, callback);
|
|
||||||
};
|
|
||||||
window.addEventListener("message", handler);
|
|
||||||
};
|
|
||||||
JUnitServer.prototype.loadScripts = function(scripts, callback) {
|
|
||||||
for (var i = 0; i < scripts.length; ++i) {
|
|
||||||
this.frame.contentWindow.postMessage({ command : "loadScript", "script" : scripts[i] }, "*");
|
|
||||||
}
|
|
||||||
var handler = function() {
|
|
||||||
window.removeEventListener("message", handler);
|
|
||||||
callback();
|
|
||||||
};
|
|
||||||
window.addEventListener("message", handler);
|
|
||||||
};
|
|
||||||
JUnitServer.prototype.runTest = function(node, callback) {
|
|
||||||
node.indicator.className = "complete-indicator in-progress";
|
|
||||||
var startTime = new Date().getTime();
|
|
||||||
if (node.testCase) {
|
|
||||||
this.expectedExceptions = node.testCase.expected;
|
|
||||||
this.currentTestNode = node;
|
|
||||||
var self = this;
|
|
||||||
this.loadCode(node.testCase.script, node.testCase.additionalScripts, function() {
|
|
||||||
function messageHandler(event) {
|
|
||||||
window.removeEventListener("message", messageHandler);
|
|
||||||
var timeSpent = new Date().getTime() - startTime;
|
|
||||||
node.timeIndicator.appendChild(document.createTextNode("(" + (timeSpent / 1000).toFixed(3) + ")"));
|
|
||||||
self.handleEvent(event.data, callback);
|
|
||||||
}
|
|
||||||
window.addEventListener("message", messageHandler);
|
|
||||||
self.frame.contentWindow.postMessage({ command : "runTest" }, "*");
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
var self = this;
|
|
||||||
var nodes = node.getNodes();
|
|
||||||
this.runTestFromList(nodes, 0, function() {
|
|
||||||
node.success = true;
|
|
||||||
for (var i = 0; i < nodes.length; ++i) {
|
|
||||||
if (!nodes[i].success) {
|
|
||||||
node.success = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
node.indicator.className = "complete-indicator " + (node.success ? "successfull" : "failed");
|
|
||||||
if (!node.success) {
|
|
||||||
node.open();
|
|
||||||
}
|
|
||||||
var timeSpent = new Date().getTime() - startTime;
|
|
||||||
node.timeIndicator.appendChild(document.createTextNode(
|
|
||||||
"(" + (timeSpent / 1000).toFixed(3) + ")"));
|
|
||||||
callback();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
JUnitServer.prototype.readTests = function(tests) {
|
|
||||||
var groups = this.groupTests(tests);
|
|
||||||
var groupNames = [];
|
|
||||||
for (var groupName in groups) {
|
|
||||||
groupNames.push(groupName);
|
|
||||||
}
|
|
||||||
groupNames.sort();
|
|
||||||
this.tests = [];
|
|
||||||
for (var i = 0; i < groupNames.length; ++i) {
|
|
||||||
var groupName = groupNames[i];
|
|
||||||
var group = groups[groupName];
|
|
||||||
var pkgNode = this.createNode(this.tree, "package", groupName);
|
|
||||||
group.sort();
|
|
||||||
for (var j = 0; j < group.length; ++j) {
|
|
||||||
var test = group[j];
|
|
||||||
var simpleName = test.name.substring(groupName.length + 1);
|
|
||||||
var testNode = this.createNode(pkgNode, "test", simpleName);
|
|
||||||
var methods = test.methods.slice();
|
|
||||||
methods.sort();
|
|
||||||
for (var k = 0; k < methods.length; ++k) {
|
|
||||||
var method = methods[k];
|
|
||||||
var caseNode = this.createNode(testNode, "case", method.name);
|
|
||||||
caseNode.testCase = method;
|
|
||||||
++this.testCaseCount;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
document.getElementById("test-count").appendChild(document.createTextNode(this.testCaseCount));
|
|
||||||
return this;
|
|
||||||
};
|
|
||||||
JUnitServer.prototype.createNode = function(parent, className, name) {
|
|
||||||
var elem = document.createElement("div");
|
|
||||||
elem.className = className;
|
|
||||||
elem.appendChild(document.createTextNode(name));
|
|
||||||
var node = parent.add(elem);
|
|
||||||
node.indicator = document.createElement("div");
|
|
||||||
node.indicator.className = "complete-indicator";
|
|
||||||
elem.appendChild(node.indicator);
|
|
||||||
node.timeIndicator = document.createElement("span");
|
|
||||||
node.timeIndicator.className = "time-indicator";
|
|
||||||
elem.appendChild(node.timeIndicator);
|
|
||||||
return node;
|
|
||||||
};
|
|
||||||
JUnitServer.prototype.groupTests = function(tests) {
|
|
||||||
var groups = {};
|
|
||||||
for (var i = 0; i < tests.length; ++i) {
|
|
||||||
var test = tests[i];
|
|
||||||
var pkg = test.name.substring(0, test.name.lastIndexOf('.'));
|
|
||||||
var group = groups[pkg];
|
|
||||||
if (!group) {
|
|
||||||
group = [];
|
|
||||||
groups[pkg] = group;
|
|
||||||
}
|
|
||||||
group.push(test);
|
|
||||||
}
|
|
||||||
return groups;
|
|
||||||
};
|
|
||||||
JUnitServer.prototype.runAllTests = function(callback) {
|
|
||||||
this.cleanupTests();
|
|
||||||
var self = this;
|
|
||||||
var startTime = new Date().getTime();
|
|
||||||
this.runTestFromList(this.tree.getNodes(), 0, function() {
|
|
||||||
self.failedElem.appendChild(document.createTextNode(self.failCount));
|
|
||||||
var totalTime = new Date().getTime() - startTime;
|
|
||||||
self.totalTimeElem.appendChild(document.createTextNode("(" +
|
|
||||||
(totalTime / 1000).toFixed(3) + ")"));
|
|
||||||
callback();
|
|
||||||
});
|
|
||||||
};
|
|
||||||
JUnitServer.prototype.runTestFromList = function(nodes, index, callback) {
|
|
||||||
if (index < nodes.length) {
|
|
||||||
var node = nodes[index];
|
|
||||||
var self = this;
|
|
||||||
this.runTest(node, function() {
|
|
||||||
self.runTestFromList(nodes, index + 1, callback);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
callback();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
JUnitServer.prototype.cleanupTests = function() {
|
|
||||||
if (this.failedElem.firstChild) {
|
|
||||||
this.failedElem.removeChild(this.failedElem.firstChild);
|
|
||||||
}
|
|
||||||
if (this.totalTimeElem.firstChild) {
|
|
||||||
this.totalTimeElem.removeChild(this.totalTimeElem.firstChild);
|
|
||||||
}
|
|
||||||
this.runCount = 0;
|
|
||||||
this.failCount = 0;
|
|
||||||
this.progressElem.style.width = "0%";
|
|
||||||
var nodes = this.tree.getNodes();
|
|
||||||
for (var i = 0; i < nodes.length; ++i) {
|
|
||||||
this.cleanupNode(nodes[i]);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
JUnitServer.prototype.cleanupNode = function(node) {
|
|
||||||
delete node.error;
|
|
||||||
node.indicator.className = "complete-indicator";
|
|
||||||
if (node.timeIndicator.firstChild) {
|
|
||||||
node.timeIndicator.removeChild(node.timeIndicator.firstChild);
|
|
||||||
}
|
|
||||||
var nodes = node.getNodes();
|
|
||||||
for (var i = 0; i < nodes.length; ++i) {
|
|
||||||
this.cleanupNode(nodes[i]);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
function Tree(container) {
|
|
||||||
this.container = container;
|
|
||||||
this.nodes = [];
|
|
||||||
this.selectedNode = null;
|
|
||||||
this.selectionListeners = [];
|
|
||||||
}
|
|
||||||
Tree.prototype.createNode = function(content) {
|
|
||||||
var elem = document.createElement("div");
|
|
||||||
elem.className = "tree-node";
|
|
||||||
var contentElem = document.createElement("div");
|
|
||||||
contentElem.className = "tree-node-content";
|
|
||||||
elem.appendChild(contentElem);
|
|
||||||
contentElem.appendChild(content);
|
|
||||||
var buttonElem = document.createElement("div");
|
|
||||||
buttonElem.className = "tree-node-button closed";
|
|
||||||
buttonElem.style.display = "none";
|
|
||||||
elem.appendChild(buttonElem);
|
|
||||||
var childrenElem = document.createElement("div");
|
|
||||||
childrenElem.className = "tree-node-children closed";
|
|
||||||
childrenElem.style.display = "none";
|
|
||||||
elem.appendChild(childrenElem);
|
|
||||||
return new TreeNode(elem, contentElem, buttonElem, childrenElem, this);
|
|
||||||
};
|
|
||||||
Tree.prototype.add = function(content) {
|
|
||||||
var node = this.createNode(content);
|
|
||||||
this.container.appendChild(node.elem);
|
|
||||||
this.nodes.push(node);
|
|
||||||
return node;
|
|
||||||
};
|
|
||||||
Tree.prototype.getNodes = function() {
|
|
||||||
return this.nodes;
|
|
||||||
};
|
|
||||||
Tree.prototype.addSelectionListener = function(listener) {
|
|
||||||
this.selectionListeners.push(listener);
|
|
||||||
};
|
|
||||||
function TreeNode(elem, content, button, children, tree) {
|
|
||||||
this.elem = elem;
|
|
||||||
this.content = content;
|
|
||||||
this.button = button;
|
|
||||||
this.children = children;
|
|
||||||
this.opened = false;
|
|
||||||
this.parent = null;
|
|
||||||
this.nodes = [];
|
|
||||||
this.tree = tree;
|
|
||||||
var self = this;
|
|
||||||
this.button.onclick = function() {
|
|
||||||
self.toggle();
|
|
||||||
};
|
|
||||||
this.content.onclick = function() {
|
|
||||||
self.select();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
TreeNode.prototype.add = function(content) {
|
|
||||||
var node = this.tree.createNode(content);
|
|
||||||
this.children.appendChild(node.elem);
|
|
||||||
this.button.style.display = "";
|
|
||||||
this.children.style.display = "";
|
|
||||||
this.content.className = "tree-node-content";
|
|
||||||
node.parent = this;
|
|
||||||
this.nodes.push(node);
|
|
||||||
return node;
|
|
||||||
};
|
|
||||||
TreeNode.prototype.isOpened = function() {
|
|
||||||
return this.opened;
|
|
||||||
};
|
|
||||||
TreeNode.prototype.open = function() {
|
|
||||||
if (this.isOpened()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.opened = true;
|
|
||||||
this.children.className = "tree-node-children opened";
|
|
||||||
this.button.className = "tree-node-button opened";
|
|
||||||
};
|
|
||||||
TreeNode.prototype.close = function() {
|
|
||||||
if (!this.isOpened()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.opened = false;
|
|
||||||
this.children.className = "tree-node-children closed";
|
|
||||||
this.button.className = "tree-node-button closed";
|
|
||||||
};
|
|
||||||
TreeNode.prototype.toggle = function() {
|
|
||||||
if (this.isOpened()) {
|
|
||||||
this.close();
|
|
||||||
} else {
|
|
||||||
this.open();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
TreeNode.prototype.getNodes = function() {
|
|
||||||
return this.nodes;
|
|
||||||
};
|
|
||||||
TreeNode.prototype.getParent = function() {
|
|
||||||
return this.parent;
|
|
||||||
};
|
|
||||||
TreeNode.prototype.getTree = function() {
|
|
||||||
return this.tree;
|
|
||||||
};
|
|
||||||
TreeNode.prototype.isSelected = function() {
|
|
||||||
return this.tree.selectedNode === this;
|
|
||||||
};
|
|
||||||
TreeNode.prototype.select = function() {
|
|
||||||
if (this.isSelected()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (this.tree.selectedNode != null) {
|
|
||||||
this.tree.selectedNode.content.className = "tree-node-content";
|
|
||||||
}
|
|
||||||
this.content.className = "tree-node-content selected";
|
|
||||||
this.tree.selectedNode = this;
|
|
||||||
for (var i = 0; i < this.tree.selectionListeners.length; ++i) {
|
|
||||||
this.tree.selectionListeners[i](this);
|
|
||||||
}
|
|
||||||
};
|
|
|
@ -1,185 +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.
|
|
||||||
*/
|
|
||||||
iframe {
|
|
||||||
width: 1px;
|
|
||||||
height: 1px;
|
|
||||||
padding: 0;
|
|
||||||
margin: 0;
|
|
||||||
border-style: none;
|
|
||||||
}
|
|
||||||
* {
|
|
||||||
font-family: sans-serif;
|
|
||||||
font-size: 10pt;
|
|
||||||
}
|
|
||||||
html, body {
|
|
||||||
position: absolute;
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
top: 0;
|
|
||||||
bottom: 0;
|
|
||||||
padding: 0;
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
.test-header {
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
right: 0;
|
|
||||||
left: 0;
|
|
||||||
height: 40px;
|
|
||||||
border-bottom-color: gray;
|
|
||||||
border-bottom-width: 1px;
|
|
||||||
border-bottom-style: solid;
|
|
||||||
}
|
|
||||||
.test-count, .failed-test-count {
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
bottom: 0;
|
|
||||||
line-height: 40px;
|
|
||||||
padding: 0;
|
|
||||||
margin: 0;
|
|
||||||
vertical-align: middle;
|
|
||||||
}
|
|
||||||
.test-count {
|
|
||||||
left: 5px;
|
|
||||||
width: 200px;
|
|
||||||
}
|
|
||||||
.failed-test-count {
|
|
||||||
left: 205px;
|
|
||||||
width: 130px;
|
|
||||||
}
|
|
||||||
#start-button {
|
|
||||||
display: block;
|
|
||||||
position: absolute;
|
|
||||||
left: 340px;
|
|
||||||
top: 6px;
|
|
||||||
bottom: 6px;
|
|
||||||
width: 70px;
|
|
||||||
}
|
|
||||||
.progress-bar {
|
|
||||||
position: absolute;
|
|
||||||
left: 420px;
|
|
||||||
right: 20px;
|
|
||||||
top: 5px;
|
|
||||||
height: 30px;
|
|
||||||
border-color: grey;
|
|
||||||
border-radius: 2px;
|
|
||||||
border-width: 1px;
|
|
||||||
border-style: solid;
|
|
||||||
}
|
|
||||||
#progress-bar-content {
|
|
||||||
position: absolute;
|
|
||||||
background-color: green;
|
|
||||||
left: 0;
|
|
||||||
top: 0;
|
|
||||||
bottom: 0;
|
|
||||||
width: 0;
|
|
||||||
}
|
|
||||||
#test-tree {
|
|
||||||
position: absolute;
|
|
||||||
top: 41px;
|
|
||||||
bottom: 0;
|
|
||||||
left: 0;
|
|
||||||
width: 50%;
|
|
||||||
border-right-color: grey;
|
|
||||||
border-right-width: 1px;
|
|
||||||
border-right-style: solid;
|
|
||||||
overflow: auto;
|
|
||||||
}
|
|
||||||
#test-trace {
|
|
||||||
position: absolute;
|
|
||||||
top: 41px;
|
|
||||||
bottom: 0;
|
|
||||||
left: 50%;
|
|
||||||
right: 0;
|
|
||||||
overflow: auto;
|
|
||||||
}
|
|
||||||
.tree-node {
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
.tree-node-content {
|
|
||||||
margin-left: 18px;
|
|
||||||
cursor: default;
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
.tree-node-content.selected {
|
|
||||||
background-color: rgb(160,160,255);
|
|
||||||
}
|
|
||||||
.tree-node-children {
|
|
||||||
padding-left: 18px;
|
|
||||||
}
|
|
||||||
.tree-node-children.closed {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
.tree-node-button {
|
|
||||||
position: absolute;
|
|
||||||
cursor: pointer;
|
|
||||||
left: 0;
|
|
||||||
top: 0;
|
|
||||||
width: 16px;
|
|
||||||
height: 16px;
|
|
||||||
background-repeat: no-repeat;
|
|
||||||
background-position: 0 0;
|
|
||||||
}
|
|
||||||
.tree-node-button.opened {
|
|
||||||
background-image: url(toggle-small.png);
|
|
||||||
}
|
|
||||||
.tree-node-button.closed {
|
|
||||||
background-image: url(toggle-small-expand.png);
|
|
||||||
}
|
|
||||||
.package, .test, .case {
|
|
||||||
min-height: 18px;
|
|
||||||
padding-left: 20px;
|
|
||||||
background-position: 2px 1px;
|
|
||||||
background-repeat: no-repeat;
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
.package {
|
|
||||||
background-image: url(package_obj.png);
|
|
||||||
}
|
|
||||||
.test {
|
|
||||||
background-image: url(class_obj.png);
|
|
||||||
}
|
|
||||||
.case {
|
|
||||||
background-image: url(methpub_obj.png);
|
|
||||||
}
|
|
||||||
.complete-indicator {
|
|
||||||
position: absolute;
|
|
||||||
left: -4px;
|
|
||||||
top: 5px;
|
|
||||||
width: 16px;
|
|
||||||
height: 16px;
|
|
||||||
background-position: 0 0;
|
|
||||||
background-repeat: no-repeat;
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
.complete-indicator.successfull {
|
|
||||||
display: block;
|
|
||||||
background-image: url(tick-small.png);
|
|
||||||
}
|
|
||||||
.complete-indicator.failed {
|
|
||||||
display: block;
|
|
||||||
background-image: url(tick-small-red.png);
|
|
||||||
}
|
|
||||||
.complete-indicator.in-progress {
|
|
||||||
display: block;
|
|
||||||
background-image: url(control-000-small.png);
|
|
||||||
}
|
|
||||||
.time-indicator {
|
|
||||||
font-size: 9pt;
|
|
||||||
font-style: italic;
|
|
||||||
color: rgb(0,80,160);
|
|
||||||
padding-left: 0.5em;
|
|
||||||
}
|
|
Before Width: | Height: | Size: 325 B |
Before Width: | Height: | Size: 345 B |
Before Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 321 B |
Before Width: | Height: | Size: 418 B |
Before Width: | Height: | Size: 394 B |
|
@ -36,15 +36,16 @@ import org.teavm.model.MethodReference;
|
||||||
final class RhinoResultParser {
|
final class RhinoResultParser {
|
||||||
private static Pattern pattern = Pattern.compile("(([A-Za-z_$]+)\\(\\))?@.+:([0-9]+)");
|
private static Pattern pattern = Pattern.compile("(([A-Za-z_$]+)\\(\\))?@.+:([0-9]+)");
|
||||||
private static Pattern lineSeparator = Pattern.compile("\\r\\n|\r|\n");
|
private static Pattern lineSeparator = Pattern.compile("\\r\\n|\r|\n");
|
||||||
private File debugFile;
|
|
||||||
private DebugInformation debugInformation;
|
private DebugInformation debugInformation;
|
||||||
private String[] script;
|
private String[] script;
|
||||||
|
|
||||||
RhinoResultParser(File debugFile) {
|
RhinoResultParser(File debugFile) {
|
||||||
debugInformation = debugFile != null ? getDebugInformation(debugFile) : null;
|
if (debugFile != null) {
|
||||||
|
debugInformation = getDebugInformation(debugFile);
|
||||||
script = getScript(new File(debugFile.getParentFile(),
|
script = getScript(new File(debugFile.getParentFile(),
|
||||||
debugFile.getName().substring(0, debugFile.getName().length() - 9)));
|
debugFile.getName().substring(0, debugFile.getName().length() - 9)));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void parseResult(Scriptable result, TestRunCallback callback) {
|
void parseResult(Scriptable result, TestRunCallback callback) {
|
||||||
if (result == null) {
|
if (result == null) {
|
||||||
|
@ -57,8 +58,6 @@ final class RhinoResultParser {
|
||||||
callback.complete();
|
callback.complete();
|
||||||
break;
|
break;
|
||||||
case "exception": {
|
case "exception": {
|
||||||
DebugInformation debugInformation = debugFile != null ? getDebugInformation(debugFile) : null;
|
|
||||||
|
|
||||||
String className = String.valueOf(result.get("className", result));
|
String className = String.valueOf(result.get("className", result));
|
||||||
if (debugInformation != null) {
|
if (debugInformation != null) {
|
||||||
String decodedName = debugInformation.getClassNameByJsName(className);
|
String decodedName = debugInformation.getClassNameByJsName(className);
|
||||||
|
|
|
@ -57,14 +57,6 @@
|
||||||
<groupId>commons-io</groupId>
|
<groupId>commons-io</groupId>
|
||||||
<artifactId>commons-io</artifactId>
|
<artifactId>commons-io</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
|
||||||
<groupId>org.seleniumhq.selenium</groupId>
|
|
||||||
<artifactId>selenium-java</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.seleniumhq.selenium</groupId>
|
|
||||||
<artifactId>selenium-remote-driver</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.fasterxml.jackson.core</groupId>
|
<groupId>com.fasterxml.jackson.core</groupId>
|
||||||
<artifactId>jackson-databind</artifactId>
|
<artifactId>jackson-databind</artifactId>
|
||||||
|
|