1// Copyright 2019 the V8 project authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include 'src/builtins/builtins-bigint-gen.h' 6 7namespace bigint { 8 9const kPositiveSign: uint32 = 0; 10const kNegativeSign: uint32 = 1; 11 12extern macro BigIntBuiltinsAssembler::CppAbsoluteAddAndCanonicalize( 13 MutableBigInt, BigIntBase, BigIntBase): void; 14extern macro BigIntBuiltinsAssembler::CppAbsoluteSubAndCanonicalize( 15 MutableBigInt, BigIntBase, BigIntBase): void; 16extern macro BigIntBuiltinsAssembler::CppAbsoluteCompare( 17 BigIntBase, BigIntBase): int32; 18 19extern macro BigIntBuiltinsAssembler::ReadBigIntSign(BigIntBase): uint32; 20extern macro BigIntBuiltinsAssembler::ReadBigIntLength(BigIntBase): intptr; 21extern macro BigIntBuiltinsAssembler::WriteBigIntSignAndLength( 22 MutableBigInt, uint32, intptr): void; 23 24extern macro CodeStubAssembler::AllocateBigInt(intptr): MutableBigInt; 25extern macro CodeStubAssembler::StoreBigIntDigit( 26 MutableBigInt, intptr, uintptr): void; 27extern macro CodeStubAssembler::LoadBigIntDigit(BigIntBase, intptr): uintptr; 28 29macro IsCanonicalized(bigint: BigIntBase): bool { 30 const length = ReadBigIntLength(bigint); 31 32 if (length == 0) { 33 return ReadBigIntSign(bigint) == kPositiveSign; 34 } 35 36 return LoadBigIntDigit(bigint, length - 1) != 0; 37} 38 39macro InvertSign(sign: uint32): uint32 { 40 return sign == kPositiveSign ? kNegativeSign : kPositiveSign; 41} 42 43macro AllocateEmptyBigIntNoThrow(implicit context: Context)( 44 sign: uint32, length: intptr): MutableBigInt labels BigIntTooBig { 45 if (length > kBigIntMaxLength) { 46 goto BigIntTooBig; 47 } 48 const result: MutableBigInt = AllocateBigInt(length); 49 50 WriteBigIntSignAndLength(result, sign, length); 51 return result; 52} 53 54macro AllocateEmptyBigInt(implicit context: Context)( 55 sign: uint32, length: intptr): MutableBigInt { 56 try { 57 return AllocateEmptyBigIntNoThrow(sign, length) otherwise BigIntTooBig; 58 } label BigIntTooBig { 59 ThrowRangeError(MessageTemplate::kBigIntTooBig); 60 } 61} 62 63macro MutableBigIntAbsoluteCompare(x: BigIntBase, y: BigIntBase): int32 { 64 return CppAbsoluteCompare(x, y); 65} 66 67macro MutableBigIntAbsoluteSub(implicit context: Context)( 68 x: BigInt, y: BigInt, resultSign: uint32): BigInt { 69 const xlength = ReadBigIntLength(x); 70 const ylength = ReadBigIntLength(y); 71 const xsign = ReadBigIntSign(x); 72 73 assert(MutableBigIntAbsoluteCompare(x, y) >= 0); 74 if (xlength == 0) { 75 assert(ylength == 0); 76 return x; 77 } 78 79 if (ylength == 0) { 80 return resultSign == xsign ? x : BigIntUnaryMinus(x); 81 } 82 83 const result = AllocateEmptyBigInt(resultSign, xlength); 84 CppAbsoluteSubAndCanonicalize(result, x, y); 85 return Convert<BigInt>(result); 86} 87 88macro MutableBigIntAbsoluteAdd(implicit context: Context)( 89 xBigint: BigInt, yBigint: BigInt, 90 resultSign: uint32): BigInt labels BigIntTooBig { 91 let xlength = ReadBigIntLength(xBigint); 92 let ylength = ReadBigIntLength(yBigint); 93 94 let x = xBigint; 95 let y = yBigint; 96 if (xlength < ylength) { 97 // Swap x and y so that x is longer. 98 x = yBigint; 99 y = xBigint; 100 const tempLength = xlength; 101 xlength = ylength; 102 ylength = tempLength; 103 } 104 105 // case: 0n + 0n 106 if (xlength == 0) { 107 assert(ylength == 0); 108 return x; 109 } 110 111 // case: x + 0n 112 if (ylength == 0) { 113 return resultSign == ReadBigIntSign(x) ? x : BigIntUnaryMinus(x); 114 } 115 116 // case: x + y 117 const result = AllocateEmptyBigIntNoThrow(resultSign, xlength + 1) 118 otherwise BigIntTooBig; 119 CppAbsoluteAddAndCanonicalize(result, x, y); 120 return Convert<BigInt>(result); 121} 122 123macro BigIntAddImpl(implicit context: Context)(x: BigInt, y: BigInt): BigInt 124 labels BigIntTooBig { 125 const xsign = ReadBigIntSign(x); 126 const ysign = ReadBigIntSign(y); 127 if (xsign == ysign) { 128 // x + y == x + y 129 // -x + -y == -(x + y) 130 return MutableBigIntAbsoluteAdd(x, y, xsign) otherwise BigIntTooBig; 131 } 132 133 // x + -y == x - y == -(y - x) 134 // -x + y == y - x == -(x - y) 135 if (MutableBigIntAbsoluteCompare(x, y) >= 0) { 136 return MutableBigIntAbsoluteSub(x, y, xsign); 137 } 138 return MutableBigIntAbsoluteSub(y, x, InvertSign(xsign)); 139} 140 141builtin BigIntAddNoThrow(implicit context: Context)( 142 x: BigInt, y: BigInt): Numeric { 143 try { 144 return BigIntAddImpl(x, y) otherwise BigIntTooBig; 145 } label BigIntTooBig { 146 // Smi sentinal is used to signal BigIntTooBig exception. 147 return Convert<Smi>(0); 148 } 149} 150 151builtin BigIntAdd(implicit context: Context)( 152 xNum: Numeric, yNum: Numeric): BigInt { 153 try { 154 const x = Cast<BigInt>(xNum) otherwise MixedTypes; 155 const y = Cast<BigInt>(yNum) otherwise MixedTypes; 156 157 return BigIntAddImpl(x, y) otherwise BigIntTooBig; 158 } label MixedTypes { 159 ThrowTypeError(MessageTemplate::kBigIntMixedTypes); 160 } label BigIntTooBig { 161 ThrowRangeError(MessageTemplate::kBigIntTooBig); 162 } 163} 164 165macro BigIntSubtractImpl(implicit context: Context)( 166 x: BigInt, y: BigInt): BigInt labels BigIntTooBig { 167 const xsign = ReadBigIntSign(x); 168 const ysign = ReadBigIntSign(y); 169 if (xsign != ysign) { 170 // x - (-y) == x + y 171 // (-x) - y == -(x + y) 172 return MutableBigIntAbsoluteAdd(x, y, xsign) otherwise BigIntTooBig; 173 } 174 175 // x - y == -(y - x) 176 // (-x) - (-y) == y - x == -(x - y) 177 if (MutableBigIntAbsoluteCompare(x, y) >= 0) { 178 return MutableBigIntAbsoluteSub(x, y, xsign); 179 } 180 return MutableBigIntAbsoluteSub(y, x, InvertSign(xsign)); 181} 182 183builtin BigIntSubtractNoThrow(implicit context: Context)( 184 x: BigInt, y: BigInt): Numeric { 185 try { 186 return BigIntSubtractImpl(x, y) otherwise BigIntTooBig; 187 } label BigIntTooBig { 188 // Smi sentinal is used to signal BigIntTooBig exception. 189 return Convert<Smi>(0); 190 } 191} 192 193builtin BigIntSubtract(implicit context: Context)( 194 xNum: Numeric, yNum: Numeric): BigInt { 195 try { 196 const x = Cast<BigInt>(xNum) otherwise MixedTypes; 197 const y = Cast<BigInt>(yNum) otherwise MixedTypes; 198 199 return BigIntSubtractImpl(x, y) otherwise BigIntTooBig; 200 } label MixedTypes { 201 ThrowTypeError(MessageTemplate::kBigIntMixedTypes); 202 } label BigIntTooBig { 203 ThrowRangeError(MessageTemplate::kBigIntTooBig); 204 } 205} 206 207builtin BigIntUnaryMinus(implicit context: Context)(bigint: BigInt): BigInt { 208 const length = ReadBigIntLength(bigint); 209 210 // There is no -0n. 211 if (length == 0) { 212 return bigint; 213 } 214 215 const result = 216 AllocateEmptyBigInt(InvertSign(ReadBigIntSign(bigint)), length); 217 for (let i: intptr = 0; i < length; ++i) { 218 StoreBigIntDigit(result, i, LoadBigIntDigit(bigint, i)); 219 } 220 return Convert<BigInt>(result); 221} 222 223} // namespace bigint 224