%PDF- %PDF-
Direktori : /home/vacivi36/vittasync.vacivitta.com.br/vittasync/node/deps/v8/src/builtins/ |
Current File : /home/vacivi36/vittasync.vacivitta.com.br/vittasync/node/deps/v8/src/builtins/builtins-bigint.tq |
// Copyright 2019 the V8 project authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include 'src/builtins/builtins-bigint-gen.h' namespace bigint { const kPositiveSign: uint32 = 0; const kNegativeSign: uint32 = 1; const kGreaterThan: intptr = 1; const kLessThan: intptr = -1; const kMustRoundDownBitShift: uint32 = 30; extern macro BigIntBuiltinsAssembler::CppAbsoluteAddAndCanonicalize( MutableBigInt, BigIntBase, BigIntBase): void; extern macro BigIntBuiltinsAssembler::CppAbsoluteSubAndCanonicalize( MutableBigInt, BigIntBase, BigIntBase): void; extern macro BigIntBuiltinsAssembler::CppAbsoluteMulAndCanonicalize( MutableBigInt, BigIntBase, BigIntBase): int32; extern macro BigIntBuiltinsAssembler::CppAbsoluteDivAndCanonicalize( MutableBigInt, BigIntBase, BigIntBase): int32; extern macro BigIntBuiltinsAssembler::CppAbsoluteModAndCanonicalize( MutableBigInt, BigIntBase, BigIntBase): int32; extern macro BigIntBuiltinsAssembler::CppBitwiseAndPosPosAndCanonicalize( MutableBigInt, BigIntBase, BigIntBase): void; extern macro BigIntBuiltinsAssembler::CppBitwiseAndNegNegAndCanonicalize( MutableBigInt, BigIntBase, BigIntBase): void; extern macro BigIntBuiltinsAssembler::CppBitwiseAndPosNegAndCanonicalize( MutableBigInt, BigIntBase, BigIntBase): void; extern macro BigIntBuiltinsAssembler::CppBitwiseOrPosPosAndCanonicalize( MutableBigInt, BigIntBase, BigIntBase): void; extern macro BigIntBuiltinsAssembler::CppBitwiseOrNegNegAndCanonicalize( MutableBigInt, BigIntBase, BigIntBase): void; extern macro BigIntBuiltinsAssembler::CppBitwiseOrPosNegAndCanonicalize( MutableBigInt, BigIntBase, BigIntBase): void; extern macro BigIntBuiltinsAssembler::CppBitwiseXorPosPosAndCanonicalize( MutableBigInt, BigIntBase, BigIntBase): void; extern macro BigIntBuiltinsAssembler::CppBitwiseXorNegNegAndCanonicalize( MutableBigInt, BigIntBase, BigIntBase): void; extern macro BigIntBuiltinsAssembler::CppBitwiseXorPosNegAndCanonicalize( MutableBigInt, BigIntBase, BigIntBase): void; extern macro BigIntBuiltinsAssembler::CppLeftShiftAndCanonicalize( MutableBigInt, BigIntBase, intptr): void; extern macro BigIntBuiltinsAssembler::CppRightShiftResultLength( BigIntBase, uint32, intptr): uint32; extern macro BigIntBuiltinsAssembler::CppRightShiftAndCanonicalize( MutableBigInt, BigIntBase, intptr, uint32): void; extern macro BigIntBuiltinsAssembler::CppAbsoluteCompare( BigIntBase, BigIntBase): int32; extern macro BigIntBuiltinsAssembler::ReadBigIntSign(BigIntBase): uint32; extern macro BigIntBuiltinsAssembler::ReadBigIntLength(BigIntBase): intptr; extern macro BigIntBuiltinsAssembler::WriteBigIntSignAndLength( MutableBigInt, uint32, intptr): void; extern macro CodeStubAssembler::AllocateBigInt(intptr): MutableBigInt; extern macro CodeStubAssembler::AllocateRawBigInt(intptr): MutableBigInt; extern macro CodeStubAssembler::StoreBigIntDigit( MutableBigInt, intptr, uintptr): void; extern macro CodeStubAssembler::LoadBigIntDigit(BigIntBase, intptr): uintptr; macro IsCanonicalized(bigint: BigIntBase): bool { const length = ReadBigIntLength(bigint); if (length == 0) { return ReadBigIntSign(bigint) == kPositiveSign; } return LoadBigIntDigit(bigint, length - 1) != 0; } macro InvertSign(sign: uint32): uint32 { return sign == kPositiveSign ? kNegativeSign : kPositiveSign; } macro AllocateEmptyBigIntNoThrow( implicit context: Context)(sign: uint32, length: intptr): MutableBigInt labels BigIntTooBig { if (length > kBigIntMaxLength) { goto BigIntTooBig; } const result: MutableBigInt = AllocateRawBigInt(length); WriteBigIntSignAndLength(result, sign, length); return result; } macro AllocateEmptyBigInt( implicit context: Context)(sign: uint32, length: intptr): MutableBigInt { try { return AllocateEmptyBigIntNoThrow(sign, length) otherwise BigIntTooBig; } label BigIntTooBig { ThrowRangeError(MessageTemplate::kBigIntTooBig); } } macro MutableBigIntAbsoluteCompare(x: BigIntBase, y: BigIntBase): int32 { return CppAbsoluteCompare(x, y); } macro MutableBigIntAbsoluteSub( implicit context: Context)(x: BigInt, y: BigInt, resultSign: uint32): BigInt { const xlength = ReadBigIntLength(x); const ylength = ReadBigIntLength(y); const xsign = ReadBigIntSign(x); dcheck(MutableBigIntAbsoluteCompare(x, y) >= 0); if (xlength == 0) { dcheck(ylength == 0); return x; } if (ylength == 0) { return resultSign == xsign ? x : BigIntUnaryMinus(x); } const result = AllocateEmptyBigInt(resultSign, xlength); CppAbsoluteSubAndCanonicalize(result, x, y); return Convert<BigInt>(result); } macro MutableBigIntAbsoluteAdd( implicit context: Context)(xBigint: BigInt, yBigint: BigInt, resultSign: uint32): BigInt labels BigIntTooBig { let xlength = ReadBigIntLength(xBigint); let ylength = ReadBigIntLength(yBigint); let x = xBigint; let y = yBigint; if (xlength < ylength) { // Swap x and y so that x is longer. x = yBigint; y = xBigint; const tempLength = xlength; xlength = ylength; ylength = tempLength; } // case: 0n + 0n if (xlength == 0) { dcheck(ylength == 0); return x; } // case: x + 0n if (ylength == 0) { return resultSign == ReadBigIntSign(x) ? x : BigIntUnaryMinus(x); } // case: x + y const result = AllocateEmptyBigIntNoThrow(resultSign, xlength + 1) otherwise BigIntTooBig; CppAbsoluteAddAndCanonicalize(result, x, y); return Convert<BigInt>(result); } macro BigIntAddImpl(implicit context: Context)(x: BigInt, y: BigInt): BigInt labels BigIntTooBig { const xsign = ReadBigIntSign(x); const ysign = ReadBigIntSign(y); if (xsign == ysign) { // x + y == x + y // -x + -y == -(x + y) return MutableBigIntAbsoluteAdd(x, y, xsign) otherwise BigIntTooBig; } // x + -y == x - y == -(y - x) // -x + y == y - x == -(x - y) if (MutableBigIntAbsoluteCompare(x, y) >= 0) { return MutableBigIntAbsoluteSub(x, y, xsign); } return MutableBigIntAbsoluteSub(y, x, InvertSign(xsign)); } builtin BigIntAddNoThrow(implicit context: Context)(x: BigInt, y: BigInt): Numeric { try { return BigIntAddImpl(x, y) otherwise BigIntTooBig; } label BigIntTooBig { // Smi sentinal is used to signal BigIntTooBig exception. return Convert<Smi>(0); } } builtin BigIntAdd(implicit context: Context)(xNum: Numeric, yNum: Numeric): BigInt { try { const x = Cast<BigInt>(xNum) otherwise MixedTypes; const y = Cast<BigInt>(yNum) otherwise MixedTypes; return BigIntAddImpl(x, y) otherwise BigIntTooBig; } label MixedTypes { ThrowTypeError(MessageTemplate::kBigIntMixedTypes); } label BigIntTooBig { ThrowRangeError(MessageTemplate::kBigIntTooBig); } } macro BigIntSubtractImpl(implicit context: Context)(x: BigInt, y: BigInt): BigInt labels BigIntTooBig { const xsign = ReadBigIntSign(x); const ysign = ReadBigIntSign(y); if (xsign != ysign) { // x - (-y) == x + y // (-x) - y == -(x + y) return MutableBigIntAbsoluteAdd(x, y, xsign) otherwise BigIntTooBig; } // x - y == -(y - x) // (-x) - (-y) == y - x == -(x - y) if (MutableBigIntAbsoluteCompare(x, y) >= 0) { return MutableBigIntAbsoluteSub(x, y, xsign); } return MutableBigIntAbsoluteSub(y, x, InvertSign(xsign)); } builtin BigIntSubtractNoThrow( implicit context: Context)(x: BigInt, y: BigInt): Numeric { try { return BigIntSubtractImpl(x, y) otherwise BigIntTooBig; } label BigIntTooBig { // Smi sentinal is used to signal BigIntTooBig exception. return Convert<Smi>(0); } } builtin BigIntSubtract( implicit context: Context)(xNum: Numeric, yNum: Numeric): BigInt { try { const x = Cast<BigInt>(xNum) otherwise MixedTypes; const y = Cast<BigInt>(yNum) otherwise MixedTypes; return BigIntSubtractImpl(x, y) otherwise BigIntTooBig; } label MixedTypes { ThrowTypeError(MessageTemplate::kBigIntMixedTypes); } label BigIntTooBig { ThrowRangeError(MessageTemplate::kBigIntTooBig); } } macro BigIntMultiplyImpl(implicit context: Context)(x: BigInt, y: BigInt): BigInt labels BigIntTooBig, TerminationRequested { const xlength = ReadBigIntLength(x); const ylength = ReadBigIntLength(y); // case: 0n * y if (xlength == 0) { return x; } // case: x * 0n if (ylength == 0) { return y; } // case: x * y const xsign = ReadBigIntSign(x); const ysign = ReadBigIntSign(y); const resultSign = (xsign != ysign) ? kNegativeSign : kPositiveSign; const result = AllocateEmptyBigIntNoThrow(resultSign, xlength + ylength) otherwise BigIntTooBig; if (CppAbsoluteMulAndCanonicalize(result, x, y) == 1) { goto TerminationRequested; } return Convert<BigInt>(result); } builtin BigIntMultiplyNoThrow( implicit context: Context)(x: BigInt, y: BigInt): Numeric { try { return BigIntMultiplyImpl(x, y) otherwise BigIntTooBig, TerminationRequested; } label BigIntTooBig { // Smi sentinel 0 is used to signal BigIntTooBig exception. return Convert<Smi>(0); } label TerminationRequested { // Smi sentinel 1 is used to signal TerminateExecution exception. return Convert<Smi>(1); } } builtin BigIntMultiply( implicit context: Context)(xNum: Numeric, yNum: Numeric): BigInt { try { const x = Cast<BigInt>(xNum) otherwise MixedTypes; const y = Cast<BigInt>(yNum) otherwise MixedTypes; return BigIntMultiplyImpl(x, y) otherwise BigIntTooBig, TerminationRequested; } label MixedTypes { ThrowTypeError(MessageTemplate::kBigIntMixedTypes); } label BigIntTooBig { ThrowRangeError(MessageTemplate::kBigIntTooBig); } label TerminationRequested { TerminateExecution(); } } macro BigIntDivideImpl(implicit context: Context)(x: BigInt, y: BigInt): BigInt labels BigIntDivZero, TerminationRequested { const xlength = ReadBigIntLength(x); const ylength = ReadBigIntLength(y); // case: x / 0n if (ylength == 0) { goto BigIntDivZero; } // case: x / y, where x < y if (MutableBigIntAbsoluteCompare(x, y) < 0) { const zero = AllocateEmptyBigInt(kPositiveSign, 0); return Convert<BigInt>(zero); } // case: x / 1n const xsign = ReadBigIntSign(x); const ysign = ReadBigIntSign(y); const resultSign = (xsign != ysign) ? kNegativeSign : kPositiveSign; if (ylength == 1 && LoadBigIntDigit(y, 0) == 1) { return resultSign == xsign ? x : BigIntUnaryMinus(x); } // case: x / y let resultLength = xlength - ylength + 1; // This implies a *very* conservative estimate that kBarrettThreshold > 10. if (ylength > 10) resultLength++; const result = AllocateEmptyBigIntNoThrow(resultSign, resultLength) otherwise unreachable; if (CppAbsoluteDivAndCanonicalize(result, x, y) == 1) { goto TerminationRequested; } return Convert<BigInt>(result); } builtin BigIntDivideNoThrow(implicit context: Context)(x: BigInt, y: BigInt): Numeric { try { return BigIntDivideImpl(x, y) otherwise BigIntDivZero, TerminationRequested; } label BigIntDivZero { // Smi sentinel 0 is used to signal BigIntDivZero exception. return Convert<Smi>(0); } label TerminationRequested { // Smi sentinel 1 is used to signal TerminateExecution exception. return Convert<Smi>(1); } } builtin BigIntDivide(implicit context: Context)(xNum: Numeric, yNum: Numeric): BigInt { try { const x = Cast<BigInt>(xNum) otherwise MixedTypes; const y = Cast<BigInt>(yNum) otherwise MixedTypes; return BigIntDivideImpl(x, y) otherwise BigIntDivZero, TerminationRequested; } label MixedTypes { ThrowTypeError(MessageTemplate::kBigIntMixedTypes); } label BigIntDivZero { ThrowRangeError(MessageTemplate::kBigIntDivZero); } label TerminationRequested { TerminateExecution(); } } macro BigIntModulusImpl(implicit context: Context)(x: BigInt, y: BigInt): BigInt labels BigIntDivZero, TerminationRequested { const ylength = ReadBigIntLength(y); // case: x % 0n if (ylength == 0) { goto BigIntDivZero; } // case: x % y, where x < y if (MutableBigIntAbsoluteCompare(x, y) < 0) { return x; } // case: x % 1n or x % -1n if (ylength == 1 && LoadBigIntDigit(y, 0) == 1) { const zero = AllocateEmptyBigInt(kPositiveSign, 0); return Convert<BigInt>(zero); } // case: x % y const resultSign = ReadBigIntSign(x); const resultLength = ylength; const result = AllocateEmptyBigIntNoThrow(resultSign, resultLength) otherwise unreachable; if (CppAbsoluteModAndCanonicalize(result, x, y) == 1) { goto TerminationRequested; } return Convert<BigInt>(result); } builtin BigIntModulusNoThrow(implicit context: Context)(x: BigInt, y: BigInt): Numeric { try { return BigIntModulusImpl(x, y) otherwise BigIntDivZero, TerminationRequested; } label BigIntDivZero { // Smi sentinel 0 is used to signal BigIntDivZero exception. return Convert<Smi>(0); } label TerminationRequested { // Smi sentinel 1 is used to signal TerminateExecution exception. return Convert<Smi>(1); } } builtin BigIntModulus( implicit context: Context)(xNum: Numeric, yNum: Numeric): BigInt { try { const x = Cast<BigInt>(xNum) otherwise MixedTypes; const y = Cast<BigInt>(yNum) otherwise MixedTypes; return BigIntModulusImpl(x, y) otherwise BigIntDivZero, TerminationRequested; } label MixedTypes { ThrowTypeError(MessageTemplate::kBigIntMixedTypes); } label BigIntDivZero { ThrowRangeError(MessageTemplate::kBigIntDivZero); } label TerminationRequested { TerminateExecution(); } } macro BigIntBitwiseAndImpl(implicit context: Context)(x: BigInt, y: BigInt): BigInt labels BigIntTooBig { const xlength = ReadBigIntLength(x); const ylength = ReadBigIntLength(y); // case: 0n & y if (xlength == 0) { return x; } // case: x & 0n if (ylength == 0) { return y; } const xsign = ReadBigIntSign(x); const ysign = ReadBigIntSign(y); if (xsign == kPositiveSign && ysign == kPositiveSign) { const resultLength = (xlength < ylength) ? xlength : ylength; const result = AllocateEmptyBigIntNoThrow(kPositiveSign, resultLength) otherwise unreachable; CppBitwiseAndPosPosAndCanonicalize(result, x, y); return Convert<BigInt>(result); } else if (xsign == kNegativeSign && ysign == kNegativeSign) { const resultLength = ((xlength > ylength) ? xlength : ylength) + 1; const result = AllocateEmptyBigIntNoThrow(kNegativeSign, resultLength) otherwise BigIntTooBig; CppBitwiseAndNegNegAndCanonicalize(result, x, y); return Convert<BigInt>(result); } else if (xsign == kPositiveSign && ysign == kNegativeSign) { const result = AllocateEmptyBigIntNoThrow(kPositiveSign, xlength) otherwise unreachable; CppBitwiseAndPosNegAndCanonicalize(result, x, y); return Convert<BigInt>(result); } else { const result = AllocateEmptyBigIntNoThrow(kPositiveSign, ylength) otherwise unreachable; CppBitwiseAndPosNegAndCanonicalize(result, y, x); return Convert<BigInt>(result); } } builtin BigIntBitwiseAndNoThrow( implicit context: Context)(x: BigInt, y: BigInt): Numeric { try { return BigIntBitwiseAndImpl(x, y) otherwise BigIntTooBig; } label BigIntTooBig { // Smi sentinel 0 is used to signal BigIntTooBig exception. return Convert<Smi>(0); } } builtin BigIntBitwiseAnd( implicit context: Context)(xNum: Numeric, yNum: Numeric): BigInt { try { const x = Cast<BigInt>(xNum) otherwise MixedTypes; const y = Cast<BigInt>(yNum) otherwise MixedTypes; return BigIntBitwiseAndImpl(x, y) otherwise BigIntTooBig; } label MixedTypes { ThrowTypeError(MessageTemplate::kBigIntMixedTypes); } label BigIntTooBig { ThrowRangeError(MessageTemplate::kBigIntTooBig); } } macro BigIntBitwiseOrImpl(implicit context: Context)(x: BigInt, y: BigInt): BigInt { const xlength = ReadBigIntLength(x); const ylength = ReadBigIntLength(y); // case: 0n | y if (xlength == 0) { return y; } // case: x | 0n if (ylength == 0) { return x; } const xsign = ReadBigIntSign(x); const ysign = ReadBigIntSign(y); const resultLength = (xlength > ylength) ? xlength : ylength; if (xsign == kPositiveSign && ysign == kPositiveSign) { const result = AllocateEmptyBigIntNoThrow(kPositiveSign, resultLength) otherwise unreachable; CppBitwiseOrPosPosAndCanonicalize(result, x, y); return Convert<BigInt>(result); } else if (xsign == kNegativeSign && ysign == kNegativeSign) { const result = AllocateEmptyBigIntNoThrow(kNegativeSign, resultLength) otherwise unreachable; CppBitwiseOrNegNegAndCanonicalize(result, x, y); return Convert<BigInt>(result); } else if (xsign == kPositiveSign && ysign == kNegativeSign) { const result = AllocateEmptyBigIntNoThrow(kNegativeSign, resultLength) otherwise unreachable; CppBitwiseOrPosNegAndCanonicalize(result, x, y); return Convert<BigInt>(result); } else { const result = AllocateEmptyBigIntNoThrow(kNegativeSign, resultLength) otherwise unreachable; CppBitwiseOrPosNegAndCanonicalize(result, y, x); return Convert<BigInt>(result); } } builtin BigIntBitwiseOrNoThrow( implicit context: Context)(x: BigInt, y: BigInt): Numeric { return BigIntBitwiseOrImpl(x, y); } builtin BigIntBitwiseOr( implicit context: Context)(xNum: Numeric, yNum: Numeric): BigInt { try { const x = Cast<BigInt>(xNum) otherwise MixedTypes; const y = Cast<BigInt>(yNum) otherwise MixedTypes; return BigIntBitwiseOrImpl(x, y); } label MixedTypes { ThrowTypeError(MessageTemplate::kBigIntMixedTypes); } } macro BigIntBitwiseXorImpl(implicit context: Context)(x: BigInt, y: BigInt): BigInt labels BigIntTooBig { const xlength = ReadBigIntLength(x); const ylength = ReadBigIntLength(y); // case: 0n ^ y if (xlength == 0) { return y; } // case: x ^ 0n if (ylength == 0) { return x; } const xsign = ReadBigIntSign(x); const ysign = ReadBigIntSign(y); if (xsign == kPositiveSign && ysign == kPositiveSign) { const resultLength = (xlength > ylength) ? xlength : ylength; const result = AllocateEmptyBigIntNoThrow(kPositiveSign, resultLength) otherwise unreachable; CppBitwiseXorPosPosAndCanonicalize(result, x, y); return Convert<BigInt>(result); } else if (xsign == kNegativeSign && ysign == kNegativeSign) { const resultLength = (xlength > ylength) ? xlength : ylength; const result = AllocateEmptyBigIntNoThrow(kPositiveSign, resultLength) otherwise unreachable; CppBitwiseXorNegNegAndCanonicalize(result, x, y); return Convert<BigInt>(result); } else if (xsign == kPositiveSign && ysign == kNegativeSign) { const resultLength = ((xlength > ylength) ? xlength : ylength) + 1; const result = AllocateEmptyBigIntNoThrow(kNegativeSign, resultLength) otherwise BigIntTooBig; CppBitwiseXorPosNegAndCanonicalize(result, x, y); return Convert<BigInt>(result); } else { const resultLength = ((xlength > ylength) ? xlength : ylength) + 1; const result = AllocateEmptyBigIntNoThrow(kNegativeSign, resultLength) otherwise BigIntTooBig; CppBitwiseXorPosNegAndCanonicalize(result, y, x); return Convert<BigInt>(result); } } builtin BigIntBitwiseXorNoThrow( implicit context: Context)(x: BigInt, y: BigInt): Numeric { try { return BigIntBitwiseXorImpl(x, y) otherwise BigIntTooBig; } label BigIntTooBig { // Smi sentinel 0 is used to signal BigIntTooBig exception. return Convert<Smi>(0); } } builtin BigIntBitwiseXor( implicit context: Context)(xNum: Numeric, yNum: Numeric): BigInt { try { const x = Cast<BigInt>(xNum) otherwise MixedTypes; const y = Cast<BigInt>(yNum) otherwise MixedTypes; return BigIntBitwiseXorImpl(x, y) otherwise BigIntTooBig; } label MixedTypes { ThrowTypeError(MessageTemplate::kBigIntMixedTypes); } label BigIntTooBig { ThrowRangeError(MessageTemplate::kBigIntTooBig); } } macro MutableBigIntLeftShiftByAbsolute( implicit context: Context)(x: BigInt, y: BigInt): BigInt labels BigIntTooBig { const xlength = ReadBigIntLength(x); const ylength = ReadBigIntLength(y); // case: 0n << y if (xlength == 0) { return x; } // case: x << 0n if (ylength == 0) { return x; } if (ylength > 1) { // Depends on kBigIntMaxLengthBits <= (1 << kBigIntDigitSize). goto BigIntTooBig; } const shiftAbs = LoadBigIntDigit(y, 0); if (shiftAbs > kBigIntMaxLengthBits) { goto BigIntTooBig; } // {shift} is positive. const shift = Convert<intptr>(shiftAbs); let resultLength = xlength + shift / kBigIntDigitBits; const bitsShift = shift % kBigIntDigitBits; const xmsd = LoadBigIntDigit(x, xlength - 1); if (bitsShift != 0 && xmsd >>> Convert<uintptr>(kBigIntDigitBits - bitsShift) != 0) { resultLength++; } const result = AllocateEmptyBigIntNoThrow(ReadBigIntSign(x), resultLength) otherwise BigIntTooBig; CppLeftShiftAndCanonicalize(result, x, shift); return Convert<BigInt>(result); } macro RightShiftByMaximum(implicit context: Context)(sign: uint32): BigInt { if (sign == kNegativeSign) { const minusOne = AllocateEmptyBigInt(kNegativeSign, 1); StoreBigIntDigit(minusOne, 0, 1); return Convert<BigInt>(minusOne); } else { return Convert<BigInt>(AllocateEmptyBigInt(kPositiveSign, 0)); } } macro MutableBigIntRightShiftByAbsolute( implicit context: Context)(x: BigInt, y: BigInt): BigInt { const xlength = ReadBigIntLength(x); const ylength = ReadBigIntLength(y); // case: 0n >> y if (xlength == 0) { return x; } // case: x >> 0n if (ylength == 0) { return x; } const sign = ReadBigIntSign(x); if (ylength > 1) { // Depends on kBigIntMaxLengthBits <= (1 << kBigIntDigitSize). return RightShiftByMaximum(sign); } const shiftAbs = LoadBigIntDigit(y, 0); if (shiftAbs > kBigIntMaxLengthBits) { return RightShiftByMaximum(sign); } // {shift} is positive. const shift = Convert<intptr>(shiftAbs); const returnVal = CppRightShiftResultLength(x, sign, shift); const mustRoundDown = returnVal >>> kMustRoundDownBitShift; const lengthMask = (1 << kMustRoundDownBitShift) - 1; const resultLength = Convert<intptr>(returnVal & lengthMask); if (resultLength == 0) { return RightShiftByMaximum(sign); } const result = AllocateEmptyBigIntNoThrow(sign, resultLength) otherwise unreachable; CppRightShiftAndCanonicalize(result, x, shift, mustRoundDown); return Convert<BigInt>(result); } macro BigIntShiftLeftImpl(implicit context: Context)(x: BigInt, y: BigInt): BigInt labels BigIntTooBig { if (ReadBigIntSign(y) == kNegativeSign) { return MutableBigIntRightShiftByAbsolute(x, y); } else { return MutableBigIntLeftShiftByAbsolute(x, y) otherwise BigIntTooBig; } } macro BigIntShiftRightImpl(implicit context: Context)(x: BigInt, y: BigInt): BigInt labels BigIntTooBig { if (ReadBigIntSign(y) == kNegativeSign) { return MutableBigIntLeftShiftByAbsolute(x, y) otherwise BigIntTooBig; } else { return MutableBigIntRightShiftByAbsolute(x, y); } } builtin BigIntShiftLeftNoThrow( implicit context: Context)(x: BigInt, y: BigInt): Numeric { try { return BigIntShiftLeftImpl(x, y) otherwise BigIntTooBig; } label BigIntTooBig { // Smi sentinel 0 is used to signal BigIntTooBig exception. return Convert<Smi>(0); } } builtin BigIntShiftLeft( implicit context: Context)(xNum: Numeric, yNum: Numeric): BigInt { try { const x = Cast<BigInt>(xNum) otherwise MixedTypes; const y = Cast<BigInt>(yNum) otherwise MixedTypes; return BigIntShiftLeftImpl(x, y) otherwise BigIntTooBig; } label MixedTypes { ThrowTypeError(MessageTemplate::kBigIntMixedTypes); } label BigIntTooBig { ThrowRangeError(MessageTemplate::kBigIntTooBig); } } builtin BigIntShiftRightNoThrow( implicit context: Context)(x: BigInt, y: BigInt): Numeric { try { return BigIntShiftRightImpl(x, y) otherwise BigIntTooBig; } label BigIntTooBig { // Smi sentinel 0 is used to signal BigIntTooBig exception. return Convert<Smi>(0); } } builtin BigIntShiftRight( implicit context: Context)(xNum: Numeric, yNum: Numeric): BigInt { try { const x = Cast<BigInt>(xNum) otherwise MixedTypes; const y = Cast<BigInt>(yNum) otherwise MixedTypes; return BigIntShiftRightImpl(x, y) otherwise BigIntTooBig; } label MixedTypes { ThrowTypeError(MessageTemplate::kBigIntMixedTypes); } label BigIntTooBig { ThrowRangeError(MessageTemplate::kBigIntTooBig); } } builtin BigIntEqual(implicit context: Context)(x: BigInt, y: BigInt): Boolean { if (ReadBigIntSign(x) != ReadBigIntSign(y)) { return False; } const xlength = ReadBigIntLength(x); const ylength = ReadBigIntLength(y); if (xlength != ylength) { return False; } for (let i: intptr = 0; i < xlength; ++i) { if (LoadBigIntDigit(x, i) != LoadBigIntDigit(y, i)) { return False; } } return True; } // Returns r such that r < 0 if |x| < |y|; r > 0 if |x| > |y|; // r == 0 if |x| == |y|. macro BigIntCompareAbsolute( implicit context: Context)(x: BigInt, y: BigInt): intptr { const xlength = ReadBigIntLength(x); const ylength = ReadBigIntLength(y); const diff = xlength - ylength; if (diff != 0) { return diff; } // case: {xlength} == {ylength} for (let i: intptr = xlength - 1; i >= 0; --i) { const xdigit = LoadBigIntDigit(x, i); const ydigit = LoadBigIntDigit(y, i); if (xdigit != ydigit) { return (xdigit > ydigit) ? kGreaterThan : kLessThan; } } return 0; } // Returns r such that r < 0 if x < y; r > 0 if x > y; r == 0 if x == y. macro BigIntCompare(implicit context: Context)(x: BigInt, y: BigInt): intptr { const xsign = ReadBigIntSign(x); const ysign = ReadBigIntSign(y); if (xsign != ysign) { return xsign == kPositiveSign ? kGreaterThan : kLessThan; } // case: {xsign} == {ysign} const diff = BigIntCompareAbsolute(x, y); return xsign == kPositiveSign ? diff : 0 - diff; } builtin BigIntLessThan(implicit context: Context)(x: BigInt, y: BigInt): Boolean { return BigIntCompare(x, y) < 0 ? True : False; } builtin BigIntGreaterThan(implicit context: Context)(x: BigInt, y: BigInt): Boolean { return BigIntCompare(x, y) > 0 ? True : False; } builtin BigIntLessThanOrEqual( implicit context: Context)(x: BigInt, y: BigInt): Boolean { return BigIntCompare(x, y) <= 0 ? True : False; } builtin BigIntGreaterThanOrEqual( implicit context: Context)(x: BigInt, y: BigInt): Boolean { return BigIntCompare(x, y) >= 0 ? True : False; } builtin BigIntUnaryMinus(implicit context: Context)(bigint: BigInt): BigInt { const length = ReadBigIntLength(bigint); // There is no -0n. if (length == 0) { return bigint; } const result = AllocateEmptyBigInt(InvertSign(ReadBigIntSign(bigint)), length); for (let i: intptr = 0; i < length; ++i) { StoreBigIntDigit(result, i, LoadBigIntDigit(bigint, i)); } return Convert<BigInt>(result); } } // namespace bigint