Commit 977da550 authored by Jakob Kummerow's avatar Jakob Kummerow Committed by Commit Bot

[bigint] Encapsulate internals in MutableBigInt

This CL creates the invariant that the BigInt class treats
BigInt objects as immutable. Writing to new BigInt objects
as part of their construction is done by the MutableBigInt
helper class, which in turn is hidden as an implementation
detail in bigint.cc.
As a side effect, this refactoring enforces right-trimming
checks for all newly created BigInts, and ensures that all
BigInt allocations possibly exceeding kMaxLength check for
this case and throw a RangeError instead of crashing.

Bug: v8:6791
Tbr: mlippautz@chromium.org
Change-Id: Id239746108e6b076b47a03ba37462001eb501507
Reviewed-on: https://chromium-review.googlesource.com/742329
Commit-Queue: Jakob Kummerow <jkummerow@chromium.org>
Reviewed-by: 's avatarGeorg Neis <neis@chromium.org>
Cr-Commit-Position: refs/heads/master@{#49462}
parent 61bf2cc6
...@@ -1774,7 +1774,6 @@ v8_source_set("v8_base") { ...@@ -1774,7 +1774,6 @@ v8_source_set("v8_base") {
"src/objects.h", "src/objects.h",
"src/objects/arguments-inl.h", "src/objects/arguments-inl.h",
"src/objects/arguments.h", "src/objects/arguments.h",
"src/objects/bigint-inl.h",
"src/objects/bigint.cc", "src/objects/bigint.cc",
"src/objects/bigint.h", "src/objects/bigint.h",
"src/objects/code-inl.h", "src/objects/code-inl.h",
......
...@@ -44,8 +44,7 @@ BUILTIN(BigIntParseInt) { ...@@ -44,8 +44,7 @@ BUILTIN(BigIntParseInt) {
// Convert {string} to a String and flatten it. // Convert {string} to a String and flatten it.
// Fast path: avoid back-and-forth conversion for Smi inputs. // Fast path: avoid back-and-forth conversion for Smi inputs.
if (string->IsSmi() && radix->IsUndefined(isolate)) { if (string->IsSmi() && radix->IsUndefined(isolate)) {
int num = Smi::ToInt(*string); RETURN_RESULT_OR_FAILURE(isolate, BigInt::FromNumber(isolate, string));
return *isolate->factory()->NewBigIntFromInt(num);
} }
Handle<String> subject; Handle<String> subject;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, subject, ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, subject,
......
...@@ -903,15 +903,13 @@ class BigIntParseIntHelper : public StringToIntHelper { ...@@ -903,15 +903,13 @@ class BigIntParseIntHelper : public StringToIntHelper {
return MaybeHandle<BigInt>(); return MaybeHandle<BigInt>();
} }
case kZero: case kZero:
return isolate()->factory()->NewBigIntFromInt(0); return BigInt::Zero(isolate());
case kError: case kError:
DCHECK_EQ(should_throw() == kThrowOnError, DCHECK_EQ(should_throw() == kThrowOnError,
isolate()->has_pending_exception()); isolate()->has_pending_exception());
return MaybeHandle<BigInt>(); return MaybeHandle<BigInt>();
case kDone: case kDone:
result_->set_sign(negative()); return BigInt::Finalize(result_, negative());
result_->RightTrim();
return result_;
case kEmpty: case kEmpty:
case kRunning: case kRunning:
break; break;
...@@ -927,7 +925,7 @@ class BigIntParseIntHelper : public StringToIntHelper { ...@@ -927,7 +925,7 @@ class BigIntParseIntHelper : public StringToIntHelper {
// junk before allocating the result? // junk before allocating the result?
int charcount = length() - cursor(); int charcount = length() - cursor();
// TODO(adamk): Pretenure if this is for a literal. // TODO(adamk): Pretenure if this is for a literal.
MaybeHandle<BigInt> maybe = MaybeHandle<FreshlyAllocatedBigInt> maybe =
BigInt::AllocateFor(isolate(), radix(), charcount, should_throw()); BigInt::AllocateFor(isolate(), radix(), charcount, should_throw());
if (!maybe.ToHandle(&result_)) { if (!maybe.ToHandle(&result_)) {
set_state(kError); set_state(kError);
...@@ -935,7 +933,7 @@ class BigIntParseIntHelper : public StringToIntHelper { ...@@ -935,7 +933,7 @@ class BigIntParseIntHelper : public StringToIntHelper {
} }
virtual void ResultMultiplyAdd(uint32_t multiplier, uint32_t part) { virtual void ResultMultiplyAdd(uint32_t multiplier, uint32_t part) {
result_->InplaceMultiplyAdd(static_cast<uintptr_t>(multiplier), BigInt::InplaceMultiplyAdd(result_, static_cast<uintptr_t>(multiplier),
static_cast<uintptr_t>(part)); static_cast<uintptr_t>(part));
} }
...@@ -944,7 +942,7 @@ class BigIntParseIntHelper : public StringToIntHelper { ...@@ -944,7 +942,7 @@ class BigIntParseIntHelper : public StringToIntHelper {
return behavior_ == Behavior::kParseInt ? kThrowOnError : kDontThrow; return behavior_ == Behavior::kParseInt ? kThrowOnError : kDontThrow;
} }
Handle<BigInt> result_; Handle<FreshlyAllocatedBigInt> result_;
Behavior behavior_; Behavior behavior_;
}; };
......
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
#include "src/conversions.h" #include "src/conversions.h"
#include "src/isolate-inl.h" #include "src/isolate-inl.h"
#include "src/macro-assembler.h" #include "src/macro-assembler.h"
#include "src/objects/bigint-inl.h" #include "src/objects/bigint.h"
#include "src/objects/debug-objects-inl.h" #include "src/objects/debug-objects-inl.h"
#include "src/objects/frame-array-inl.h" #include "src/objects/frame-array-inl.h"
#include "src/objects/module.h" #include "src/objects/module.h"
...@@ -1413,55 +1413,9 @@ Handle<HeapNumber> Factory::NewHeapNumber(MutableMode mode, ...@@ -1413,55 +1413,9 @@ Handle<HeapNumber> Factory::NewHeapNumber(MutableMode mode,
HeapNumber); HeapNumber);
} }
Handle<BigInt> Factory::NewBigInt(int length, PretenureFlag pretenure) { Handle<FreshlyAllocatedBigInt> Factory::NewBigInt(int length) {
CALL_HEAP_FUNCTION(isolate(), CALL_HEAP_FUNCTION(isolate(), isolate()->heap()->AllocateBigInt(length),
isolate()->heap()->AllocateBigInt(length, true, pretenure), FreshlyAllocatedBigInt);
BigInt);
}
Handle<BigInt> Factory::NewBigIntRaw(int length, PretenureFlag pretenure) {
CALL_HEAP_FUNCTION(
isolate(), isolate()->heap()->AllocateBigInt(length, false, pretenure),
BigInt);
}
Handle<BigInt> Factory::NewBigIntFromSafeInteger(double value,
PretenureFlag pretenure) {
if (value == 0) return NewBigInt(0);
uint64_t absolute = std::abs(value);
#if V8_TARGET_ARCH_64_BIT
static_assert(sizeof(BigInt::digit_t) == sizeof(uint64_t),
"unexpected BigInt digit size");
Handle<BigInt> result = NewBigIntRaw(1);
result->set_digit(0, absolute);
#else
static_assert(sizeof(BigInt::digit_t) == sizeof(uint32_t),
"unexpected BigInt digit size");
Handle<BigInt> result = NewBigIntRaw(2);
result->set_digit(0, absolute);
result->set_digit(1, absolute >> 32);
#endif
result->set_sign(value < 0); // Treats -0 like 0.
return result;
}
Handle<BigInt> Factory::NewBigIntFromInt(int value, PretenureFlag pretenure) {
if (value == 0) return NewBigInt(0);
Handle<BigInt> result = NewBigIntRaw(1);
if (value > 0) {
result->set_digit(0, value);
} else if (value == kMinInt) {
STATIC_ASSERT(kMinInt == -kMaxInt - 1);
result->set_digit(0, static_cast<BigInt::digit_t>(kMaxInt) + 1);
result->set_sign(true);
} else {
result->set_digit(0, -value);
result->set_sign(true);
}
return result;
} }
Handle<Object> Factory::NewError(Handle<JSFunction> constructor, Handle<Object> Factory::NewError(Handle<JSFunction> constructor,
......
...@@ -22,15 +22,15 @@ namespace internal { ...@@ -22,15 +22,15 @@ namespace internal {
// Forward declarations. // Forward declarations.
class AliasedArgumentsEntry; class AliasedArgumentsEntry;
class BigInt;
class BreakPointInfo; class BreakPointInfo;
class BreakPoint; class BreakPoint;
class BoilerplateDescription; class BoilerplateDescription;
class ConstantElementsPair; class ConstantElementsPair;
class CoverageInfo; class CoverageInfo;
class DebugInfo; class DebugInfo;
class NewFunctionArgs; class FreshlyAllocatedBigInt;
class JSModuleNamespace; class JSModuleNamespace;
class NewFunctionArgs;
struct SourceRange; struct SourceRange;
class PreParsedScopeData; class PreParsedScopeData;
class TemplateObjectDescription; class TemplateObjectDescription;
...@@ -485,15 +485,9 @@ class V8_EXPORT_PRIVATE Factory final { ...@@ -485,15 +485,9 @@ class V8_EXPORT_PRIVATE Factory final {
Handle<HeapNumber> NewHeapNumber(MutableMode mode, Handle<HeapNumber> NewHeapNumber(MutableMode mode,
PretenureFlag pretenure = NOT_TENURED); PretenureFlag pretenure = NOT_TENURED);
// Allocates a new BigInt with {length} digits and zero-initializes them. // Allocates a new BigInt with {length} digits. Only to be used by
Handle<BigInt> NewBigInt(int length, PretenureFlag pretenure = NOT_TENURED); // MutableBigInt::New*.
// Initializes length and sign fields, but leaves digits uninitialized. Handle<FreshlyAllocatedBigInt> NewBigInt(int length);
Handle<BigInt> NewBigIntRaw(int length,
PretenureFlag pretenure = NOT_TENURED);
Handle<BigInt> NewBigIntFromInt(int value,
PretenureFlag pretenure = NOT_TENURED);
Handle<BigInt> NewBigIntFromSafeInteger(
double value, PretenureFlag pretenure = NOT_TENURED);
Handle<JSObject> NewArgumentsObject(Handle<JSFunction> callee, int length); Handle<JSObject> NewArgumentsObject(Handle<JSFunction> callee, int length);
......
...@@ -2496,20 +2496,18 @@ AllocationResult Heap::AllocateHeapNumber(MutableMode mode, ...@@ -2496,20 +2496,18 @@ AllocationResult Heap::AllocateHeapNumber(MutableMode mode,
return result; return result;
} }
AllocationResult Heap::AllocateBigInt(int length, bool zero_initialize, AllocationResult Heap::AllocateBigInt(int length) {
PretenureFlag pretenure) {
if (length < 0 || length > BigInt::kMaxLength) { if (length < 0 || length > BigInt::kMaxLength) {
v8::internal::Heap::FatalProcessOutOfMemory("invalid BigInt length", true); v8::internal::Heap::FatalProcessOutOfMemory("invalid BigInt length", true);
} }
int size = BigInt::SizeFor(length); int size = BigInt::SizeFor(length);
AllocationSpace space = SelectSpace(pretenure); AllocationSpace space = SelectSpace(NOT_TENURED);
HeapObject* result = nullptr; HeapObject* result = nullptr;
{ {
AllocationResult allocation = AllocateRaw(size, space); AllocationResult allocation = AllocateRaw(size, space);
if (!allocation.To(&result)) return allocation; if (!allocation.To(&result)) return allocation;
} }
result->set_map_after_allocation(bigint_map(), SKIP_WRITE_BARRIER); result->set_map_after_allocation(bigint_map(), SKIP_WRITE_BARRIER);
BigInt::cast(result)->Initialize(length, zero_initialize);
return result; return result;
} }
......
...@@ -2030,9 +2030,7 @@ class Heap { ...@@ -2030,9 +2030,7 @@ class Heap {
MUST_USE_RESULT AllocationResult AllocateHeapNumber( MUST_USE_RESULT AllocationResult AllocateHeapNumber(
MutableMode mode = IMMUTABLE, PretenureFlag pretenure = NOT_TENURED); MutableMode mode = IMMUTABLE, PretenureFlag pretenure = NOT_TENURED);
MUST_USE_RESULT AllocationResult AllocateBigInt(int length, MUST_USE_RESULT AllocationResult AllocateBigInt(int length);
bool zero_initialize,
PretenureFlag pretenure);
// Allocates a byte array of the specified length // Allocates a byte array of the specified length
MUST_USE_RESULT AllocationResult MUST_USE_RESULT AllocationResult
......
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
#include "src/layout-descriptor.h" #include "src/layout-descriptor.h"
#include "src/macro-assembler.h" #include "src/macro-assembler.h"
#include "src/objects-inl.h" #include "src/objects-inl.h"
#include "src/objects/bigint-inl.h" #include "src/objects/bigint.h"
#include "src/objects/debug-objects-inl.h" #include "src/objects/debug-objects-inl.h"
#include "src/objects/literal-objects.h" #include "src/objects/literal-objects.h"
#include "src/objects/module.h" #include "src/objects/module.h"
......
...@@ -33,7 +33,7 @@ ...@@ -33,7 +33,7 @@
#include "src/lookup.h" #include "src/lookup.h"
#include "src/objects.h" #include "src/objects.h"
#include "src/objects/arguments-inl.h" #include "src/objects/arguments-inl.h"
#include "src/objects/bigint-inl.h" #include "src/objects/bigint.h"
#include "src/objects/hash-table-inl.h" #include "src/objects/hash-table-inl.h"
#include "src/objects/hash-table.h" #include "src/objects/hash-table.h"
#include "src/objects/js-array-inl.h" #include "src/objects/js-array-inl.h"
...@@ -74,6 +74,7 @@ int PropertyDetails::field_width_in_words() const { ...@@ -74,6 +74,7 @@ int PropertyDetails::field_width_in_words() const {
return representation().IsDouble() ? kDoubleSize / kPointerSize : 1; return representation().IsDouble() ? kDoubleSize / kPointerSize : 1;
} }
TYPE_CHECKER(BigInt, BIGINT_TYPE)
TYPE_CHECKER(BreakPoint, TUPLE2_TYPE) TYPE_CHECKER(BreakPoint, TUPLE2_TYPE)
TYPE_CHECKER(BreakPointInfo, TUPLE2_TYPE) TYPE_CHECKER(BreakPointInfo, TUPLE2_TYPE)
TYPE_CHECKER(ByteArray, BYTE_ARRAY_TYPE) TYPE_CHECKER(ByteArray, BYTE_ARRAY_TYPE)
......
// Copyright 2017 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_OBJECTS_BIGINT_INL_H_
#define V8_OBJECTS_BIGINT_INL_H_
#include "src/objects/bigint.h"
#include "src/objects.h"
// Has to be the last include (doesn't have include guards):
#include "src/objects/object-macros.h"
namespace v8 {
namespace internal {
int BigInt::length() const {
intptr_t bitfield = READ_INTPTR_FIELD(this, kBitfieldOffset);
return LengthBits::decode(static_cast<uint32_t>(bitfield));
}
void BigInt::set_length(int new_length) {
intptr_t bitfield = READ_INTPTR_FIELD(this, kBitfieldOffset);
bitfield = LengthBits::update(static_cast<uint32_t>(bitfield), new_length);
WRITE_INTPTR_FIELD(this, kBitfieldOffset, bitfield);
}
bool BigInt::sign() const {
intptr_t bitfield = READ_INTPTR_FIELD(this, kBitfieldOffset);
return SignBits::decode(static_cast<uint32_t>(bitfield));
}
void BigInt::set_sign(bool new_sign) {
intptr_t bitfield = READ_INTPTR_FIELD(this, kBitfieldOffset);
bitfield = SignBits::update(static_cast<uint32_t>(bitfield), new_sign);
WRITE_INTPTR_FIELD(this, kBitfieldOffset, bitfield);
}
BigInt::digit_t BigInt::digit(int n) const {
SLOW_DCHECK(0 <= n && n < length());
const byte* address = FIELD_ADDR_CONST(this, kDigitsOffset + n * kDigitSize);
return *reinterpret_cast<digit_t*>(reinterpret_cast<intptr_t>(address));
}
void BigInt::set_digit(int n, digit_t value) {
SLOW_DCHECK(0 <= n && n < length());
byte* address = FIELD_ADDR(this, kDigitsOffset + n * kDigitSize);
(*reinterpret_cast<digit_t*>(reinterpret_cast<intptr_t>(address))) = value;
}
TYPE_CHECKER(BigInt, BIGINT_TYPE)
} // namespace internal
} // namespace v8
#include "src/objects/object-macros-undef.h"
#endif // V8_OBJECTS_BIGINT_INL_H_
This diff is collapsed.
This diff is collapsed.
...@@ -1149,7 +1149,6 @@ ...@@ -1149,7 +1149,6 @@
'objects.h', 'objects.h',
'objects/arguments-inl.h', 'objects/arguments-inl.h',
'objects/arguments.h', 'objects/arguments.h',
'objects/bigint-inl.h',
'objects/bigint.cc', 'objects/bigint.cc',
'objects/bigint.h', 'objects/bigint.h',
'objects/code-inl.h', 'objects/code-inl.h',
......
...@@ -57,7 +57,9 @@ TEST(NoSideEffectsToString) { ...@@ -57,7 +57,9 @@ TEST(NoSideEffectsToString) {
CheckBoolean(isolate, true, "true"); CheckBoolean(isolate, true, "true");
CheckBoolean(isolate, false, "false"); CheckBoolean(isolate, false, "false");
CheckBoolean(isolate, false, "false"); CheckBoolean(isolate, false, "false");
CheckObject(isolate, factory->NewBigIntFromInt(42), "42"); Handle<Object> smi_42 = handle(Smi::FromInt(42), isolate);
CheckObject(isolate, BigInt::FromNumber(isolate, smi_42).ToHandleChecked(),
"42");
CheckObject(isolate, factory->undefined_value(), "undefined"); CheckObject(isolate, factory->undefined_value(), "undefined");
CheckObject(isolate, factory->null_value(), "null"); CheckObject(isolate, factory->null_value(), "null");
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
#include "src/factory.h" #include "src/factory.h"
#include "src/isolate.h" #include "src/isolate.h"
#include "src/objects-inl.h" #include "src/objects-inl.h"
#include "src/objects/bigint-inl.h" #include "src/objects/bigint.h"
#include "test/unittests/test-utils.h" #include "test/unittests/test-utils.h"
#include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest/include/gtest/gtest.h"
...@@ -22,11 +22,15 @@ void Compare(Handle<BigInt> x, double value, ComparisonResult expected) { ...@@ -22,11 +22,15 @@ void Compare(Handle<BigInt> x, double value, ComparisonResult expected) {
CHECK_EQ(expected, BigInt::CompareToDouble(x, value)); CHECK_EQ(expected, BigInt::CompareToDouble(x, value));
} }
Handle<BigInt> NewFromInt(Isolate* isolate, int value) {
Handle<Smi> smi_value = handle(Smi::FromInt(value), isolate);
return BigInt::FromNumber(isolate, smi_value).ToHandleChecked();
}
TEST_F(BigIntWithIsolate, CompareToDouble) { TEST_F(BigIntWithIsolate, CompareToDouble) {
Factory* factory = isolate()->factory(); Handle<BigInt> zero = NewFromInt(isolate(), 0);
Handle<BigInt> zero = factory->NewBigIntFromInt(0); Handle<BigInt> one = NewFromInt(isolate(), 1);
Handle<BigInt> one = factory->NewBigIntFromInt(1); Handle<BigInt> minus_one = NewFromInt(isolate(), -1);
Handle<BigInt> minus_one = factory->NewBigIntFromInt(-1);
// Non-finite doubles. // Non-finite doubles.
Compare(zero, std::nan(""), ComparisonResult::kUndefined); Compare(zero, std::nan(""), ComparisonResult::kUndefined);
...@@ -53,8 +57,8 @@ TEST_F(BigIntWithIsolate, CompareToDouble) { ...@@ -53,8 +57,8 @@ TEST_F(BigIntWithIsolate, CompareToDouble) {
Compare(minus_one, -0.5, ComparisonResult::kLessThan); Compare(minus_one, -0.5, ComparisonResult::kLessThan);
// Different bit lengths. // Different bit lengths.
Handle<BigInt> four = factory->NewBigIntFromInt(4); Handle<BigInt> four = NewFromInt(isolate(), 4);
Handle<BigInt> minus_five = factory->NewBigIntFromInt(-5); Handle<BigInt> minus_five = NewFromInt(isolate(), -5);
Compare(four, 3.9, ComparisonResult::kGreaterThan); Compare(four, 3.9, ComparisonResult::kGreaterThan);
Compare(four, 1.5, ComparisonResult::kGreaterThan); Compare(four, 1.5, ComparisonResult::kGreaterThan);
Compare(four, 8, ComparisonResult::kLessThan); Compare(four, 8, ComparisonResult::kLessThan);
...@@ -90,7 +94,7 @@ TEST_F(BigIntWithIsolate, CompareToDouble) { ...@@ -90,7 +94,7 @@ TEST_F(BigIntWithIsolate, CompareToDouble) {
// Same bit length, difference in fractional part. // Same bit length, difference in fractional part.
Compare(one, 1.5, ComparisonResult::kLessThan); Compare(one, 1.5, ComparisonResult::kLessThan);
Compare(minus_one, -1.25, ComparisonResult::kGreaterThan); Compare(minus_one, -1.25, ComparisonResult::kGreaterThan);
big = factory->NewBigIntFromInt(0xF00D00); big = NewFromInt(isolate(), 0xF00D00);
Compare(big, 15731968.125, ComparisonResult::kLessThan); Compare(big, 15731968.125, ComparisonResult::kLessThan);
Compare(big, 15731967.875, ComparisonResult::kGreaterThan); Compare(big, 15731967.875, ComparisonResult::kGreaterThan);
big = BigIntLiteral(isolate(), "0x123456789ab").ToHandleChecked(); big = BigIntLiteral(isolate(), "0x123456789ab").ToHandleChecked();
......
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