mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 08:14:09 -08:00
Improve float to string conversion
This commit is contained in:
parent
f23c71cd97
commit
2bb146af47
|
@ -130,6 +130,9 @@ public final class DoubleAnalyzer {
|
|||
if (decMantissa >= 1000000000000000000L) {
|
||||
decExponent++;
|
||||
decMantissa /= 10;
|
||||
} else if (decMantissa < 100000000000000000L) {
|
||||
decExponent--;
|
||||
decMantissa *= 10;
|
||||
}
|
||||
|
||||
result.mantissa = decMantissa;
|
||||
|
|
|
@ -0,0 +1,174 @@
|
|||
/*
|
||||
* 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.text;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
public final class FloatAnalyzer {
|
||||
public static final int PRECISION = 9;
|
||||
public static final int MAX_POS = 100000000;
|
||||
|
||||
private static final int MAX_ABS_DEC_EXP = 50;
|
||||
private static final int[] mantissa10Table = new int[MAX_ABS_DEC_EXP * 2];
|
||||
private static final int[] exp10Table = new int[MAX_ABS_DEC_EXP * 2];
|
||||
|
||||
private FloatAnalyzer() {
|
||||
}
|
||||
|
||||
static {
|
||||
int decMantissaOne = 2000000000;
|
||||
|
||||
int mantissa = decMantissaOne;
|
||||
int exponent = 127;
|
||||
|
||||
for (int i = 0; i < MAX_ABS_DEC_EXP; ++i) {
|
||||
mantissa10Table[i + MAX_ABS_DEC_EXP] = Integer.divideUnsigned(mantissa, 20);
|
||||
exp10Table[i + MAX_ABS_DEC_EXP] = exponent;
|
||||
|
||||
mantissa = Integer.divideUnsigned(mantissa, 10);
|
||||
int remainder = Integer.remainderUnsigned(mantissa, 10);
|
||||
while (mantissa <= decMantissaOne && (mantissa & (1 << 31)) == 0) {
|
||||
mantissa <<= 1;
|
||||
exponent++;
|
||||
remainder <<= 1;
|
||||
}
|
||||
mantissa += remainder / 10;
|
||||
}
|
||||
|
||||
int maxMantissa = Integer.MAX_VALUE / 10;
|
||||
mantissa = decMantissaOne;
|
||||
exponent = 127;
|
||||
for (int i = 0; i < MAX_ABS_DEC_EXP; ++i) {
|
||||
int nextMantissa = mantissa;
|
||||
int shift = 0;
|
||||
while (nextMantissa > maxMantissa) {
|
||||
nextMantissa >>= 1;
|
||||
shift++;
|
||||
exponent--;
|
||||
}
|
||||
|
||||
nextMantissa *= 10;
|
||||
if (shift > 0) {
|
||||
long shiftedOffPart = mantissa & ((1 << shift) - 1);
|
||||
nextMantissa += (shiftedOffPart * 10) >> shift;
|
||||
}
|
||||
mantissa = nextMantissa;
|
||||
|
||||
mantissa10Table[MAX_ABS_DEC_EXP - i - 1] = Integer.divideUnsigned(mantissa, 20);
|
||||
exp10Table[MAX_ABS_DEC_EXP - i - 1] = exponent;
|
||||
}
|
||||
}
|
||||
|
||||
public static void analyze(float d, Result result) {
|
||||
int bits = Float.floatToIntBits(d);
|
||||
result.sign = (bits & (1 << 31)) != 0;
|
||||
int mantissa = bits & ((1 << 23) - 1);
|
||||
int exponent = (bits >> 23) & ((1 << 8) - 1);
|
||||
if (mantissa == 0 && exponent == 0) {
|
||||
result.mantissa = 0;
|
||||
result.exponent = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
int errorShift = 0;
|
||||
if (exponent == 0) {
|
||||
mantissa <<= 1;
|
||||
while ((mantissa & (1L << 23)) == 0) {
|
||||
mantissa <<= 1;
|
||||
exponent--;
|
||||
++errorShift;
|
||||
}
|
||||
} else {
|
||||
mantissa |= 1 << 23;
|
||||
}
|
||||
|
||||
int decExponent = Arrays.binarySearch(exp10Table, exponent);
|
||||
if (decExponent < 0) {
|
||||
decExponent = -decExponent - 2;
|
||||
}
|
||||
int binExponentCorrection = exponent - exp10Table[decExponent];
|
||||
int mantissaShift = 9 + binExponentCorrection;
|
||||
|
||||
int decMantissa = (int) (((long) mantissa * mantissa10Table[decExponent]) >>> (32 - mantissaShift));
|
||||
if (decMantissa >= 1000000000) {
|
||||
++decExponent;
|
||||
binExponentCorrection = exponent - exp10Table[decExponent];
|
||||
mantissaShift = 9 + binExponentCorrection;
|
||||
decMantissa = (int) (((long) mantissa * mantissa10Table[decExponent]) >>> (32 - mantissaShift));
|
||||
}
|
||||
|
||||
errorShift = 31 - mantissaShift - errorShift;
|
||||
int error = errorShift >= 0
|
||||
? mantissa10Table[decExponent] >>> errorShift
|
||||
: mantissa10Table[decExponent] << (-errorShift);
|
||||
int upError = (error + 1) >> 1;
|
||||
int downError = error >> 1;
|
||||
if (mantissa == (1 << 22)) {
|
||||
downError >>= 2;
|
||||
}
|
||||
|
||||
int lowerPos = findLowerDistanceToZero(decMantissa, downError);
|
||||
int upperPos = findUpperDistanceToZero(decMantissa, upError);
|
||||
if (lowerPos > upperPos) {
|
||||
decMantissa = (decMantissa / lowerPos) * lowerPos;
|
||||
} else if (lowerPos < upperPos) {
|
||||
decMantissa = (decMantissa / upperPos) * upperPos + upperPos;
|
||||
} else {
|
||||
decMantissa = ((decMantissa + upperPos / 2) / upperPos) * upperPos;
|
||||
}
|
||||
|
||||
if (decMantissa >= 1000000000) {
|
||||
decExponent++;
|
||||
decMantissa /= 10;
|
||||
} else if (decMantissa < 100000000) {
|
||||
decExponent--;
|
||||
decMantissa *= 10;
|
||||
}
|
||||
|
||||
result.mantissa = decMantissa;
|
||||
result.exponent = decExponent - MAX_ABS_DEC_EXP;
|
||||
}
|
||||
|
||||
private static int findLowerDistanceToZero(int mantissa, int error) {
|
||||
int pos = 10;
|
||||
while (pos <= error) {
|
||||
pos *= 10;
|
||||
}
|
||||
int mantissaRight = mantissa % pos;
|
||||
if (mantissaRight >= error / 2) {
|
||||
pos /= 10;
|
||||
}
|
||||
return pos;
|
||||
}
|
||||
|
||||
private static int findUpperDistanceToZero(int mantissa, int error) {
|
||||
int pos = 10;
|
||||
while (pos <= error) {
|
||||
pos *= 10;
|
||||
}
|
||||
int mantissaRight = mantissa % pos;
|
||||
if (pos - mantissaRight > error / 2) {
|
||||
pos /= 10;
|
||||
}
|
||||
return pos;
|
||||
}
|
||||
|
||||
public static class Result {
|
||||
public int mantissa;
|
||||
public int exponent;
|
||||
public boolean sign;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* 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.java.lang;
|
||||
|
||||
import java.io.IOException;
|
||||
import org.teavm.backend.javascript.spi.Injector;
|
||||
import org.teavm.backend.javascript.spi.InjectorContext;
|
||||
import org.teavm.model.MethodReference;
|
||||
|
||||
public class IntegerNativeGenerator implements Injector {
|
||||
@Override
|
||||
public void generate(InjectorContext context, MethodReference methodRef) throws IOException {
|
||||
switch (methodRef.getName()) {
|
||||
case "divideUnsigned":
|
||||
context.getWriter().append("$rt_udiv(");
|
||||
context.writeExpr(context.getArgument(0));
|
||||
context.getWriter().append(",").ws();
|
||||
context.writeExpr(context.getArgument(1));
|
||||
context.getWriter().append(")");
|
||||
break;
|
||||
case "remainderUnsigned":
|
||||
context.getWriter().append("$rt_umod(");
|
||||
context.writeExpr(context.getArgument(0));
|
||||
context.getWriter().append(",").ws();
|
||||
context.writeExpr(context.getArgument(1));
|
||||
context.getWriter().append(")");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -16,13 +16,12 @@
|
|||
package org.teavm.classlib.java.lang;
|
||||
|
||||
import org.teavm.classlib.impl.text.DoubleAnalyzer;
|
||||
import org.teavm.classlib.impl.text.FloatAnalyzer;
|
||||
import org.teavm.classlib.java.io.TSerializable;
|
||||
import org.teavm.classlib.java.util.TArrays;
|
||||
|
||||
class TAbstractStringBuilder extends TObject implements TSerializable, TCharSequence {
|
||||
static class Constants {
|
||||
static float[] powersOfTen = { 1E1f, 1E2f, 1E4f, 1E8f, 1E16f, 1E32f };
|
||||
static float[] negPowersOfTen = { 1E-1f, 1E-2f, 1E-4f, 1E-8f, 1E-16f, 1E-32f };
|
||||
static int[] intPowersOfTen = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000,
|
||||
1000000000 };
|
||||
static long[] longPowersOfTen = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000,
|
||||
|
@ -30,12 +29,8 @@ class TAbstractStringBuilder extends TObject implements TSerializable, TCharSequ
|
|||
1000000000000000L, 10000000000000000L, 100000000000000000L, 1000000000000000000L };
|
||||
static final long[] longLogPowersOfTen = { 1, 10, 100, 10000, 100000000, 10000000000000000L, };
|
||||
|
||||
static final int FLOAT_DECIMAL_PRECISION = 7;
|
||||
static final float FLOAT_DECIMAL_FACTOR = 1E6f;
|
||||
static final int FLOAT_MAX_EXPONENT = 38;
|
||||
static final int FLOAT_MAX_POS = 1000000;
|
||||
|
||||
static final DoubleAnalyzer.Result doubleAnalysisResult = new DoubleAnalyzer.Result();
|
||||
static final FloatAnalyzer.Result floatAnalysisResult = new FloatAnalyzer.Result();
|
||||
}
|
||||
|
||||
char[] buffer;
|
||||
|
@ -225,54 +220,21 @@ class TAbstractStringBuilder extends TObject implements TSerializable, TCharSequ
|
|||
buffer[target++] = 'y';
|
||||
return this;
|
||||
}
|
||||
// Get absolute value
|
||||
boolean negative = false;
|
||||
|
||||
FloatAnalyzer.Result number = Constants.floatAnalysisResult;
|
||||
FloatAnalyzer.analyze(value, number);
|
||||
int mantissa = number.mantissa;
|
||||
int exp = number.exponent;
|
||||
boolean negative = number.sign;
|
||||
int intPart = 1;
|
||||
int sz = 1; // Decimal point always included
|
||||
if (value < 0) {
|
||||
if (negative) {
|
||||
negative = true;
|
||||
value = -value;
|
||||
++sz; // including '-' sign of mantissa
|
||||
}
|
||||
|
||||
// Split into decimal mantissa and decimal exponent
|
||||
int exp = 0;
|
||||
int mantissa = 0;
|
||||
int intPart = 1;
|
||||
int digits = 0;
|
||||
if (value >= 1) {
|
||||
int bit = 32;
|
||||
exp = 0;
|
||||
float digit = 1;
|
||||
for (int i = Constants.powersOfTen.length - 1; i >= 0; --i) {
|
||||
if ((exp | bit) <= Constants.FLOAT_MAX_EXPONENT && Constants.powersOfTen[i] * digit <= value) {
|
||||
digit *= Constants.powersOfTen[i];
|
||||
exp |= bit;
|
||||
}
|
||||
bit >>= 1;
|
||||
}
|
||||
mantissa = (int) ((value / (digit / Constants.FLOAT_DECIMAL_FACTOR)) + 0.5f);
|
||||
} else {
|
||||
int bit = 32;
|
||||
exp = 0;
|
||||
float digit = 1;
|
||||
for (int i = Constants.negPowersOfTen.length - 1; i >= 0; --i) {
|
||||
if ((exp | bit) <= 38 && Constants.negPowersOfTen[i] * digit * 10 > value) {
|
||||
digit *= Constants.negPowersOfTen[i];
|
||||
exp |= bit;
|
||||
}
|
||||
bit >>= 1;
|
||||
}
|
||||
exp = -exp;
|
||||
mantissa = (int) (((value * Constants.FLOAT_MAX_POS) / digit) + 0.5f);
|
||||
|
||||
while (mantissa >= 10000000) {
|
||||
mantissa /= 10;
|
||||
exp--;
|
||||
}
|
||||
}
|
||||
|
||||
// Remove trailing zeros
|
||||
digits = Constants.FLOAT_DECIMAL_PRECISION;
|
||||
int digits = FloatAnalyzer.PRECISION;
|
||||
int zeros = trailingDecimalZeros(mantissa);
|
||||
if (zeros > 0) {
|
||||
digits -= zeros;
|
||||
|
@ -312,7 +274,7 @@ class TAbstractStringBuilder extends TObject implements TSerializable, TCharSequ
|
|||
if (negative) {
|
||||
buffer[target++] = '-';
|
||||
}
|
||||
int pos = Constants.FLOAT_MAX_POS;
|
||||
int pos = FloatAnalyzer.MAX_POS;
|
||||
for (int i = 0; i < digits; ++i) {
|
||||
int intDigit;
|
||||
if (pos > 0) {
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
package org.teavm.classlib.java.lang;
|
||||
|
||||
import static org.teavm.classlib.impl.IntegerUtil.toUnsignedLogRadixString;
|
||||
import org.teavm.backend.javascript.spi.InjectedBy;
|
||||
|
||||
public class TInteger extends TNumber implements TComparable<TInteger> {
|
||||
public static final int SIZE = 32;
|
||||
|
@ -353,4 +354,10 @@ public class TInteger extends TNumber implements TComparable<TInteger> {
|
|||
public static int signum(int i) {
|
||||
return (i >> 31) | (-i >>> 31);
|
||||
}
|
||||
|
||||
@InjectedBy(IntegerNativeGenerator.class)
|
||||
public static native int divideUnsigned(int dividend, int divisor);
|
||||
|
||||
@InjectedBy(IntegerNativeGenerator.class)
|
||||
public static native int remainderUnsigned(int dividend, int divisor);
|
||||
}
|
||||
|
|
|
@ -47,6 +47,7 @@ import org.teavm.backend.c.intrinsic.AllocatorIntrinsic;
|
|||
import org.teavm.backend.c.intrinsic.ExceptionHandlingIntrinsic;
|
||||
import org.teavm.backend.c.intrinsic.FunctionIntrinsic;
|
||||
import org.teavm.backend.c.intrinsic.GCIntrinsic;
|
||||
import org.teavm.backend.c.intrinsic.IntegerIntrinsic;
|
||||
import org.teavm.backend.c.intrinsic.Intrinsic;
|
||||
import org.teavm.backend.c.intrinsic.IntrinsicFactory;
|
||||
import org.teavm.backend.c.intrinsic.LongIntrinsic;
|
||||
|
@ -236,6 +237,7 @@ public class CTarget implements TeaVMTarget, TeaVMCHost {
|
|||
intrinsics.add(new FunctionIntrinsic(characteristics, exportDependencyListener.getResolvedMethods()));
|
||||
intrinsics.add(new RuntimeClassIntrinsic());
|
||||
intrinsics.add(new LongIntrinsic());
|
||||
intrinsics.add(new IntegerIntrinsic());
|
||||
|
||||
List<Generator> generators = new ArrayList<>();
|
||||
generators.add(new ArrayGenerator());
|
||||
|
|
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
* 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.backend.c.intrinsic;
|
||||
|
||||
import org.teavm.ast.InvocationExpr;
|
||||
import org.teavm.model.MethodReference;
|
||||
|
||||
public class IntegerIntrinsic implements Intrinsic {
|
||||
@Override
|
||||
public boolean canHandle(MethodReference method) {
|
||||
if (!method.getClassName().equals(Integer.class.getName())) {
|
||||
return false;
|
||||
}
|
||||
switch (method.getName()) {
|
||||
case "divideUnsigned":
|
||||
case "remainderUnsigned":
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void apply(IntrinsicContext context, InvocationExpr invocation) {
|
||||
switch (invocation.getMethod().getName()) {
|
||||
case "divideUnsigned":
|
||||
writeBinary(context, invocation, "/");
|
||||
break;
|
||||
case "remainderUnsigned":
|
||||
writeBinary(context, invocation, "%");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void writeBinary(IntrinsicContext context, InvocationExpr invocation, String operation) {
|
||||
context.writer().print("((int32_t) ((uint32_t) ");
|
||||
context.emit(invocation.getArguments().get(0));
|
||||
context.writer().print(" " + operation + " (uint32_t) ");
|
||||
context.emit(invocation.getArguments().get(1));
|
||||
context.writer().print("))");
|
||||
}
|
||||
}
|
|
@ -694,7 +694,12 @@ public class StatementRenderer implements ExprVisitor, StatementVisitor {
|
|||
visitBinary(expr, "-", expr.getType() == OperationType.INT);
|
||||
break;
|
||||
case MULTIPLY:
|
||||
if (expr.getType() != OperationType.INT || isSmallInteger(expr.getFirstOperand())
|
||||
|| isSmallInteger(expr.getSecondOperand())) {
|
||||
visitBinary(expr, "*", expr.getType() == OperationType.INT);
|
||||
} else {
|
||||
visitBinaryFunction(expr, naming.getNameForFunction("$rt_imul"));
|
||||
}
|
||||
break;
|
||||
case DIVIDE:
|
||||
visitBinary(expr, "/", expr.getType() == OperationType.INT);
|
||||
|
@ -759,6 +764,20 @@ public class StatementRenderer implements ExprVisitor, StatementVisitor {
|
|||
}
|
||||
}
|
||||
|
||||
private static boolean isSmallInteger(Expr expr) {
|
||||
if (!(expr instanceof ConstantExpr)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Object constant = ((ConstantExpr) expr).getValue();
|
||||
if (!(constant instanceof Integer)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int value = (Integer) constant;
|
||||
return Math.abs(value) < (1 << 18);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(UnaryExpr expr) {
|
||||
try {
|
||||
|
|
|
@ -49,6 +49,7 @@ import org.teavm.backend.wasm.intrinsics.ExceptionHandlingIntrinsic;
|
|||
import org.teavm.backend.wasm.intrinsics.FloatIntrinsic;
|
||||
import org.teavm.backend.wasm.intrinsics.FunctionIntrinsic;
|
||||
import org.teavm.backend.wasm.intrinsics.GCIntrinsic;
|
||||
import org.teavm.backend.wasm.intrinsics.IntegerIntrinsic;
|
||||
import org.teavm.backend.wasm.intrinsics.LongIntrinsic;
|
||||
import org.teavm.backend.wasm.intrinsics.MutatorIntrinsic;
|
||||
import org.teavm.backend.wasm.intrinsics.ObjectIntrinsic;
|
||||
|
@ -345,6 +346,7 @@ public class WasmTarget implements TeaVMTarget, TeaVMWasmHost {
|
|||
context.addIntrinsic(new FloatIntrinsic());
|
||||
context.addIntrinsic(new DoubleIntrinsic());
|
||||
context.addIntrinsic(new LongIntrinsic());
|
||||
context.addIntrinsic(new IntegerIntrinsic());
|
||||
context.addIntrinsic(new ObjectIntrinsic());
|
||||
context.addGenerator(new ArrayGenerator());
|
||||
|
||||
|
|
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* 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.backend.wasm.intrinsics;
|
||||
|
||||
import org.teavm.ast.InvocationExpr;
|
||||
import org.teavm.backend.wasm.model.expression.WasmExpression;
|
||||
import org.teavm.backend.wasm.model.expression.WasmIntBinary;
|
||||
import org.teavm.backend.wasm.model.expression.WasmIntBinaryOperation;
|
||||
import org.teavm.backend.wasm.model.expression.WasmIntType;
|
||||
import org.teavm.model.MethodReference;
|
||||
|
||||
public class IntegerIntrinsic implements WasmIntrinsic {
|
||||
@Override
|
||||
public boolean isApplicable(MethodReference methodReference) {
|
||||
if (!methodReference.getClassName().equals(Integer.class.getName())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (methodReference.getName()) {
|
||||
case "divideUnsigned":
|
||||
case "remainderUnsigned":
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public WasmExpression apply(InvocationExpr invocation, WasmIntrinsicManager manager) {
|
||||
switch (invocation.getMethod().getName()) {
|
||||
case "divideUnsigned":
|
||||
return new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.DIV_UNSIGNED,
|
||||
manager.generate(invocation.getArguments().get(0)),
|
||||
manager.generate(invocation.getArguments().get(1)));
|
||||
case "remainderUnsigned":
|
||||
return new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.REM_UNSIGNED,
|
||||
manager.generate(invocation.getArguments().get(0)),
|
||||
manager.generate(invocation.getArguments().get(1)));
|
||||
default:
|
||||
throw new AssertionError();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -623,3 +623,29 @@ function Long_toNumber(val) {
|
|||
}
|
||||
return 0x100000000 * hi + lo;
|
||||
}
|
||||
|
||||
var $rt_imul = Math.imul || function(a, b) {
|
||||
var ah = (a >>> 16) & 0xFFFF;
|
||||
var al = a & 0xFFFF;
|
||||
var bh = (b >>> 16) & 0xFFFF;
|
||||
var bl = b & 0xFFFF;
|
||||
return (al * bl + (((ah * bl + al * bh) << 16) >>> 0)) | 0;
|
||||
};
|
||||
var $rt_udiv = function(a, b) {
|
||||
if (a < 0) {
|
||||
a += 0x100000000;
|
||||
}
|
||||
if (b < 0) {
|
||||
b += 0x100000000;
|
||||
}
|
||||
return (a / b) | 0;
|
||||
};
|
||||
var $rt_umod = function(a, b) {
|
||||
if (a < 0) {
|
||||
a += 0x100000000;
|
||||
}
|
||||
if (b < 0) {
|
||||
b += 0x100000000;
|
||||
}
|
||||
return (a % b) | 0;
|
||||
};
|
|
@ -164,8 +164,8 @@ public class StringBuilderTest {
|
|||
@Test
|
||||
public void minFloatAppended() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(1.175494E-38f);
|
||||
assertEquals("1.175494E-38", sb.toString());
|
||||
sb.append(1.17549E-38f);
|
||||
assertEquals("1.17549E-38", sb.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
Loading…
Reference in New Issue
Block a user