Commit aa3aaa76 authored by Leszek Swirski's avatar Leszek Swirski Committed by Commit Bot

[offthread] OffThreadFactory support for BigInt

This CL templatizes some methods in BigInt on the Isolate type, to allow
BigInts to be allocated off-thread from a BigInt literal.

A necessary side-effect is exporting the Isolate class in its entirety,
to allow it to be used as a specializing type for ' HandleFor' in
unittests.

Bug: chromium:1011762
Change-Id: I768f9e4d46a4532d6818d9a67c13801bc5952e5d
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2036079
Commit-Queue: Leszek Swirski <leszeks@chromium.org>
Reviewed-by: 's avatarUlan Degenbaev <ulan@chromium.org>
Reviewed-by: 's avatarJakob Kummerow <jkummerow@chromium.org>
Cr-Commit-Position: refs/heads/master@{#66105}
parent e9559993
......@@ -453,14 +453,14 @@ struct HandleTraits<Isolate> {
template <typename T>
using HandleType = Handle<T>;
template <typename T>
using MaybeHandleType = v8::internal::MaybeHandle<T>;
using MaybeHandleType = MaybeHandle<T>;
};
// HiddenFactory exists so Isolate can privately inherit from it without making
// Factory's members available to Isolate directly.
class V8_EXPORT_PRIVATE HiddenFactory : private Factory {};
class Isolate final : private HiddenFactory {
class V8_EXPORT_PRIVATE Isolate final : private HiddenFactory {
// These forward declarations are required to make the friend declarations in
// PerIsolateThreadData work on some older versions of gcc.
class ThreadDataTable;
......@@ -519,7 +519,7 @@ class Isolate final : private HiddenFactory {
// Creates Isolate object. Must be used instead of constructing Isolate with
// new operator.
static V8_EXPORT_PRIVATE Isolate* New(
static Isolate* New(
IsolateAllocationMode mode = IsolateAllocationMode::kDefault);
// Deletes Isolate object. Must be used instead of delete operator.
......@@ -623,7 +623,7 @@ class Isolate final : private HiddenFactory {
inline void set_pending_exception(Object exception_obj);
inline void clear_pending_exception();
V8_EXPORT_PRIVATE bool AreWasmThreadsEnabled(Handle<Context> context);
bool AreWasmThreadsEnabled(Handle<Context> context);
THREAD_LOCAL_TOP_ADDRESS(Object, pending_exception)
......@@ -686,9 +686,9 @@ class Isolate final : private HiddenFactory {
return &thread_local_top()->js_entry_sp_;
}
V8_EXPORT_PRIVATE std::vector<MemoryRange>* GetCodePages() const;
std::vector<MemoryRange>* GetCodePages() const;
V8_EXPORT_PRIVATE void SetCodePages(std::vector<MemoryRange>* new_code_pages);
void SetCodePages(std::vector<MemoryRange>* new_code_pages);
// Returns the global object of the current context. It could be
// a builtin object, or a JS global object.
......@@ -704,7 +704,7 @@ class Isolate final : private HiddenFactory {
// exceptions. If an exception was thrown and not handled by an external
// handler the exception is scheduled to be rethrown when we return to running
// JavaScript code. If an exception is scheduled true is returned.
V8_EXPORT_PRIVATE bool OptionalRescheduleException(bool clear_exception);
bool OptionalRescheduleException(bool clear_exception);
// Push and pop a promise and the current try-catch handler.
void PushPromise(Handle<JSObject> promise);
......@@ -729,7 +729,7 @@ class Isolate final : private HiddenFactory {
Handle<Object> pending_exception_;
};
V8_EXPORT_PRIVATE void SetCaptureStackTraceForUncaughtExceptions(
void SetCaptureStackTraceForUncaughtExceptions(
bool capture, int frame_limit, StackTrace::StackTraceOptions options);
void SetAbortOnUncaughtExceptionCallback(
......@@ -739,8 +739,7 @@ class Isolate final : private HiddenFactory {
void PrintCurrentStackTrace(FILE* out);
void PrintStack(StringStream* accumulator,
PrintStackMode mode = kPrintStackVerbose);
V8_EXPORT_PRIVATE void PrintStack(FILE* out,
PrintStackMode mode = kPrintStackVerbose);
void PrintStack(FILE* out, PrintStackMode mode = kPrintStackVerbose);
Handle<String> StackTraceString();
// Stores a stack trace in a stack-allocated temporary buffer which will
// end up in the minidump for debugging purposes.
......@@ -821,7 +820,7 @@ class Isolate final : private HiddenFactory {
};
CatchType PredictExceptionCatcher();
V8_EXPORT_PRIVATE void ScheduleThrow(Object exception);
void ScheduleThrow(Object exception);
// Re-set pending message, script and positions reported to the TryCatch
// back to the TLS for re-use when rethrowing.
void RestorePendingMessageFromTryCatch(v8::TryCatch* handler);
......@@ -843,19 +842,18 @@ class Isolate final : private HiddenFactory {
bool ComputeLocation(MessageLocation* target);
bool ComputeLocationFromException(MessageLocation* target,
Handle<Object> exception);
V8_EXPORT_PRIVATE bool ComputeLocationFromStackTrace(
MessageLocation* target, Handle<Object> exception);
bool ComputeLocationFromStackTrace(MessageLocation* target,
Handle<Object> exception);
V8_EXPORT_PRIVATE Handle<JSMessageObject> CreateMessage(
Handle<Object> exception, MessageLocation* location);
Handle<JSMessageObject> CreateMessage(Handle<Object> exception,
MessageLocation* location);
// Out of resource exception helpers.
Object StackOverflow();
Object TerminateExecution();
void CancelTerminateExecution();
V8_EXPORT_PRIVATE void RequestInterrupt(InterruptCallback callback,
void* data);
void RequestInterrupt(InterruptCallback callback, void* data);
void InvokeApiInterruptCallbacks();
// Administration
......@@ -1099,13 +1097,13 @@ class Isolate final : private HiddenFactory {
bool IsDead() { return has_fatal_error_; }
void SignalFatalError() { has_fatal_error_ = true; }
V8_EXPORT_PRIVATE bool use_optimizer();
bool use_optimizer();
bool initialized_from_snapshot() { return initialized_from_snapshot_; }
bool NeedsSourcePositionsForProfiling() const;
V8_EXPORT_PRIVATE bool NeedsDetailedOptimizedCodeLineInfo() const;
bool NeedsDetailedOptimizedCodeLineInfo() const;
bool is_best_effort_code_coverage() const {
return code_coverage_mode() == debug::CoverageMode::kBestEffort;
......@@ -1158,7 +1156,7 @@ class Isolate final : private HiddenFactory {
DateCache* date_cache() { return date_cache_; }
V8_EXPORT_PRIVATE void set_date_cache(DateCache* date_cache);
void set_date_cache(DateCache* date_cache);
#ifdef V8_INTL_SUPPORT
......@@ -1230,7 +1228,7 @@ class Isolate final : private HiddenFactory {
int id() const { return id_; }
CompilationStatistics* GetTurboStatistics();
V8_EXPORT_PRIVATE CodeTracer* GetCodeTracer();
CodeTracer* GetCodeTracer();
void DumpAndResetStats();
......@@ -1244,16 +1242,16 @@ class Isolate final : private HiddenFactory {
return &debug_execution_mode_;
}
V8_EXPORT_PRIVATE base::RandomNumberGenerator* random_number_generator();
base::RandomNumberGenerator* random_number_generator();
V8_EXPORT_PRIVATE base::RandomNumberGenerator* fuzzer_rng();
base::RandomNumberGenerator* fuzzer_rng();
// Generates a random number that is non-zero when masked
// with the provided mask.
int GenerateIdentityHash(uint32_t mask);
// Given an address occupied by a live code object, return that object.
V8_EXPORT_PRIVATE Code FindCodeObject(Address a);
Code FindCodeObject(Address a);
int NextOptimizationId() {
int id = next_optimization_id_++;
......@@ -1283,8 +1281,7 @@ class Isolate final : private HiddenFactory {
Handle<Symbol> SymbolFor(RootIndex dictionary_index, Handle<String> name,
bool private_symbol);
V8_EXPORT_PRIVATE void SetUseCounterCallback(
v8::Isolate::UseCounterCallback callback);
void SetUseCounterCallback(v8::Isolate::UseCounterCallback callback);
void CountUsage(v8::Isolate::UseCounterFeature feature);
static std::string GetTurboCfgFileName(Isolate* isolate);
......@@ -1322,9 +1319,8 @@ class Isolate final : private HiddenFactory {
double timeout_in_ms,
AtomicsWaitWakeHandle* stop_handle);
V8_EXPORT_PRIVATE void SetPromiseHook(PromiseHook hook);
V8_EXPORT_PRIVATE void RunPromiseHook(PromiseHookType type,
Handle<JSPromise> promise,
void SetPromiseHook(PromiseHook hook);
void RunPromiseHook(PromiseHookType type, Handle<JSPromise> promise,
Handle<Object> parent);
void PromiseHookStateUpdated();
......@@ -1350,14 +1346,14 @@ class Isolate final : private HiddenFactory {
// builtins constants table to remain unchanged from build-time.
size_t HashIsolateForEmbeddedBlob();
V8_EXPORT_PRIVATE static const uint8_t* CurrentEmbeddedBlob();
V8_EXPORT_PRIVATE static uint32_t CurrentEmbeddedBlobSize();
static const uint8_t* CurrentEmbeddedBlob();
static uint32_t CurrentEmbeddedBlobSize();
static bool CurrentEmbeddedBlobIsBinaryEmbedded();
// These always return the same result as static methods above, but don't
// access the global atomic variable (and thus *might be* slightly faster).
V8_EXPORT_PRIVATE const uint8_t* embedded_blob() const;
V8_EXPORT_PRIVATE uint32_t embedded_blob_size() const;
const uint8_t* embedded_blob() const;
uint32_t embedded_blob_size() const;
void set_array_buffer_allocator(v8::ArrayBuffer::Allocator* allocator) {
array_buffer_allocator_ = allocator;
......@@ -1411,13 +1407,12 @@ class Isolate final : private HiddenFactory {
void SetHostImportModuleDynamicallyCallback(
HostImportModuleDynamicallyCallback callback);
V8_EXPORT_PRIVATE MaybeHandle<JSPromise>
RunHostImportModuleDynamicallyCallback(Handle<Script> referrer,
Handle<Object> specifier);
MaybeHandle<JSPromise> RunHostImportModuleDynamicallyCallback(
Handle<Script> referrer, Handle<Object> specifier);
void SetHostInitializeImportMetaObjectCallback(
HostInitializeImportMetaObjectCallback callback);
V8_EXPORT_PRIVATE Handle<JSObject> RunHostInitializeImportMetaObjectCallback(
Handle<JSObject> RunHostInitializeImportMetaObjectCallback(
Handle<SourceTextModule> module);
void RegisterEmbeddedFileWriter(EmbeddedFileWriterInterface* writer) {
......@@ -1476,8 +1471,7 @@ class Isolate final : private HiddenFactory {
bool allow_atomics_wait() { return allow_atomics_wait_; }
// Register a finalizer to be called at isolate teardown.
V8_EXPORT_PRIVATE void RegisterManagedPtrDestructor(
ManagedPtrDestructor* finalizer);
void RegisterManagedPtrDestructor(ManagedPtrDestructor* finalizer);
// Removes a previously-registered shared object finalizer.
void UnregisterManagedPtrDestructor(ManagedPtrDestructor* finalizer);
......@@ -1488,8 +1482,7 @@ class Isolate final : private HiddenFactory {
}
wasm::WasmEngine* wasm_engine() const { return wasm_engine_.get(); }
V8_EXPORT_PRIVATE void SetWasmEngine(
std::shared_ptr<wasm::WasmEngine> engine);
void SetWasmEngine(std::shared_ptr<wasm::WasmEngine> engine);
const v8::Context::BackupIncumbentScope* top_backup_incumbent_scope() const {
return top_backup_incumbent_scope_;
......@@ -1499,22 +1492,22 @@ class Isolate final : private HiddenFactory {
top_backup_incumbent_scope_ = top_backup_incumbent_scope;
}
V8_EXPORT_PRIVATE void SetIdle(bool is_idle);
void SetIdle(bool is_idle);
// Changing various modes can cause differences in generated bytecode which
// interferes with lazy source positions, so this should be called immediately
// before such a mode change to ensure that this cannot happen.
V8_EXPORT_PRIVATE void CollectSourcePositionsForAllBytecodeArrays();
void CollectSourcePositionsForAllBytecodeArrays();
void AddCodeMemoryChunk(MemoryChunk* chunk);
void RemoveCodeMemoryChunk(MemoryChunk* chunk);
V8_EXPORT_PRIVATE void AddCodeRange(Address begin, size_t length_in_bytes);
void AddCodeRange(Address begin, size_t length_in_bytes);
private:
explicit Isolate(std::unique_ptr<IsolateAllocator> isolate_allocator);
~Isolate();
V8_EXPORT_PRIVATE bool Init(ReadOnlyDeserializer* read_only_deserializer,
bool Init(ReadOnlyDeserializer* read_only_deserializer,
StartupDeserializer* startup_deserializer);
void CheckIsolateLayout();
......@@ -1712,7 +1705,7 @@ class Isolate final : private HiddenFactory {
double time_millis_at_init_ = 0;
#ifdef DEBUG
V8_EXPORT_PRIVATE static std::atomic<size_t> non_disposed_isolates_;
static std::atomic<size_t> non_disposed_isolates_;
JSObject::SpillInformation js_spill_information_;
#endif
......@@ -1748,7 +1741,7 @@ class Isolate final : private HiddenFactory {
// preprocessor defines. Make sure the offsets of these fields agree
// between compilation units.
#define ISOLATE_FIELD_OFFSET(type, name, ignored) \
V8_EXPORT_PRIVATE static const intptr_t name##_debug_offset_;
static const intptr_t name##_debug_offset_;
ISOLATE_INIT_LIST(ISOLATE_FIELD_OFFSET)
ISOLATE_INIT_ARRAY_LIST(ISOLATE_FIELD_OFFSET)
#undef ISOLATE_FIELD_OFFSET
......
......@@ -173,6 +173,19 @@ HandleFor<Impl, String> FactoryBase<Impl>::NewConsString(
return result;
}
template <typename Impl>
HandleFor<Impl, FreshlyAllocatedBigInt> FactoryBase<Impl>::NewBigInt(
int length, AllocationType allocation) {
if (length < 0 || length > BigInt::kMaxLength) {
isolate()->FatalProcessOutOfHeapMemory("invalid BigInt length");
}
HeapObject result = AllocateRawWithImmortalMap(
BigInt::SizeFor(length), allocation, read_only_roots().bigint_map());
FreshlyAllocatedBigInt bigint = FreshlyAllocatedBigInt::cast(result);
bigint.clear_padding();
return handle(bigint, isolate());
}
template <typename Impl>
HandleFor<Impl, SeqOneByteString>
FactoryBase<Impl>::AllocateRawOneByteInternalizedString(int length,
......
......@@ -15,6 +15,7 @@ namespace internal {
class HeapObject;
class SeqOneByteString;
class SeqTwoByteString;
class FreshlyAllocatedBigInt;
template <typename Impl>
class V8_EXPORT_PRIVATE FactoryBase {
......@@ -47,6 +48,11 @@ class V8_EXPORT_PRIVATE FactoryBase {
HandleFor<Impl, String> left, HandleFor<Impl, String> right, int length,
bool one_byte, AllocationType allocation = AllocationType::kYoung);
// Allocates a new BigInt with {length} digits. Only to be used by
// MutableBigInt::New*.
HandleFor<Impl, FreshlyAllocatedBigInt> NewBigInt(
int length, AllocationType allocation = AllocationType::kYoung);
protected:
HeapObject AllocateRawWithImmortalMap(
int size, AllocationType allocation, Map map,
......
......@@ -2071,18 +2071,6 @@ Handle<HeapNumber> Factory::NewHeapNumberForCodeAssembler(double value) {
: NewHeapNumber<AllocationType::kOld>(value);
}
Handle<FreshlyAllocatedBigInt> Factory::NewBigInt(int length,
AllocationType allocation) {
if (length < 0 || length > BigInt::kMaxLength) {
isolate()->heap()->FatalProcessOutOfMemory("invalid BigInt length");
}
HeapObject result = AllocateRawWithImmortalMap(BigInt::SizeFor(length),
allocation, *bigint_map());
FreshlyAllocatedBigInt bigint = FreshlyAllocatedBigInt::cast(result);
bigint.clear_padding();
return handle(bigint, isolate());
}
Handle<JSObject> Factory::NewError(Handle<JSFunction> constructor,
MessageTemplate template_index,
Handle<Object> arg0, Handle<Object> arg1,
......
......@@ -113,7 +113,7 @@ struct HandleTraits<Factory> {
template <typename T>
using HandleType = Handle<T>;
template <typename T>
using MaybeHandleType = v8::internal::MaybeHandle<T>;
using MaybeHandleType = MaybeHandle<T>;
};
// Interface for handle based allocation.
......@@ -556,11 +556,6 @@ class V8_EXPORT_PRIVATE Factory : public FactoryBase<Factory> {
inline Handle<HeapNumber> NewHeapNumberWithHoleNaN();
// Allocates a new BigInt with {length} digits. Only to be used by
// MutableBigInt::New*.
Handle<FreshlyAllocatedBigInt> NewBigInt(
int length, AllocationType allocation = AllocationType::kYoung);
Handle<JSObject> NewArgumentsObject(Handle<JSFunction> callee, int length);
// Allocates and initializes a new JavaScript object based on a
......
......@@ -162,11 +162,6 @@ void OffThreadFactory::Publish(Isolate* isolate) {
}
}
OffThreadHandle<Object> OffThreadFactory::NewInvalidStringLengthError() {
// TODO(leszeks): Implement.
UNREACHABLE();
}
// Hacky method for creating a simple object with a slot pointing to a string.
// TODO(leszeks): Remove once we have full FixedArray support.
OffThreadHandle<FixedArray> OffThreadFactory::StringWrapperForTest(
......
......@@ -7,6 +7,7 @@
#include <map>
#include <vector>
#include "src/base/logging.h"
#include "src/common/globals.h"
#include "src/handles/handles.h"
#include "src/heap/factory-base.h"
......@@ -59,7 +60,12 @@ class V8_EXPORT_PRIVATE OffThreadFactory
void FinishOffThread();
void Publish(Isolate* isolate);
OffThreadHandle<Object> NewInvalidStringLengthError();
// The parser shouldn't allow the OffThreadFactory to get into a state where
// it generates errors.
OffThreadHandle<Object> NewInvalidStringLengthError() { UNREACHABLE(); }
OffThreadHandle<Object> NewRangeError(MessageTemplate template_index) {
UNREACHABLE();
}
OffThreadHandle<FixedArray> StringWrapperForTest(
OffThreadHandle<String> string);
......
......@@ -9,6 +9,7 @@
#include <cmath>
#include "src/common/assert-scope.h"
#include "src/execution/off-thread-isolate.h"
#include "src/handles/handles.h"
#include "src/heap/factory.h"
#include "src/numbers/dtoa.h"
......@@ -167,18 +168,29 @@ double InternalStringToIntDouble(Iterator current, EndMark end, bool negative,
return std::ldexp(static_cast<double>(negative ? -number : number), exponent);
}
namespace {
// Subclasses of StringToIntHelper get access to internal state:
enum class State { kRunning, kError, kJunk, kEmpty, kZero, kDone };
enum class Sign { kNegative, kPositive, kNone };
} // namespace
// ES6 18.2.5 parseInt(string, radix) (with NumberParseIntHelper subclass);
// and BigInt parsing cases from https://tc39.github.io/proposal-bigint/
// (with StringToBigIntHelper subclass).
template <typename Isolate>
class StringToIntHelper {
public:
StringToIntHelper(Isolate* isolate, Handle<String> subject, int radix)
StringToIntHelper(Isolate* isolate, HandleFor<Isolate, String> subject,
int radix)
: isolate_(isolate), subject_(subject), radix_(radix) {
DCHECK(subject->IsFlat());
}
// Used for the StringToBigInt operation.
StringToIntHelper(Isolate* isolate, Handle<String> subject)
StringToIntHelper(Isolate* isolate, HandleFor<Isolate, String> subject)
: isolate_(isolate), subject_(subject) {
DCHECK(subject->IsFlat());
}
......@@ -225,11 +237,6 @@ class StringToIntHelper {
return subject_->GetFlatContent(no_gc).ToUC16Vector();
}
// Subclasses get access to internal state:
enum State { kRunning, kError, kJunk, kEmpty, kZero, kDone };
enum class Sign { kNegative, kPositive, kNone };
Isolate* isolate() { return isolate_; }
int radix() { return radix_; }
int cursor() { return cursor_; }
......@@ -246,7 +253,7 @@ class StringToIntHelper {
void ParseInternal(Char start);
Isolate* isolate_;
Handle<String> subject_;
HandleFor<Isolate, String> subject_;
const uint8_t* raw_one_byte_subject_ = nullptr;
int radix_ = 0;
int cursor_ = 0;
......@@ -255,10 +262,11 @@ class StringToIntHelper {
bool leading_zero_ = false;
bool allow_binary_and_octal_prefixes_ = false;
bool allow_trailing_junk_ = true;
State state_ = kRunning;
State state_ = State::kRunning;
};
void StringToIntHelper::ParseInt() {
template <typename Isolate>
void StringToIntHelper<Isolate>::ParseInt() {
{
DisallowHeapAllocation no_gc;
if (IsOneByte()) {
......@@ -269,10 +277,10 @@ void StringToIntHelper::ParseInt() {
DetectRadixInternal(vector.begin(), vector.length());
}
}
if (state_ != kRunning) return;
if (state_ != State::kRunning) return;
AllocateResult();
HandleSpecialCases();
if (state_ != kRunning) return;
if (state_ != State::kRunning) return;
{
DisallowHeapAllocation no_gc;
if (IsOneByte()) {
......@@ -285,30 +293,31 @@ void StringToIntHelper::ParseInt() {
ParseInternal(vector.begin());
}
}
DCHECK_NE(state_, kRunning);
DCHECK_NE(state_, State::kRunning);
}
template <typename Isolate>
template <class Char>
void StringToIntHelper::DetectRadixInternal(Char current, int length) {
void StringToIntHelper<Isolate>::DetectRadixInternal(Char current, int length) {
Char start = current;
length_ = length;
Char end = start + length;
if (!AdvanceToNonspace(&current, end)) {
return set_state(kEmpty);
return set_state(State::kEmpty);
}
if (*current == '+') {
// Ignore leading sign; skip following spaces.
++current;
if (current == end) {
return set_state(kJunk);
return set_state(State::kJunk);
}
sign_ = Sign::kPositive;
} else if (*current == '-') {
++current;
if (current == end) {
return set_state(kJunk);
return set_state(State::kJunk);
}
sign_ = Sign::kNegative;
}
......@@ -318,21 +327,21 @@ void StringToIntHelper::DetectRadixInternal(Char current, int length) {
radix_ = 10;
if (*current == '0') {
++current;
if (current == end) return set_state(kZero);
if (current == end) return set_state(State::kZero);
if (*current == 'x' || *current == 'X') {
radix_ = 16;
++current;
if (current == end) return set_state(kJunk);
if (current == end) return set_state(State::kJunk);
} else if (allow_binary_and_octal_prefixes_ &&
(*current == 'o' || *current == 'O')) {
radix_ = 8;
++current;
if (current == end) return set_state(kJunk);
if (current == end) return set_state(State::kJunk);
} else if (allow_binary_and_octal_prefixes_ &&
(*current == 'b' || *current == 'B')) {
radix_ = 2;
++current;
if (current == end) return set_state(kJunk);
if (current == end) return set_state(State::kJunk);
} else {
leading_zero_ = true;
}
......@@ -341,10 +350,10 @@ void StringToIntHelper::DetectRadixInternal(Char current, int length) {
if (*current == '0') {
// Allow "0x" prefix.
++current;
if (current == end) return set_state(kZero);
if (current == end) return set_state(State::kZero);
if (*current == 'x' || *current == 'X') {
++current;
if (current == end) return set_state(kJunk);
if (current == end) return set_state(State::kJunk);
} else {
leading_zero_ = true;
}
......@@ -354,11 +363,11 @@ void StringToIntHelper::DetectRadixInternal(Char current, int length) {
while (*current == '0') {
leading_zero_ = true;
++current;
if (current == end) return set_state(kZero);
if (current == end) return set_state(State::kZero);
}
if (!leading_zero_ && !isDigit(*current, radix_)) {
return set_state(kJunk);
return set_state(State::kJunk);
}
DCHECK(radix_ >= 2 && radix_ <= 36);
......@@ -366,8 +375,9 @@ void StringToIntHelper::DetectRadixInternal(Char current, int length) {
cursor_ = static_cast<int>(current - start);
}
template <typename Isolate>
template <class Char>
void StringToIntHelper::ParseInternal(Char start) {
void StringToIntHelper<Isolate>::ParseInternal(Char start) {
Char current = start + cursor_;
Char end = start + length_;
......@@ -426,13 +436,13 @@ void StringToIntHelper::ParseInternal(Char start) {
} while (!done);
if (!allow_trailing_junk_ && AdvanceToNonspace(&current, end)) {
return set_state(kJunk);
return set_state(State::kJunk);
}
return set_state(kDone);
return set_state(State::kDone);
}
class NumberParseIntHelper : public StringToIntHelper {
class NumberParseIntHelper : public StringToIntHelper<Isolate> {
public:
NumberParseIntHelper(Isolate* isolate, Handle<String> string, int radix)
: StringToIntHelper(isolate, string, radix) {}
......@@ -440,15 +450,15 @@ class NumberParseIntHelper : public StringToIntHelper {
double GetResult() {
ParseInt();
switch (state()) {
case kJunk:
case kEmpty:
case State::kJunk:
case State::kEmpty:
return JunkStringValue();
case kZero:
case State::kZero:
return SignedZero(negative());
case kDone:
case State::kDone:
return negative() ? -result_ : result_;
case kError:
case kRunning:
case State::kError:
case State::kRunning:
break;
}
UNREACHABLE();
......@@ -476,7 +486,7 @@ class NumberParseIntHelper : public StringToIntHelper {
result_ = is_power_of_two ? HandlePowerOfTwoCase(vector.begin())
: HandleBaseTenCase(vector.begin());
}
set_state(kDone);
set_state(State::kDone);
}
template <class Char>
......@@ -825,59 +835,50 @@ double StringToInt(Isolate* isolate, Handle<String> string, int radix) {
return helper.GetResult();
}
class StringToBigIntHelper : public StringToIntHelper {
template <typename Isolate>
class StringToBigIntHelper : public StringToIntHelper<Isolate> {
public:
enum class Behavior { kStringToBigInt, kLiteral };
// Used for StringToBigInt operation (BigInt constructor and == operator).
StringToBigIntHelper(Isolate* isolate, Handle<String> string)
: StringToIntHelper(isolate, string),
StringToBigIntHelper(Isolate* isolate, HandleFor<Isolate, String> string)
: StringToIntHelper<Isolate>(isolate, string),
behavior_(Behavior::kStringToBigInt) {
set_allow_binary_and_octal_prefixes();
set_disallow_trailing_junk();
this->set_allow_binary_and_octal_prefixes();
this->set_disallow_trailing_junk();
}
// Used for parsing BigInt literals, where the input is a buffer of
// one-byte ASCII digits, along with an optional radix prefix.
StringToBigIntHelper(Isolate* isolate, const uint8_t* string, int length)
: StringToIntHelper(isolate, string, length),
: StringToIntHelper<Isolate>(isolate, string, length),
behavior_(Behavior::kLiteral) {
set_allow_binary_and_octal_prefixes();
this->set_allow_binary_and_octal_prefixes();
}
MaybeHandle<BigInt> GetResult() {
ParseInt();
if (behavior_ == Behavior::kStringToBigInt && sign() != Sign::kNone &&
radix() != 10) {
return MaybeHandle<BigInt>();
MaybeHandleFor<Isolate, BigInt> GetResult() {
this->ParseInt();
if (behavior_ == Behavior::kStringToBigInt && this->sign() != Sign::kNone &&
this->radix() != 10) {
return MaybeHandleFor<Isolate, BigInt>();
}
if (state() == kEmpty) {
if (this->state() == State::kEmpty) {
if (behavior_ == Behavior::kStringToBigInt) {
set_state(kZero);
this->set_state(State::kZero);
} else {
UNREACHABLE();
}
}
switch (state()) {
case kJunk:
if (should_throw() == kThrowOnError) {
THROW_NEW_ERROR(isolate(),
NewSyntaxError(MessageTemplate::kBigIntInvalidString),
BigInt);
} else {
DCHECK_EQ(should_throw(), kDontThrow);
return MaybeHandle<BigInt>();
}
case kZero:
return BigInt::Zero(isolate());
case kError:
DCHECK_EQ(should_throw() == kThrowOnError,
isolate()->has_pending_exception());
return MaybeHandle<BigInt>();
case kDone:
return BigInt::Finalize(result_, negative());
case kEmpty:
case kRunning:
switch (this->state()) {
case State::kJunk:
case State::kError:
return MaybeHandleFor<Isolate, BigInt>();
case State::kZero:
return BigInt::Zero(this->isolate());
case State::kDone:
return BigInt::Finalize<Isolate>(result_, this->negative());
case State::kEmpty:
case State::kRunning:
break;
}
UNREACHABLE();
......@@ -889,42 +890,48 @@ class StringToBigIntHelper : public StringToIntHelper {
// Conseratively assume that all remaining digits are significant.
// Optimization opportunity: Would it makes sense to scan for trailing
// junk before allocating the result?
int charcount = length() - cursor();
int charcount = this->length() - this->cursor();
// For literals, we pretenure the allocated BigInt, since it's about
// to be stored in the interpreter's constants array.
AllocationType allocation = behavior_ == Behavior::kLiteral
? AllocationType::kOld
: AllocationType::kYoung;
MaybeHandle<FreshlyAllocatedBigInt> maybe = BigInt::AllocateFor(
isolate(), radix(), charcount, should_throw(), allocation);
MaybeHandleFor<Isolate, FreshlyAllocatedBigInt> maybe = BigInt::AllocateFor(
this->isolate(), this->radix(), charcount, kDontThrow, allocation);
if (!maybe.ToHandle(&result_)) {
set_state(kError);
this->set_state(State::kError);
}
}
void ResultMultiplyAdd(uint32_t multiplier, uint32_t part) override {
BigInt::InplaceMultiplyAdd(result_, static_cast<uintptr_t>(multiplier),
BigInt::InplaceMultiplyAdd(*result_, static_cast<uintptr_t>(multiplier),
static_cast<uintptr_t>(part));
}
private:
ShouldThrow should_throw() const { return kDontThrow; }
Handle<FreshlyAllocatedBigInt> result_;
HandleFor<Isolate, FreshlyAllocatedBigInt> result_;
Behavior behavior_;
};
MaybeHandle<BigInt> StringToBigInt(Isolate* isolate, Handle<String> string) {
string = String::Flatten(isolate, string);
StringToBigIntHelper helper(isolate, string);
StringToBigIntHelper<Isolate> helper(isolate, string);
return helper.GetResult();
}
MaybeHandle<BigInt> BigIntLiteral(Isolate* isolate, const char* string) {
StringToBigIntHelper helper(isolate, reinterpret_cast<const uint8_t*>(string),
template <typename Isolate>
MaybeHandleFor<Isolate, BigInt> BigIntLiteral(Isolate* isolate,
const char* string) {
StringToBigIntHelper<Isolate> helper(isolate,
reinterpret_cast<const uint8_t*>(string),
static_cast<int>(strlen(string)));
return helper.GetResult();
}
template EXPORT_TEMPLATE_DEFINE(V8_EXPORT_PRIVATE)
MaybeHandle<BigInt> BigIntLiteral(Isolate* isolate, const char* string);
template EXPORT_TEMPLATE_DEFINE(V8_EXPORT_PRIVATE)
OffThreadHandle<BigInt> BigIntLiteral(OffThreadIsolate* isolate,
const char* string);
const char* DoubleToCString(double v, Vector<char> buffer) {
switch (FPCLASSIFY_NAMESPACE::fpclassify(v)) {
......
......@@ -5,8 +5,10 @@
#ifndef V8_NUMBERS_CONVERSIONS_H_
#define V8_NUMBERS_CONVERSIONS_H_
#include "src/base/export-template.h"
#include "src/base/logging.h"
#include "src/common/globals.h"
#include "src/handles/handle-for.h"
#include "src/utils/vector.h"
namespace v8 {
......@@ -99,7 +101,9 @@ MaybeHandle<BigInt> StringToBigInt(Isolate* isolate, Handle<String> string);
// 0x -> hex
// 0o -> octal
// 0b -> binary
V8_EXPORT_PRIVATE MaybeHandle<BigInt> BigIntLiteral(Isolate* isolate,
template <typename Isolate>
EXPORT_TEMPLATE_DECLARE(V8_EXPORT_PRIVATE)
MaybeHandleFor<Isolate, BigInt> BigIntLiteral(Isolate* isolate,
const char* string);
const int kDoubleToCStringMinBufferSize = 100;
......
......@@ -20,6 +20,7 @@
#include "src/objects/bigint.h"
#include "src/execution/isolate-inl.h"
#include "src/execution/off-thread-isolate.h"
#include "src/heap/factory.h"
#include "src/heap/heap-write-barrier-inl.h"
#include "src/numbers/conversions.h"
......@@ -44,12 +45,15 @@ class MutableBigInt : public FreshlyAllocatedBigInt {
public:
// Bottleneck for converting MutableBigInts to BigInts.
static MaybeHandle<BigInt> MakeImmutable(MaybeHandle<MutableBigInt> maybe);
static Handle<BigInt> MakeImmutable(Handle<MutableBigInt> result);
template <typename Isolate = v8::internal::Isolate>
static HandleFor<Isolate, BigInt> MakeImmutable(
HandleFor<Isolate, MutableBigInt> result);
static void Canonicalize(MutableBigInt result);
// Allocation helpers.
static MaybeHandle<MutableBigInt> New(
template <typename Isolate>
static MaybeHandleFor<Isolate, MutableBigInt> New(
Isolate* isolate, int length,
AllocationType allocation = AllocationType::kYoung);
static Handle<BigInt> NewFromInt(Isolate* isolate, int value);
......@@ -57,15 +61,21 @@ class MutableBigInt : public FreshlyAllocatedBigInt {
void InitializeDigits(int length, byte value = 0);
static Handle<MutableBigInt> Copy(Isolate* isolate,
Handle<BigIntBase> source);
static Handle<BigInt> Zero(Isolate* isolate) {
template <typename Isolate>
static HandleFor<Isolate, BigInt> Zero(Isolate* isolate) {
// TODO(jkummerow): Consider caching a canonical zero-BigInt.
return MakeImmutable(New(isolate, 0)).ToHandleChecked();
return MakeImmutable<Isolate>(New(isolate, 0).ToHandleChecked());
}
static Handle<MutableBigInt> Cast(Handle<FreshlyAllocatedBigInt> bigint) {
SLOW_DCHECK(bigint->IsBigInt());
return Handle<MutableBigInt>::cast(bigint);
}
static OffThreadHandle<MutableBigInt> Cast(
OffThreadHandle<FreshlyAllocatedBigInt> bigint) {
SLOW_DCHECK(bigint->IsBigInt());
return OffThreadHandle<MutableBigInt>::cast(bigint);
}
static MutableBigInt cast(Object o) {
SLOW_DCHECK(o.IsBigInt());
return MutableBigInt(o.ptr());
......@@ -236,8 +246,8 @@ NEVER_READ_ONLY_SPACE_IMPL(MutableBigInt)
#include "src/objects/object-macros-undef.h"
template <typename T>
MaybeHandle<T> ThrowBigIntTooBig(Isolate* isolate) {
template <typename T, typename Isolate>
MaybeHandleFor<Isolate, T> ThrowBigIntTooBig(Isolate* isolate) {
// If the result of a BigInt computation is truncated to 64 bit, Turbofan
// can sometimes truncate intermediate results already, which can prevent
// those from exceeding the maximum length, effectively preventing a
......@@ -250,12 +260,13 @@ MaybeHandle<T> ThrowBigIntTooBig(Isolate* isolate) {
THROW_NEW_ERROR(isolate, NewRangeError(MessageTemplate::kBigIntTooBig), T);
}
MaybeHandle<MutableBigInt> MutableBigInt::New(Isolate* isolate, int length,
AllocationType allocation) {
template <typename Isolate>
MaybeHandleFor<Isolate, MutableBigInt> MutableBigInt::New(
Isolate* isolate, int length, AllocationType allocation) {
if (length > BigInt::kMaxLength) {
return ThrowBigIntTooBig<MutableBigInt>(isolate);
}
Handle<MutableBigInt> result =
HandleFor<Isolate, MutableBigInt> result =
Cast(isolate->factory()->NewBigInt(length, allocation));
result->initialize_bitfield(false, length);
#if DEBUG
......@@ -367,14 +378,16 @@ void MutableBigInt::InitializeDigits(int length, byte value) {
MaybeHandle<BigInt> MutableBigInt::MakeImmutable(
MaybeHandle<MutableBigInt> maybe) {
Handle<MutableBigInt> result;
if (!maybe.ToHandle(&result)) return MaybeHandle<BigInt>();
HandleFor<Isolate, MutableBigInt> result;
if (!maybe.ToHandle(&result)) return MaybeHandleFor<Isolate, BigInt>();
return MakeImmutable(result);
}
Handle<BigInt> MutableBigInt::MakeImmutable(Handle<MutableBigInt> result) {
template <typename Isolate>
HandleFor<Isolate, BigInt> MutableBigInt::MakeImmutable(
HandleFor<Isolate, MutableBigInt> result) {
MutableBigInt::Canonicalize(*result);
return Handle<BigInt>::cast(result);
return HandleFor<Isolate, BigInt>::cast(result);
}
void MutableBigInt::Canonicalize(MutableBigInt result) {
......@@ -405,9 +418,13 @@ void MutableBigInt::Canonicalize(MutableBigInt result) {
result.digit(result.length() - 1) != 0); // MSD is non-zero.
}
Handle<BigInt> BigInt::Zero(Isolate* isolate) {
template <typename Isolate>
HandleFor<Isolate, BigInt> BigInt::Zero(Isolate* isolate) {
return MutableBigInt::Zero(isolate);
}
template Handle<BigInt> BigInt::Zero<Isolate>(Isolate* isolate);
template OffThreadHandle<BigInt> BigInt::Zero<OffThreadIsolate>(
OffThreadIsolate* isolate);
Handle<BigInt> BigInt::UnaryMinus(Isolate* isolate, Handle<BigInt> x) {
// Special case: There is no -0n.
......@@ -1505,13 +1522,13 @@ void MutableBigInt::InternalMultiplyAdd(BigIntBase source, digit_t factor,
}
// Multiplies {x} with {factor} and then adds {summand} to it.
void BigInt::InplaceMultiplyAdd(Handle<FreshlyAllocatedBigInt> x,
uintptr_t factor, uintptr_t summand) {
void BigInt::InplaceMultiplyAdd(FreshlyAllocatedBigInt x, uintptr_t factor,
uintptr_t summand) {
STATIC_ASSERT(sizeof(factor) == sizeof(digit_t));
STATIC_ASSERT(sizeof(summand) == sizeof(digit_t));
Handle<MutableBigInt> bigint = MutableBigInt::Cast(x);
MutableBigInt::InternalMultiplyAdd(*bigint, factor, summand, bigint->length(),
*bigint);
MutableBigInt bigint = MutableBigInt::cast(x);
MutableBigInt::InternalMultiplyAdd(bigint, factor, summand, bigint.length(),
bigint);
}
// Divides {x} by {divisor}, returning the result in {quotient} and {remainder}.
......@@ -1907,7 +1924,8 @@ constexpr uint8_t kMaxBitsPerChar[] = {
static const int kBitsPerCharTableShift = 5;
static const size_t kBitsPerCharTableMultiplier = 1u << kBitsPerCharTableShift;
MaybeHandle<FreshlyAllocatedBigInt> BigInt::AllocateFor(
template <typename Isolate>
MaybeHandleFor<Isolate, FreshlyAllocatedBigInt> BigInt::AllocateFor(
Isolate* isolate, int radix, int charcount, ShouldThrow should_throw,
AllocationType allocation) {
DCHECK(2 <= radix && radix <= 36);
......@@ -1923,7 +1941,7 @@ MaybeHandle<FreshlyAllocatedBigInt> BigInt::AllocateFor(
// Divide by kDigitsBits, rounding up.
int length = static_cast<int>((bits_min + kDigitBits - 1) / kDigitBits);
if (length <= kMaxLength) {
Handle<MutableBigInt> result =
HandleFor<Isolate, MutableBigInt> result =
MutableBigInt::New(isolate, length, allocation).ToHandleChecked();
result->InitializeDigits(length);
return result;
......@@ -1934,16 +1952,31 @@ MaybeHandle<FreshlyAllocatedBigInt> BigInt::AllocateFor(
if (should_throw == kThrowOnError) {
return ThrowBigIntTooBig<FreshlyAllocatedBigInt>(isolate);
} else {
return MaybeHandle<FreshlyAllocatedBigInt>();
return MaybeHandleFor<Isolate, FreshlyAllocatedBigInt>();
}
}
Handle<BigInt> BigInt::Finalize(Handle<FreshlyAllocatedBigInt> x, bool sign) {
Handle<MutableBigInt> bigint = MutableBigInt::Cast(x);
template MaybeHandle<FreshlyAllocatedBigInt> BigInt::AllocateFor<Isolate>(
Isolate* isolate, int radix, int charcount, ShouldThrow should_throw,
AllocationType allocation);
template OffThreadHandle<FreshlyAllocatedBigInt>
BigInt::AllocateFor<OffThreadIsolate>(OffThreadIsolate* isolate, int radix,
int charcount, ShouldThrow should_throw,
AllocationType allocation);
template <typename Isolate>
HandleFor<Isolate, BigInt> BigInt::Finalize(
HandleFor<Isolate, FreshlyAllocatedBigInt> x, bool sign) {
HandleFor<Isolate, MutableBigInt> bigint =
HandleFor<Isolate, MutableBigInt>::cast(x);
bigint->set_sign(sign);
return MutableBigInt::MakeImmutable(bigint);
return MutableBigInt::MakeImmutable<Isolate>(bigint);
}
template Handle<BigInt> BigInt::Finalize<Isolate>(
Handle<FreshlyAllocatedBigInt>, bool);
template OffThreadHandle<BigInt> BigInt::Finalize<OffThreadIsolate>(
OffThreadHandle<FreshlyAllocatedBigInt>, bool);
// The serialization format MUST NOT CHANGE without updating the format
// version in value-serializer.cc!
uint32_t BigInt::GetBitfieldForSerialization() const {
......
......@@ -6,6 +6,7 @@
#define V8_OBJECTS_BIGINT_H_
#include "src/common/globals.h"
#include "src/handles/handle-for.h"
#include "src/objects/objects.h"
#include "src/objects/primitive-heap-object.h"
#include "src/utils/utils.h"
......@@ -238,18 +239,23 @@ class BigInt : public BigIntBase {
class BodyDescriptor;
private:
template <typename Isolate>
friend class StringToBigIntHelper;
friend class ValueDeserializer;
friend class ValueSerializer;
// Special functions for StringToBigIntHelper:
static Handle<BigInt> Zero(Isolate* isolate);
static MaybeHandle<FreshlyAllocatedBigInt> AllocateFor(
template <typename Isolate>
static HandleFor<Isolate, BigInt> Zero(Isolate* isolate);
template <typename Isolate>
static MaybeHandleFor<Isolate, FreshlyAllocatedBigInt> AllocateFor(
Isolate* isolate, int radix, int charcount, ShouldThrow should_throw,
AllocationType allocation);
static void InplaceMultiplyAdd(Handle<FreshlyAllocatedBigInt> x,
uintptr_t factor, uintptr_t summand);
static Handle<BigInt> Finalize(Handle<FreshlyAllocatedBigInt> x, bool sign);
static void InplaceMultiplyAdd(FreshlyAllocatedBigInt x, uintptr_t factor,
uintptr_t summand);
template <typename Isolate>
static HandleFor<Isolate, BigInt> Finalize(
HandleFor<Isolate, FreshlyAllocatedBigInt> x, bool sign);
// Special functions for ValueSerializer/ValueDeserializer:
uint32_t GetBitfieldForSerialization() const;
......
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