Reland "[offthread] Add SFI support to OffThreadFactory"
This is a reland of 453e1a3b03
Added canonical "empty" arrays to ScannerStream::ForTesting, for the
zero-length nullptr data case.
Original change's description:
> [offthread] Add SFI support to OffThreadFactory
>
> Add support for off-thread SharedFunctionInfo allocation, which
> includes UncompiledData and PreparseData allocation.
>
> Bug: chromium:1011762
> Change-Id: Ia10f9ce762c7d7eb1108b9e71da75131dce919b7
> Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2050393
> Commit-Queue: Leszek Swirski <leszeks@chromium.org>
> Reviewed-by: Ulan Degenbaev <ulan@chromium.org>
> Reviewed-by: Igor Sheludko <ishell@chromium.org>
> Cr-Commit-Position: refs/heads/master@{#66246}
TBR=ulan@chromium.org
Bug: chromium:1011762
Change-Id: I37d2c6b9317548922913887940a0164cc2067efb
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2054085
Reviewed-by: Igor Sheludko <ishell@chromium.org>
Reviewed-by: Ulan Degenbaev <ulan@chromium.org>
Commit-Queue: Leszek Swirski <leszeks@chromium.org>
Cr-Commit-Position: refs/heads/master@{#66253}
This commit is contained in:
parent
a44b20abe3
commit
a046c5fcf9
@ -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<String> GetName(Isolate* isolate) const {
|
||||
return raw_name_ ? raw_name_->AllocateFlat(isolate) : MaybeHandle<String>();
|
||||
template <typename Isolate>
|
||||
MaybeHandleFor<Isolate, String> GetName(Isolate* isolate) const {
|
||||
return raw_name_ ? raw_name_->AllocateFlat(isolate)
|
||||
: MaybeHandleFor<Isolate, String>();
|
||||
}
|
||||
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<String> 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.
|
||||
|
@ -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());
|
||||
}
|
||||
|
@ -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<int> next_unique_sfi_id_;
|
||||
#endif
|
||||
|
||||
// Vector of callbacks before a Call starts execution.
|
||||
|
@ -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();
|
||||
|
@ -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();
|
||||
|
@ -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
|
||||
|
@ -114,6 +114,35 @@ HandleFor<Impl, FixedArrayBase> FactoryBase<Impl>::NewFixedDoubleArray(
|
||||
return array;
|
||||
}
|
||||
|
||||
template <typename Impl>
|
||||
HandleFor<Impl, WeakFixedArray> FactoryBase<Impl>::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<Impl, WeakFixedArray> array =
|
||||
handle(WeakFixedArray::cast(result), isolate());
|
||||
array->set_length(length);
|
||||
MemsetTagged(ObjectSlot(array->data_start()),
|
||||
read_only_roots().undefined_value(), length);
|
||||
|
||||
return array;
|
||||
}
|
||||
|
||||
template <typename Impl>
|
||||
HandleFor<Impl, WeakFixedArray> FactoryBase<Impl>::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 <typename Impl>
|
||||
HandleFor<Impl, Script> FactoryBase<Impl>::NewScript(
|
||||
HandleFor<Impl, String> source) {
|
||||
@ -148,6 +177,111 @@ HandleFor<Impl, Script> FactoryBase<Impl>::NewScriptWithId(
|
||||
return script;
|
||||
}
|
||||
|
||||
template <typename Impl>
|
||||
HandleFor<Impl, SharedFunctionInfo>
|
||||
FactoryBase<Impl>::NewSharedFunctionInfoForLiteral(
|
||||
FunctionLiteral* literal, HandleFor<Impl, Script> script,
|
||||
bool is_toplevel) {
|
||||
FunctionKind kind = literal->kind();
|
||||
HandleFor<Impl, SharedFunctionInfo> shared = NewSharedFunctionInfo(
|
||||
literal->GetName(isolate()), MaybeHandleFor<Impl, Code>(),
|
||||
Builtins::kCompileLazy, kind);
|
||||
SharedFunctionInfo::InitFromFunctionLiteral(isolate(), shared, literal,
|
||||
is_toplevel);
|
||||
shared->SetScript(read_only_roots(), *script, literal->function_literal_id(),
|
||||
false);
|
||||
return shared;
|
||||
}
|
||||
|
||||
template <typename Impl>
|
||||
HandleFor<Impl, PreparseData> FactoryBase<Impl>::NewPreparseData(
|
||||
int data_length, int children_length) {
|
||||
int size = PreparseData::SizeFor(data_length, children_length);
|
||||
HandleFor<Impl, PreparseData> 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 <typename Impl>
|
||||
HandleFor<Impl, UncompiledDataWithoutPreparseData>
|
||||
FactoryBase<Impl>::NewUncompiledDataWithoutPreparseData(
|
||||
HandleFor<Impl, String> inferred_name, int32_t start_position,
|
||||
int32_t end_position) {
|
||||
HandleFor<Impl, UncompiledDataWithoutPreparseData> 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 <typename Impl>
|
||||
HandleFor<Impl, UncompiledDataWithPreparseData>
|
||||
FactoryBase<Impl>::NewUncompiledDataWithPreparseData(
|
||||
HandleFor<Impl, String> inferred_name, int32_t start_position,
|
||||
int32_t end_position, HandleFor<Impl, PreparseData> preparse_data) {
|
||||
HandleFor<Impl, UncompiledDataWithPreparseData> 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 <typename Impl>
|
||||
HandleFor<Impl, SharedFunctionInfo> FactoryBase<Impl>::NewSharedFunctionInfo(
|
||||
MaybeHandleFor<Impl, String> maybe_name,
|
||||
MaybeHandleFor<Impl, HeapObject> maybe_function_data,
|
||||
int maybe_builtin_index, FunctionKind kind) {
|
||||
HandleFor<Impl, SharedFunctionInfo> shared = NewSharedFunctionInfo();
|
||||
|
||||
// Function names are assumed to be flat elsewhere.
|
||||
HandleFor<Impl, String> 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<Impl, HeapObject> 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 <typename Impl>
|
||||
HandleFor<Impl, ObjectBoilerplateDescription>
|
||||
FactoryBase<Impl>::NewObjectBoilerplateDescription(int boilerplate,
|
||||
@ -403,6 +537,26 @@ FactoryBase<Impl>::NewSourceTextModuleInfo() {
|
||||
AllocationType::kOld));
|
||||
}
|
||||
|
||||
template <typename Impl>
|
||||
HandleFor<Impl, SharedFunctionInfo> FactoryBase<Impl>::NewSharedFunctionInfo() {
|
||||
Map map = read_only_roots().shared_function_info_map();
|
||||
|
||||
HandleFor<Impl, SharedFunctionInfo> 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 <typename Impl>
|
||||
HandleFor<Impl, SeqOneByteString>
|
||||
FactoryBase<Impl>::AllocateRawOneByteInternalizedString(int length,
|
||||
|
@ -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 <typename Impl>
|
||||
class EXPORT_TEMPLATE_DECLARE(V8_EXPORT_PRIVATE) FactoryBase {
|
||||
@ -73,6 +79,16 @@ class EXPORT_TEMPLATE_DECLARE(V8_EXPORT_PRIVATE) FactoryBase {
|
||||
HandleFor<Impl, FixedArrayBase> NewFixedDoubleArray(
|
||||
int length, AllocationType allocation = AllocationType::kYoung);
|
||||
|
||||
// Allocates a weak fixed array-like object with given map and initialized
|
||||
// with undefined values.
|
||||
HandleFor<Impl, WeakFixedArray> 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<Impl, WeakFixedArray> 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<Impl, ObjectBoilerplateDescription> NewObjectBoilerplateDescription(
|
||||
@ -92,6 +108,24 @@ class EXPORT_TEMPLATE_DECLARE(V8_EXPORT_PRIVATE) FactoryBase {
|
||||
HandleFor<Impl, Script> NewScriptWithId(HandleFor<Impl, String> source,
|
||||
int script_id);
|
||||
|
||||
HandleFor<Impl, SharedFunctionInfo> NewSharedFunctionInfoForLiteral(
|
||||
FunctionLiteral* literal, HandleFor<Impl, Script> script,
|
||||
bool is_toplevel);
|
||||
|
||||
HandleFor<Impl, PreparseData> NewPreparseData(int data_length,
|
||||
int children_length);
|
||||
|
||||
HandleFor<Impl, UncompiledDataWithoutPreparseData>
|
||||
NewUncompiledDataWithoutPreparseData(HandleFor<Impl, String> inferred_name,
|
||||
int32_t start_position,
|
||||
int32_t end_position);
|
||||
|
||||
HandleFor<Impl, UncompiledDataWithPreparseData>
|
||||
NewUncompiledDataWithPreparseData(HandleFor<Impl, String> inferred_name,
|
||||
int32_t start_position,
|
||||
int32_t end_position,
|
||||
HandleFor<Impl, PreparseData>);
|
||||
|
||||
HandleFor<Impl, SeqOneByteString> NewOneByteInternalizedString(
|
||||
const Vector<const uint8_t>& str, uint32_t hash_field);
|
||||
HandleFor<Impl, SeqTwoByteString> NewTwoByteInternalizedString(
|
||||
@ -145,6 +179,12 @@ class EXPORT_TEMPLATE_DECLARE(V8_EXPORT_PRIVATE) FactoryBase {
|
||||
HandleFor<Impl, FixedArray> NewFixedArrayWithFiller(
|
||||
Map map, int length, Oddball filler, AllocationType allocation);
|
||||
|
||||
HandleFor<Impl, SharedFunctionInfo> NewSharedFunctionInfo();
|
||||
HandleFor<Impl, SharedFunctionInfo> NewSharedFunctionInfo(
|
||||
MaybeHandleFor<Impl, String> maybe_name,
|
||||
MaybeHandleFor<Impl, HeapObject> maybe_function_data,
|
||||
int maybe_builtin_index, FunctionKind kind = kNormalFunction);
|
||||
|
||||
private:
|
||||
Impl* impl() { return static_cast<Impl*>(this); }
|
||||
auto isolate() { return impl()->isolate(); }
|
||||
|
@ -10,7 +10,6 @@
|
||||
#include <utility> // 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<FixedArray> Factory::NewFixedArrayWithMapRootIndex(
|
||||
length, allocation);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
Handle<T> Factory::NewWeakFixedArrayWithMap(Map map, int length,
|
||||
AllocationType allocation) {
|
||||
static_assert(std::is_base_of<WeakFixedArray, T>::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<WeakFixedArray> array(WeakFixedArray::cast(result), isolate());
|
||||
array->set_length(length);
|
||||
MemsetTagged(ObjectSlot(array->data_start()), *undefined_value(), length);
|
||||
|
||||
return Handle<T>::cast(array);
|
||||
}
|
||||
|
||||
Handle<WeakFixedArray> 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<WeakFixedArray> array(WeakFixedArray::cast(result), isolate());
|
||||
array->set_length(length);
|
||||
MemsetTagged(ObjectSlot(array->data_start()), *undefined_value(), length);
|
||||
return array;
|
||||
}
|
||||
|
||||
MaybeHandle<FixedArray> Factory::TryNewFixedArray(
|
||||
int length, AllocationType allocation_type) {
|
||||
DCHECK_LE(0, length);
|
||||
@ -1482,8 +1447,9 @@ Handle<DescriptorArray> Factory::NewDescriptorArray(int number_of_descriptors,
|
||||
Handle<TransitionArray> Factory::NewTransitionArray(int number_of_transitions,
|
||||
int slack) {
|
||||
int capacity = TransitionArray::LengthFor(number_of_transitions + slack);
|
||||
Handle<TransitionArray> array = NewWeakFixedArrayWithMap<TransitionArray>(
|
||||
read_only_roots().transition_array_map(), capacity, AllocationType::kOld);
|
||||
Handle<TransitionArray> array = Handle<TransitionArray>::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<JSFunction> Factory::NewFunctionFromSharedFunctionInfo(
|
||||
return result;
|
||||
}
|
||||
|
||||
Handle<PreparseData> Factory::NewPreparseData(int data_length,
|
||||
int children_length) {
|
||||
int size = PreparseData::SizeFor(data_length, children_length);
|
||||
Handle<PreparseData> 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<UncompiledDataWithoutPreparseData>
|
||||
Factory::NewUncompiledDataWithoutPreparseData(Handle<String> inferred_name,
|
||||
int32_t start_position,
|
||||
int32_t end_position) {
|
||||
Handle<UncompiledDataWithoutPreparseData> result(
|
||||
UncompiledDataWithoutPreparseData::cast(New(
|
||||
uncompiled_data_without_preparse_data_map(), AllocationType::kOld)),
|
||||
isolate());
|
||||
|
||||
result->Init(*inferred_name, start_position, end_position);
|
||||
return result;
|
||||
}
|
||||
|
||||
Handle<UncompiledDataWithPreparseData>
|
||||
Factory::NewUncompiledDataWithPreparseData(Handle<String> inferred_name,
|
||||
int32_t start_position,
|
||||
int32_t end_position,
|
||||
Handle<PreparseData> preparse_data) {
|
||||
Handle<UncompiledDataWithPreparseData> 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<JSObject> Factory::NewExternal(void* value) {
|
||||
Handle<Foreign> foreign = NewForeign(reinterpret_cast<Address>(value));
|
||||
Handle<JSObject> external = NewJSObjectFromMap(external_map());
|
||||
@ -2965,18 +2889,6 @@ void Factory::ReinitializeJSGlobalProxy(Handle<JSGlobalProxy> object,
|
||||
InitializeJSObjectFromMap(object, raw_properties_or_hash, map);
|
||||
}
|
||||
|
||||
Handle<SharedFunctionInfo> Factory::NewSharedFunctionInfoForLiteral(
|
||||
FunctionLiteral* literal, Handle<Script> script, bool is_toplevel) {
|
||||
FunctionKind kind = literal->kind();
|
||||
Handle<SharedFunctionInfo> shared = NewSharedFunctionInfoForBuiltin(
|
||||
literal->GetName(isolate()), Builtins::kCompileLazy, kind);
|
||||
SharedFunctionInfo::InitFromFunctionLiteral(isolate(), shared, literal,
|
||||
is_toplevel);
|
||||
shared->SetScript(ReadOnlyRoots(isolate()), *script,
|
||||
literal->function_literal_id(), false);
|
||||
return shared;
|
||||
}
|
||||
|
||||
Handle<JSMessageObject> Factory::NewJSMessageObject(
|
||||
MessageTemplate message, Handle<Object> argument, int start_position,
|
||||
int end_position, Handle<SharedFunctionInfo> shared_info,
|
||||
@ -3036,64 +2948,6 @@ Handle<SharedFunctionInfo> Factory::NewSharedFunctionInfoForBuiltin(
|
||||
return shared;
|
||||
}
|
||||
|
||||
Handle<SharedFunctionInfo> Factory::NewSharedFunctionInfo(
|
||||
MaybeHandle<String> maybe_name, MaybeHandle<HeapObject> maybe_function_data,
|
||||
int maybe_builtin_index, FunctionKind kind) {
|
||||
Handle<SharedFunctionInfo> shared = NewSharedFunctionInfo();
|
||||
|
||||
// Function names are assumed to be flat elsewhere. Must flatten before
|
||||
// allocating SharedFunctionInfo to avoid GC seeing the uninitialized SFI.
|
||||
Handle<String> 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);
|
||||
}
|
||||
|
||||
Handle<HeapObject> 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;
|
||||
}
|
||||
|
||||
Handle<SharedFunctionInfo> Factory::NewSharedFunctionInfo() {
|
||||
Handle<Map> map = shared_function_info_map();
|
||||
|
||||
Handle<SharedFunctionInfo> shared(
|
||||
SharedFunctionInfo::cast(New(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(ReadOnlyRoots(isolate()), unique_id);
|
||||
|
||||
#ifdef VERIFY_HEAP
|
||||
shared->SharedFunctionInfoVerify(isolate());
|
||||
#endif // VERIFY_HEAP
|
||||
return shared;
|
||||
}
|
||||
|
||||
namespace {
|
||||
inline int NumberToStringCacheHash(Handle<FixedArray> cache, Smi number) {
|
||||
int mask = (cache->length() >> 1) - 1;
|
||||
|
@ -16,7 +16,6 @@
|
||||
#include "src/heap/heap.h"
|
||||
#include "src/objects/code.h"
|
||||
#include "src/objects/dictionary.h"
|
||||
#include "src/objects/function-kind.h"
|
||||
#include "src/objects/js-array.h"
|
||||
#include "src/objects/js-regexp.h"
|
||||
#include "src/objects/string.h"
|
||||
@ -55,7 +54,6 @@ class JSWeakMap;
|
||||
class LoadHandler;
|
||||
class NativeContext;
|
||||
class NewFunctionArgs;
|
||||
class PreparseData;
|
||||
class PromiseResolveThenableJobTask;
|
||||
class RegExpMatchInfo;
|
||||
class ScriptContextTable;
|
||||
@ -65,8 +63,6 @@ class StackTraceFrame;
|
||||
class StoreHandler;
|
||||
class SyntheticModule;
|
||||
class TemplateObjectDescription;
|
||||
class UncompiledDataWithoutPreparseData;
|
||||
class UncompiledDataWithPreparseData;
|
||||
class WasmCapiFunctionData;
|
||||
class WasmExportedFunctionData;
|
||||
class WasmJSFunctionData;
|
||||
@ -134,17 +130,6 @@ class V8_EXPORT_PRIVATE Factory : public FactoryBase<Factory> {
|
||||
RootIndex map_root_index, int length,
|
||||
AllocationType allocation = AllocationType::kYoung);
|
||||
|
||||
// Allocates a weak fixed array-like object with given map and initialized
|
||||
// with undefined values.
|
||||
template <typename T = WeakFixedArray>
|
||||
Handle<T> 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
|
||||
Handle<WeakFixedArray> NewWeakFixedArray(
|
||||
int length, AllocationType allocation = AllocationType::kYoung);
|
||||
|
||||
// Allocates a property array initialized with undefined values.
|
||||
Handle<PropertyArray> NewPropertyArray(int length);
|
||||
// Tries allocating a fixed array initialized with undefined values.
|
||||
@ -674,17 +659,6 @@ class V8_EXPORT_PRIVATE Factory : public FactoryBase<Factory> {
|
||||
Handle<Map> map, Handle<SharedFunctionInfo> info, Handle<Context> context,
|
||||
AllocationType allocation = AllocationType::kOld);
|
||||
|
||||
Handle<PreparseData> NewPreparseData(int data_length, int children_length);
|
||||
|
||||
Handle<UncompiledDataWithoutPreparseData>
|
||||
NewUncompiledDataWithoutPreparseData(Handle<String> inferred_name,
|
||||
int32_t start_position,
|
||||
int32_t end_position);
|
||||
|
||||
Handle<UncompiledDataWithPreparseData> NewUncompiledDataWithPreparseData(
|
||||
Handle<String> inferred_name, int32_t start_position,
|
||||
int32_t end_position, Handle<PreparseData>);
|
||||
|
||||
// Create an External object for V8's external API.
|
||||
Handle<JSObject> NewExternal(void* value);
|
||||
|
||||
@ -758,9 +732,6 @@ class V8_EXPORT_PRIVATE Factory : public FactoryBase<Factory> {
|
||||
MaybeHandle<String> name, int builtin_index,
|
||||
FunctionKind kind = kNormalFunction);
|
||||
|
||||
Handle<SharedFunctionInfo> NewSharedFunctionInfoForLiteral(
|
||||
FunctionLiteral* literal, Handle<Script> script, bool is_toplevel);
|
||||
|
||||
static bool IsFunctionModeWithPrototype(FunctionMode function_mode) {
|
||||
return (function_mode & kWithPrototypeBits) != 0;
|
||||
}
|
||||
@ -1009,11 +980,6 @@ class V8_EXPORT_PRIVATE Factory : public FactoryBase<Factory> {
|
||||
ElementsKind elements_kind, int capacity,
|
||||
ArrayStorageAllocationMode mode = DONT_INITIALIZE_ARRAY_ELEMENTS);
|
||||
|
||||
Handle<SharedFunctionInfo> NewSharedFunctionInfo();
|
||||
Handle<SharedFunctionInfo> NewSharedFunctionInfo(
|
||||
MaybeHandle<String> name, MaybeHandle<HeapObject> maybe_function_data,
|
||||
int maybe_builtin_index, FunctionKind kind = kNormalFunction);
|
||||
|
||||
void InitializeAllocationMemento(AllocationMemento memento,
|
||||
AllocationSite allocation_site);
|
||||
|
||||
|
@ -2217,7 +2217,7 @@ void MarkCompactCollector::FlushBytecodeFromSFI(
|
||||
|
||||
// Initialize the uncompiled data.
|
||||
UncompiledData uncompiled_data = UncompiledData::cast(compiled_data);
|
||||
uncompiled_data.Init(
|
||||
uncompiled_data.InitAfterBytecodeFlush(
|
||||
inferred_name, start_position, end_position,
|
||||
[](HeapObject object, ObjectSlot slot, HeapObject target) {
|
||||
RecordSlot(object, slot, target);
|
||||
|
@ -16,6 +16,7 @@
|
||||
#include "src/objects/heap-object.h"
|
||||
#include "src/objects/map-inl.h"
|
||||
#include "src/objects/objects-body-descriptors-inl.h"
|
||||
#include "src/objects/shared-function-info.h"
|
||||
#include "src/objects/string.h"
|
||||
#include "src/objects/visitors.h"
|
||||
#include "src/roots/roots-inl.h"
|
||||
|
@ -17,6 +17,7 @@
|
||||
#include "src/objects/heap-object.h"
|
||||
#include "src/objects/map.h"
|
||||
#include "src/objects/objects.h"
|
||||
#include "src/objects/shared-function-info.h"
|
||||
#include "src/roots/roots.h"
|
||||
|
||||
namespace v8 {
|
||||
|
@ -37,7 +37,8 @@ void FreeSpace::set_next(FreeSpace next) {
|
||||
}
|
||||
|
||||
FreeSpace FreeSpace::cast(HeapObject o) {
|
||||
SLOW_DCHECK(!GetHeapFromWritableObject(o)->deserialization_complete() ||
|
||||
SLOW_DCHECK((!Heap::InOffThreadSpace(o) &&
|
||||
!GetHeapFromWritableObject(o)->deserialization_complete()) ||
|
||||
o.IsFreeSpace());
|
||||
return bit_cast<FreeSpace>(o);
|
||||
}
|
||||
|
@ -33,6 +33,7 @@
|
||||
#include "src/execution/frames-inl.h"
|
||||
#include "src/execution/isolate-inl.h"
|
||||
#include "src/execution/microtask-queue.h"
|
||||
#include "src/execution/off-thread-isolate.h"
|
||||
#include "src/execution/protectors-inl.h"
|
||||
#include "src/heap/factory-inl.h"
|
||||
#include "src/heap/heap-inl.h"
|
||||
@ -5332,8 +5333,9 @@ void SharedFunctionInfo::DisableOptimization(BailoutReason reason) {
|
||||
}
|
||||
|
||||
// static
|
||||
template <typename Isolate>
|
||||
void SharedFunctionInfo::InitFromFunctionLiteral(
|
||||
Isolate* isolate, Handle<SharedFunctionInfo> shared_info,
|
||||
Isolate* isolate, HandleFor<Isolate, SharedFunctionInfo> shared_info,
|
||||
FunctionLiteral* lit, bool is_toplevel) {
|
||||
DCHECK(!shared_info->name_or_scope_info().IsScopeInfo());
|
||||
|
||||
@ -5387,12 +5389,12 @@ void SharedFunctionInfo::InitFromFunctionLiteral(
|
||||
shared_info->set_is_safe_to_skip_arguments_adaptor(false);
|
||||
shared_info->UpdateExpectedNofPropertiesFromEstimate(lit);
|
||||
|
||||
Handle<UncompiledData> data;
|
||||
HandleFor<Isolate, UncompiledData> data;
|
||||
|
||||
ProducedPreparseData* scope_data = lit->produced_preparse_data();
|
||||
if (scope_data != nullptr) {
|
||||
Handle<PreparseData> preparse_data =
|
||||
scope_data->Serialize(shared_info->GetIsolate());
|
||||
HandleFor<Isolate, PreparseData> preparse_data =
|
||||
scope_data->Serialize(isolate);
|
||||
|
||||
data = isolate->factory()->NewUncompiledDataWithPreparseData(
|
||||
lit->GetInferredName(isolate), lit->start_position(),
|
||||
@ -5406,6 +5408,16 @@ void SharedFunctionInfo::InitFromFunctionLiteral(
|
||||
shared_info->set_uncompiled_data(*data);
|
||||
}
|
||||
|
||||
template EXPORT_TEMPLATE_DEFINE(V8_EXPORT_PRIVATE) void SharedFunctionInfo::
|
||||
InitFromFunctionLiteral<Isolate>(Isolate* isolate,
|
||||
Handle<SharedFunctionInfo> shared_info,
|
||||
FunctionLiteral* lit, bool is_toplevel);
|
||||
template EXPORT_TEMPLATE_DEFINE(V8_EXPORT_PRIVATE) void SharedFunctionInfo::
|
||||
InitFromFunctionLiteral<OffThreadIsolate>(
|
||||
OffThreadIsolate* isolate,
|
||||
OffThreadHandle<SharedFunctionInfo> shared_info, FunctionLiteral* lit,
|
||||
bool is_toplevel);
|
||||
|
||||
uint16_t SharedFunctionInfo::get_property_estimate_from_literal(
|
||||
FunctionLiteral* literal) {
|
||||
int estimate = literal->expected_property_count();
|
||||
|
@ -329,7 +329,7 @@ ScopeInfo SharedFunctionInfo::scope_info() const {
|
||||
if (maybe_scope_info.IsScopeInfo()) {
|
||||
return ScopeInfo::cast(maybe_scope_info);
|
||||
}
|
||||
return ScopeInfo::Empty(GetIsolate());
|
||||
return GetReadOnlyRoots().empty_scope_info();
|
||||
}
|
||||
|
||||
void SharedFunctionInfo::set_scope_info(ScopeInfo scope_info,
|
||||
@ -619,7 +619,15 @@ void SharedFunctionInfo::ClearPreparseData() {
|
||||
DCHECK(HasUncompiledDataWithoutPreparseData());
|
||||
}
|
||||
|
||||
void UncompiledData::Init(
|
||||
template <typename Isolate>
|
||||
void UncompiledData::Init(Isolate* isolate, String inferred_name,
|
||||
int start_position, int end_position) {
|
||||
set_inferred_name(inferred_name);
|
||||
set_start_position(start_position);
|
||||
set_end_position(end_position);
|
||||
}
|
||||
|
||||
void UncompiledData::InitAfterBytecodeFlush(
|
||||
String inferred_name, int start_position, int end_position,
|
||||
std::function<void(HeapObject object, ObjectSlot slot, HeapObject target)>
|
||||
gc_notify_updated_slot) {
|
||||
@ -630,17 +638,14 @@ void UncompiledData::Init(
|
||||
set_end_position(end_position);
|
||||
}
|
||||
|
||||
void UncompiledDataWithPreparseData::Init(
|
||||
String inferred_name, int start_position, int end_position,
|
||||
PreparseData scope_data,
|
||||
std::function<void(HeapObject object, ObjectSlot slot, HeapObject target)>
|
||||
gc_notify_updated_slot) {
|
||||
this->UncompiledData::Init(inferred_name, start_position, end_position,
|
||||
gc_notify_updated_slot);
|
||||
template <typename Isolate>
|
||||
void UncompiledDataWithPreparseData::Init(Isolate* isolate,
|
||||
String inferred_name,
|
||||
int start_position, int end_position,
|
||||
PreparseData scope_data) {
|
||||
this->UncompiledData::Init(isolate, inferred_name, start_position,
|
||||
end_position);
|
||||
set_preparse_data(scope_data);
|
||||
gc_notify_updated_slot(
|
||||
*this, RawField(UncompiledDataWithPreparseData::kPreparseDataOffset),
|
||||
scope_data);
|
||||
}
|
||||
|
||||
bool SharedFunctionInfo::HasWasmExportedFunctionData() const {
|
||||
|
@ -9,6 +9,7 @@
|
||||
|
||||
#include "src/base/bit-field.h"
|
||||
#include "src/codegen/bailout-reason.h"
|
||||
#include "src/handles/handle-for.h"
|
||||
#include "src/objects/compressed-slots.h"
|
||||
#include "src/objects/function-kind.h"
|
||||
#include "src/objects/function-syntax-kind.h"
|
||||
@ -99,11 +100,14 @@ class PreparseData
|
||||
class UncompiledData
|
||||
: public TorqueGeneratedUncompiledData<UncompiledData, HeapObject> {
|
||||
public:
|
||||
inline void Init(
|
||||
template <typename Isolate>
|
||||
inline void Init(Isolate* isolate, String inferred_name, int start_position,
|
||||
int end_position);
|
||||
|
||||
inline void InitAfterBytecodeFlush(
|
||||
String inferred_name, int start_position, int end_position,
|
||||
std::function<void(HeapObject object, ObjectSlot slot, HeapObject target)>
|
||||
gc_notify_updated_slot =
|
||||
[](HeapObject object, ObjectSlot slot, HeapObject target) {});
|
||||
gc_notify_updated_slot);
|
||||
|
||||
using BodyDescriptor =
|
||||
FixedBodyDescriptor<kStartOfStrongFieldsOffset, kEndOfStrongFieldsOffset,
|
||||
@ -135,12 +139,9 @@ class UncompiledDataWithPreparseData
|
||||
public:
|
||||
DECL_PRINTER(UncompiledDataWithPreparseData)
|
||||
|
||||
inline void Init(
|
||||
String inferred_name, int start_position, int end_position,
|
||||
PreparseData scope_data,
|
||||
std::function<void(HeapObject object, ObjectSlot slot, HeapObject target)>
|
||||
gc_notify_updated_slot =
|
||||
[](HeapObject object, ObjectSlot slot, HeapObject target) {});
|
||||
template <typename Isolate>
|
||||
inline void Init(Isolate* isolate, String inferred_name, int start_position,
|
||||
int end_position, PreparseData scope_data);
|
||||
|
||||
using BodyDescriptor = SubclassBodyDescriptor<
|
||||
UncompiledData::BodyDescriptor,
|
||||
@ -553,8 +554,9 @@ class SharedFunctionInfo : public HeapObject {
|
||||
inline bool has_simple_parameters();
|
||||
|
||||
// Initialize a SharedFunctionInfo from a parsed function literal.
|
||||
static void InitFromFunctionLiteral(Isolate* isolate,
|
||||
Handle<SharedFunctionInfo> shared_info,
|
||||
template <typename Isolate>
|
||||
static void InitFromFunctionLiteral(
|
||||
Isolate* isolate, HandleFor<Isolate, SharedFunctionInfo> shared_info,
|
||||
FunctionLiteral* lit, bool is_toplevel);
|
||||
|
||||
// Updates the expected number of properties based on estimate from parser.
|
||||
@ -587,6 +589,7 @@ class SharedFunctionInfo : public HeapObject {
|
||||
// Dispatched behavior.
|
||||
DECL_PRINTER(SharedFunctionInfo)
|
||||
DECL_VERIFIER(SharedFunctionInfo)
|
||||
void SharedFunctionInfoVerify(OffThreadIsolate* isolate);
|
||||
#ifdef OBJECT_PRINT
|
||||
void PrintSourceCode(std::ostream& os);
|
||||
#endif
|
||||
@ -638,6 +641,8 @@ class SharedFunctionInfo : public HeapObject {
|
||||
inline bool needs_home_object() const;
|
||||
|
||||
private:
|
||||
void SharedFunctionInfoVerify(ReadOnlyRoots roots);
|
||||
|
||||
// [name_or_scope_info]: Function name string, kNoSharedNameSentinel or
|
||||
// ScopeInfo.
|
||||
DECL_ACCESSORS(name_or_scope_info, Object)
|
||||
@ -660,7 +665,8 @@ class SharedFunctionInfo : public HeapObject {
|
||||
|
||||
inline uint16_t get_property_estimate_from_literal(FunctionLiteral* literal);
|
||||
|
||||
friend class Factory;
|
||||
template <typename Impl>
|
||||
friend class FactoryBase;
|
||||
friend class V8HeapExplorer;
|
||||
FRIEND_TEST(PreParserTest, LazyFunctionLength);
|
||||
|
||||
|
@ -199,6 +199,7 @@ class ZonePreparseData : public ZoneObject {
|
||||
int child_length);
|
||||
|
||||
Handle<PreparseData> Serialize(Isolate* isolate);
|
||||
OffThreadHandle<PreparseData> Serialize(OffThreadIsolate* isolate);
|
||||
|
||||
int children_length() const { return static_cast<int>(children_.size()); }
|
||||
|
||||
|
@ -9,11 +9,13 @@
|
||||
#include "src/ast/scopes.h"
|
||||
#include "src/ast/variables.h"
|
||||
#include "src/handles/handles.h"
|
||||
#include "src/heap/off-thread-factory.h"
|
||||
#include "src/objects/objects-inl.h"
|
||||
#include "src/objects/shared-function-info.h"
|
||||
#include "src/parsing/parser.h"
|
||||
#include "src/parsing/preparse-data-impl.h"
|
||||
#include "src/parsing/preparser.h"
|
||||
#include "src/roots/roots.h"
|
||||
#include "src/zone/zone-list-inl.h" // crbug.com/v8/8816
|
||||
|
||||
namespace v8 {
|
||||
@ -431,6 +433,17 @@ Handle<PreparseData> PreparseDataBuilder::ByteData::CopyToHeap(
|
||||
return data;
|
||||
}
|
||||
|
||||
OffThreadHandle<PreparseData>
|
||||
PreparseDataBuilder::ByteData::CopyToOffThreadHeap(OffThreadIsolate* isolate,
|
||||
int children_length) {
|
||||
DCHECK(is_finalized_);
|
||||
int data_length = zone_byte_data_.length();
|
||||
OffThreadHandle<PreparseData> data =
|
||||
isolate->factory()->NewPreparseData(data_length, children_length);
|
||||
data->copy_in(0, zone_byte_data_.begin(), data_length);
|
||||
return data;
|
||||
}
|
||||
|
||||
Handle<PreparseData> PreparseDataBuilder::Serialize(Isolate* isolate) {
|
||||
DCHECK(HasData());
|
||||
DCHECK(!ThisOrParentBailedOut());
|
||||
@ -447,6 +460,23 @@ Handle<PreparseData> PreparseDataBuilder::Serialize(Isolate* isolate) {
|
||||
return data;
|
||||
}
|
||||
|
||||
OffThreadHandle<PreparseData> PreparseDataBuilder::Serialize(
|
||||
OffThreadIsolate* isolate) {
|
||||
DCHECK(HasData());
|
||||
DCHECK(!ThisOrParentBailedOut());
|
||||
OffThreadHandle<PreparseData> data =
|
||||
byte_data_.CopyToOffThreadHeap(isolate, num_inner_with_data_);
|
||||
int i = 0;
|
||||
DCHECK(finalized_children_);
|
||||
for (const auto& builder : children_) {
|
||||
if (!builder->HasData()) continue;
|
||||
OffThreadHandle<PreparseData> child_data = builder->Serialize(isolate);
|
||||
data->set_child(i++, *child_data);
|
||||
}
|
||||
DCHECK_EQ(i, data->children_length());
|
||||
return data;
|
||||
}
|
||||
|
||||
ZonePreparseData* PreparseDataBuilder::Serialize(Zone* zone) {
|
||||
DCHECK(HasData());
|
||||
DCHECK(!ThisOrParentBailedOut());
|
||||
@ -473,6 +503,10 @@ class BuilderProducedPreparseData final : public ProducedPreparseData {
|
||||
return builder_->Serialize(isolate);
|
||||
}
|
||||
|
||||
OffThreadHandle<PreparseData> Serialize(OffThreadIsolate* isolate) final {
|
||||
return builder_->Serialize(isolate);
|
||||
}
|
||||
|
||||
ZonePreparseData* Serialize(Zone* zone) final {
|
||||
return builder_->Serialize(zone);
|
||||
}
|
||||
@ -491,6 +525,11 @@ class OnHeapProducedPreparseData final : public ProducedPreparseData {
|
||||
return data_;
|
||||
}
|
||||
|
||||
OffThreadHandle<PreparseData> Serialize(OffThreadIsolate* isolate) final {
|
||||
// Not required.
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
ZonePreparseData* Serialize(Zone* zone) final {
|
||||
// Not required.
|
||||
UNREACHABLE();
|
||||
@ -508,6 +547,10 @@ class ZoneProducedPreparseData final : public ProducedPreparseData {
|
||||
return data_->Serialize(isolate);
|
||||
}
|
||||
|
||||
OffThreadHandle<PreparseData> Serialize(OffThreadIsolate* isolate) final {
|
||||
return data_->Serialize(isolate);
|
||||
}
|
||||
|
||||
ZonePreparseData* Serialize(Zone* zone) final { return data_; }
|
||||
|
||||
private:
|
||||
@ -750,6 +793,23 @@ Handle<PreparseData> ZonePreparseData::Serialize(Isolate* isolate) {
|
||||
return result;
|
||||
}
|
||||
|
||||
OffThreadHandle<PreparseData> ZonePreparseData::Serialize(
|
||||
OffThreadIsolate* isolate) {
|
||||
int data_size = static_cast<int>(byte_data()->size());
|
||||
int child_data_length = children_length();
|
||||
OffThreadHandle<PreparseData> result =
|
||||
isolate->factory()->NewPreparseData(data_size, child_data_length);
|
||||
result->copy_in(0, byte_data()->data(), data_size);
|
||||
|
||||
for (int i = 0; i < child_data_length; i++) {
|
||||
ZonePreparseData* child = get_child(i);
|
||||
DCHECK_NOT_NULL(child);
|
||||
OffThreadHandle<PreparseData> child_data = child->Serialize(isolate);
|
||||
result->set_child(i, *child_data);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
ZoneConsumedPreparseData::ZoneConsumedPreparseData(Zone* zone,
|
||||
ZonePreparseData* data)
|
||||
: data_(data), scope_data_wrapper_(data_->byte_data()) {
|
||||
|
@ -140,6 +140,8 @@ class V8_EXPORT_PRIVATE PreparseDataBuilder : public ZoneObject,
|
||||
void Finalize(Zone* zone);
|
||||
|
||||
Handle<PreparseData> CopyToHeap(Isolate* isolate, int children_length);
|
||||
OffThreadHandle<PreparseData> CopyToOffThreadHeap(OffThreadIsolate* isolate,
|
||||
int children_length);
|
||||
inline ZonePreparseData* CopyToZone(Zone* zone, int children_length);
|
||||
|
||||
void Reserve(size_t bytes);
|
||||
@ -208,6 +210,7 @@ class V8_EXPORT_PRIVATE PreparseDataBuilder : public ZoneObject,
|
||||
friend class BuilderProducedPreparseData;
|
||||
|
||||
Handle<PreparseData> Serialize(Isolate* isolate);
|
||||
OffThreadHandle<PreparseData> Serialize(OffThreadIsolate* isolate);
|
||||
ZonePreparseData* Serialize(Zone* zone);
|
||||
|
||||
void FinalizeChildren(Zone* zone);
|
||||
@ -250,6 +253,12 @@ class ProducedPreparseData : public ZoneObject {
|
||||
// MaybeHandle.
|
||||
virtual Handle<PreparseData> Serialize(Isolate* isolate) = 0;
|
||||
|
||||
// If there is data (if the Scope contains skippable inner functions), move
|
||||
// the data into the heap and return a Handle to it; otherwise return a null
|
||||
// MaybeHandle.
|
||||
virtual OffThreadHandle<PreparseData> Serialize(
|
||||
OffThreadIsolate* isolate) = 0;
|
||||
|
||||
// If there is data (if the Scope contains skippable inner functions), return
|
||||
// an off-heap ZonePreparseData representing the data; otherwise
|
||||
// return nullptr.
|
||||
|
@ -792,10 +792,35 @@ std::unique_ptr<Utf16CharacterStream> ScannerStream::ForTesting(
|
||||
|
||||
std::unique_ptr<Utf16CharacterStream> ScannerStream::ForTesting(
|
||||
const char* data, size_t length) {
|
||||
if (data == nullptr) {
|
||||
DCHECK_EQ(length, 0);
|
||||
|
||||
// We don't want to pass in a null pointer into the the character stream,
|
||||
// because then the one-past-the-end pointer is undefined, so instead pass
|
||||
// through this static array.
|
||||
static const char non_null_empty_string[1] = {0};
|
||||
data = non_null_empty_string;
|
||||
}
|
||||
|
||||
return std::unique_ptr<Utf16CharacterStream>(
|
||||
new BufferedCharacterStream<TestingStream>(
|
||||
static_cast<size_t>(0), reinterpret_cast<const uint8_t*>(data),
|
||||
static_cast<size_t>(length)));
|
||||
0, reinterpret_cast<const uint8_t*>(data), length));
|
||||
}
|
||||
|
||||
std::unique_ptr<Utf16CharacterStream> ScannerStream::ForTesting(
|
||||
const uint16_t* data, size_t length) {
|
||||
if (data == nullptr) {
|
||||
DCHECK_EQ(length, 0);
|
||||
|
||||
// We don't want to pass in a null pointer into the the character stream,
|
||||
// because then the one-past-the-end pointer is undefined, so instead pass
|
||||
// through this static array.
|
||||
static const uint16_t non_null_empty_uint16_t_string[1] = {0};
|
||||
data = non_null_empty_uint16_t_string;
|
||||
}
|
||||
|
||||
return std::unique_ptr<Utf16CharacterStream>(
|
||||
new UnbufferedCharacterStream<TestingStream>(0, data, length));
|
||||
}
|
||||
|
||||
Utf16CharacterStream* ScannerStream::For(
|
||||
|
@ -31,6 +31,8 @@ class V8_EXPORT_PRIVATE ScannerStream {
|
||||
static std::unique_ptr<Utf16CharacterStream> ForTesting(const char* data);
|
||||
static std::unique_ptr<Utf16CharacterStream> ForTesting(const char* data,
|
||||
size_t length);
|
||||
static std::unique_ptr<Utf16CharacterStream> ForTesting(const uint16_t* data,
|
||||
size_t length);
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
|
@ -8,12 +8,25 @@
|
||||
#include <memory>
|
||||
|
||||
#include "src/ast/ast-value-factory.h"
|
||||
#include "src/ast/ast.h"
|
||||
#include "src/ast/scopes.h"
|
||||
#include "src/common/assert-scope.h"
|
||||
#include "src/common/globals.h"
|
||||
#include "src/execution/off-thread-isolate.h"
|
||||
#include "src/handles/handles-inl.h"
|
||||
#include "src/handles/handles.h"
|
||||
#include "src/heap/off-thread-factory.h"
|
||||
#include "src/heap/off-thread-factory-inl.h"
|
||||
#include "src/objects/fixed-array.h"
|
||||
#include "src/objects/script.h"
|
||||
#include "src/objects/shared-function-info.h"
|
||||
#include "src/objects/string.h"
|
||||
#include "src/parsing/parse-info.h"
|
||||
#include "src/parsing/parser.h"
|
||||
#include "src/parsing/rewriter.h"
|
||||
#include "src/parsing/scanner-character-streams.h"
|
||||
#include "src/parsing/scanner.h"
|
||||
#include "src/strings/unicode-inl.h"
|
||||
#include "src/utils/utils.h"
|
||||
#include "test/unittests/test-utils.h"
|
||||
|
||||
namespace v8 {
|
||||
@ -21,10 +34,74 @@ namespace internal {
|
||||
|
||||
class OffThreadIsolate;
|
||||
|
||||
namespace {
|
||||
|
||||
std::vector<uint16_t> DecodeUtf8(const std::string& string) {
|
||||
if (string.empty()) return {};
|
||||
|
||||
auto utf8_data =
|
||||
Vector<const uint8_t>::cast(VectorOf(string.data(), string.length()));
|
||||
Utf8Decoder decoder(utf8_data);
|
||||
|
||||
std::vector<uint16_t> utf16(decoder.utf16_length());
|
||||
decoder.Decode(&utf16[0], utf8_data);
|
||||
|
||||
return utf16;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
class OffThreadFactoryTest : public TestWithIsolateAndZone {
|
||||
public:
|
||||
OffThreadFactoryTest()
|
||||
: TestWithIsolateAndZone(), off_thread_isolate_(isolate()) {}
|
||||
: TestWithIsolateAndZone(),
|
||||
off_thread_isolate_(isolate()),
|
||||
parse_info_(isolate()) {}
|
||||
|
||||
FunctionLiteral* ParseProgram(const char* source) {
|
||||
auto utf16_source = DecodeUtf8(source);
|
||||
|
||||
// Normally this would be an external string or whatever, we don't have to
|
||||
// worry about it for now.
|
||||
source_string_ =
|
||||
factory()->NewStringFromUtf8(CStrVector(source)).ToHandleChecked();
|
||||
|
||||
parse_info_.set_character_stream(
|
||||
ScannerStream::ForTesting(utf16_source.data(), utf16_source.size()));
|
||||
parse_info_.set_toplevel();
|
||||
parse_info_.set_allow_lazy_parsing();
|
||||
|
||||
{
|
||||
DisallowHeapAllocation no_allocation;
|
||||
DisallowHandleAllocation no_handles;
|
||||
DisallowHeapAccess no_heap_access;
|
||||
|
||||
Parser parser(parse_info());
|
||||
parser.InitializeEmptyScopeChain(parse_info());
|
||||
parser.ParseOnBackground(parse_info());
|
||||
|
||||
CHECK(DeclarationScope::Analyze(parse_info()));
|
||||
}
|
||||
|
||||
parse_info()->ast_value_factory()->Internalize(off_thread_isolate());
|
||||
DeclarationScope::AllocateScopeInfos(parse_info(), off_thread_isolate());
|
||||
|
||||
script_ = parse_info_.CreateScript(off_thread_isolate(),
|
||||
off_thread_factory()->empty_string(),
|
||||
ScriptOriginOptions());
|
||||
|
||||
// Create the SFI list on the script so that SFI SetScript works.
|
||||
OffThreadHandle<WeakFixedArray> infos =
|
||||
off_thread_factory()->NewWeakFixedArray(
|
||||
parse_info()->max_function_literal_id() + 1, AllocationType::kOld);
|
||||
script_->set_shared_function_infos(*infos);
|
||||
|
||||
return parse_info()->literal();
|
||||
}
|
||||
|
||||
ParseInfo* parse_info() { return &parse_info_; }
|
||||
|
||||
OffThreadHandle<Script> script() { return script_; }
|
||||
|
||||
OffThreadIsolate* off_thread_isolate() { return &off_thread_isolate_; }
|
||||
OffThreadFactory* off_thread_factory() {
|
||||
@ -41,6 +118,9 @@ class OffThreadFactoryTest : public TestWithIsolateAndZone {
|
||||
|
||||
private:
|
||||
OffThreadIsolate off_thread_isolate_;
|
||||
ParseInfo parse_info_;
|
||||
Handle<String> source_string_;
|
||||
OffThreadHandle<Script> script_;
|
||||
};
|
||||
|
||||
TEST_F(OffThreadFactoryTest, HandleOrOffThreadHandle_IsNullWhenConstructed) {
|
||||
@ -173,5 +253,95 @@ TEST_F(OffThreadFactoryTest, AstConsString_CreatesConsString) {
|
||||
"foobar-plus-padding-for-length")));
|
||||
}
|
||||
|
||||
TEST_F(OffThreadFactoryTest, EmptyScript) {
|
||||
FunctionLiteral* program = ParseProgram("");
|
||||
|
||||
SharedFunctionInfo shared =
|
||||
*off_thread_factory()->NewSharedFunctionInfoForLiteral(program, script(),
|
||||
true);
|
||||
|
||||
off_thread_factory()->FinishOffThread();
|
||||
|
||||
Handle<SharedFunctionInfo> root_sfi = handle(shared, isolate());
|
||||
off_thread_factory()->Publish(isolate());
|
||||
|
||||
EXPECT_EQ(root_sfi->function_literal_id(), 0);
|
||||
}
|
||||
|
||||
TEST_F(OffThreadFactoryTest, LazyFunction) {
|
||||
FunctionLiteral* program = ParseProgram("function lazy() {}");
|
||||
FunctionLiteral* lazy = program->scope()
|
||||
->declarations()
|
||||
->AtForTest(0)
|
||||
->AsFunctionDeclaration()
|
||||
->fun();
|
||||
|
||||
SharedFunctionInfo shared =
|
||||
*off_thread_factory()->NewSharedFunctionInfoForLiteral(lazy, script(),
|
||||
true);
|
||||
|
||||
off_thread_factory()->FinishOffThread();
|
||||
|
||||
Handle<SharedFunctionInfo> lazy_sfi = handle(shared, isolate());
|
||||
off_thread_factory()->Publish(isolate());
|
||||
|
||||
EXPECT_EQ(lazy_sfi->function_literal_id(), 1);
|
||||
EXPECT_TRUE(lazy_sfi->Name().IsOneByteEqualTo(CStrVector("lazy")));
|
||||
EXPECT_FALSE(lazy_sfi->is_compiled());
|
||||
EXPECT_TRUE(lazy_sfi->HasUncompiledDataWithoutPreparseData());
|
||||
}
|
||||
|
||||
TEST_F(OffThreadFactoryTest, EagerFunction) {
|
||||
FunctionLiteral* program = ParseProgram("(function eager() {})");
|
||||
FunctionLiteral* eager = program->body()
|
||||
->at(0)
|
||||
->AsExpressionStatement()
|
||||
->expression()
|
||||
->AsFunctionLiteral();
|
||||
|
||||
SharedFunctionInfo shared =
|
||||
*off_thread_factory()->NewSharedFunctionInfoForLiteral(eager, script(),
|
||||
true);
|
||||
|
||||
off_thread_factory()->FinishOffThread();
|
||||
|
||||
Handle<SharedFunctionInfo> eager_sfi = handle(shared, isolate());
|
||||
off_thread_factory()->Publish(isolate());
|
||||
|
||||
EXPECT_EQ(eager_sfi->function_literal_id(), 1);
|
||||
EXPECT_TRUE(eager_sfi->Name().IsOneByteEqualTo(CStrVector("eager")));
|
||||
EXPECT_FALSE(eager_sfi->HasUncompiledData());
|
||||
// TODO(leszeks): Allocate bytecode and enable these checks.
|
||||
// EXPECT_TRUE(eager_sfi->is_compiled());
|
||||
// EXPECT_TRUE(eager_sfi->HasBytecodeArray());
|
||||
}
|
||||
|
||||
TEST_F(OffThreadFactoryTest, ImplicitNameFunction) {
|
||||
FunctionLiteral* program = ParseProgram("let implicit_name = function() {}");
|
||||
FunctionLiteral* implicit_name = program->body()
|
||||
->at(0)
|
||||
->AsBlock()
|
||||
->statements()
|
||||
->at(0)
|
||||
->AsExpressionStatement()
|
||||
->expression()
|
||||
->AsAssignment()
|
||||
->value()
|
||||
->AsFunctionLiteral();
|
||||
|
||||
SharedFunctionInfo shared =
|
||||
*off_thread_factory()->NewSharedFunctionInfoForLiteral(implicit_name,
|
||||
script(), true);
|
||||
|
||||
off_thread_factory()->FinishOffThread();
|
||||
|
||||
Handle<SharedFunctionInfo> implicit_name_sfi = handle(shared, isolate());
|
||||
off_thread_factory()->Publish(isolate());
|
||||
|
||||
EXPECT_EQ(implicit_name_sfi->function_literal_id(), 1);
|
||||
EXPECT_TRUE(
|
||||
implicit_name_sfi->Name().IsOneByteEqualTo(CStrVector("implicit_name")));
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
Loading…
Reference in New Issue
Block a user