Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ object PrivateLibHolder {
"org/scalajs/linker/runtime/RuntimeLong.sjsir",
"org/scalajs/linker/runtime/RuntimeLong$.sjsir",
"org/scalajs/linker/runtime/UndefinedBehaviorError.sjsir",
"org/scalajs/linker/runtime/WasmRuntime.sjsir",
"org/scalajs/linker/runtime/WasmRuntime$.sjsir",
"scala/scalajs/js/JavaScriptException.sjsir"
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -377,8 +377,6 @@ final class CoreWasmLib(coreSpec: CoreSpec, globalInfo: LinkedGlobalInfo) {
addHelperImport(genFunctionID.uIFallback, List(anyref), List(Int32))
addHelperImport(genFunctionID.typeTest(IntRef), List(anyref), List(Int32))

addHelperImport(genFunctionID.fmod, List(Float64, Float64), List(Float64))

addHelperImport(genFunctionID.jsValueToString, List(RefType.any), List(RefType.extern))
addHelperImport(genFunctionID.jsValueToStringForConcat, List(anyref), List(RefType.extern))
addHelperImport(genFunctionID.booleanToString, List(Int32), List(RefType.extern))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -446,7 +446,11 @@ object Emitter {

// See genIdentityHashCode in HelperFunctions
callMethodStatically(BoxedDoubleClass, hashCodeMethodName),
callMethodStatically(BoxedStringClass, hashCodeMethodName)
callMethodStatically(BoxedStringClass, hashCodeMethodName),

// Implementation of Float_% and Double_%
callStaticMethod(WasmRuntimeClass, fmodfMethodName),
callStaticMethod(WasmRuntimeClass, fmoddMethodName)
)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1648,9 +1648,18 @@ private class FunctionEmitter private (

def genLongShiftOp(shiftInstr: wa.Instr): Type = {
genTree(lhs, LongType)
genTree(rhs, IntType)
markPosition(tree)
fb += wa.I64ExtendI32S
rhs match {
case IntLiteral(r) =>
// common case: fold the extension to 64 bits into the literal
markPosition(rhs)
fb += wa.I64Const(r.toLong)
markPosition(tree)
case _ =>
// otherwise, extend at run-time
genTree(rhs, IntType)
markPosition(tree)
fb += wa.I64ExtendI32S
}
fb += shiftInstr
LongType
}
Expand Down Expand Up @@ -1712,31 +1721,6 @@ private class FunctionEmitter private (
case Long_>> =>
genLongShiftOp(wa.I64ShrS)

/* Floating point remainders are specified by
* https://262.ecma-international.org/#sec-numeric-types-number-remainder
* which says that it is equivalent to the C library function `fmod`.
* For `Float`s, we promote and demote to `Double`s.
* `fmod` seems quite hard to correctly implement, so we delegate to a
* JavaScript Helper.
* (The naive function `x - trunc(x / y) * y` that we can find on the
* Web does not work.)
*/
case Float_% =>
genTree(lhs, FloatType)
fb += wa.F64PromoteF32
genTree(rhs, FloatType)
fb += wa.F64PromoteF32
markPosition(tree)
fb += wa.Call(genFunctionID.fmod)
fb += wa.F32DemoteF64
FloatType
case Double_% =>
genTree(lhs, DoubleType)
genTree(rhs, DoubleType)
markPosition(tree)
fb += wa.Call(genFunctionID.fmod)
DoubleType

case String_charAt =>
genTree(lhs, StringType)
genTree(rhs, IntType)
Expand Down Expand Up @@ -1875,6 +1859,9 @@ private class FunctionEmitter private (
private def getElementaryBinaryOpInstr(op: BinaryOp.Code): wa.Instr = {
import BinaryOp._

def fmodFunctionID(methodName: MethodName): wanme.FunctionID =
genFunctionID.forMethod(MemberNamespace.PublicStatic, SpecialNames.WasmRuntimeClass, methodName)

(op: @switch) match {
case Boolean_== => wa.I32Eq
case Boolean_!= => wa.I32Ne
Expand Down Expand Up @@ -1915,11 +1902,13 @@ private class FunctionEmitter private (
case Float_- => wa.F32Sub
case Float_* => wa.F32Mul
case Float_/ => wa.F32Div
case Float_% => wa.Call(fmodFunctionID(SpecialNames.fmodfMethodName))

case Double_+ => wa.F64Add
case Double_- => wa.F64Sub
case Double_* => wa.F64Mul
case Double_/ => wa.F64Div
case Double_% => wa.Call(fmodFunctionID(SpecialNames.fmoddMethodName))

case Double_== => wa.F64Eq
case Double_!= => wa.F64Ne
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,9 +100,6 @@ const scalaJSHelpers = {
tF: (x) => typeof x === 'number' && (Math.fround(x) === x || x !== x),
tD: (x) => typeof x === 'number',

// fmod, to implement Float_% and Double_% (it is apparently quite hard to implement fmod otherwise)
fmod: (x, y) => x % y,

// Strings
emptyString: "",
jsValueToString: (x) => (x === void 0) ? "undefined" : x.toString(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ object SpecialNames {
val UndefinedBehaviorErrorClass =
ClassName("org.scalajs.linker.runtime.UndefinedBehaviorError")

val WasmRuntimeClass =
ClassName("org.scalajs.linker.runtime.WasmRuntime")

// Field names

val valueFieldSimpleName = SimpleFieldName("value")
Expand All @@ -52,6 +55,9 @@ object SpecialNames {

val hashCodeMethodName = MethodName("hashCode", Nil, IntRef)

val fmodfMethodName = MethodName("fmodf", List(FloatRef, FloatRef), FloatRef)
val fmoddMethodName = MethodName("fmodd", List(DoubleRef, DoubleRef), DoubleRef)

/** A unique simple method name to map all method *signatures* into `MethodName`s. */
val normalizedSimpleMethodName = SimpleMethodName("m")
}
Original file line number Diff line number Diff line change
Expand Up @@ -130,8 +130,6 @@ object VarGen {
case object bIFallback extends JSHelperFunctionID
case object uIFallback extends JSHelperFunctionID

case object fmod extends JSHelperFunctionID

case object jsValueToString extends JSHelperFunctionID // for actual toString() call
case object jsValueToStringForConcat extends JSHelperFunctionID
case object booleanToString extends JSHelperFunctionID
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,8 @@ class DoubleTest {
test(Double.NaN, Double.NaN, 2.1)
test(Double.NaN, Double.NaN, 5.5)
test(Double.NaN, Double.NaN, -151.189)
test(Double.NaN, Double.NaN, 3.123e-320)
test(Double.NaN, Double.NaN, 2.253547e-318)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you add an explanation to the commit message what these additional values are?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. They're subnormals.


// If d is NaN, return NaN
test(Double.NaN, Double.NaN, Double.NaN)
Expand All @@ -231,6 +233,8 @@ class DoubleTest {
test(Double.NaN, 2.1, Double.NaN)
test(Double.NaN, 5.5, Double.NaN)
test(Double.NaN, -151.189, Double.NaN)
test(Double.NaN, 3.123e-320, Double.NaN)
test(Double.NaN, 2.253547e-318, Double.NaN)

// If n is PositiveInfinity, return NaN
test(Double.NaN, Double.PositiveInfinity, Double.PositiveInfinity)
Expand All @@ -240,6 +244,8 @@ class DoubleTest {
test(Double.NaN, Double.PositiveInfinity, 2.1)
test(Double.NaN, Double.PositiveInfinity, 5.5)
test(Double.NaN, Double.PositiveInfinity, -151.189)
test(Double.NaN, Double.PositiveInfinity, 3.123e-320)
test(Double.NaN, Double.PositiveInfinity, 2.253547e-318)

// If n is NegativeInfinity, return NaN
test(Double.NaN, Double.NegativeInfinity, Double.PositiveInfinity)
Expand All @@ -249,56 +255,87 @@ class DoubleTest {
test(Double.NaN, Double.NegativeInfinity, 2.1)
test(Double.NaN, Double.NegativeInfinity, 5.5)
test(Double.NaN, Double.NegativeInfinity, -151.189)
test(Double.NaN, Double.NegativeInfinity, 3.123e-320)
test(Double.NaN, Double.NegativeInfinity, 2.253547e-318)

// If d is PositiveInfinity, return n
test(+0.0, +0.0, Double.PositiveInfinity)
test(-0.0, -0.0, Double.PositiveInfinity)
test(2.1, 2.1, Double.PositiveInfinity)
test(5.5, 5.5, Double.PositiveInfinity)
test(-151.189, -151.189, Double.PositiveInfinity)
test(3.123e-320, 3.123e-320, Double.PositiveInfinity)
test(2.253547e-318, 2.253547e-318, Double.PositiveInfinity)

// If d is NegativeInfinity, return n
test(+0.0, +0.0, Double.NegativeInfinity)
test(-0.0, -0.0, Double.NegativeInfinity)
test(2.1, 2.1, Double.NegativeInfinity)
test(5.5, 5.5, Double.NegativeInfinity)
test(-151.189, -151.189, Double.NegativeInfinity)
test(3.123e-320, 3.123e-320, Double.NegativeInfinity)
test(2.253547e-318, 2.253547e-318, Double.NegativeInfinity)

// If d is +0.0, return NaN
test(Double.NaN, +0.0, +0.0)
test(Double.NaN, -0.0, +0.0)
test(Double.NaN, 2.1, +0.0)
test(Double.NaN, 5.5, +0.0)
test(Double.NaN, -151.189, +0.0)
test(Double.NaN, 3.123e-320, +0.0)
test(Double.NaN, 2.253547e-318, +0.0)

// If d is -0.0, return NaN
test(Double.NaN, +0.0, -0.0)
test(Double.NaN, -0.0, -0.0)
test(Double.NaN, 2.1, -0.0)
test(Double.NaN, 5.5, -0.0)
test(Double.NaN, -151.189, -0.0)
test(Double.NaN, 3.123e-320, -0.0)
test(Double.NaN, 2.253547e-318, -0.0)

// If n is +0.0, return n
test(+0.0, +0.0, 2.1)
test(+0.0, +0.0, 5.5)
test(+0.0, +0.0, -151.189)
test(+0.0, +0.0, 3.123e-320)
test(+0.0, +0.0, 2.253547e-318)

// If n is -0.0, return n
test(-0.0, -0.0, 2.1)
test(-0.0, -0.0, 5.5)
test(-0.0, -0.0, -151.189)
test(-0.0, -0.0, 3.123e-320)
test(-0.0, -0.0, 2.253547e-318)

// Non-special values
// { val l = List(2.1, 5.5, -151.189); for (n <- l; d <- l) println(s" test(${n % d}, $n, $d)") }
// { val l = List(2.1, 5.5, -151.189, 3.123e-320, 2.253547e-318);
// for (n <- l; d <- l) println(s" test(${n % d}, $n, $d)".toLowerCase()) }
test(0.0, 2.1, 2.1)
test(2.1, 2.1, 5.5)
test(2.1, 2.1, -151.189)
test(2.0696e-320, 2.1, 3.123e-320)
test(1.772535e-318, 2.1, 2.253547e-318)
test(1.2999999999999998, 5.5, 2.1)
test(0.0, 5.5, 5.5)
test(5.5, 5.5, -151.189)
test(3.607e-321, 5.5, 3.123e-320)
test(6.8103e-319, 5.5, 2.253547e-318)
test(-2.0889999999999866, -151.189, 2.1)
test(-2.688999999999993, -151.189, 5.5)
test(-0.0, -151.189, -151.189)
test(-1.94e-320, -151.189, 3.123e-320)
test(-4.1349e-319, -151.189, 2.253547e-318)
test(3.123e-320, 3.123e-320, 2.1)
test(3.123e-320, 3.123e-320, 5.5)
test(3.123e-320, 3.123e-320, -151.189)
test(0.0, 3.123e-320, 3.123e-320)
test(3.123e-320, 3.123e-320, 2.253547e-318)
test(2.253547e-318, 2.253547e-318, 2.1)
test(2.253547e-318, 2.253547e-318, 5.5)
test(2.253547e-318, 2.253547e-318, -151.189)
test(4.995e-321, 2.253547e-318, 3.123e-320)
test(0.0, 2.253547e-318, 2.253547e-318)
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,8 @@ class FloatTest {
test(Float.NaN, Float.NaN, 2.1f)
test(Float.NaN, Float.NaN, 5.5f)
test(Float.NaN, Float.NaN, -151.189f)
test(Float.NaN, Float.NaN, 8.858e-42f)
test(Float.NaN, Float.NaN, 6.39164e-40f)

// If d is NaN, return NaN
test(Float.NaN, Float.NaN, Float.NaN)
Expand All @@ -83,6 +85,8 @@ class FloatTest {
test(Float.NaN, 2.1f, Float.NaN)
test(Float.NaN, 5.5f, Float.NaN)
test(Float.NaN, -151.189f, Float.NaN)
test(Float.NaN, 8.858e-42f, Float.NaN)
test(Float.NaN, 6.39164e-40f, Float.NaN)

// If n is PositiveInfinity, return NaN
test(Float.NaN, Float.PositiveInfinity, Float.PositiveInfinity)
Expand All @@ -92,6 +96,8 @@ class FloatTest {
test(Float.NaN, Float.PositiveInfinity, 2.1f)
test(Float.NaN, Float.PositiveInfinity, 5.5f)
test(Float.NaN, Float.PositiveInfinity, -151.189f)
test(Float.NaN, Float.PositiveInfinity, 8.858e-42f)
test(Float.NaN, Float.PositiveInfinity, 6.39164e-40f)

// If n is NegativeInfinity, return NaN
test(Float.NaN, Float.NegativeInfinity, Float.PositiveInfinity)
Expand All @@ -101,56 +107,87 @@ class FloatTest {
test(Float.NaN, Float.NegativeInfinity, 2.1f)
test(Float.NaN, Float.NegativeInfinity, 5.5f)
test(Float.NaN, Float.NegativeInfinity, -151.189f)
test(Float.NaN, Float.NegativeInfinity, 8.858e-42f)
test(Float.NaN, Float.NegativeInfinity, 6.39164e-40f)

// If d is PositiveInfinity, return n
test(+0.0f, +0.0f, Float.PositiveInfinity)
test(-0.0f, -0.0f, Float.PositiveInfinity)
test(2.1f, 2.1f, Float.PositiveInfinity)
test(5.5f, 5.5f, Float.PositiveInfinity)
test(-151.189f, -151.189f, Float.PositiveInfinity)
test(8.858e-42f, 8.858e-42f, Float.PositiveInfinity)
test(6.39164e-40f, 6.39164e-40f, Float.PositiveInfinity)

// If d is NegativeInfinity, return n
test(+0.0f, +0.0f, Float.NegativeInfinity)
test(-0.0f, -0.0f, Float.NegativeInfinity)
test(2.1f, 2.1f, Float.NegativeInfinity)
test(5.5f, 5.5f, Float.NegativeInfinity)
test(-151.189f, -151.189f, Float.NegativeInfinity)
test(8.858e-42f, 8.858e-42f, Float.NegativeInfinity)
test(6.39164e-40f, 6.39164e-40f, Float.NegativeInfinity)

// If d is +0.0, return NaN
test(Float.NaN, +0.0f, +0.0f)
test(Float.NaN, -0.0f, +0.0f)
test(Float.NaN, 2.1f, +0.0f)
test(Float.NaN, 5.5f, +0.0f)
test(Float.NaN, -151.189f, +0.0f)
test(Float.NaN, 8.858e-42f, +0.0f)
test(Float.NaN, 6.39164e-40f, +0.0f)

// If d is -0.0, return NaN
test(Float.NaN, +0.0f, -0.0f)
test(Float.NaN, -0.0f, -0.0f)
test(Float.NaN, 2.1f, -0.0f)
test(Float.NaN, 5.5f, -0.0f)
test(Float.NaN, -151.189f, -0.0f)
test(Float.NaN, 8.858e-42f, -0.0f)
test(Float.NaN, 6.39164e-40f, -0.0f)

// If n is +0.0, return n
test(+0.0f, +0.0f, 2.1f)
test(+0.0f, +0.0f, 5.5f)
test(+0.0f, +0.0f, -151.189f)
test(+0.0f, +0.0f, 8.858e-42f)
test(+0.0f, +0.0f, 6.39164e-40f)

// If n is -0.0, return n
test(-0.0f, -0.0f, 2.1f)
test(-0.0f, -0.0f, 5.5f)
test(-0.0f, -0.0f, -151.189f)
test(-0.0f, -0.0f, 8.858e-42f)
test(-0.0f, -0.0f, 6.39164e-40f)

// Non-special values
// { val l = List(2.1f, 5.5f, -151.189f); for (n <- l; d <- l) println(s" test(${n % d}f, ${n}f, ${d}f)") }
// { val l = List(2.1f, 5.5f, -151.189f, 8.858e-42f, 6.39164e-40f);
// for (n <- l; d <- l) println(s" test(${n % d}f, ${n}f, ${d}f)".toLowerCase()) }
test(0.0f, 2.1f, 2.1f)
test(2.1f, 2.1f, 5.5f)
test(2.1f, 2.1f, -151.189f)
test(8.085e-42f, 2.1f, 8.858e-42f)
test(6.1636e-40f, 2.1f, 6.39164e-40f)
test(1.3000002f, 5.5f, 2.1f)
test(0.0f, 5.5f, 5.5f)
test(5.5f, 5.5f, -151.189f)
test(5.11e-43f, 5.5f, 8.858e-42f)
test(4.77036e-40f, 5.5f, 6.39164e-40f)
test(-2.0890021f, -151.189f, 2.1f)
test(-2.6889954f, -151.189f, 5.5f)
test(-0.0f, -151.189f, -151.189f)
test(-1.139e-42f, -151.189f, 8.858e-42f)
test(-5.64734e-40f, -151.189f, 6.39164e-40f)
test(8.858e-42f, 8.858e-42f, 2.1f)
test(8.858e-42f, 8.858e-42f, 5.5f)
test(8.858e-42f, 8.858e-42f, -151.189f)
test(0.0f, 8.858e-42f, 8.858e-42f)
test(8.858e-42f, 8.858e-42f, 6.39164e-40f)
test(6.39164e-40f, 6.39164e-40f, 2.1f)
test(6.39164e-40f, 6.39164e-40f, 5.5f)
test(6.39164e-40f, 6.39164e-40f, -151.189f)
test(1.417e-42f, 6.39164e-40f, 8.858e-42f)
test(0.0f, 6.39164e-40f, 6.39164e-40f)
}

@Test
Expand Down