Commit c875e86d authored by Jakob Kummerow's avatar Jakob Kummerow Committed by V8 LUCI CQ

[bigint] Convert BigInt property names to decimal

Hexadecimal/octal/binary BigInt property names should be converted
to decimal, i.e. the following object literals should all be equivalent:
var o = {0xF: 1}, p = {0xFn: 1}, q = {15: 1}, r = {15n: 1}.

Test case by yangwenming@bytedance.com, uploaded at
https://chromium-review.googlesource.com/c/v8/v8/+/3634937

Fixed: v8:10600
Change-Id: Ie1d8a16e95697cd31cbc0784843779c921ce91fa
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3642302Reviewed-by: 's avatarToon Verwaest <verwaest@chromium.org>
Commit-Queue: Jakob Kummerow <jkummerow@chromium.org>
Cr-Commit-Position: refs/heads/main@{#80490}
parent b62a3ebf
......@@ -12,6 +12,7 @@
#include "src/base/numbers/dtoa.h"
#include "src/base/numbers/strtod.h"
#include "src/base/platform/wrappers.h"
#include "src/base/small-vector.h"
#include "src/bigint/bigint.h"
#include "src/common/assert-scope.h"
#include "src/handles/handles.h"
......@@ -970,6 +971,23 @@ class StringToBigIntHelper : public StringToIntHelper<IsolateT> {
UNREACHABLE();
}
// Used for converting BigInt literals. The scanner has already checked
// that the literal is valid and not too big, so this always succeeds.
std::unique_ptr<char[]> DecimalString(bigint::Processor* processor) {
DCHECK_EQ(behavior_, Behavior::kLiteral);
this->ParseInt();
DCHECK_EQ(this->state(), State::kDone);
int num_digits = accumulator_.ResultLength();
base::SmallVector<bigint::digit_t, 8> digit_storage(num_digits);
bigint::RWDigits digits(digit_storage.data(), num_digits);
processor->FromString(digits, &accumulator_);
int num_chars = bigint::ToStringResultLength(digits, 10, false);
std::unique_ptr<char[]> out(new char[num_chars + 1]);
processor->ToString(out.get(), &num_chars, digits, 10, false);
out[num_chars] = '\0';
return out;
}
private:
template <class Char>
void ParseInternal(Char start) {
......@@ -1018,6 +1036,13 @@ template EXPORT_TEMPLATE_DEFINE(V8_EXPORT_PRIVATE)
MaybeHandle<BigInt> BigIntLiteral(LocalIsolate* isolate,
const char* string);
std::unique_ptr<char[]> BigIntLiteralToDecimal(
LocalIsolate* isolate, base::Vector<const uint8_t> literal) {
StringToBigIntHelper<LocalIsolate> helper(nullptr, literal.begin(),
literal.length());
return helper.DecimalString(isolate->bigint_processor());
}
const char* DoubleToCString(double v, base::Vector<char> buffer) {
switch (FPCLASSIFY_NAMESPACE::fpclassify(v)) {
case FP_NAN:
......
......@@ -119,6 +119,8 @@ const int kDoubleToCStringMinBufferSize = 100;
V8_EXPORT_PRIVATE const char* DoubleToCString(double value,
base::Vector<char> buffer);
V8_EXPORT_PRIVATE std::unique_ptr<char[]> BigIntLiteralToDecimal(
LocalIsolate* isolate, base::Vector<const uint8_t> literal);
// Convert an int to a null-terminated string. The returned string is
// located inside the buffer, but not necessarily at the start.
V8_EXPORT_PRIVATE const char* IntToCString(int n, base::Vector<char> buffer);
......
......@@ -2293,7 +2293,7 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseProperty(
case Token::BIGINT: {
Consume(Token::BIGINT);
prop_info->name = impl()->GetSymbol();
prop_info->name = impl()->GetBigIntAsSymbol();
is_array_index = impl()->IsArrayIndex(prop_info->name, &index);
break;
}
......
......@@ -247,6 +247,16 @@ bool Parser::CollapseNaryExpression(Expression** x, Expression* y,
return true;
}
const AstRawString* Parser::GetBigIntAsSymbol() {
base::Vector<const uint8_t> literal = scanner()->BigIntLiteral();
if (literal[0] != '0' || literal.length() == 1) {
return ast_value_factory()->GetOneByteString(literal);
}
std::unique_ptr<char[]> decimal =
BigIntLiteralToDecimal(local_isolate_, literal);
return ast_value_factory()->GetOneByteString(decimal.get());
}
Expression* Parser::BuildUnaryExpression(Expression* expression,
Token::Value op, int pos) {
DCHECK_NOT_NULL(expression);
......
......@@ -790,6 +790,8 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) {
return ast_value_factory()->GetOneByteString(string);
}
const AstRawString* GetBigIntAsSymbol();
class ThisExpression* ThisExpression() {
UseThis();
return factory()->ThisExpression();
......
......@@ -1522,6 +1522,10 @@ class PreParser : public ParserBase<PreParser> {
return PreParserIdentifier::Default();
}
V8_INLINE PreParserIdentifier GetBigIntAsSymbol() const {
return PreParserIdentifier::Default();
}
V8_INLINE PreParserExpression ThisExpression() {
UseThis();
return PreParserExpression::This();
......
......@@ -336,6 +336,9 @@ class V8_EXPORT_PRIVATE Scanner {
AstValueFactory* ast_value_factory) const;
double DoubleValue();
base::Vector<const uint8_t> BigIntLiteral() const {
return literal_one_byte_string();
}
const char* CurrentLiteralAsCString(Zone* zone) const;
......
......@@ -7,3 +7,26 @@ assertEquals(it, 1);
var { 999999999999999999n: it } = { 999999999999999999n: 1 }; // greater than max safe integer
assertEquals(it, 1);
var obj = { 0xfffffffffffffffffffffn: 1};
assertEquals(1, obj["19342813113834066795298815"]);
var obj2 = {0o777777777777777777777777777n: 1};
assertEquals(1, obj2["2417851639229258349412351"]);
var obj3 = { 0x4n: 'hi' };
assertEquals('hi', obj3[4]);
assertEquals(undefined, obj3["0x4"]);
let obj4 =
{12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890n: 1};
assertEquals(
1,
obj4["12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890"]);
// 130 hex digits
let obj5 = {0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffn: 1};
assertEquals(
1,
obj5["3432398830065304857490950399540696608634717650071652704697231729592771591698828026061279820330727277488648155695740429018560993999858321906287014145557528575"]);
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment