Reland "Reland "[Torque] Generalize Torque literals to larger size""
This is a reland of 517ed4ad00
Original change's description:
> Reland "[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.
>
> Changes in the reland: Simplified IntegerLiteral to single digit.
>
> Bug: v8:7793, chromium:1289282
> Change-Id: I31c762c2f31165c7a1d0b07842b764e5851ce189
> Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3406750
> Reviewed-by: Jakob Kummerow <jkummerow@chromium.org>
> Reviewed-by: Tobias Tebbi <tebbi@chromium.org>
> Commit-Queue: Nico Hartmann <nicohartmann@chromium.org>
> Cr-Commit-Position: refs/heads/main@{#78811}
Bug: v8:7793, chromium:1289282
Change-Id: I7aadc4d2c9494f03eae85e94949c8f4cab7a075c
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3437047
Reviewed-by: Jakob Kummerow <jkummerow@chromium.org>
Reviewed-by: Tobias Tebbi <tebbi@chromium.org>
Commit-Queue: Nico Hartmann <nicohartmann@chromium.org>
Cr-Commit-Position: refs/heads/main@{#78939}
This commit is contained in:
parent
bc2a8f6475
commit
362b30eb1e
@ -923,6 +923,8 @@ filegroup(
|
||||
filegroup(
|
||||
name = "torque_base_files",
|
||||
srcs = [
|
||||
"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",
|
||||
@ -2802,6 +2804,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"],
|
||||
|
4
BUILD.gn
4
BUILD.gn
@ -2380,6 +2380,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) {
|
||||
@ -4872,6 +4874,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",
|
||||
|
@ -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);
|
||||
|
@ -27,6 +27,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';
|
||||
@ -613,7 +615,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;
|
||||
@ -989,6 +991,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;
|
||||
@ -1178,19 +1212,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"
|
||||
@ -14892,6 +14893,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"
|
||||
@ -3776,6 +3777,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; }
|
||||
|
43
src/numbers/integer-literal-inl.h
Normal file
43
src/numbers/integer-literal-inl.h
Normal file
@ -0,0 +1,43 @@
|
||||
// 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 {
|
||||
if (negative_) return std::string("-") + std::to_string(absolute_value_);
|
||||
return std::to_string(absolute_value_);
|
||||
}
|
||||
|
||||
inline IntegerLiteral operator<<(const IntegerLiteral& x,
|
||||
const IntegerLiteral& y) {
|
||||
DCHECK(!y.is_negative());
|
||||
DCHECK_LT(y.absolute_value(), sizeof(uint64_t) * kBitsPerByte);
|
||||
return IntegerLiteral(x.is_negative(), x.absolute_value()
|
||||
<< y.absolute_value());
|
||||
}
|
||||
|
||||
inline IntegerLiteral operator+(const IntegerLiteral& x,
|
||||
const IntegerLiteral& y) {
|
||||
if (x.is_negative() == y.is_negative()) {
|
||||
DCHECK_GE(x.absolute_value() + y.absolute_value(), x.absolute_value());
|
||||
return IntegerLiteral(x.is_negative(),
|
||||
x.absolute_value() + y.absolute_value());
|
||||
}
|
||||
if (x.absolute_value() >= y.absolute_value()) {
|
||||
return IntegerLiteral(x.is_negative(),
|
||||
x.absolute_value() - y.absolute_value());
|
||||
}
|
||||
return IntegerLiteral(!x.is_negative(),
|
||||
y.absolute_value() - x.absolute_value());
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
#endif // V8_NUMBERS_INTEGER_LITERAL_INL_H_
|
106
src/numbers/integer-literal.h
Normal file
106
src/numbers/integer-literal.h
Normal file
@ -0,0 +1,106 @@
|
||||
// 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/common/globals.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
class IntegerLiteral {
|
||||
public:
|
||||
IntegerLiteral(bool negative, uint64_t absolute_value)
|
||||
: negative_(negative), absolute_value_(absolute_value) {
|
||||
if (absolute_value == 0) negative_ = false;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
explicit IntegerLiteral(T value) : IntegerLiteral(value, true) {}
|
||||
|
||||
bool is_negative() const { return negative_; }
|
||||
uint64_t absolute_value() const { return absolute_value_; }
|
||||
|
||||
template <typename T>
|
||||
bool IsRepresentableAs() const {
|
||||
static_assert(std::is_integral<T>::value, "Integral type required");
|
||||
static_assert(sizeof(T) <= sizeof(uint64_t),
|
||||
"Types with more than 64 bits are not supported");
|
||||
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");
|
||||
DCHECK(IsRepresentableAs<T>());
|
||||
uint64_t v = absolute_value_;
|
||||
if (negative_) v = ~v + 1;
|
||||
return static_cast<T>(v);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
base::Optional<T> TryTo() const {
|
||||
static_assert(std::is_integral<T>::value, "Integral type required");
|
||||
if (!IsRepresentableAs<T>()) return base::nullopt;
|
||||
return To<T>();
|
||||
}
|
||||
|
||||
int Compare(const IntegerLiteral& other) const {
|
||||
if (absolute_value_ == other.absolute_value_) {
|
||||
if (absolute_value_ == 0 || negative_ == other.negative_) return 0;
|
||||
return negative_ ? -1 : 1;
|
||||
} else if (absolute_value_ < other.absolute_value_) {
|
||||
return other.negative_ ? 1 : -1;
|
||||
} else {
|
||||
return negative_ ? -1 : 1;
|
||||
}
|
||||
}
|
||||
|
||||
std::string ToString() const;
|
||||
|
||||
private:
|
||||
template <typename T>
|
||||
explicit IntegerLiteral(T value, bool perform_dcheck) : negative_(false) {
|
||||
static_assert(std::is_integral<T>::value, "Integral type required");
|
||||
absolute_value_ = static_cast<uint64_t>(value);
|
||||
if (value < T(0)) {
|
||||
negative_ = true;
|
||||
absolute_value_ = ~absolute_value_ + 1;
|
||||
}
|
||||
if (perform_dcheck) DCHECK_EQ(To<T>(), value);
|
||||
}
|
||||
|
||||
bool negative_;
|
||||
uint64_t absolute_value_;
|
||||
};
|
||||
|
||||
inline bool operator==(const IntegerLiteral& x, const IntegerLiteral& y) {
|
||||
return x.Compare(y) == 0;
|
||||
}
|
||||
|
||||
inline bool operator!=(const IntegerLiteral& x, const IntegerLiteral& y) {
|
||||
return x.Compare(y) != 0;
|
||||
}
|
||||
|
||||
inline std::ostream& operator<<(std::ostream& stream,
|
||||
const IntegerLiteral& literal) {
|
||||
return stream << literal.ToString();
|
||||
}
|
||||
|
||||
inline IntegerLiteral operator|(const IntegerLiteral& x,
|
||||
const IntegerLiteral& y) {
|
||||
DCHECK(!x.is_negative());
|
||||
DCHECK(!y.is_negative());
|
||||
return IntegerLiteral(false, x.absolute_value() | y.absolute_value());
|
||||
}
|
||||
|
||||
IntegerLiteral operator<<(const IntegerLiteral& x, const IntegerLiteral& y);
|
||||
IntegerLiteral operator+(const IntegerLiteral& x, const IntegerLiteral& y);
|
||||
|
||||
} // 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"
|
||||
|
@ -80,7 +80,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(
|
||||
@ -94,13 +94,13 @@ macro TestTurbofanBitsetType(
|
||||
if (IsInteger(value)) {
|
||||
if (IsMinusZero(valueF)) {
|
||||
return bitsetLow.minus_zero;
|
||||
} else if (valueF < Convert<float64>(-0x80000000)) {
|
||||
} else if (valueF < -0x80000000) {
|
||||
return bitsetLow.other_number;
|
||||
} else if (valueF < -0x40000000) {
|
||||
return bitsetLow.other_signed32;
|
||||
} else if (valueF < 0) {
|
||||
return bitsetLow.negative31;
|
||||
} else if (valueF < Convert<float64>(0x40000000)) {
|
||||
} else if (valueF < 0x40000000) {
|
||||
return bitsetLow.unsigned30;
|
||||
} else if (valueF < 0x80000000) {
|
||||
return bitsetLow.other_unsigned31;
|
||||
|
@ -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,20 @@ 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.is_negative() ? "true, 0x" : "false, 0x") << std::hex
|
||||
<< expr->value.absolute_value() << std::dec << "ull)";
|
||||
return VisitResult{result_type, str.str()};
|
||||
}
|
||||
|
||||
@ -2848,7 +2848,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 +2864,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 {
|
||||
|
||||
@ -35,6 +37,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
|
||||
|
@ -93,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;
|
||||
@ -866,8 +872,8 @@ bool ProcessIfAnnotation(ParseResultIterator* child_results) {
|
||||
return true;
|
||||
}
|
||||
|
||||
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 {
|
||||
@ -884,6 +890,43 @@ 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) {
|
||||
std::string value = child_results->matched_input().ToString();
|
||||
// Consume a leading minus.
|
||||
bool negative = false;
|
||||
if (value.size() > 0 && value[0] == '-') {
|
||||
negative = true;
|
||||
value = value.substr(1);
|
||||
}
|
||||
uint64_t absolute_value;
|
||||
try {
|
||||
size_t parsed = 0;
|
||||
absolute_value = std::stoull(value, &parsed, 0);
|
||||
DCHECK_EQ(parsed, value.size());
|
||||
} catch (const std::invalid_argument&) {
|
||||
Error("integer literal could not be parsed").Throw();
|
||||
} catch (const std::out_of_range&) {
|
||||
Error("integer literal value out of range").Throw();
|
||||
}
|
||||
return ParseResult(IntegerLiteral(negative, absolute_value));
|
||||
}
|
||||
|
||||
base::Optional<ParseResult> MakeStringAnnotationParameter(
|
||||
ParseResultIterator* child_results) {
|
||||
std::string value = child_results->NextAs<std::string>();
|
||||
@ -1904,29 +1947,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};
|
||||
}
|
||||
|
||||
@ -2086,8 +2117,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};
|
||||
}
|
||||
@ -2206,12 +2248,24 @@ struct TorqueGrammar : Grammar {
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool MatchDecimalLiteral(InputPosition* pos) {
|
||||
static bool MatchIntegerLiteral(InputPosition* pos) {
|
||||
InputPosition current = *pos;
|
||||
bool found_digit = false;
|
||||
MatchString("-", ¤t);
|
||||
while (MatchChar(std::isdigit, ¤t)) found_digit = true;
|
||||
MatchString(".", ¤t);
|
||||
if (found_digit) {
|
||||
*pos = current;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool MatchFloatingPointLiteral(InputPosition* pos) {
|
||||
InputPosition current = *pos;
|
||||
bool found_digit = false;
|
||||
MatchString("-", ¤t);
|
||||
while (MatchChar(std::isdigit, ¤t)) found_digit = true;
|
||||
if (!MatchString(".", ¤t)) return false;
|
||||
while (MatchChar(std::isdigit, ¤t)) found_digit = true;
|
||||
if (!found_digit) return false;
|
||||
*pos = current;
|
||||
@ -2285,13 +2339,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 = {
|
||||
@ -2510,7 +2569,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 'IntegerLiteral';
|
||||
|
||||
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"
|
||||
|
||||
@ -81,6 +82,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};
|
||||
@ -101,6 +105,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
|
||||
|
Loading…
Reference in New Issue
Block a user