diff --git a/src/ast/ast.h b/src/ast/ast.h index 5f38e429ed..f5eb536872 100644 --- a/src/ast/ast.h +++ b/src/ast/ast.h @@ -15,6 +15,7 @@ #include "src/codegen/label.h" #include "src/common/globals.h" #include "src/execution/isolate.h" +#include "src/execution/off-thread-isolate.h" #include "src/heap/factory.h" #include "src/objects/elements-kind.h" #include "src/objects/function-syntax-kind.h" @@ -2208,8 +2209,10 @@ class FunctionLiteral final : public Expression { // Empty handle means that the function does not have a shared name (i.e. // the name will be set dynamically after creation of the function closure). - MaybeHandle GetName(Isolate* isolate) const { - return raw_name_ ? raw_name_->AllocateFlat(isolate) : MaybeHandle(); + template + MaybeHandleFor GetName(Isolate* isolate) const { + return raw_name_ ? raw_name_->AllocateFlat(isolate) + : MaybeHandleFor(); } bool has_shared_name() const { return raw_name_ != nullptr; } const AstConsString* raw_name() const { return raw_name_; } @@ -2277,6 +2280,11 @@ class FunctionLiteral final : public Expression { } UNREACHABLE(); } + OffThreadHandle GetInferredName(OffThreadIsolate* isolate) const { + DCHECK(inferred_name_.is_null()); + DCHECK_NOT_NULL(raw_inferred_name_); + return raw_inferred_name_->GetString(isolate); + } const AstConsString* raw_inferred_name() { return raw_inferred_name_; } // Only one of {set_inferred_name, set_raw_inferred_name} should be called. diff --git a/src/diagnostics/objects-debug.cc b/src/diagnostics/objects-debug.cc index 3bf9240eb6..6007618fab 100644 --- a/src/diagnostics/objects-debug.cc +++ b/src/diagnostics/objects-debug.cc @@ -32,6 +32,7 @@ #include "src/objects/js-array-inl.h" #include "src/objects/layout-descriptor.h" #include "src/objects/objects-inl.h" +#include "src/roots/roots.h" #ifdef V8_INTL_SUPPORT #include "src/objects/js-break-iterator-inl.h" #include "src/objects/js-collator-inl.h" @@ -816,12 +817,20 @@ void JSFunction::JSFunctionVerify(Isolate* isolate) { } void SharedFunctionInfo::SharedFunctionInfoVerify(Isolate* isolate) { + // TODO(leszeks): Add a TorqueGeneratedClassVerifier for OffThreadIsolate. TorqueGeneratedClassVerifiers::SharedFunctionInfoVerify(*this, isolate); + this->SharedFunctionInfoVerify(ReadOnlyRoots(isolate)); +} +void SharedFunctionInfo::SharedFunctionInfoVerify(OffThreadIsolate* isolate) { + this->SharedFunctionInfoVerify(ReadOnlyRoots(isolate)); +} + +void SharedFunctionInfo::SharedFunctionInfoVerify(ReadOnlyRoots roots) { Object value = name_or_scope_info(); if (value.IsScopeInfo()) { CHECK_LT(0, ScopeInfo::cast(value).length()); - CHECK_NE(value, ReadOnlyRoots(isolate).empty_scope_info()); + CHECK_NE(value, roots.empty_scope_info()); } CHECK(HasWasmExportedFunctionData() || IsApiFunction() || @@ -830,13 +839,13 @@ void SharedFunctionInfo::SharedFunctionInfoVerify(Isolate* isolate) { HasUncompiledDataWithoutPreparseData() || HasWasmJSFunctionData() || HasWasmCapiFunctionData()); - CHECK(script_or_debug_info().IsUndefined(isolate) || + CHECK(script_or_debug_info().IsUndefined(roots) || script_or_debug_info().IsScript() || HasDebugInfo()); if (!is_compiled()) { CHECK(!HasFeedbackMetadata()); CHECK(outer_scope_info().IsScopeInfo() || - outer_scope_info().IsTheHole(isolate)); + outer_scope_info().IsTheHole(roots)); } else if (HasBytecodeArray() && HasFeedbackMetadata()) { CHECK(feedback_metadata().IsFeedbackMetadata()); } diff --git a/src/execution/isolate.h b/src/execution/isolate.h index a7fd02e800..066f43889a 100644 --- a/src/execution/isolate.h +++ b/src/execution/isolate.h @@ -1290,7 +1290,19 @@ class V8_EXPORT_PRIVATE Isolate final : private HiddenFactory { int GetNextScriptId(); #if V8_SFI_HAS_UNIQUE_ID - int GetNextUniqueSharedFunctionInfoId() { return next_unique_sfi_id_++; } + int GetNextUniqueSharedFunctionInfoId() { + int current_id = next_unique_sfi_id_.load(std::memory_order_relaxed); + int next_id; + do { + if (current_id >= Smi::kMaxValue) { + next_id = 0; + } else { + next_id = current_id + 1; + } + } while (!next_unique_sfi_id_.compare_exchange_weak( + current_id, next_id, std::memory_order_relaxed)); + return current_id; + } #endif Address promise_hook_address() { @@ -1765,7 +1777,7 @@ class V8_EXPORT_PRIVATE Isolate final : private HiddenFactory { int next_optimization_id_ = 0; #if V8_SFI_HAS_UNIQUE_ID - int next_unique_sfi_id_ = 0; + std::atomic next_unique_sfi_id_; #endif // Vector of callbacks before a Call starts execution. diff --git a/src/execution/off-thread-isolate.cc b/src/execution/off-thread-isolate.cc index 6111235344..fc62cd8681 100644 --- a/src/execution/off-thread-isolate.cc +++ b/src/execution/off-thread-isolate.cc @@ -18,6 +18,12 @@ OffThreadIsolate::~OffThreadIsolate() { delete logger_; } int OffThreadIsolate::GetNextScriptId() { return isolate_->GetNextScriptId(); } +#if V8_SFI_HAS_UNIQUE_ID +int OffThreadIsolate::GetNextUniqueSharedFunctionInfoId() { + return isolate_->GetNextUniqueSharedFunctionInfoId(); +} +#endif // V8_SFI_HAS_UNIQUE_ID + bool OffThreadIsolate::NeedsSourcePositionsForProfiling() { // TODO(leszeks): Figure out if it makes sense to check this asynchronously. return isolate_->NeedsSourcePositionsForProfiling(); diff --git a/src/execution/off-thread-isolate.h b/src/execution/off-thread-isolate.h index ddfcb507e9..8ca60af94e 100644 --- a/src/execution/off-thread-isolate.h +++ b/src/execution/off-thread-isolate.h @@ -61,6 +61,9 @@ class V8_EXPORT_PRIVATE OffThreadIsolate final } int GetNextScriptId(); +#if V8_SFI_HAS_UNIQUE_ID + int GetNextUniqueSharedFunctionInfoId(); +#endif // V8_SFI_HAS_UNIQUE_ID bool NeedsSourcePositionsForProfiling(); bool is_collecting_type_profile(); diff --git a/src/handles/handles.h b/src/handles/handles.h index eb256acda2..4f575bab78 100644 --- a/src/handles/handles.h +++ b/src/handles/handles.h @@ -233,7 +233,7 @@ class OffThreadHandle { } private: - Address address_; + Address address_ = 0; }; // A helper class which wraps an normal or off-thread handle, and returns one diff --git a/src/heap/factory-base.cc b/src/heap/factory-base.cc index 47348d1bad..5aa631f249 100644 --- a/src/heap/factory-base.cc +++ b/src/heap/factory-base.cc @@ -114,6 +114,35 @@ HandleFor FactoryBase::NewFixedDoubleArray( return array; } +template +HandleFor FactoryBase::NewWeakFixedArrayWithMap( + Map map, int length, AllocationType allocation) { + // Zero-length case must be handled outside. + DCHECK_LT(0, length); + DCHECK(ReadOnlyHeap::Contains(map)); + + HeapObject result = + AllocateRawArray(WeakFixedArray::SizeFor(length), allocation); + result.set_map_after_allocation(map, SKIP_WRITE_BARRIER); + + HandleFor array = + handle(WeakFixedArray::cast(result), isolate()); + array->set_length(length); + MemsetTagged(ObjectSlot(array->data_start()), + read_only_roots().undefined_value(), length); + + return array; +} + +template +HandleFor FactoryBase::NewWeakFixedArray( + int length, AllocationType allocation) { + DCHECK_LE(0, length); + if (length == 0) return impl()->empty_weak_fixed_array(); + return NewWeakFixedArrayWithMap(read_only_roots().weak_fixed_array_map(), + length, allocation); +} + template HandleFor FactoryBase::NewScript( HandleFor source) { @@ -148,6 +177,111 @@ HandleFor FactoryBase::NewScriptWithId( return script; } +template +HandleFor +FactoryBase::NewSharedFunctionInfoForLiteral( + FunctionLiteral* literal, HandleFor script, + bool is_toplevel) { + FunctionKind kind = literal->kind(); + HandleFor shared = NewSharedFunctionInfo( + literal->GetName(isolate()), MaybeHandleFor(), + Builtins::kCompileLazy, kind); + SharedFunctionInfo::InitFromFunctionLiteral(isolate(), shared, literal, + is_toplevel); + shared->SetScript(read_only_roots(), *script, literal->function_literal_id(), + false); + return shared; +} + +template +HandleFor FactoryBase::NewPreparseData( + int data_length, int children_length) { + int size = PreparseData::SizeFor(data_length, children_length); + HandleFor result = handle( + PreparseData::cast(AllocateRawWithImmortalMap( + size, AllocationType::kOld, read_only_roots().preparse_data_map())), + isolate()); + result->set_data_length(data_length); + result->set_children_length(children_length); + MemsetTagged(result->inner_data_start(), read_only_roots().null_value(), + children_length); + result->clear_padding(); + return result; +} + +template +HandleFor +FactoryBase::NewUncompiledDataWithoutPreparseData( + HandleFor inferred_name, int32_t start_position, + int32_t end_position) { + HandleFor result = handle( + UncompiledDataWithoutPreparseData::cast(NewWithImmortalMap( + impl()->read_only_roots().uncompiled_data_without_preparse_data_map(), + AllocationType::kOld)), + isolate()); + + result->Init(impl(), *inferred_name, start_position, end_position); + return result; +} + +template +HandleFor +FactoryBase::NewUncompiledDataWithPreparseData( + HandleFor inferred_name, int32_t start_position, + int32_t end_position, HandleFor preparse_data) { + HandleFor result = handle( + UncompiledDataWithPreparseData::cast(NewWithImmortalMap( + impl()->read_only_roots().uncompiled_data_with_preparse_data_map(), + AllocationType::kOld)), + isolate()); + + result->Init(impl(), *inferred_name, start_position, end_position, + *preparse_data); + + return result; +} + +template +HandleFor FactoryBase::NewSharedFunctionInfo( + MaybeHandleFor maybe_name, + MaybeHandleFor maybe_function_data, + int maybe_builtin_index, FunctionKind kind) { + HandleFor shared = NewSharedFunctionInfo(); + + // Function names are assumed to be flat elsewhere. + HandleFor shared_name; + bool has_shared_name = maybe_name.ToHandle(&shared_name); + if (has_shared_name) { + DCHECK(shared_name->IsFlat()); + shared->set_name_or_scope_info(*shared_name); + } else { + DCHECK_EQ(shared->name_or_scope_info(), + SharedFunctionInfo::kNoSharedNameSentinel); + } + + HandleFor function_data; + if (maybe_function_data.ToHandle(&function_data)) { + // If we pass function_data then we shouldn't pass a builtin index, and + // the function_data should not be code with a builtin. + DCHECK(!Builtins::IsBuiltinId(maybe_builtin_index)); + DCHECK_IMPLIES(function_data->IsCode(), + !Code::cast(*function_data).is_builtin()); + shared->set_function_data(*function_data); + } else if (Builtins::IsBuiltinId(maybe_builtin_index)) { + shared->set_builtin_id(maybe_builtin_index); + } else { + shared->set_builtin_id(Builtins::kIllegal); + } + + shared->CalculateConstructAsBuiltin(); + shared->set_kind(kind); + +#ifdef VERIFY_HEAP + shared->SharedFunctionInfoVerify(isolate()); +#endif // VERIFY_HEAP + return shared; +} + template HandleFor FactoryBase::NewObjectBoilerplateDescription(int boilerplate, @@ -403,6 +537,26 @@ FactoryBase::NewSourceTextModuleInfo() { AllocationType::kOld)); } +template +HandleFor FactoryBase::NewSharedFunctionInfo() { + Map map = read_only_roots().shared_function_info_map(); + + HandleFor shared = handle( + SharedFunctionInfo::cast(NewWithImmortalMap(map, AllocationType::kOld)), + isolate()); + int unique_id = -1; +#if V8_SFI_HAS_UNIQUE_ID + unique_id = isolate()->GetNextUniqueSharedFunctionInfoId(); +#endif // V8_SFI_HAS_UNIQUE_ID + + shared->Init(read_only_roots(), unique_id); + +#ifdef VERIFY_HEAP + shared->SharedFunctionInfoVerify(isolate()); +#endif // VERIFY_HEAP + return shared; +} + template HandleFor FactoryBase::AllocateRawOneByteInternalizedString(int length, diff --git a/src/heap/factory-base.h b/src/heap/factory-base.h index c82b8da08d..ff08f0ab8b 100644 --- a/src/heap/factory-base.h +++ b/src/heap/factory-base.h @@ -8,6 +8,7 @@ #include "src/base/export-template.h" #include "src/common/globals.h" #include "src/handles/handle-for.h" +#include "src/objects/function-kind.h" #include "src/objects/instance-type.h" #include "src/roots/roots.h" @@ -15,6 +16,8 @@ namespace v8 { namespace internal { class HeapObject; +class SharedFunctionInfo; +class FunctionLiteral; class SeqOneByteString; class SeqTwoByteString; class FreshlyAllocatedBigInt; @@ -22,6 +25,9 @@ class ObjectBoilerplateDescription; class ArrayBoilerplateDescription; class TemplateObjectDescription; class SourceTextModuleInfo; +class PreparseData; +class UncompiledDataWithoutPreparseData; +class UncompiledDataWithPreparseData; template class EXPORT_TEMPLATE_DECLARE(V8_EXPORT_PRIVATE) FactoryBase { @@ -73,6 +79,16 @@ class EXPORT_TEMPLATE_DECLARE(V8_EXPORT_PRIVATE) FactoryBase { HandleFor NewFixedDoubleArray( int length, AllocationType allocation = AllocationType::kYoung); + // Allocates a weak fixed array-like object with given map and initialized + // with undefined values. + HandleFor NewWeakFixedArrayWithMap( + Map map, int length, AllocationType allocation = AllocationType::kYoung); + + // Allocates a fixed array which may contain in-place weak references. The + // array is initialized with undefined values + HandleFor NewWeakFixedArray( + int length, AllocationType allocation = AllocationType::kYoung); + // Allocates a fixed array for name-value pairs of boilerplate properties and // calculates the number of properties we need to store in the backing store. HandleFor NewObjectBoilerplateDescription( @@ -92,6 +108,24 @@ class EXPORT_TEMPLATE_DECLARE(V8_EXPORT_PRIVATE) FactoryBase { HandleFor NewScriptWithId(HandleFor source, int script_id); + HandleFor NewSharedFunctionInfoForLiteral( + FunctionLiteral* literal, HandleFor script, + bool is_toplevel); + + HandleFor NewPreparseData(int data_length, + int children_length); + + HandleFor + NewUncompiledDataWithoutPreparseData(HandleFor inferred_name, + int32_t start_position, + int32_t end_position); + + HandleFor + NewUncompiledDataWithPreparseData(HandleFor inferred_name, + int32_t start_position, + int32_t end_position, + HandleFor); + HandleFor NewOneByteInternalizedString( const Vector& str, uint32_t hash_field); HandleFor NewTwoByteInternalizedString( @@ -145,6 +179,12 @@ class EXPORT_TEMPLATE_DECLARE(V8_EXPORT_PRIVATE) FactoryBase { HandleFor NewFixedArrayWithFiller( Map map, int length, Oddball filler, AllocationType allocation); + HandleFor NewSharedFunctionInfo(); + HandleFor NewSharedFunctionInfo( + MaybeHandleFor maybe_name, + MaybeHandleFor maybe_function_data, + int maybe_builtin_index, FunctionKind kind = kNormalFunction); + private: Impl* impl() { return static_cast(this); } auto isolate() { return impl()->isolate(); } diff --git a/src/heap/factory.cc b/src/heap/factory.cc index ba971a5ca8..d8a1e4ce07 100644 --- a/src/heap/factory.cc +++ b/src/heap/factory.cc @@ -10,7 +10,6 @@ #include // For move #include "src/ast/ast-source-ranges.h" -#include "src/ast/ast.h" #include "src/base/bits.h" #include "src/builtins/accessors.h" #include "src/builtins/constants-table-builder.h" @@ -341,40 +340,6 @@ Handle Factory::NewFixedArrayWithMapRootIndex( length, allocation); } -template -Handle Factory::NewWeakFixedArrayWithMap(Map map, int length, - AllocationType allocation) { - static_assert(std::is_base_of::value, - "T must be a descendant of WeakFixedArray"); - - // Zero-length case must be handled outside. - DCHECK_LT(0, length); - - HeapObject result = - AllocateRawArray(WeakFixedArray::SizeFor(length), AllocationType::kOld); - result.set_map_after_allocation(map, SKIP_WRITE_BARRIER); - - Handle array(WeakFixedArray::cast(result), isolate()); - array->set_length(length); - MemsetTagged(ObjectSlot(array->data_start()), *undefined_value(), length); - - return Handle::cast(array); -} - -Handle Factory::NewWeakFixedArray(int length, - AllocationType allocation) { - DCHECK_LE(0, length); - if (length == 0) return empty_weak_fixed_array(); - HeapObject result = - AllocateRawArray(WeakFixedArray::SizeFor(length), allocation); - result.set_map_after_allocation(read_only_roots().weak_fixed_array_map(), - SKIP_WRITE_BARRIER); - Handle array(WeakFixedArray::cast(result), isolate()); - array->set_length(length); - MemsetTagged(ObjectSlot(array->data_start()), *undefined_value(), length); - return array; -} - MaybeHandle Factory::TryNewFixedArray( int length, AllocationType allocation_type) { DCHECK_LE(0, length); @@ -1482,8 +1447,9 @@ Handle Factory::NewDescriptorArray(int number_of_descriptors, Handle Factory::NewTransitionArray(int number_of_transitions, int slack) { int capacity = TransitionArray::LengthFor(number_of_transitions + slack); - Handle array = NewWeakFixedArrayWithMap( - read_only_roots().transition_array_map(), capacity, AllocationType::kOld); + Handle array = Handle::cast( + NewWeakFixedArrayWithMap(read_only_roots().transition_array_map(), + capacity, AllocationType::kOld)); // Transition arrays are AllocationType::kOld. When black allocation is on we // have to add the transition array to the list of // encountered_transition_arrays. @@ -2130,48 +2096,6 @@ Handle Factory::NewFunctionFromSharedFunctionInfo( return result; } -Handle Factory::NewPreparseData(int data_length, - int children_length) { - int size = PreparseData::SizeFor(data_length, children_length); - Handle result( - PreparseData::cast(AllocateRawWithImmortalMap(size, AllocationType::kOld, - *preparse_data_map())), - isolate()); - result->set_data_length(data_length); - result->set_children_length(children_length); - MemsetTagged(result->inner_data_start(), *null_value(), children_length); - result->clear_padding(); - return result; -} - -Handle -Factory::NewUncompiledDataWithoutPreparseData(Handle inferred_name, - int32_t start_position, - int32_t end_position) { - Handle result( - UncompiledDataWithoutPreparseData::cast(New( - uncompiled_data_without_preparse_data_map(), AllocationType::kOld)), - isolate()); - - result->Init(*inferred_name, start_position, end_position); - return result; -} - -Handle -Factory::NewUncompiledDataWithPreparseData(Handle inferred_name, - int32_t start_position, - int32_t end_position, - Handle preparse_data) { - Handle result( - UncompiledDataWithPreparseData::cast( - New(uncompiled_data_with_preparse_data_map(), AllocationType::kOld)), - isolate()); - - result->Init(*inferred_name, start_position, end_position, *preparse_data); - - return result; -} - Handle Factory::NewExternal(void* value) { Handle foreign = NewForeign(reinterpret_cast
(value)); Handle external = NewJSObjectFromMap(external_map()); @@ -2965,18 +2889,6 @@ void Factory::ReinitializeJSGlobalProxy(Handle object, InitializeJSObjectFromMap(object, raw_properties_or_hash, map); } -Handle Factory::NewSharedFunctionInfoForLiteral( - FunctionLiteral* literal, Handle