11cb0ef41Sopenharmony_ci// Copyright 2019 the V8 project authors. All rights reserved.
21cb0ef41Sopenharmony_ci// Use of this source code is governed by a BSD-style license that can be
31cb0ef41Sopenharmony_ci// found in the LICENSE file.
41cb0ef41Sopenharmony_ci
51cb0ef41Sopenharmony_ci#include 'src/builtins/builtins-bigint-gen.h'
61cb0ef41Sopenharmony_ci
71cb0ef41Sopenharmony_cinamespace bigint {
81cb0ef41Sopenharmony_ci
91cb0ef41Sopenharmony_ciconst kPositiveSign: uint32 = 0;
101cb0ef41Sopenharmony_ciconst kNegativeSign: uint32 = 1;
111cb0ef41Sopenharmony_ci
121cb0ef41Sopenharmony_ciextern macro BigIntBuiltinsAssembler::CppAbsoluteAddAndCanonicalize(
131cb0ef41Sopenharmony_ci    MutableBigInt, BigIntBase, BigIntBase): void;
141cb0ef41Sopenharmony_ciextern macro BigIntBuiltinsAssembler::CppAbsoluteSubAndCanonicalize(
151cb0ef41Sopenharmony_ci    MutableBigInt, BigIntBase, BigIntBase): void;
161cb0ef41Sopenharmony_ciextern macro BigIntBuiltinsAssembler::CppAbsoluteCompare(
171cb0ef41Sopenharmony_ci    BigIntBase, BigIntBase): int32;
181cb0ef41Sopenharmony_ci
191cb0ef41Sopenharmony_ciextern macro BigIntBuiltinsAssembler::ReadBigIntSign(BigIntBase): uint32;
201cb0ef41Sopenharmony_ciextern macro BigIntBuiltinsAssembler::ReadBigIntLength(BigIntBase): intptr;
211cb0ef41Sopenharmony_ciextern macro BigIntBuiltinsAssembler::WriteBigIntSignAndLength(
221cb0ef41Sopenharmony_ci    MutableBigInt, uint32, intptr): void;
231cb0ef41Sopenharmony_ci
241cb0ef41Sopenharmony_ciextern macro CodeStubAssembler::AllocateBigInt(intptr): MutableBigInt;
251cb0ef41Sopenharmony_ciextern macro CodeStubAssembler::StoreBigIntDigit(
261cb0ef41Sopenharmony_ci    MutableBigInt, intptr, uintptr): void;
271cb0ef41Sopenharmony_ciextern macro CodeStubAssembler::LoadBigIntDigit(BigIntBase, intptr): uintptr;
281cb0ef41Sopenharmony_ci
291cb0ef41Sopenharmony_cimacro IsCanonicalized(bigint: BigIntBase): bool {
301cb0ef41Sopenharmony_ci  const length = ReadBigIntLength(bigint);
311cb0ef41Sopenharmony_ci
321cb0ef41Sopenharmony_ci  if (length == 0) {
331cb0ef41Sopenharmony_ci    return ReadBigIntSign(bigint) == kPositiveSign;
341cb0ef41Sopenharmony_ci  }
351cb0ef41Sopenharmony_ci
361cb0ef41Sopenharmony_ci  return LoadBigIntDigit(bigint, length - 1) != 0;
371cb0ef41Sopenharmony_ci}
381cb0ef41Sopenharmony_ci
391cb0ef41Sopenharmony_cimacro InvertSign(sign: uint32): uint32 {
401cb0ef41Sopenharmony_ci  return sign == kPositiveSign ? kNegativeSign : kPositiveSign;
411cb0ef41Sopenharmony_ci}
421cb0ef41Sopenharmony_ci
431cb0ef41Sopenharmony_cimacro AllocateEmptyBigIntNoThrow(implicit context: Context)(
441cb0ef41Sopenharmony_ci    sign: uint32, length: intptr): MutableBigInt labels BigIntTooBig {
451cb0ef41Sopenharmony_ci  if (length > kBigIntMaxLength) {
461cb0ef41Sopenharmony_ci    goto BigIntTooBig;
471cb0ef41Sopenharmony_ci  }
481cb0ef41Sopenharmony_ci  const result: MutableBigInt = AllocateBigInt(length);
491cb0ef41Sopenharmony_ci
501cb0ef41Sopenharmony_ci  WriteBigIntSignAndLength(result, sign, length);
511cb0ef41Sopenharmony_ci  return result;
521cb0ef41Sopenharmony_ci}
531cb0ef41Sopenharmony_ci
541cb0ef41Sopenharmony_cimacro AllocateEmptyBigInt(implicit context: Context)(
551cb0ef41Sopenharmony_ci    sign: uint32, length: intptr): MutableBigInt {
561cb0ef41Sopenharmony_ci  try {
571cb0ef41Sopenharmony_ci    return AllocateEmptyBigIntNoThrow(sign, length) otherwise BigIntTooBig;
581cb0ef41Sopenharmony_ci  } label BigIntTooBig {
591cb0ef41Sopenharmony_ci    ThrowRangeError(MessageTemplate::kBigIntTooBig);
601cb0ef41Sopenharmony_ci  }
611cb0ef41Sopenharmony_ci}
621cb0ef41Sopenharmony_ci
631cb0ef41Sopenharmony_cimacro MutableBigIntAbsoluteCompare(x: BigIntBase, y: BigIntBase): int32 {
641cb0ef41Sopenharmony_ci  return CppAbsoluteCompare(x, y);
651cb0ef41Sopenharmony_ci}
661cb0ef41Sopenharmony_ci
671cb0ef41Sopenharmony_cimacro MutableBigIntAbsoluteSub(implicit context: Context)(
681cb0ef41Sopenharmony_ci    x: BigInt, y: BigInt, resultSign: uint32): BigInt {
691cb0ef41Sopenharmony_ci  const xlength = ReadBigIntLength(x);
701cb0ef41Sopenharmony_ci  const ylength = ReadBigIntLength(y);
711cb0ef41Sopenharmony_ci  const xsign = ReadBigIntSign(x);
721cb0ef41Sopenharmony_ci
731cb0ef41Sopenharmony_ci  dcheck(MutableBigIntAbsoluteCompare(x, y) >= 0);
741cb0ef41Sopenharmony_ci  if (xlength == 0) {
751cb0ef41Sopenharmony_ci    dcheck(ylength == 0);
761cb0ef41Sopenharmony_ci    return x;
771cb0ef41Sopenharmony_ci  }
781cb0ef41Sopenharmony_ci
791cb0ef41Sopenharmony_ci  if (ylength == 0) {
801cb0ef41Sopenharmony_ci    return resultSign == xsign ? x : BigIntUnaryMinus(x);
811cb0ef41Sopenharmony_ci  }
821cb0ef41Sopenharmony_ci
831cb0ef41Sopenharmony_ci  const result = AllocateEmptyBigInt(resultSign, xlength);
841cb0ef41Sopenharmony_ci  CppAbsoluteSubAndCanonicalize(result, x, y);
851cb0ef41Sopenharmony_ci  return Convert<BigInt>(result);
861cb0ef41Sopenharmony_ci}
871cb0ef41Sopenharmony_ci
881cb0ef41Sopenharmony_cimacro MutableBigIntAbsoluteAdd(implicit context: Context)(
891cb0ef41Sopenharmony_ci    xBigint: BigInt, yBigint: BigInt,
901cb0ef41Sopenharmony_ci    resultSign: uint32): BigInt labels BigIntTooBig {
911cb0ef41Sopenharmony_ci  let xlength = ReadBigIntLength(xBigint);
921cb0ef41Sopenharmony_ci  let ylength = ReadBigIntLength(yBigint);
931cb0ef41Sopenharmony_ci
941cb0ef41Sopenharmony_ci  let x = xBigint;
951cb0ef41Sopenharmony_ci  let y = yBigint;
961cb0ef41Sopenharmony_ci  if (xlength < ylength) {
971cb0ef41Sopenharmony_ci    // Swap x and y so that x is longer.
981cb0ef41Sopenharmony_ci    x = yBigint;
991cb0ef41Sopenharmony_ci    y = xBigint;
1001cb0ef41Sopenharmony_ci    const tempLength = xlength;
1011cb0ef41Sopenharmony_ci    xlength = ylength;
1021cb0ef41Sopenharmony_ci    ylength = tempLength;
1031cb0ef41Sopenharmony_ci  }
1041cb0ef41Sopenharmony_ci
1051cb0ef41Sopenharmony_ci  // case: 0n + 0n
1061cb0ef41Sopenharmony_ci  if (xlength == 0) {
1071cb0ef41Sopenharmony_ci    dcheck(ylength == 0);
1081cb0ef41Sopenharmony_ci    return x;
1091cb0ef41Sopenharmony_ci  }
1101cb0ef41Sopenharmony_ci
1111cb0ef41Sopenharmony_ci  // case: x + 0n
1121cb0ef41Sopenharmony_ci  if (ylength == 0) {
1131cb0ef41Sopenharmony_ci    return resultSign == ReadBigIntSign(x) ? x : BigIntUnaryMinus(x);
1141cb0ef41Sopenharmony_ci  }
1151cb0ef41Sopenharmony_ci
1161cb0ef41Sopenharmony_ci  // case: x + y
1171cb0ef41Sopenharmony_ci  const result = AllocateEmptyBigIntNoThrow(resultSign, xlength + 1)
1181cb0ef41Sopenharmony_ci      otherwise BigIntTooBig;
1191cb0ef41Sopenharmony_ci  CppAbsoluteAddAndCanonicalize(result, x, y);
1201cb0ef41Sopenharmony_ci  return Convert<BigInt>(result);
1211cb0ef41Sopenharmony_ci}
1221cb0ef41Sopenharmony_ci
1231cb0ef41Sopenharmony_cimacro BigIntAddImpl(implicit context: Context)(x: BigInt, y: BigInt): BigInt
1241cb0ef41Sopenharmony_ci    labels BigIntTooBig {
1251cb0ef41Sopenharmony_ci  const xsign = ReadBigIntSign(x);
1261cb0ef41Sopenharmony_ci  const ysign = ReadBigIntSign(y);
1271cb0ef41Sopenharmony_ci  if (xsign == ysign) {
1281cb0ef41Sopenharmony_ci    // x + y == x + y
1291cb0ef41Sopenharmony_ci    // -x + -y == -(x + y)
1301cb0ef41Sopenharmony_ci    return MutableBigIntAbsoluteAdd(x, y, xsign) otherwise BigIntTooBig;
1311cb0ef41Sopenharmony_ci  }
1321cb0ef41Sopenharmony_ci
1331cb0ef41Sopenharmony_ci  // x + -y == x - y == -(y - x)
1341cb0ef41Sopenharmony_ci  // -x + y == y - x == -(x - y)
1351cb0ef41Sopenharmony_ci  if (MutableBigIntAbsoluteCompare(x, y) >= 0) {
1361cb0ef41Sopenharmony_ci    return MutableBigIntAbsoluteSub(x, y, xsign);
1371cb0ef41Sopenharmony_ci  }
1381cb0ef41Sopenharmony_ci  return MutableBigIntAbsoluteSub(y, x, InvertSign(xsign));
1391cb0ef41Sopenharmony_ci}
1401cb0ef41Sopenharmony_ci
1411cb0ef41Sopenharmony_cibuiltin BigIntAddNoThrow(implicit context: Context)(
1421cb0ef41Sopenharmony_ci    x: BigInt, y: BigInt): Numeric {
1431cb0ef41Sopenharmony_ci  try {
1441cb0ef41Sopenharmony_ci    return BigIntAddImpl(x, y) otherwise BigIntTooBig;
1451cb0ef41Sopenharmony_ci  } label BigIntTooBig {
1461cb0ef41Sopenharmony_ci    // Smi sentinal is used to signal BigIntTooBig exception.
1471cb0ef41Sopenharmony_ci    return Convert<Smi>(0);
1481cb0ef41Sopenharmony_ci  }
1491cb0ef41Sopenharmony_ci}
1501cb0ef41Sopenharmony_ci
1511cb0ef41Sopenharmony_cibuiltin BigIntAdd(implicit context: Context)(
1521cb0ef41Sopenharmony_ci    xNum: Numeric, yNum: Numeric): BigInt {
1531cb0ef41Sopenharmony_ci  try {
1541cb0ef41Sopenharmony_ci    const x = Cast<BigInt>(xNum) otherwise MixedTypes;
1551cb0ef41Sopenharmony_ci    const y = Cast<BigInt>(yNum) otherwise MixedTypes;
1561cb0ef41Sopenharmony_ci
1571cb0ef41Sopenharmony_ci    return BigIntAddImpl(x, y) otherwise BigIntTooBig;
1581cb0ef41Sopenharmony_ci  } label MixedTypes {
1591cb0ef41Sopenharmony_ci    ThrowTypeError(MessageTemplate::kBigIntMixedTypes);
1601cb0ef41Sopenharmony_ci  } label BigIntTooBig {
1611cb0ef41Sopenharmony_ci    ThrowRangeError(MessageTemplate::kBigIntTooBig);
1621cb0ef41Sopenharmony_ci  }
1631cb0ef41Sopenharmony_ci}
1641cb0ef41Sopenharmony_ci
1651cb0ef41Sopenharmony_cimacro BigIntSubtractImpl(implicit context: Context)(
1661cb0ef41Sopenharmony_ci    x: BigInt, y: BigInt): BigInt labels BigIntTooBig {
1671cb0ef41Sopenharmony_ci  const xsign = ReadBigIntSign(x);
1681cb0ef41Sopenharmony_ci  const ysign = ReadBigIntSign(y);
1691cb0ef41Sopenharmony_ci  if (xsign != ysign) {
1701cb0ef41Sopenharmony_ci    // x - (-y) == x + y
1711cb0ef41Sopenharmony_ci    // (-x) - y == -(x + y)
1721cb0ef41Sopenharmony_ci    return MutableBigIntAbsoluteAdd(x, y, xsign) otherwise BigIntTooBig;
1731cb0ef41Sopenharmony_ci  }
1741cb0ef41Sopenharmony_ci
1751cb0ef41Sopenharmony_ci  // x - y == -(y - x)
1761cb0ef41Sopenharmony_ci  // (-x) - (-y) == y - x == -(x - y)
1771cb0ef41Sopenharmony_ci  if (MutableBigIntAbsoluteCompare(x, y) >= 0) {
1781cb0ef41Sopenharmony_ci    return MutableBigIntAbsoluteSub(x, y, xsign);
1791cb0ef41Sopenharmony_ci  }
1801cb0ef41Sopenharmony_ci  return MutableBigIntAbsoluteSub(y, x, InvertSign(xsign));
1811cb0ef41Sopenharmony_ci}
1821cb0ef41Sopenharmony_ci
1831cb0ef41Sopenharmony_cibuiltin BigIntSubtractNoThrow(implicit context: Context)(
1841cb0ef41Sopenharmony_ci    x: BigInt, y: BigInt): Numeric {
1851cb0ef41Sopenharmony_ci  try {
1861cb0ef41Sopenharmony_ci    return BigIntSubtractImpl(x, y) otherwise BigIntTooBig;
1871cb0ef41Sopenharmony_ci  } label BigIntTooBig {
1881cb0ef41Sopenharmony_ci    // Smi sentinal is used to signal BigIntTooBig exception.
1891cb0ef41Sopenharmony_ci    return Convert<Smi>(0);
1901cb0ef41Sopenharmony_ci  }
1911cb0ef41Sopenharmony_ci}
1921cb0ef41Sopenharmony_ci
1931cb0ef41Sopenharmony_cibuiltin BigIntSubtract(implicit context: Context)(
1941cb0ef41Sopenharmony_ci    xNum: Numeric, yNum: Numeric): BigInt {
1951cb0ef41Sopenharmony_ci  try {
1961cb0ef41Sopenharmony_ci    const x = Cast<BigInt>(xNum) otherwise MixedTypes;
1971cb0ef41Sopenharmony_ci    const y = Cast<BigInt>(yNum) otherwise MixedTypes;
1981cb0ef41Sopenharmony_ci
1991cb0ef41Sopenharmony_ci    return BigIntSubtractImpl(x, y) otherwise BigIntTooBig;
2001cb0ef41Sopenharmony_ci  } label MixedTypes {
2011cb0ef41Sopenharmony_ci    ThrowTypeError(MessageTemplate::kBigIntMixedTypes);
2021cb0ef41Sopenharmony_ci  } label BigIntTooBig {
2031cb0ef41Sopenharmony_ci    ThrowRangeError(MessageTemplate::kBigIntTooBig);
2041cb0ef41Sopenharmony_ci  }
2051cb0ef41Sopenharmony_ci}
2061cb0ef41Sopenharmony_ci
2071cb0ef41Sopenharmony_cibuiltin BigIntUnaryMinus(implicit context: Context)(bigint: BigInt): BigInt {
2081cb0ef41Sopenharmony_ci  const length = ReadBigIntLength(bigint);
2091cb0ef41Sopenharmony_ci
2101cb0ef41Sopenharmony_ci  // There is no -0n.
2111cb0ef41Sopenharmony_ci  if (length == 0) {
2121cb0ef41Sopenharmony_ci    return bigint;
2131cb0ef41Sopenharmony_ci  }
2141cb0ef41Sopenharmony_ci
2151cb0ef41Sopenharmony_ci  const result =
2161cb0ef41Sopenharmony_ci      AllocateEmptyBigInt(InvertSign(ReadBigIntSign(bigint)), length);
2171cb0ef41Sopenharmony_ci  for (let i: intptr = 0; i < length; ++i) {
2181cb0ef41Sopenharmony_ci    StoreBigIntDigit(result, i, LoadBigIntDigit(bigint, i));
2191cb0ef41Sopenharmony_ci  }
2201cb0ef41Sopenharmony_ci  return Convert<BigInt>(result);
2211cb0ef41Sopenharmony_ci}
2221cb0ef41Sopenharmony_ci
2231cb0ef41Sopenharmony_ci}  // namespace bigint
224