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}
This commit is contained in:
parent
9f4f472b33
commit
517ed4ad00
@ -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",
|
||||
@ -2801,6 +2803,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
@ -2363,6 +2363,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) {
|
||||
@ -4854,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",
|
||||
|
@ -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"
|
||||
@ -14863,6 +14864,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"
|
||||
@ -3771,6 +3772,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,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
|
||||
|
@ -92,6 +92,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;
|
||||
@ -865,8 +871,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 {
|
||||
@ -883,6 +889,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>();
|
||||
@ -1903,29 +1946,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};
|
||||
}
|
||||
|
||||
@ -2085,8 +2116,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};
|
||||
}
|
||||
@ -2205,12 +2247,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;
|
||||
@ -2284,13 +2338,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 = {
|
||||
@ -2509,7 +2568,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"
|
||||
|
||||
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user