Commit 757830b0 authored by Nico Hartmann's avatar Nico Hartmann Committed by V8 LUCI CQ

[Torque] Generalize Torque literals to larger size

Previously, literals in Torque were stored as double values, which
made it impossible to precisely represent 64 bit integer values.
This CL replaces the old literal expression with an integer and
floating point literal expression that are unbounded in size. We
allow implicit conversion of these literals to arbitary integer
and floating point types respectively and insert a corresponding
bounds check into generated CSA.

Bug: v8:7793
Change-Id: I46c231aab92bc2f0c26955d1876079f306b358c6
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3329792Reviewed-by: 's avatarJakob Kummerow <jkummerow@chromium.org>
Reviewed-by: 's avatarTobias Tebbi <tebbi@chromium.org>
Commit-Queue: Nico Hartmann <nicohartmann@chromium.org>
Cr-Commit-Position: refs/heads/main@{#78671}
parent f4ce0839
......@@ -922,6 +922,9 @@ filegroup(
filegroup(
name = "torque_base_files",
srcs = [
":v8_bigint",
"src/numbers/integer-literal-inl.h",
"src/numbers/integer-literal.h",
"src/torque/ast.h",
"src/torque/cc-generator.cc",
"src/torque/cc-generator.h",
......@@ -2797,6 +2800,8 @@ filegroup(
"src/interpreter/interpreter-generator.h",
"src/interpreter/interpreter-intrinsics-generator.cc",
"src/interpreter/interpreter-intrinsics-generator.h",
"src/numbers/integer-literal-inl.h",
"src/numbers/integer-literal.h",
] + select({
"@v8//bazel/config:v8_target_ia32": ["src/builtins/ia32/builtins-ia32.cc"],
"@v8//bazel/config:v8_target_x64": ["src/builtins/x64/builtins-x64.cc"],
......
......@@ -2290,6 +2290,7 @@ v8_source_set("v8_initializers") {
deps = [
":torque_generated_initializers",
":v8_base_without_compiler",
":v8_bigint",
":v8_shared_internal_headers",
":v8_tracing",
]
......@@ -2365,6 +2366,8 @@ v8_source_set("v8_initializers") {
"src/interpreter/interpreter-generator.h",
"src/interpreter/interpreter-intrinsics-generator.cc",
"src/interpreter/interpreter-intrinsics-generator.h",
"src/numbers/integer-literal-inl.h",
"src/numbers/integer-literal.h",
]
if (v8_enable_webassembly) {
......@@ -4853,6 +4856,8 @@ v8_source_set("torque_base") {
visibility = [ ":*" ] # Only targets in this file can depend on this.
sources = [
"src/numbers/integer-literal-inl.h",
"src/numbers/integer-literal.h",
"src/torque/ast.h",
"src/torque/cc-generator.cc",
"src/torque/cc-generator.h",
......@@ -4906,6 +4911,7 @@ v8_source_set("torque_base") {
]
deps = [
":v8_bigint",
":v8_flags",
":v8_shared_internal_headers",
]
......
......@@ -301,6 +301,10 @@ class Processor {
// Z := the contents of {accumulator}.
// Assume that this leaves {accumulator} in unusable state.
Status FromString(RWDigits Z, FromStringAccumulator* accumulator);
protected:
// Use {Destroy} or {Destroyer} instead of the destructor directly.
~Processor() = default;
};
inline int AddResultLength(int x_length, int y_length) {
......@@ -418,13 +422,13 @@ class FromStringAccumulator {
: max_digits_(std::max(max_digits, kStackParts)) {}
// Step 2: Call this method to read all characters.
// {Char} should be a character type, such as uint8_t or uint16_t.
// {end} should be one past the last character (i.e. {start == end} would
// indicate an empty string).
// Returns the current position when an invalid character is encountered.
template <class Char>
ALWAYS_INLINE const Char* Parse(const Char* start, const Char* end,
digit_t radix);
// {CharIt} should be a forward iterator and
// std::iterator_traits<CharIt>::value_type shall be a character type, such as
// uint8_t or uint16_t. {end} should be one past the last character (i.e.
// {start == end} would indicate an empty string). Returns the current
// position when an invalid character is encountered.
template <class CharIt>
ALWAYS_INLINE CharIt Parse(CharIt start, CharIt end, digit_t radix);
// Step 3: Check if a result is available, and determine its required
// allocation size (guaranteed to be <= max_digits passed to the constructor).
......@@ -434,14 +438,13 @@ class FromStringAccumulator {
}
// Step 4: Use BigIntProcessor::FromString() to retrieve the result into an
// {RWDigits} struct allocated for the size returned by step 2.
// {RWDigits} struct allocated for the size returned by step 3.
private:
friend class ProcessorImpl;
template <class Char>
ALWAYS_INLINE const Char* ParsePowerTwo(const Char* start, const Char* end,
digit_t radix);
template <class CharIt>
ALWAYS_INLINE CharIt ParsePowerTwo(CharIt start, CharIt end, digit_t radix);
ALWAYS_INLINE bool AddPart(digit_t multiplier, digit_t part, bool is_last);
ALWAYS_INLINE bool AddPart(digit_t part);
......@@ -491,10 +494,9 @@ static constexpr uint8_t kCharValue[] = {
// A space- and time-efficient way to map {2,4,8,16,32} to {1,2,3,4,5}.
static constexpr uint8_t kCharBits[] = {1, 2, 3, 0, 4, 0, 0, 0, 5};
template <class Char>
const Char* FromStringAccumulator::ParsePowerTwo(const Char* current,
const Char* end,
digit_t radix) {
template <class CharIt>
CharIt FromStringAccumulator::ParsePowerTwo(CharIt current, CharIt end,
digit_t radix) {
radix_ = static_cast<uint8_t>(radix);
const int char_bits = kCharBits[radix >> 2];
int bits_left;
......@@ -528,11 +530,10 @@ const Char* FromStringAccumulator::ParsePowerTwo(const Char* current,
return current;
}
template <class Char>
const Char* FromStringAccumulator::Parse(const Char* start, const Char* end,
digit_t radix) {
template <class CharIt>
CharIt FromStringAccumulator::Parse(CharIt start, CharIt end, digit_t radix) {
BIGINT_H_DCHECK(2 <= radix && radix <= 36);
const Char* current = start;
CharIt current = start;
#if !HAVE_BUILTIN_MUL_OVERFLOW
const digit_t kMaxMultiplier = (~digit_t{0}) / radix;
#endif
......
......@@ -127,6 +127,7 @@ class ToStringFormatter {
out_end_(out + chars_available),
out_(out_end_),
processor_(processor) {
digits_.Normalize();
DCHECK(chars_available >= ToStringResultLength(digits_, radix_, sign_));
}
......
......@@ -548,7 +548,7 @@ macro JoinStackPopInline(implicit context: Context)(receiver: JSReceiver):
// Builtin call was not nested (receiver is the first entry) and
// did not contain other nested arrays that expanded the stack.
if (stack.objects[0] == receiver && len == kMinJoinStackSize) {
StoreFixedArrayElement(stack, 0, TheHole, SKIP_WRITE_BARRIER);
stack.objects[0] = TheHole;
} else
deferred {
JoinStackPop(stack, receiver);
......
......@@ -26,6 +26,8 @@
type void;
type never;
type IntegerLiteral constexpr 'IntegerLiteral';
type Tagged generates 'TNode<MaybeObject>' constexpr 'MaybeObject';
type StrongTagged extends Tagged
generates 'TNode<Object>' constexpr 'Object';
......@@ -612,7 +614,7 @@ transitioning macro ToIntegerImpl(implicit context: Context)(input: JSAny):
if (Float64IsNaN(value)) return SmiConstant(0);
value = math::Float64Trunc(value);
// ToInteger normalizes -0 to +0.
if (value == 0.0) return SmiConstant(0);
if (value == 0) return SmiConstant(0);
const result = ChangeFloat64ToTagged(value);
dcheck(IsNumberNormalized(result));
return result;
......@@ -984,6 +986,38 @@ extern operator '==' macro ConstexprInt32Equal(
extern operator '!=' macro ConstexprInt32NotEqual(
constexpr int32, constexpr int32): constexpr bool;
// IntegerLiteral overloads
extern macro ConstexprIntegerLiteralToInt31(constexpr IntegerLiteral):
constexpr int31;
extern macro ConstexprIntegerLiteralToInt32(constexpr IntegerLiteral):
constexpr int32;
extern macro ConstexprIntegerLiteralToUint32(constexpr IntegerLiteral):
constexpr uint32;
extern macro ConstexprIntegerLiteralToUint64(constexpr IntegerLiteral):
constexpr uint64;
extern macro ConstexprIntegerLiteralToIntptr(constexpr IntegerLiteral):
constexpr intptr;
extern macro ConstexprIntegerLiteralToUintptr(constexpr IntegerLiteral):
constexpr uintptr;
extern macro ConstexprIntegerLiteralToInt8(constexpr IntegerLiteral):
constexpr int8;
extern macro ConstexprIntegerLiteralToUint8(constexpr IntegerLiteral):
constexpr uint8;
extern macro ConstexprIntegerLiteralToFloat64(constexpr IntegerLiteral):
constexpr float64;
extern operator '==' macro ConstexprIntegerLiteralEqual(
constexpr IntegerLiteral, constexpr IntegerLiteral): constexpr bool;
extern operator '+' macro ConstexprIntegerLiteralAdd(
constexpr IntegerLiteral,
constexpr IntegerLiteral): constexpr IntegerLiteral;
extern operator '<<' macro ConstexprIntegerLiteralLeftShift(
constexpr IntegerLiteral,
constexpr IntegerLiteral): constexpr IntegerLiteral;
extern operator '|' macro ConstexprIntegerLiteralBitwiseOr(
constexpr IntegerLiteral,
constexpr IntegerLiteral): constexpr IntegerLiteral;
extern operator '==' macro Word32Equal(int32, int32): bool;
extern operator '==' macro Word32Equal(uint32, uint32): bool;
extern operator '!=' macro Word32NotEqual(int32, int32): bool;
......@@ -1173,19 +1207,29 @@ extern macro IntPtrConstant(constexpr int32): intptr;
extern macro Uint16Constant(constexpr uint16): uint16;
extern macro Int32Constant(constexpr int31): int31;
extern macro Int32Constant(constexpr int32): int32;
macro Int32Constant(i: constexpr IntegerLiteral): int32 {
return Int32Constant(ConstexprIntegerLiteralToInt32(i));
}
extern macro Int64Constant(constexpr int64): int64;
extern macro Uint64Constant(constexpr uint64): uint64;
extern macro Float64Constant(constexpr int32): float64;
extern macro Float64Constant(constexpr float64): float64;
extern macro Float64Constant(constexpr IntegerLiteral): float64;
extern macro SmiConstant(constexpr int31): Smi;
extern macro SmiConstant(constexpr Smi): Smi;
extern macro SmiConstant(constexpr MessageTemplate): Smi;
extern macro SmiConstant(constexpr bool): Smi;
extern macro SmiConstant(constexpr uint32): Smi;
macro SmiConstant(il: constexpr IntegerLiteral): Smi {
return SmiConstant(ConstexprIntegerLiteralToInt31(il));
}
extern macro BoolConstant(constexpr bool): bool;
extern macro StringConstant(constexpr string): String;
extern macro IntPtrConstant(constexpr ContextSlot): ContextSlot;
extern macro IntPtrConstant(constexpr intptr): intptr;
macro IntPtrConstant(il: constexpr IntegerLiteral): intptr {
return IntPtrConstant(ConstexprIntegerLiteralToIntptr(il));
}
extern macro PointerConstant(constexpr RawPtr): RawPtr;
extern macro SingleCharacterStringConstant(constexpr string): String;
extern macro Float64SilenceNaN(float64): float64;
......
......@@ -4,6 +4,59 @@
intrinsic %FromConstexpr<To: type, From: type>(b: From): To;
macro FromConstexpr<To: type, From: type>(o: From): To;
// Conversions for IntegerLiteral
FromConstexpr<intptr, constexpr IntegerLiteral>(i: constexpr IntegerLiteral):
intptr {
return ConstexprIntegerLiteralToIntptr(i);
}
FromConstexpr<uintptr, constexpr IntegerLiteral>(i: constexpr IntegerLiteral):
uintptr {
return ConstexprIntegerLiteralToUintptr(i);
}
FromConstexpr<int32, constexpr IntegerLiteral>(i: constexpr IntegerLiteral):
int32 {
return ConstexprIntegerLiteralToInt32(i);
}
FromConstexpr<uint32, constexpr IntegerLiteral>(i: constexpr IntegerLiteral):
uint32 {
return ConstexprIntegerLiteralToUint32(i);
}
FromConstexpr<int31, constexpr IntegerLiteral>(i: constexpr IntegerLiteral):
int31 {
return ConstexprIntegerLiteralToInt31(i);
}
FromConstexpr<int8, constexpr IntegerLiteral>(i: constexpr IntegerLiteral):
int8 {
return ConstexprIntegerLiteralToInt8(i);
}
FromConstexpr<uint8, constexpr IntegerLiteral>(i: constexpr IntegerLiteral):
uint8 {
return ConstexprIntegerLiteralToUint8(i);
}
FromConstexpr<uint64, constexpr IntegerLiteral>(i: constexpr IntegerLiteral):
uint64 {
return ConstexprIntegerLiteralToUint64(i);
}
FromConstexpr<constexpr int31, constexpr IntegerLiteral>(
i: constexpr IntegerLiteral): constexpr int31 {
return ConstexprIntegerLiteralToInt31(i);
}
FromConstexpr<constexpr int32, constexpr IntegerLiteral>(
i: constexpr IntegerLiteral): constexpr int32 {
return ConstexprIntegerLiteralToInt32(i);
}
FromConstexpr<Number, constexpr IntegerLiteral>(i: constexpr IntegerLiteral):
Number {
return NumberConstant(ConstexprIntegerLiteralToFloat64(i));
}
FromConstexpr<Smi, constexpr IntegerLiteral>(i: constexpr IntegerLiteral): Smi {
return Convert<Smi>(ConstexprIntegerLiteralToInt31(i));
}
FromConstexpr<char8, constexpr IntegerLiteral>(i: constexpr IntegerLiteral):
char8 {
return %RawDownCast<char8>(FromConstexpr<uint8>(i));
}
FromConstexpr<int31, constexpr int31>(i: constexpr int31): int31 {
return %FromConstexpr<int31>(i);
}
......@@ -325,6 +378,10 @@ Convert<intptr, Number>(n: Number): intptr {
Convert<bint, int32>(v: int32): bint {
return IntPtrToBInt(Convert<intptr>(v));
}
FromConstexpr<float64, constexpr IntegerLiteral>(v: constexpr IntegerLiteral):
float64 {
return ConstexprIntegerLiteralToFloat64(v);
}
extern macro IntPtrToBInt(intptr): bint;
Convert<bint, intptr>(v: intptr): bint {
return IntPtrToBInt(v);
......
......@@ -90,7 +90,7 @@ macro NumberToStringSmi(x: int32, radix: int32): String labels Slow {
// Calculate length and pre-allocate the result string.
let temp: int32 = n;
let length: int32 = isNegative ? 1 : 0;
let length: int32 = isNegative ? Convert<int32>(1) : Convert<int32>(0);
while (temp > 0) {
temp = temp / radix;
length = length + 1;
......@@ -277,7 +277,7 @@ transitioning builtin ParseInt(implicit context: Context)(
// the runtime for the range [0,1[ because the result could be -0.
const kMaxAbsValue: float64 = 2147483648.0;
const absInput: float64 = math::Float64Abs(asFloat64);
if (absInput < kMaxAbsValue && absInput >= 1) goto Int32(asInt32);
if (absInput < kMaxAbsValue && absInput >= 1.0) goto Int32(asInt32);
goto CallRuntime;
}
case (s: String): {
......@@ -690,7 +690,7 @@ builtin Negate(implicit context: Context)(value: JSAny): Numeric {
} label Smi(s: Smi) {
return SmiMul(s, -1);
} label HeapNumber(h: HeapNumber) {
return AllocateHeapNumberWithValue(Convert<float64>(h) * -1);
return AllocateHeapNumberWithValue(Convert<float64>(h) * -1.0);
} label BigInt(b: BigInt) {
tail runtime::BigIntUnaryOp(
context, b, SmiTag<Operation>(Operation::kNegate));
......
......@@ -55,7 +55,7 @@ transitioning javascript builtin StringPrototypeRepeat(
// 4. If n < 0, throw a RangeError exception.
// 5. If n is +∞, throw a RangeError exception.
if (n == V8_INFINITY || n < 0.0) goto InvalidCount;
if (n == V8_INFINITY || n < 0) goto InvalidCount;
// 6. If n is 0, return the empty String.
if (s.length_uint32 == 0) goto EmptyString;
......
......@@ -105,6 +105,10 @@ struct Slice<T: type, Reference: type> {
return this.TryAtIndex(Convert<intptr>(index)) otherwise unreachable;
}
macro AtIndex(index: constexpr IntegerLiteral): Reference {
return this.AtIndex(FromConstexpr<uintptr>(index));
}
macro AtIndex(index: constexpr int31): Reference {
const i: intptr = Convert<intptr>(index);
return this.TryAtIndex(i) otherwise unreachable;
......
......@@ -17,6 +17,7 @@
#include "src/heap/heap-inl.h" // For MemoryChunk. TODO(jkummerow): Drop.
#include "src/heap/memory-chunk.h"
#include "src/logging/counters.h"
#include "src/numbers/integer-literal-inl.h"
#include "src/objects/api-callbacks.h"
#include "src/objects/cell.h"
#include "src/objects/descriptor-array.h"
......@@ -14754,6 +14755,19 @@ void CodeStubAssembler::Print(const char* prefix,
CallRuntime(Runtime::kDebugPrint, NoContextConstant(), arg);
}
IntegerLiteral CodeStubAssembler::ConstexprIntegerLiteralAdd(
const IntegerLiteral& lhs, const IntegerLiteral& rhs) {
return lhs + rhs;
}
IntegerLiteral CodeStubAssembler::ConstexprIntegerLiteralLeftShift(
const IntegerLiteral& lhs, const IntegerLiteral& rhs) {
return lhs << rhs;
}
IntegerLiteral CodeStubAssembler::ConstexprIntegerLiteralBitwiseOr(
const IntegerLiteral& lhs, const IntegerLiteral& rhs) {
return lhs | rhs;
}
void CodeStubAssembler::PerformStackCheck(TNode<Context> context) {
Label ok(this), stack_check_interrupt(this, Label::kDeferred);
......
......@@ -13,6 +13,7 @@
#include "src/common/globals.h"
#include "src/common/message-template.h"
#include "src/compiler/code-assembler.h"
#include "src/numbers/integer-literal.h"
#include "src/objects/arguments.h"
#include "src/objects/bigint.h"
#include "src/objects/cell.h"
......@@ -3743,6 +3744,45 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
}
bool ConstexprBoolNot(bool value) { return !value; }
int31_t ConstexprIntegerLiteralToInt31(const IntegerLiteral& i) {
return int31_t(i.To<int32_t>());
}
int32_t ConstexprIntegerLiteralToInt32(const IntegerLiteral& i) {
return i.To<int32_t>();
}
uint32_t ConstexprIntegerLiteralToUint32(const IntegerLiteral& i) {
return i.To<uint32_t>();
}
int8_t ConstexprIntegerLiteralToInt8(const IntegerLiteral& i) {
return i.To<int8_t>();
}
uint8_t ConstexprIntegerLiteralToUint8(const IntegerLiteral& i) {
return i.To<uint8_t>();
}
uint64_t ConstexprIntegerLiteralToUint64(const IntegerLiteral& i) {
return i.To<uint64_t>();
}
intptr_t ConstexprIntegerLiteralToIntptr(const IntegerLiteral& i) {
return i.To<intptr_t>();
}
uintptr_t ConstexprIntegerLiteralToUintptr(const IntegerLiteral& i) {
return i.To<uintptr_t>();
}
double ConstexprIntegerLiteralToFloat64(const IntegerLiteral& i) {
int64_t i_value = i.To<int64_t>();
double d_value = static_cast<double>(i_value);
CHECK_EQ(i_value, static_cast<int64_t>(d_value));
return d_value;
}
bool ConstexprIntegerLiteralEqual(IntegerLiteral lhs, IntegerLiteral rhs) {
return lhs == rhs;
}
IntegerLiteral ConstexprIntegerLiteralAdd(const IntegerLiteral& lhs,
const IntegerLiteral& rhs);
IntegerLiteral ConstexprIntegerLiteralLeftShift(const IntegerLiteral& lhs,
const IntegerLiteral& rhs);
IntegerLiteral ConstexprIntegerLiteralBitwiseOr(const IntegerLiteral& lhs,
const IntegerLiteral& rhs);
bool ConstexprInt31Equal(int31_t a, int31_t b) { return a == b; }
bool ConstexprInt31NotEqual(int31_t a, int31_t b) { return a != b; }
......
// Copyright 2022 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.
#ifndef V8_NUMBERS_INTEGER_LITERAL_INL_H_
#define V8_NUMBERS_INTEGER_LITERAL_INL_H_
#include "src/numbers/integer-literal.h"
namespace v8 {
namespace internal {
inline std::string IntegerLiteral::ToString() const {
// Special case 0 here.
if (IsZero()) return "0";
int len = bigint::ToStringResultLength(GetDigits(), 10, sign());
std::vector<char> buffer(len);
bigint::Processor* processor = bigint::Processor::New(new bigint::Platform());
processor->ToString(buffer.data(), &len, GetDigits(), 10, sign());
processor->Destroy();
return std::string(buffer.begin(), buffer.begin() + len);
}
inline IntegerLiteral operator<<(const IntegerLiteral& lhs,
const IntegerLiteral& rhs) {
if (lhs.IsZero() || rhs.IsZero()) return lhs;
CHECK_EQ(rhs.length(), 1);
// We don't support negative left shift here.
CHECK(!rhs.sign());
const int result_length = bigint::LeftShift_ResultLength(
lhs.length(), lhs.GetDigits().msd(), rhs.GetDigits()[0]);
DCHECK_LE(result_length, IntegerLiteral::kMaxLength);
auto result = IntegerLiteral::ForLength(result_length, lhs.sign());
bigint::LeftShift(result.GetRWDigits(), lhs.GetDigits(), rhs.GetDigits()[0]);
return result;
}
inline IntegerLiteral operator+(const IntegerLiteral& lhs,
const IntegerLiteral& rhs) {
const int result_length = bigint::AddSignedResultLength(
lhs.length(), rhs.length(), lhs.sign() == rhs.sign());
auto result = IntegerLiteral::ForLength(result_length);
bool result_sign = bigint::AddSigned(result.GetRWDigits(), lhs.GetDigits(),
lhs.sign(), rhs.GetDigits(), rhs.sign());
result.set_sign(result_sign);
result.Normalize();
return result;
}
inline IntegerLiteral operator|(const IntegerLiteral& lhs,
const IntegerLiteral& rhs) {
int result_length = bigint::BitwiseOrResultLength(lhs.length(), rhs.length());
auto result =
IntegerLiteral::ForLength(result_length, lhs.sign() || rhs.sign());
if (lhs.sign()) {
if (rhs.sign()) {
bigint::BitwiseOr_NegNeg(result.GetRWDigits(), lhs.GetDigits(),
rhs.GetDigits());
} else {
bigint::BitwiseOr_PosNeg(result.GetRWDigits(), rhs.GetDigits(),
lhs.GetDigits());
}
} else {
if (rhs.sign()) {
bigint::BitwiseOr_PosNeg(result.GetRWDigits(), lhs.GetDigits(),
rhs.GetDigits());
} else {
bigint::BitwiseOr_PosPos(result.GetRWDigits(), lhs.GetDigits(),
rhs.GetDigits());
}
}
return result;
}
} // namespace internal
} // namespace v8
#endif // V8_NUMBERS_INTEGER_LITERAL_INL_H_
// Copyright 2022 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.
#ifndef V8_NUMBERS_INTEGER_LITERAL_H_
#define V8_NUMBERS_INTEGER_LITERAL_H_
#include "src/base/optional.h"
#include "src/bigint/bigint.h"
#include "src/common/globals.h"
namespace v8 {
namespace internal {
class IntegerLiteral {
public:
using digit_t = bigint::digit_t;
static constexpr int kMaxLength =
(1 << 30) / (kSystemPointerSize * kBitsPerByte);
template <typename T>
explicit IntegerLiteral(T value) : IntegerLiteral(value, true) {}
static IntegerLiteral ForLength(int length, bool sign = false) {
return IntegerLiteral(sign, std::vector<digit_t>(length));
}
bool sign() const { return sign_; }
void set_sign(bool sign) { sign_ = sign; }
int length() const { return static_cast<int>(digits_.size()); }
bigint::RWDigits GetRWDigits() {
return bigint::RWDigits(digits_.data(), static_cast<int>(digits_.size()));
}
bigint::Digits GetDigits() const {
return bigint::Digits(const_cast<digit_t*>(digits_.data()),
static_cast<int>(digits_.size()));
}
template <typename T>
bool IsRepresentableAs() const {
static_assert(std::is_integral<T>::value, "Integral type required");
return Compare(IntegerLiteral(std::numeric_limits<T>::min(), false)) >= 0 &&
Compare(IntegerLiteral(std::numeric_limits<T>::max(), false)) <= 0;
}
template <typename T>
T To() const {
static_assert(std::is_integral<T>::value, "Integral type required");
base::Optional<T> result_opt = TryTo<T>();
DCHECK(result_opt.has_value());
return *result_opt;
}
template <typename T>
base::Optional<T> TryTo() const {
static_assert(std::is_integral<T>::value, "Integral type required");
if (!IsRepresentableAs<T>()) return base::nullopt;
using unsigned_t = std::make_unsigned_t<T>;
unsigned_t value = 0;
if (digits_.empty()) return static_cast<T>(value);
for (size_t i = 0; i < digits_.size(); ++i) {
value = value | (static_cast<unsigned_t>(digits_[i])
<< (sizeof(digit_t) * kBitsPerByte * i));
}
if (sign_) {
value = (~value + 1);
}
return static_cast<T>(value);
}
bool IsZero() const {
return std::all_of(digits_.begin(), digits_.end(),
[](digit_t d) { return d == 0; });
}
void Normalize() {
while (digits_.size() > 0 && digits_[0] == 0) digits_.pop_back();
if (digits_.empty()) sign_ = false;
}
int Compare(const IntegerLiteral& other) const {
int diff = bigint::Compare(GetDigits(), other.GetDigits());
if (diff == 0) {
if (IsZero() || sign() == other.sign()) return 0;
return sign() ? -1 : 1;
} else if (diff < 0) {
return other.sign() ? 1 : -1;
} else {
return sign() ? -1 : 1;
}
}
std::string ToString() const;
private:
IntegerLiteral(bool sign, std::vector<digit_t> digits)
: sign_(sign), digits_(std::move(digits)) {}
template <typename T>
explicit IntegerLiteral(T value, bool perform_dcheck) : sign_(false) {
static_assert(std::is_integral<T>::value, "Integral type required");
if (value == T(0)) return;
auto absolute = static_cast<typename std::make_unsigned<T>::type>(value);
if (value < T(0)) {
sign_ = true;
absolute = (~absolute) + 1;
}
if (sizeof(absolute) <= sizeof(digit_t)) {
digits_.push_back(absolute);
} else {
do {
digits_.push_back(static_cast<digit_t>(absolute));
absolute >>= sizeof(digit_t) * kBitsPerByte;
} while (absolute != 0);
}
if (perform_dcheck) DCHECK_EQ(To<T>(), value);
}
bool sign_;
std::vector<digit_t> digits_;
};
inline bool operator==(const IntegerLiteral& lhs, const IntegerLiteral& rhs) {
return lhs.Compare(rhs) == 0;
}
inline bool operator!=(const IntegerLiteral& lhs, const IntegerLiteral& rhs) {
return lhs.Compare(rhs) != 0;
}
inline std::ostream& operator<<(std::ostream& stream,
const IntegerLiteral& literal) {
return stream << literal.ToString();
}
IntegerLiteral operator<<(const IntegerLiteral& lhs, const IntegerLiteral& rhs);
IntegerLiteral operator+(const IntegerLiteral& lhs, const IntegerLiteral& rhs);
IntegerLiteral operator|(const IntegerLiteral& lhs, const IntegerLiteral& rhs);
} // namespace internal
} // namespace v8
#endif // V8_NUMBERS_INTEGER_LITERAL_H_
......@@ -5,12 +5,11 @@
#ifndef V8_OBJECTS_DESCRIPTOR_ARRAY_INL_H_
#define V8_OBJECTS_DESCRIPTOR_ARRAY_INL_H_
#include "src/objects/descriptor-array.h"
#include "src/execution/isolate.h"
#include "src/handles/maybe-handles-inl.h"
#include "src/heap/heap-write-barrier.h"
#include "src/heap/heap.h"
#include "src/objects/descriptor-array.h"
#include "src/objects/field-type.h"
#include "src/objects/heap-object-inl.h"
#include "src/objects/lookup-cache-inl.h"
......
......@@ -5,13 +5,12 @@
#ifndef V8_OBJECTS_FIXED_ARRAY_INL_H_
#define V8_OBJECTS_FIXED_ARRAY_INL_H_
#include "src/objects/fixed-array.h"
#include "src/handles/handles-inl.h"
#include "src/heap/heap-write-barrier-inl.h"
#include "src/numbers/conversions.h"
#include "src/objects/bigint.h"
#include "src/objects/compressed-slots.h"
#include "src/objects/fixed-array.h"
#include "src/objects/map.h"
#include "src/objects/maybe-object-inl.h"
#include "src/objects/objects-inl.h"
......
......@@ -81,7 +81,7 @@ class TurbofanOtherNumberConstantType extends TurbofanType {
}
macro IsMinusZero(x: float64): bool {
return x == 0 && 1 / x < 0;
return x == 0 && 1.0 / x < 0;
}
macro TestTurbofanBitsetType(
......@@ -95,17 +95,17 @@ macro TestTurbofanBitsetType(
if (IsInteger(value)) {
if (IsMinusZero(valueF)) {
return bitsetLow.minus_zero;
} else if (valueF < Convert<float64>(-0x80000000)) {
} else if (valueF < 0 - Convert<float64>(0x80000000)) {
return bitsetLow.other_number;
} else if (valueF < -0x40000000) {
} else if (valueF < 0 - Convert<float64>(0x40000000)) {
return bitsetLow.other_signed32;
} else if (valueF < 0) {
return bitsetLow.negative31;
} else if (valueF < Convert<float64>(0x40000000)) {
return bitsetLow.unsigned30;
} else if (valueF < 0x80000000) {
} else if (valueF < Convert<float64>(0x80000000)) {
return bitsetLow.other_unsigned31;
} else if (valueF <= 0xffffffff) {
} else if (valueF <= Convert<float64>(0xffffffff)) {
return bitsetLow.other_unsigned32;
} else {
return bitsetLow.other_number;
......
......@@ -14,6 +14,7 @@
#include <vector>
#include "src/base/optional.h"
#include "src/numbers/integer-literal.h"
#include "src/torque/constants.h"
#include "src/torque/source-positions.h"
#include "src/torque/utils.h"
......@@ -33,7 +34,8 @@ namespace torque {
V(ConditionalExpression) \
V(IdentifierExpression) \
V(StringLiteralExpression) \
V(NumberLiteralExpression) \
V(IntegerLiteralExpression) \
V(FloatingPointLiteralExpression) \
V(FieldAccessExpression) \
V(ElementAccessExpression) \
V(DereferenceExpression) \
......@@ -459,16 +461,28 @@ struct StringLiteralExpression : Expression {
std::string literal;
};
struct NumberLiteralExpression : Expression {
DEFINE_AST_NODE_LEAF_BOILERPLATE(NumberLiteralExpression)
NumberLiteralExpression(SourcePosition pos, double number)
: Expression(kKind, pos), number(number) {}
struct IntegerLiteralExpression : Expression {
DEFINE_AST_NODE_LEAF_BOILERPLATE(IntegerLiteralExpression)
IntegerLiteralExpression(SourcePosition pos, IntegerLiteral value)
: Expression(kKind, pos), value(std::move(value)) {}
void VisitAllSubExpressions(VisitCallback callback) override {
callback(this);
}
double number;
IntegerLiteral value;
};
struct FloatingPointLiteralExpression : Expression {
DEFINE_AST_NODE_LEAF_BOILERPLATE(FloatingPointLiteralExpression)
FloatingPointLiteralExpression(SourcePosition pos, double value)
: Expression(kKind, pos), value(value) {}
void VisitAllSubExpressions(VisitCallback callback) override {
callback(this);
}
double value;
};
struct ElementAccessExpression : LocationExpression {
......
......@@ -67,6 +67,8 @@ static const char* const FLOAT64_OR_HOLE_TYPE_STRING = "float64_or_hole";
static const char* const CONST_INT31_TYPE_STRING = "constexpr int31";
static const char* const CONST_INT32_TYPE_STRING = "constexpr int32";
static const char* const CONST_FLOAT64_TYPE_STRING = "constexpr float64";
static const char* const INTEGER_LITERAL_TYPE_STRING =
"constexpr IntegerLiteral";
static const char* const TORQUE_INTERNAL_NAMESPACE_STRING = "torque_internal";
static const char* const MUTABLE_REFERENCE_TYPE_STRING = "MutableReference";
static const char* const CONST_REFERENCE_TYPE_STRING = "ConstReference";
......
......@@ -127,6 +127,7 @@ LexerResult Lexer::RunLexer(const std::string& input) {
while (pos != end) {
token_start = pos;
Symbol* symbol = MatchToken(&pos, end);
DCHECK_IMPLIES(symbol != nullptr, pos != token_start);
InputPosition token_end = pos;
line_column_tracker.Advance(token_start, token_end);
if (!symbol) {
......
......@@ -44,6 +44,8 @@ enum class ParseResultHolderBase::TypeId {
kStdString,
kBool,
kInt32,
kDouble,
kIntegerLiteral,
kStdVectorOfString,
kExpressionPtr,
kIdentifierPtr,
......
......@@ -10,6 +10,7 @@
#include "src/base/optional.h"
#include "src/common/globals.h"
#include "src/numbers/integer-literal-inl.h"
#include "src/torque/cc-generator.h"
#include "src/torque/cfg.h"
#include "src/torque/constants.h"
......@@ -182,6 +183,7 @@ void ImplementationVisitor::BeginDebugMacrosFile() {
header << "#ifndef " << kHeaderDefine << "\n";
header << "#define " << kHeaderDefine << "\n\n";
header << "#include \"tools/debug_helper/debug-helper-internal.h\"\n";
header << "#include \"src/numbers/integer-literal.h\"\n";
header << "\n";
header << "namespace v8 {\n"
......@@ -943,22 +945,18 @@ VisitResult ImplementationVisitor::Visit(AssignmentExpression* expr) {
return scope.Yield(assignment_value);
}
VisitResult ImplementationVisitor::Visit(NumberLiteralExpression* expr) {
VisitResult ImplementationVisitor::Visit(FloatingPointLiteralExpression* expr) {
const Type* result_type = TypeOracle::GetConstFloat64Type();
if (expr->number >= std::numeric_limits<int32_t>::min() &&
expr->number <= std::numeric_limits<int32_t>::max()) {
int32_t i = static_cast<int32_t>(expr->number);
if (i == expr->number) {
if ((i >> 30) == (i >> 31)) {
result_type = TypeOracle::GetConstInt31Type();
} else {
result_type = TypeOracle::GetConstInt32Type();
}
}
}
std::stringstream str;
str << std::setprecision(std::numeric_limits<double>::digits10 + 1)
<< expr->number;
<< expr->value;
return VisitResult{result_type, str.str()};
}
VisitResult ImplementationVisitor::Visit(IntegerLiteralExpression* expr) {
const Type* result_type = TypeOracle::GetIntegerLiteralType();
std::stringstream str;
str << "IntegerLiteral(" << expr->value << ")";
return VisitResult{result_type, str.str()};
}
......@@ -2848,7 +2846,9 @@ VisitResult ImplementationVisitor::GenerateCall(
// If we're currently generating a C++ macro and it's calling another macro,
// then we need to make sure that we also generate C++ code for the called
// macro within the same -inl.inc file.
if (output_type_ == OutputType::kCC && !inline_macro) {
if ((output_type_ == OutputType::kCC ||
output_type_ == OutputType::kCCDebug) &&
!inline_macro) {
if (auto* torque_macro = TorqueMacro::DynamicCast(macro)) {
auto* streams = CurrentFileStreams::Get();
SourceId file = streams ? streams->file : SourceId::Invalid();
......@@ -2862,14 +2862,32 @@ VisitResult ImplementationVisitor::GenerateCall(
std::stringstream result;
result << "(";
bool first = true;
if (auto* extern_macro = ExternMacro::DynamicCast(macro)) {
result << extern_macro->external_assembler_name() << "(state_)."
<< extern_macro->ExternalName() << "(";
} else {
result << macro->ExternalName() << "(state_";
first = false;
switch (output_type_) {
case OutputType::kCSA: {
if (auto* extern_macro = ExternMacro::DynamicCast(macro)) {
result << extern_macro->external_assembler_name() << "(state_)."
<< extern_macro->ExternalName() << "(";
} else {
result << macro->ExternalName() << "(state_";
first = false;
}
break;
}
case OutputType::kCC: {
auto* extern_macro = ExternMacro::DynamicCast(macro);
CHECK_NOT_NULL(extern_macro);
result << extern_macro->CCName() << "(";
break;
}
case OutputType::kCCDebug: {
auto* extern_macro = ExternMacro::DynamicCast(macro);
CHECK_NOT_NULL(extern_macro);
result << extern_macro->CCDebugName() << "(accessor";
first = false;
break;
}
}
for (VisitResult arg : arguments.parameters) {
for (VisitResult arg : converted_arguments) {
DCHECK(!arg.IsOnStack());
if (!first) {
result << ", ";
......
......@@ -555,7 +555,8 @@ class ImplementationVisitor {
VisitResult Visit(IncrementDecrementExpression* expr);
VisitResult Visit(AssignmentExpression* expr);
VisitResult Visit(StringLiteralExpression* expr);
VisitResult Visit(NumberLiteralExpression* expr);
VisitResult Visit(FloatingPointLiteralExpression* expr);
VisitResult Visit(IntegerLiteralExpression* expr);
VisitResult Visit(AssumeTypeImpossibleExpression* expr);
VisitResult Visit(TryLabelExpression* expr);
VisitResult Visit(StatementExpression* expr);
......
......@@ -10,6 +10,8 @@
#include <cstdint>
#include "src/numbers/integer-literal.h"
namespace v8 {
namespace internal {
......@@ -34,6 +36,15 @@ inline uintptr_t Unsigned(intptr_t s) { return static_cast<uintptr_t>(s); }
#endif
inline bool Word32Equal(uint32_t a, uint32_t b) { return a == b; }
inline bool Word32NotEqual(uint32_t a, uint32_t b) { return a != b; }
inline int32_t ConstexprIntegerLiteralToInt32(const IntegerLiteral& i) {
return i.To<int32_t>();
}
inline int31_t ConstexprIntegerLiteralToInt31(const IntegerLiteral& i) {
return int31_t(ConstexprIntegerLiteralToInt32(i));
}
inline intptr_t ConstexprIntegerLiteralToIntptr(const IntegerLiteral& i) {
return i.To<intptr_t>();
}
} // namespace CodeStubAssembler
} // namespace TorqueRuntimeMacroShims
......
......@@ -10,6 +10,7 @@
#include <stdexcept>
#include <unordered_map>
#include "src/bigint/bigint.h"
#include "src/flags/flags.h"
#include "src/torque/ast.h"
#include "src/torque/constants.h"
......@@ -92,6 +93,12 @@ template <>
V8_EXPORT_PRIVATE const ParseResultTypeId ParseResultHolder<int32_t>::id =
ParseResultTypeId::kInt32;
template <>
V8_EXPORT_PRIVATE const ParseResultTypeId ParseResultHolder<double>::id =
ParseResultTypeId::kDouble;
template <>
V8_EXPORT_PRIVATE const ParseResultTypeId
ParseResultHolder<IntegerLiteral>::id = ParseResultTypeId::kIntegerLiteral;
template <>
V8_EXPORT_PRIVATE const ParseResultTypeId
ParseResultHolder<std::vector<std::string>>::id =
ParseResultTypeId::kStdVectorOfString;
......@@ -847,8 +854,8 @@ class AnnotationSet {
std::map<std::string, std::pair<AnnotationParameter, SourcePosition>> map_;
};
base::Optional<ParseResult> MakeInt32(ParseResultIterator* child_results) {
std::string value = child_results->NextAs<std::string>();
base::Optional<ParseResult> YieldInt32(ParseResultIterator* child_results) {
std::string value = child_results->matched_input().ToString();
size_t num_chars_converted = 0;
int result = 0;
try {
......@@ -865,6 +872,58 @@ base::Optional<ParseResult> MakeInt32(ParseResultIterator* child_results) {
return ParseResult{result};
}
base::Optional<ParseResult> YieldDouble(ParseResultIterator* child_results) {
std::string value = child_results->matched_input().ToString();
size_t num_chars_converted = 0;
double result = 0;
try {
result = std::stod(value, &num_chars_converted);
} catch (const std::out_of_range&) {
Error("double literal out-of-range");
return ParseResult{result};
}
// Tokenizer shouldn't have included extra trailing characters.
DCHECK_EQ(num_chars_converted, value.size());
return ParseResult{result};
}
base::Optional<ParseResult> YieldIntegerLiteral(
ParseResultIterator* child_results) {
// Note that kMaxDigits is rather arbitrary and we just need something that
// is large enough on all platforms to hold all (signed and unsigned) 64 bit
// integer values. We will insert range checks for the actual types later
// anyway, so we allow arbitrarily large literals here.
constexpr int kMaxDigits = 10;
std::string value = child_results->matched_input().ToString();
auto pos = value.begin();
auto end = value.end();
// Consume a leading minus.
bool sign = false;
if (*pos == '-') {
sign = true;
++pos;
}
DCHECK_NE(pos, end);
bigint::FromStringAccumulator accumulator(kMaxDigits);
if (StringStartsWith({pos, end}, "0x")) {
// Parse hexadecimal literal.
pos += 2;
pos = accumulator.Parse(pos, end, 16);
} else {
// Parse decimal literal.
pos = accumulator.Parse(pos, end, 10);
}
// Should have processed all characters in the input.
DCHECK_EQ(pos, end);
auto literal = IntegerLiteral::ForLength(accumulator.ResultLength(), sign);
auto processor = bigint::Processor::New(new bigint::Platform());
processor->FromString(literal.GetRWDigits(), &accumulator);
processor->Destroy();
return ParseResult(std::move(literal));
}
base::Optional<ParseResult> MakeStringAnnotationParameter(
ParseResultIterator* child_results) {
std::string value = child_results->NextAs<std::string>();
......@@ -1885,29 +1944,17 @@ base::Optional<ParseResult> MakeAssignmentExpression(
return ParseResult{result};
}
base::Optional<ParseResult> MakeNumberLiteralExpression(
base::Optional<ParseResult> MakeFloatingPointLiteralExpression(
ParseResultIterator* child_results) {
auto number = child_results->NextAs<std::string>();
// TODO(turbofan): Support 64bit literals.
// Meanwhile, we type it as constexpr float64 when out of int32 range.
double value = 0;
try {
#if defined(V8_OS_SOLARIS)
// stod() on Solaris does not currently support hex strings. Use strtol()
// specifically for hex literals until stod() support is available.
if (number.find("0x") == std::string::npos &&
number.find("0X") == std::string::npos) {
value = std::stod(number);
} else {
value = static_cast<double>(strtol(number.c_str(), nullptr, 0));
}
#else
value = std::stod(number);
#endif // !defined(V8_OS_SOLARIS)
} catch (const std::out_of_range&) {
Error("double literal out-of-range").Throw();
}
Expression* result = MakeNode<NumberLiteralExpression>(value);
auto value = child_results->NextAs<double>();
Expression* result = MakeNode<FloatingPointLiteralExpression>(value);
return ParseResult{result};
}
base::Optional<ParseResult> MakeIntegerLiteralExpression(
ParseResultIterator* child_results) {
auto value = child_results->NextAs<IntegerLiteral>();
Expression* result = MakeNode<IntegerLiteralExpression>(std::move(value));
return ParseResult{result};
}
......@@ -2067,8 +2114,19 @@ base::Optional<ParseResult> MakeClassField(ParseResultIterator* child_results) {
// Internally, an optional field is just an indexed field where the count
// is zero or one.
index = MakeNode<ConditionalExpression>(
*index, MakeNode<NumberLiteralExpression>(1),
MakeNode<NumberLiteralExpression>(0));
*index,
MakeCall(
MakeNode<Identifier>("FromConstexpr"),
{MakeNode<BasicTypeExpression>(std::vector<std::string>{},
MakeNode<Identifier>("intptr"),
std::vector<TypeExpression*>{})},
{MakeNode<IntegerLiteralExpression>(IntegerLiteral(1))}, {}),
MakeCall(
MakeNode<Identifier>("FromConstexpr"),
{MakeNode<BasicTypeExpression>(std::vector<std::string>{},
MakeNode<Identifier>("intptr"),
std::vector<TypeExpression*>{})},
{MakeNode<IntegerLiteralExpression>(IntegerLiteral(0))}, {}));
}
index_info = ClassFieldIndexInfo{*index, optional};
}
......@@ -2187,12 +2245,24 @@ struct TorqueGrammar : Grammar {
return false;
}
static bool MatchDecimalLiteral(InputPosition* pos) {
static bool MatchIntegerLiteral(InputPosition* pos) {
InputPosition current = *pos;
bool found_digit = false;
MatchString("-", &current);
while (MatchChar(std::isdigit, &current)) found_digit = true;
if (found_digit) {
*pos = current;
return true;
}
return false;
}
static bool MatchFloatingPointLiteral(InputPosition* pos) {
InputPosition current = *pos;
bool found_digit = false;
MatchString("-", &current);
while (MatchChar(std::isdigit, &current)) found_digit = true;
MatchString(".", &current);
if (!MatchString(".", &current)) return false;
while (MatchChar(std::isdigit, &current)) found_digit = true;
if (!found_digit) return false;
*pos = current;
......@@ -2277,13 +2347,18 @@ struct TorqueGrammar : Grammar {
// Result: std::string
Symbol externalString = {Rule({&stringLiteral}, StringLiteralUnquoteAction)};
// Result: std::string
Symbol decimalLiteral = {
Rule({Pattern(MatchDecimalLiteral)}, YieldMatchedInput),
Rule({Pattern(MatchHexLiteral)}, YieldMatchedInput)};
// Result: IntegerLiteral
Symbol integerLiteral = {
Rule({Pattern(MatchIntegerLiteral)}, YieldIntegerLiteral),
Rule({Pattern(MatchHexLiteral)}, YieldIntegerLiteral)};
// Result: double
Symbol floatingPointLiteral = {
Rule({Pattern(MatchFloatingPointLiteral)}, YieldDouble)};
// Result: int32_t
Symbol int32Literal = {Rule({&decimalLiteral}, MakeInt32)};
Symbol int32Literal = {Rule({Pattern(MatchIntegerLiteral)}, YieldInt32),
Rule({Pattern(MatchHexLiteral)}, YieldInt32)};
// Result: AnnotationParameter
Symbol annotationParameter = {
......@@ -2502,7 +2577,8 @@ struct TorqueGrammar : Grammar {
MakeReferenceFieldAccessExpression),
Rule({&primaryExpression, Token("["), expression, Token("]")},
MakeElementAccessExpression),
Rule({&decimalLiteral}, MakeNumberLiteralExpression),
Rule({&integerLiteral}, MakeIntegerLiteralExpression),
Rule({&floatingPointLiteral}, MakeFloatingPointLiteralExpression),
Rule({&stringLiteral}, MakeStringLiteralExpression),
Rule({&simpleType, &initializerList}, MakeStructExpression),
Rule({&newExpression}),
......
......@@ -315,6 +315,10 @@ class TypeOracle : public ContextualClass<TypeOracle> {
return Get().GetBuiltinType(CONST_FLOAT64_TYPE_STRING);
}
static const Type* GetIntegerLiteralType() {
return Get().GetBuiltinType(INTEGER_LITERAL_TYPE_STRING);
}
static const Type* GetNeverType() {
return Get().GetBuiltinType(NEVER_TYPE_STRING);
}
......
......@@ -459,12 +459,12 @@ void TypeVisitor::VisitClassFieldsAndMethods(
field_size * ResidueClass::Unknown());
if (auto literal =
NumberLiteralExpression::DynamicCast(field.index->expr)) {
size_t value = static_cast<size_t>(literal->number);
if (value != literal->number) {
Error("non-integral array length").Position(field.pos);
IntegerLiteralExpression::DynamicCast(field.index->expr)) {
if (auto value = literal->value.TryTo<size_t>()) {
field_size *= *value;
} else {
Error("Not a valid field index").Position(field.pos);
}
field_size *= value;
} else {
field_size *= ResidueClass::Unknown();
}
......
......@@ -850,7 +850,7 @@ void ClassType::GenerateSliceAccessor(size_t field_index) {
if (field.offset.has_value()) {
offset_expression =
MakeNode<NumberLiteralExpression>(static_cast<double>(*field.offset));
MakeNode<IntegerLiteralExpression>(IntegerLiteral(*field.offset));
} else {
const Field* previous = GetFieldPreceding(field_index);
DCHECK_NOT_NULL(previous);
......@@ -879,8 +879,8 @@ void ClassType::GenerateSliceAccessor(size_t field_index) {
std::tie(previous_element_size, std::ignore) =
*SizeOf(previous->name_and_type.type);
Expression* previous_element_size_expression =
MakeNode<NumberLiteralExpression>(
static_cast<double>(previous_element_size));
MakeNode<IntegerLiteralExpression>(
IntegerLiteral(previous_element_size));
// previous.length
Expression* previous_length_expression = MakeFieldAccessExpression(
......
......@@ -196,8 +196,8 @@ macro TestFunctionPointers(implicit context: Context)(): Boolean {
@export
macro TestVariableRedeclaration(implicit context: Context)(): Boolean {
let _var1: int31 = FromConstexpr<bool>(42 == 0) ? 0 : 1;
let _var2: int31 = FromConstexpr<bool>(42 == 0) ? 1 : 0;
let _var1: int31 = FromConstexpr<bool>(42 == 0) ? FromConstexpr<int31>(0) : 1;
let _var2: int31 = FromConstexpr<bool>(42 == 0) ? FromConstexpr<int31>(1) : 0;
return True;
}
......
......@@ -20,6 +20,8 @@ constexpr const char* kTestTorquePrelude = R"(
type void;
type never;
type IntegerLiteral constexpr 'int64_t';
namespace torque_internal {
struct Reference<T: type> {
const object: HeapObject;
......@@ -112,6 +114,8 @@ extern macro TaggedToHeapObject(Object): HeapObject
extern macro Float64SilenceNaN(float64): float64;
extern macro IntPtrConstant(constexpr int31): intptr;
extern macro ConstexprIntegerLiteralToInt32(constexpr IntegerLiteral): constexpr int32;
extern macro SmiFromInt32(int32): Smi;
macro FromConstexpr<To: type, From: type>(o: From): To;
FromConstexpr<Smi, constexpr Smi>(s: constexpr Smi): Smi {
......@@ -133,6 +137,15 @@ FromConstexpr<bool, constexpr bool>(b: constexpr bool): bool {
FromConstexpr<int32, constexpr int31>(i: constexpr int31): int32 {
return %FromConstexpr<int32>(i);
}
FromConstexpr<int32, constexpr int32>(i: constexpr int32): int32 {
return %FromConstexpr<int32>(i);
}
FromConstexpr<int32, constexpr IntegerLiteral>(i: constexpr IntegerLiteral): int32 {
return FromConstexpr<int32>(ConstexprIntegerLiteralToInt32(i));
}
FromConstexpr<Smi, constexpr IntegerLiteral>(i: constexpr IntegerLiteral): Smi {
return SmiFromInt32(FromConstexpr<int32>(i));
}
macro Cast<A : type extends Object>(implicit context: Context)(o: Object): A
labels CastError {
......
......@@ -8,6 +8,7 @@
#ifndef V8_TORQUE_DEBUG_MACRO_SHIMS_H_
#define V8_TORQUE_DEBUG_MACRO_SHIMS_H_
#include "src/numbers/integer-literal.h"
#include "src/objects/smi.h"
#include "tools/debug_helper/debug-helper-internal.h"
......@@ -77,6 +78,9 @@ inline Value<int32_t> SmiUntag(d::MemoryAccessor accessor, uintptr_t s_t) {
Smi s(s_t);
return {d::MemoryAccessResult::kOk, s.value()};
}
inline Value<uintptr_t> SmiFromInt32(d::MemoryAccessor accessor, int32_t i) {
return {d::MemoryAccessResult::kOk, Smi::FromInt(i).ptr()};
}
inline Value<bool> UintPtrLessThan(d::MemoryAccessor accessor, uintptr_t a,
uintptr_t b) {
return {d::MemoryAccessResult::kOk, a < b};
......@@ -97,6 +101,19 @@ inline Value<bool> Word32NotEqual(d::MemoryAccessor accessor, uint32_t a,
uint32_t b) {
return {d::MemoryAccessResult::kOk, a != b};
}
// This is used in a nested call where we cannot pass Value<int32_t>.
inline int31_t ConstexprIntegerLiteralToInt31(d::MemoryAccessor accessor,
const IntegerLiteral& i) {
return i.To<int32_t>();
}
inline int32_t ConstexprIntegerLiteralToInt32(d::MemoryAccessor accessor,
const IntegerLiteral& i) {
return i.To<int32_t>();
}
inline intptr_t ConstexprIntegerLiteralToIntptr(d::MemoryAccessor accessor,
const IntegerLiteral& i) {
return i.To<intptr_t>();
}
} // namespace CodeStubAssembler
} // namespace TorqueDebugMacroShims
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment