[objects] Merge SFI outer_scope_info and feedback_metadata

Merge the outer_scope_info and feedback_metadata fields on
SharedFunctionInfo. outer_scope_info is only used during parsing,
and feedback_metadata is only available after compilation, so the
two never exist at the same time. Thus, they can share a field slot.

The exception is un-compiling and re-compiling a function, where we
need the outer_scope_info again. Fortunately, the outer_scope_info
can be re-calculated from the SFI's scope_info.

Bug: v8:7606
Cq-Include-Trybots: luci.chromium.try:linux_chromium_rel_ng
Change-Id: I6b97fefe859e89df75ad870da4a0bfa4b869772a
Reviewed-on: https://chromium-review.googlesource.com/992432
Reviewed-by: Igor Sheludko <ishell@chromium.org>
Reviewed-by: Yang Guo <yangguo@chromium.org>
Reviewed-by: Michael Starzinger <mstarzinger@chromium.org>
Reviewed-by: Camillo Bruni <cbruni@chromium.org>
Reviewed-by: Georg Neis <neis@chromium.org>
Commit-Queue: Leszek Swirski <leszeks@chromium.org>
Cr-Commit-Position: refs/heads/master@{#52454}
This commit is contained in:
Leszek Swirski 2018-04-06 12:49:15 +01:00 committed by Commit Bot
parent 48d1525daf
commit 6bd1d3c280
25 changed files with 260 additions and 182 deletions

View File

@ -734,10 +734,14 @@ StartupData SnapshotCreator::CreateBlob(
i::HeapIterator heap_iterator(isolate->heap());
while (i::HeapObject* current_obj = heap_iterator.next()) {
// Complete in-object slack tracking for all functions.
if (current_obj->IsJSFunction()) {
i::JSFunction* fun = i::JSFunction::cast(current_obj);
// Complete in-object slack tracking for all functions.
fun->CompleteInobjectSlackTrackingIfActive();
// Also, clear out feedback vectors.
fun->feedback_cell()->set_value(isolate->heap()->undefined_value());
}
// Clear out re-compilable data from all shared function infos. Any
@ -746,12 +750,8 @@ StartupData SnapshotCreator::CreateBlob(
if (current_obj->IsSharedFunctionInfo() &&
function_code_handling == FunctionCodeHandling::kClear) {
i::SharedFunctionInfo* shared = i::SharedFunctionInfo::cast(current_obj);
if (shared->HasBytecodeArray()) {
shared->ClearBytecodeArray();
} else if (shared->HasAsmWasmData()) {
shared->ClearAsmWasmData();
} else if (shared->HasPreParsedScopeData()) {
shared->ClearPreParsedScopeData();
if (shared->CanFlushCompiled()) {
shared->FlushCompiled();
}
DCHECK(shared->HasCodeObject() || shared->HasBuiltinId() ||
shared->IsApiFunction());

View File

@ -77,8 +77,7 @@ UnoptimizedCompileJob::UnoptimizedCompileJob(Isolate* isolate,
trace_compiler_dispatcher_jobs_(FLAG_trace_compiler_dispatcher_jobs) {
DCHECK(!shared_->is_toplevel());
// TODO(rmcilroy): Handle functions with non-empty outer scope info.
DCHECK(shared_->outer_scope_info()->IsTheHole(isolate) ||
ScopeInfo::cast(shared_->outer_scope_info())->length() == 0);
DCHECK(!shared_->HasOuterScopeInfo());
HandleScope scope(isolate);
Handle<Script> script(Script::cast(shared_->script()), isolate);
Handle<String> source(String::cast(script->source()), isolate);
@ -206,9 +205,8 @@ void UnoptimizedCompileJob::PrepareOnMainThread(Isolate* isolate) {
parser_.reset(new Parser(parse_info_.get()));
MaybeHandle<ScopeInfo> outer_scope_info;
if (!shared_->outer_scope_info()->IsTheHole(isolate) &&
ScopeInfo::cast(shared_->outer_scope_info())->length() > 0) {
outer_scope_info = handle(ScopeInfo::cast(shared_->outer_scope_info()));
if (shared_->HasOuterScopeInfo()) {
outer_scope_info = handle(shared_->GetOuterScopeInfo());
}
parser_->DeserializeScopeChain(parse_info_.get(), outer_scope_info);

View File

@ -283,9 +283,10 @@ void OptimizedCompilationJob::RecordFunctionCompilation(
time_taken_to_execute_.InMillisecondsF() +
time_taken_to_finalize_.InMillisecondsF();
LogFunctionCompilation(tag, compilation_info()->shared_info(),
parse_info()->script(), abstract_code, true,
time_taken_ms, isolate);
Handle<Script> script(
Script::cast(compilation_info()->shared_info()->script()));
LogFunctionCompilation(tag, compilation_info()->shared_info(), script,
abstract_code, true, time_taken_ms, isolate);
}
// ----------------------------------------------------------------------------
@ -293,27 +294,6 @@ void OptimizedCompilationJob::RecordFunctionCompilation(
namespace {
void EnsureFeedbackMetadata(UnoptimizedCompilationInfo* compilation_info,
Handle<SharedFunctionInfo> shared_info,
Isolate* isolate) {
// If no type feedback metadata exists, create it. At this point the
// AstNumbering pass has already run. Note the snapshot can contain outdated
// vectors for a different configuration, hence we also recreate a new vector
// when the function is not compiled (i.e. no code was serialized).
if (shared_info->feedback_metadata()->is_empty() ||
!shared_info->is_compiled()) {
Handle<FeedbackMetadata> feedback_metadata = FeedbackMetadata::New(
isolate, compilation_info->feedback_vector_spec());
shared_info->set_feedback_metadata(*feedback_metadata);
}
// It's very important that recompiles do not alter the structure of the type
// feedback vector. Verify that the structure fits the function literal.
CHECK(!shared_info->feedback_metadata()->SpecDiffersFrom(
compilation_info->feedback_vector_spec()));
}
bool UseAsmWasm(FunctionLiteral* literal, bool asm_wasm_broken) {
// Check whether asm.js validation is enabled.
if (!FLAG_validate_asm) return false;
@ -335,23 +315,25 @@ void InstallUnoptimizedCode(UnoptimizedCompilationInfo* compilation_info,
DCHECK_EQ(shared_info->language_mode(),
compilation_info->literal()->language_mode());
// Ensure feedback metadata is installed.
EnsureFeedbackMetadata(compilation_info, shared_info, isolate);
// Update the shared function info with the scope info.
Handle<ScopeInfo> scope_info = compilation_info->scope()->scope_info();
shared_info->set_scope_info(*scope_info);
Scope* outer_scope = compilation_info->scope()->GetOuterScopeWithContext();
if (outer_scope)
shared_info->set_outer_scope_info(*outer_scope->scope_info());
if (compilation_info->has_bytecode_array()) {
DCHECK(!shared_info->HasBytecodeArray()); // Only compiled once.
DCHECK(!compilation_info->has_asm_wasm_data());
DCHECK(!shared_info->HasFeedbackMetadata());
Handle<FeedbackMetadata> feedback_metadata = FeedbackMetadata::New(
isolate, compilation_info->feedback_vector_spec());
shared_info->set_bytecode_array(*compilation_info->bytecode_array());
shared_info->set_feedback_metadata(*feedback_metadata);
} else {
DCHECK(compilation_info->has_asm_wasm_data());
shared_info->set_asm_wasm_data(*compilation_info->asm_wasm_data());
shared_info->set_feedback_metadata(
isolate->heap()->empty_feedback_metadata());
}
// Install coverage info on the shared function info.
@ -690,7 +672,6 @@ MaybeHandle<Code> GetOptimizedCode(Handle<JSFunction> function,
std::unique_ptr<OptimizedCompilationJob> job(
compiler::Pipeline::NewCompilationJob(function, has_script));
OptimizedCompilationInfo* compilation_info = job->compilation_info();
ParseInfo* parse_info = job->parse_info();
compilation_info->SetOptimizingForOsr(osr_offset, osr_frame);
@ -734,7 +715,6 @@ MaybeHandle<Code> GetOptimizedCode(Handle<JSFunction> function,
// Reopen handles in the new CompilationHandleScope.
compilation_info->ReopenHandlesInNewHandleScope();
parse_info->ReopenHandlesInNewHandleScope();
if (mode == ConcurrencyMode::kConcurrent) {
if (GetOptimizedCodeLater(job.get(), isolate)) {
@ -843,9 +823,8 @@ MaybeHandle<SharedFunctionInfo> FinalizeTopLevel(
DCHECK_EQ(kNoSourcePosition,
parse_info->literal()->function_token_position());
Handle<SharedFunctionInfo> shared_info =
isolate->factory()->NewSharedFunctionInfoForLiteral(parse_info->literal(),
parse_info->script());
shared_info->set_is_toplevel(true);
isolate->factory()->NewSharedFunctionInfoForLiteral(
parse_info->literal(), parse_info->script(), true);
// Finalize compilation of the unoptimized bytecode or asm-js data.
if (!FinalizeUnoptimizedCode(parse_info, isolate, shared_info,
@ -1900,12 +1879,8 @@ Handle<SharedFunctionInfo> Compiler::GetSharedFunctionInfo(
// Allocate a shared function info object which will be compiled lazily.
Handle<SharedFunctionInfo> result =
isolate->factory()->NewSharedFunctionInfoForLiteral(literal, script);
result->set_is_toplevel(false);
Scope* outer_scope = literal->scope()->GetOuterScopeWithContext();
if (outer_scope) {
result->set_outer_scope_info(*outer_scope->scope_info());
}
isolate->factory()->NewSharedFunctionInfoForLiteral(literal, script,
false);
return result;
}

View File

@ -268,12 +268,11 @@ class UnoptimizedCompilationJob : public CompilationJob {
// Each of the three phases can either fail or succeed.
class OptimizedCompilationJob : public CompilationJob {
public:
OptimizedCompilationJob(uintptr_t stack_limit, ParseInfo* parse_info,
OptimizedCompilationJob(uintptr_t stack_limit,
OptimizedCompilationInfo* compilation_info,
const char* compiler_name,
State initial_state = State::kReadyToPrepare)
: CompilationJob(stack_limit, initial_state),
parse_info_(parse_info),
compilation_info_(compilation_info),
compiler_name_(compiler_name) {}
@ -299,7 +298,6 @@ class OptimizedCompilationJob : public CompilationJob {
void RecordFunctionCompilation(CodeEventListener::LogEventsAndTags tag,
Isolate* isolate) const;
ParseInfo* parse_info() const { return parse_info_; }
OptimizedCompilationInfo* compilation_info() const {
return compilation_info_;
}
@ -312,8 +310,6 @@ class OptimizedCompilationJob : public CompilationJob {
virtual Status FinalizeJobImpl(Isolate* isolate) = 0;
private:
// TODO(rmcilroy): Remove parse_info.
ParseInfo* parse_info_;
OptimizedCompilationInfo* compilation_info_;
base::TimeDelta time_taken_to_prepare_;
base::TimeDelta time_taken_to_execute_;

View File

@ -744,21 +744,21 @@ PipelineStatistics* CreatePipelineStatistics(Handle<Script> script,
class PipelineCompilationJob final : public OptimizedCompilationJob {
public:
PipelineCompilationJob(ParseInfo* parse_info,
Handle<SharedFunctionInfo> shared_info,
PipelineCompilationJob(Handle<SharedFunctionInfo> shared_info,
Handle<JSFunction> function)
// Note that the OptimizedCompilationInfo is not initialized at the time
// we pass it to the CompilationJob constructor, but it is not
// dereferenced there.
: OptimizedCompilationJob(parse_info->stack_limit(), parse_info,
&compilation_info_, "TurboFan"),
parse_info_(parse_info),
: OptimizedCompilationJob(
function->GetIsolate()->stack_guard()->real_climit(),
&compilation_info_, "TurboFan"),
zone_(function->GetIsolate()->allocator(), ZONE_NAME),
zone_stats_(function->GetIsolate()->allocator()),
compilation_info_(parse_info_.get()->zone(), function->GetIsolate(),
shared_info, function),
pipeline_statistics_(
CreatePipelineStatistics(parse_info_->script(), compilation_info(),
function->GetIsolate(), &zone_stats_)),
compilation_info_(&zone_, function->GetIsolate(), shared_info,
function),
pipeline_statistics_(CreatePipelineStatistics(
handle(Script::cast(shared_info->script())), compilation_info(),
function->GetIsolate(), &zone_stats_)),
data_(&zone_stats_, function->GetIsolate(), compilation_info(),
pipeline_statistics_.get()),
pipeline_(&data_),
@ -773,7 +773,7 @@ class PipelineCompilationJob final : public OptimizedCompilationJob {
void RegisterWeakObjectsInOptimizedCode(Handle<Code> code, Isolate* isolate);
private:
std::unique_ptr<ParseInfo> parse_info_;
Zone zone_;
ZoneStats zone_stats_;
OptimizedCompilationInfo compilation_info_;
std::unique_ptr<PipelineStatistics> pipeline_statistics_;
@ -889,8 +889,8 @@ class PipelineWasmCompilationJob final : public OptimizedCompilationJob {
OptimizedCompilationInfo* info, Isolate* isolate, JSGraph* jsgraph,
CallDescriptor* call_descriptor, SourcePositionTable* source_positions,
WasmCompilationData* wasm_compilation_data, bool asmjs_origin)
: OptimizedCompilationJob(isolate->stack_guard()->real_climit(), nullptr,
info, "TurboFan", State::kReadyToExecute),
: OptimizedCompilationJob(isolate->stack_guard()->real_climit(), info,
"TurboFan", State::kReadyToExecute),
zone_stats_(isolate->allocator()),
pipeline_statistics_(CreatePipelineStatistics(
Handle<Script>::null(), info, isolate, &zone_stats_)),
@ -2075,13 +2075,7 @@ Handle<Code> Pipeline::GenerateCodeForTesting(
OptimizedCompilationJob* Pipeline::NewCompilationJob(
Handle<JSFunction> function, bool has_script) {
Handle<SharedFunctionInfo> shared = handle(function->shared());
ParseInfo* parse_info;
if (!has_script) {
parse_info = ParseInfo::AllocateWithoutScript(shared);
} else {
parse_info = new ParseInfo(shared);
}
return new PipelineCompilationJob(parse_info, shared, function);
return new PipelineCompilationJob(shared, function);
}
// static

View File

@ -826,7 +826,7 @@ void LiveEdit::ReplaceFunctionCode(
if (shared_info->is_compiled()) {
// Clear old bytecode. This will trigger self-healing if we do not install
// new bytecode.
shared_info->ClearBytecodeArray();
shared_info->FlushCompiled();
shared_info->set_bytecode_array(new_shared_info->bytecode_array());
if (shared_info->HasBreakInfo()) {
@ -835,16 +835,12 @@ void LiveEdit::ReplaceFunctionCode(
handle(shared_info->GetDebugInfo()));
}
shared_info->set_scope_info(new_shared_info->scope_info());
shared_info->set_outer_scope_info(new_shared_info->outer_scope_info());
shared_info->set_feedback_metadata(new_shared_info->feedback_metadata());
shared_info->DisableOptimization(BailoutReason::kLiveEdit);
// Update the type feedback vector, if needed.
Handle<FeedbackMetadata> new_feedback_metadata(
new_shared_info->feedback_metadata());
shared_info->set_feedback_metadata(*new_feedback_metadata);
} else {
// Use an empty FeedbackMetadata.
Handle<FeedbackMetadata> feedback_metadata = FeedbackMetadata::New(isolate);
shared_info->set_feedback_metadata(*feedback_metadata);
// There should not be any feedback metadata. Keep the outer scope info the
// same.
DCHECK(!shared_info->HasFeedbackMetadata());
}
int start_position = compile_info_wrapper.GetStartPosition();

View File

@ -2545,11 +2545,11 @@ void Factory::ReinitializeJSGlobalProxy(Handle<JSGlobalProxy> object,
}
Handle<SharedFunctionInfo> Factory::NewSharedFunctionInfoForLiteral(
FunctionLiteral* literal, Handle<Script> script) {
FunctionLiteral* literal, Handle<Script> script, bool is_toplevel) {
FunctionKind kind = literal->kind();
Handle<SharedFunctionInfo> shared = NewSharedFunctionInfoForBuiltin(
literal->name(), Builtins::kCompileLazy, kind);
SharedFunctionInfo::InitFromFunctionLiteral(shared, literal);
SharedFunctionInfo::InitFromFunctionLiteral(shared, literal, is_toplevel);
SharedFunctionInfo::SetScript(shared, script, false);
return shared;
}
@ -2577,14 +2577,16 @@ Handle<JSMessageObject> Factory::NewJSMessageObject(
Handle<SharedFunctionInfo> Factory::NewSharedFunctionInfoForApiFunction(
MaybeHandle<String> maybe_name,
Handle<FunctionTemplateInfo> function_template_info, FunctionKind kind) {
return NewSharedFunctionInfo(maybe_name, function_template_info,
Builtins::kNoBuiltinId, kind);
Handle<SharedFunctionInfo> shared = NewSharedFunctionInfo(
maybe_name, function_template_info, Builtins::kNoBuiltinId, kind);
return shared;
}
Handle<SharedFunctionInfo> Factory::NewSharedFunctionInfoForBuiltin(
MaybeHandle<String> maybe_name, int builtin_index, FunctionKind kind) {
return NewSharedFunctionInfo(maybe_name, MaybeHandle<Code>(), builtin_index,
kind);
Handle<SharedFunctionInfo> shared = NewSharedFunctionInfo(
maybe_name, MaybeHandle<Code>(), builtin_index, kind);
return shared;
}
Handle<SharedFunctionInfo> Factory::NewSharedFunctionInfo(
@ -2621,12 +2623,19 @@ Handle<SharedFunctionInfo> Factory::NewSharedFunctionInfo(
} else {
share->set_builtin_id(Builtins::kIllegal);
}
share->set_outer_scope_info(*the_hole_value());
// Generally functions won't have feedback, unless they have been created
// from a FunctionLiteral. Those can just reset this field to keep the
// SharedFunctionInfo in a consistent state.
if (maybe_builtin_index == Builtins::kCompileLazy) {
share->set_raw_outer_scope_info_or_feedback_metadata(*the_hole_value(),
SKIP_WRITE_BARRIER);
} else {
share->set_raw_outer_scope_info_or_feedback_metadata(
*empty_feedback_metadata(), SKIP_WRITE_BARRIER);
}
share->set_script(*undefined_value(), SKIP_WRITE_BARRIER);
share->set_debug_info(Smi::kZero, SKIP_WRITE_BARRIER);
share->set_function_identifier(*undefined_value(), SKIP_WRITE_BARRIER);
share->set_feedback_metadata(isolate()->heap()->empty_feedback_metadata(),
SKIP_WRITE_BARRIER);
share->set_function_literal_id(FunctionLiteral::kIdTypeInvalid);
#if V8_SFI_HAS_UNIQUE_ID
share->set_unique_id(isolate()->GetNextUniqueSharedFunctionInfoId());

View File

@ -805,7 +805,7 @@ class V8_EXPORT_PRIVATE Factory final {
FunctionKind kind = kNormalFunction);
Handle<SharedFunctionInfo> NewSharedFunctionInfoForLiteral(
FunctionLiteral* literal, Handle<Script> script);
FunctionLiteral* literal, Handle<Script> script, bool is_toplevel);
static bool IsFunctionModeWithPrototype(FunctionMode function_mode) {
return (function_mode & kWithPrototypeBits) != 0;

View File

@ -1910,8 +1910,8 @@ void AccessorAssembler::BranchIfStrictMode(Node* vector, Node* slot,
Label* if_strict) {
Node* sfi =
LoadObjectField(vector, FeedbackVector::kSharedFunctionInfoOffset);
Node* metadata =
LoadObjectField(sfi, SharedFunctionInfo::kFeedbackMetadataOffset);
TNode<FeedbackMetadata> metadata = CAST(LoadObjectField(
sfi, SharedFunctionInfo::kOuterScopeInfoOrFeedbackMetadataOffset));
Node* slot_int = SmiToInt32(slot);
// See VectorICComputer::index().

View File

@ -864,10 +864,9 @@ void SharedFunctionInfo::SharedFunctionInfoVerify() {
VerifyObjectField(kFunctionDataOffset);
VerifyObjectField(kDebugInfoOffset);
VerifyObjectField(kFeedbackMetadataOffset);
VerifyObjectField(kOuterScopeInfoOrFeedbackMetadataOffset);
VerifyObjectField(kFunctionIdentifierOffset);
VerifyObjectField(kNameOrScopeInfoOffset);
VerifyObjectField(kOuterScopeInfoOffset);
VerifyObjectField(kScriptOffset);
Object* value = name_or_scope_info();
@ -885,6 +884,15 @@ void SharedFunctionInfo::SharedFunctionInfoVerify() {
CHECK(function_identifier()->IsUndefined(isolate) || HasBuiltinFunctionId() ||
HasInferredName());
if (!is_compiled()) {
CHECK(!HasFeedbackMetadata());
CHECK(outer_scope_info()->IsScopeInfo() ||
outer_scope_info()->IsTheHole(isolate));
} else if (HasBytecodeArray()) {
CHECK(HasFeedbackMetadata());
CHECK(feedback_metadata()->IsFeedbackMetadata());
}
int expected_map_index = Context::FunctionMapIndex(
language_mode(), kind(), true, HasSharedName(), needs_home_object());
CHECK_EQ(expected_map_index, function_map_index());

View File

@ -1286,9 +1286,16 @@ void SharedFunctionInfo::SharedFunctionInfoPrint(std::ostream& os) { // NOLINT
os << "\n - no debug info";
}
os << "\n - scope info: " << Brief(scope_info());
if (HasOuterScopeInfo()) {
os << "\n - outer scope info: " << Brief(GetOuterScopeInfo());
}
os << "\n - length: " << length();
os << "\n - feedback_metadata: ";
feedback_metadata()->FeedbackMetadataPrint(os);
if (HasFeedbackMetadata()) {
feedback_metadata()->FeedbackMetadataPrint(os);
} else {
os << "<none>";
}
os << "\n";
}

View File

@ -13872,7 +13872,8 @@ void SharedFunctionInfo::DisableOptimization(BailoutReason reason) {
}
void SharedFunctionInfo::InitFromFunctionLiteral(
Handle<SharedFunctionInfo> shared_info, FunctionLiteral* lit) {
Handle<SharedFunctionInfo> shared_info, FunctionLiteral* lit,
bool is_toplevel) {
// When adding fields here, make sure DeclarationScope::AnalyzePartially is
// updated accordingly.
shared_info->set_internal_formal_parameter_count(lit->parameter_count());
@ -13899,6 +13900,16 @@ void SharedFunctionInfo::InitFromFunctionLiteral(
IsClassConstructor(lit->kind()));
shared_info->set_requires_instance_fields_initializer(
lit->requires_instance_fields_initializer());
shared_info->set_is_toplevel(is_toplevel);
DCHECK(shared_info->outer_scope_info()->IsTheHole(shared_info->GetIsolate()));
if (!is_toplevel) {
Scope* outer_scope = lit->scope()->GetOuterScopeWithContext();
if (outer_scope) {
shared_info->set_outer_scope_info(*outer_scope->scope_info());
}
}
// For lazy parsed functions, the following flags will be inaccurate since we
// don't have the information yet. They're set later in
// SetSharedFunctionFlagsFromLiteral (compiler.cc), when the function is

View File

@ -25,8 +25,6 @@ DEFINE_DEOPT_ELEMENT_ACCESSORS(SharedFunctionInfo, Object)
ACCESSORS(SharedFunctionInfo, name_or_scope_info, Object,
kNameOrScopeInfoOffset)
ACCESSORS(SharedFunctionInfo, feedback_metadata, FeedbackMetadata,
kFeedbackMetadataOffset)
ACCESSORS(SharedFunctionInfo, function_data, Object, kFunctionDataOffset)
ACCESSORS(SharedFunctionInfo, script, Object, kScriptOffset)
ACCESSORS(SharedFunctionInfo, debug_info, Object, kDebugInfoOffset)
@ -331,8 +329,56 @@ void SharedFunctionInfo::set_scope_info(ScopeInfo* scope_info,
reinterpret_cast<Object*>(scope_info), mode);
}
ACCESSORS(SharedFunctionInfo, outer_scope_info, HeapObject,
kOuterScopeInfoOffset)
ACCESSORS(SharedFunctionInfo, raw_outer_scope_info_or_feedback_metadata,
HeapObject, kOuterScopeInfoOrFeedbackMetadataOffset)
HeapObject* SharedFunctionInfo::outer_scope_info() const {
DCHECK(!is_compiled());
DCHECK(!HasFeedbackMetadata());
return raw_outer_scope_info_or_feedback_metadata();
}
bool SharedFunctionInfo::HasOuterScopeInfo() const {
ScopeInfo* outer_info = nullptr;
if (!is_compiled()) {
if (!outer_scope_info()->IsScopeInfo()) return false;
outer_info = ScopeInfo::cast(outer_scope_info());
} else {
if (!scope_info()->HasOuterScopeInfo()) return false;
outer_info = scope_info()->OuterScopeInfo();
}
return outer_info->length() > 0;
}
ScopeInfo* SharedFunctionInfo::GetOuterScopeInfo() const {
DCHECK(HasOuterScopeInfo());
if (!is_compiled()) return ScopeInfo::cast(outer_scope_info());
return scope_info()->OuterScopeInfo();
}
void SharedFunctionInfo::set_outer_scope_info(HeapObject* value,
WriteBarrierMode mode) {
DCHECK(!is_compiled());
DCHECK(raw_outer_scope_info_or_feedback_metadata()->IsTheHole(GetIsolate()));
DCHECK(value->IsScopeInfo() || value->IsTheHole(GetIsolate()));
return set_raw_outer_scope_info_or_feedback_metadata(value, mode);
}
bool SharedFunctionInfo::HasFeedbackMetadata() const {
return raw_outer_scope_info_or_feedback_metadata()->IsFeedbackMetadata();
}
FeedbackMetadata* SharedFunctionInfo::feedback_metadata() const {
DCHECK(HasFeedbackMetadata());
return FeedbackMetadata::cast(raw_outer_scope_info_or_feedback_metadata());
}
void SharedFunctionInfo::set_feedback_metadata(FeedbackMetadata* value,
WriteBarrierMode mode) {
DCHECK(!HasFeedbackMetadata());
DCHECK(value->IsFeedbackMetadata());
return set_raw_outer_scope_info_or_feedback_metadata(value, mode);
}
bool SharedFunctionInfo::is_compiled() const {
Object* data = function_data();
@ -384,12 +430,6 @@ void SharedFunctionInfo::set_bytecode_array(BytecodeArray* bytecode) {
set_function_data(bytecode);
}
void SharedFunctionInfo::ClearBytecodeArray() {
DCHECK(function_data() == Smi::FromEnum(Builtins::kCompileLazy) ||
HasBytecodeArray());
set_builtin_id(Builtins::kCompileLazy);
}
bool SharedFunctionInfo::HasAsmWasmData() const {
return function_data()->IsFixedArray();
}
@ -405,11 +445,6 @@ void SharedFunctionInfo::set_asm_wasm_data(FixedArray* data) {
set_function_data(data);
}
void SharedFunctionInfo::ClearAsmWasmData() {
DCHECK(HasAsmWasmData());
set_builtin_id(Builtins::kCompileLazy);
}
bool SharedFunctionInfo::HasBuiltinId() const {
return function_data()->IsSmi();
}
@ -494,6 +529,36 @@ bool SharedFunctionInfo::IsSubjectToDebugging() {
return IsUserJavaScript() && !HasAsmWasmData();
}
bool SharedFunctionInfo::CanFlushCompiled() const {
bool can_decompile =
(HasBytecodeArray() || HasAsmWasmData() || HasPreParsedScopeData());
return can_decompile;
}
void SharedFunctionInfo::FlushCompiled() {
DisallowHeapAllocation no_gc;
DCHECK(CanFlushCompiled());
Oddball* the_hole = GetIsolate()->heap()->the_hole_value();
if (is_compiled()) {
HeapObject* outer_scope_info = the_hole;
if (!is_toplevel()) {
if (scope_info()->HasOuterScopeInfo()) {
outer_scope_info = scope_info()->OuterScopeInfo();
}
}
// Raw setter to avoid validity checks, since we're performing the unusual
// task of decompiling.
set_raw_outer_scope_info_or_feedback_metadata(outer_scope_info);
} else {
DCHECK(outer_scope_info()->IsScopeInfo() || is_toplevel());
}
set_builtin_id(Builtins::kCompileLazy);
}
} // namespace internal
} // namespace v8

View File

@ -92,9 +92,18 @@ class SharedFunctionInfo : public HeapObject {
// Start position of this function in the script source.
inline int StartPosition() const;
// The outer scope info for the purpose of parsing this function, or the hole
// value if it isn't yet known.
DECL_ACCESSORS(outer_scope_info, HeapObject)
// [outer scope info | feedback metadata] Shared storage for outer scope info
// (on uncompiled functions) and feedback metadata (on compiled functions).
DECL_ACCESSORS(raw_outer_scope_info_or_feedback_metadata, HeapObject)
// Get the outer scope info whether this function is compiled or not.
inline bool HasOuterScopeInfo() const;
inline ScopeInfo* GetOuterScopeInfo() const;
// [feedback metadata] Metadata template for feedback vectors of instances of
// this function.
inline bool HasFeedbackMetadata() const;
DECL_ACCESSORS(feedback_metadata, FeedbackMetadata)
// Returns if this function has been compiled to native code yet.
inline bool is_compiled() const;
@ -119,11 +128,6 @@ class SharedFunctionInfo : public HeapObject {
// function. The value is only reliable when the function has been compiled.
DECL_INT_ACCESSORS(expected_nof_properties)
// [feedback_metadata] - describes ast node feedback from full-codegen and
// (increasingly) from crankshafted code where sufficient feedback isn't
// available.
DECL_ACCESSORS(feedback_metadata, FeedbackMetadata)
// [function_literal_id] - uniquely identifies the FunctionLiteral this
// SharedFunctionInfo represents within its script, or -1 if this
// SharedFunctionInfo object doesn't correspond to a parsed FunctionLiteral.
@ -151,11 +155,9 @@ class SharedFunctionInfo : public HeapObject {
inline bool HasBytecodeArray() const;
inline BytecodeArray* bytecode_array() const;
inline void set_bytecode_array(BytecodeArray* bytecode);
inline void ClearBytecodeArray();
inline bool HasAsmWasmData() const;
inline FixedArray* asm_wasm_data() const;
inline void set_asm_wasm_data(FixedArray* data);
inline void ClearAsmWasmData();
// A brief note to clear up possible confusion:
// builtin_id corresponds to the auto-generated
// Builtins::Name id, while builtin_function_id corresponds to
@ -364,6 +366,14 @@ class SharedFunctionInfo : public HeapObject {
// Whether this function is defined in user-provided JavaScript code.
inline bool IsUserJavaScript();
// True if one can flush compiled code from this function, in such a way that
// it can later be re-compiled.
inline bool CanFlushCompiled() const;
// Flush compiled data from this function, setting it back to CompileLazy and
// clearing any feedback metadata.
inline void FlushCompiled();
// Check whether or not this function is inlineable.
bool IsInlineable();
@ -377,7 +387,7 @@ class SharedFunctionInfo : public HeapObject {
// Initialize a SharedFunctionInfo from a parsed function literal.
static void InitFromFunctionLiteral(Handle<SharedFunctionInfo> shared_info,
FunctionLiteral* lit);
FunctionLiteral* lit, bool is_toplevel);
// Sets the expected number of properties based on estimate from parser.
void SetExpectedNofPropertiesFromEstimate(FunctionLiteral* literal);
@ -443,28 +453,27 @@ class SharedFunctionInfo : public HeapObject {
#endif
// Layout description.
#define SHARED_FUNCTION_INFO_FIELDS(V) \
/* Pointer fields. */ \
V(kStartOfPointerFieldsOffset, 0) \
V(kFunctionDataOffset, kPointerSize) \
V(kNameOrScopeInfoOffset, kPointerSize) \
V(kOuterScopeInfoOffset, kPointerSize) \
V(kScriptOffset, kPointerSize) \
V(kDebugInfoOffset, kPointerSize) \
V(kFunctionIdentifierOffset, kPointerSize) \
V(kFeedbackMetadataOffset, kPointerSize) \
V(kEndOfPointerFieldsOffset, 0) \
/* Raw data fields. */ \
V(kFunctionLiteralIdOffset, kInt32Size) \
V(kUniqueIdOffset, kUniqueIdFieldSize) \
V(kLengthOffset, kInt32Size) \
V(kFormalParameterCountOffset, kInt32Size) \
V(kExpectedNofPropertiesOffset, kInt32Size) \
V(kStartPositionAndTypeOffset, kInt32Size) \
V(kEndPositionOffset, kInt32Size) \
V(kFunctionTokenPositionOffset, kInt32Size) \
V(kFlagsOffset, kInt32Size) \
/* Total size. */ \
#define SHARED_FUNCTION_INFO_FIELDS(V) \
/* Pointer fields. */ \
V(kStartOfPointerFieldsOffset, 0) \
V(kFunctionDataOffset, kPointerSize) \
V(kNameOrScopeInfoOffset, kPointerSize) \
V(kOuterScopeInfoOrFeedbackMetadataOffset, kPointerSize) \
V(kScriptOffset, kPointerSize) \
V(kDebugInfoOffset, kPointerSize) \
V(kFunctionIdentifierOffset, kPointerSize) \
V(kEndOfPointerFieldsOffset, 0) \
/* Raw data fields. */ \
V(kFunctionLiteralIdOffset, kInt32Size) \
V(kUniqueIdOffset, kUniqueIdFieldSize) \
V(kLengthOffset, kInt32Size) \
V(kFormalParameterCountOffset, kInt32Size) \
V(kExpectedNofPropertiesOffset, kInt32Size) \
V(kStartPositionAndTypeOffset, kInt32Size) \
V(kEndPositionOffset, kInt32Size) \
V(kFunctionTokenPositionOffset, kInt32Size) \
V(kFlagsOffset, kInt32Size) \
/* Total size. */ \
V(kSize, 0)
DEFINE_FIELD_OFFSET_CONSTANTS(HeapObject::kHeaderSize,
@ -543,6 +552,10 @@ class SharedFunctionInfo : public HeapObject {
// ScopeInfo.
DECL_ACCESSORS(name_or_scope_info, Object)
// [outer scope info] The outer scope info, needed to lazily parse this
// function.
DECL_ACCESSORS(outer_scope_info, HeapObject)
inline void set_kind(FunctionKind kind);
inline void set_needs_home_object(bool value);

View File

@ -66,10 +66,8 @@ ParseInfo::ParseInfo(Handle<SharedFunctionInfo> shared)
set_module(script->origin_options().IsModule());
DCHECK(!(is_eval() && is_module()));
Handle<HeapObject> scope_info(shared->outer_scope_info());
if (!scope_info->IsTheHole(isolate) &&
Handle<ScopeInfo>::cast(scope_info)->length() > 0) {
set_outer_scope_info(Handle<ScopeInfo>::cast(scope_info));
if (shared->HasOuterScopeInfo()) {
set_outer_scope_info(handle(shared->GetOuterScopeInfo()));
}
// CollectTypeProfile uses its own feedback slots. If we have existing
@ -77,9 +75,9 @@ ParseInfo::ParseInfo(Handle<SharedFunctionInfo> shared)
// has the appropriate slots.
set_collect_type_profile(
isolate->is_collecting_type_profile() &&
(shared->feedback_metadata()->is_empty()
? script->IsUserJavaScript()
: shared->feedback_metadata()->HasTypeProfileSlot()));
(shared->HasFeedbackMetadata()
? shared->feedback_metadata()->HasTypeProfileSlot()
: script->IsUserJavaScript()));
if (block_coverage_enabled() && script->IsUserJavaScript()) {
AllocateSourceRangeMap();
}
@ -136,7 +134,7 @@ ParseInfo* ParseInfo::AllocateWithoutScript(Handle<SharedFunctionInfo> shared) {
p->set_module(false);
DCHECK_NE(shared->kind(), FunctionKind::kModule);
Handle<HeapObject> scope_info(shared->outer_scope_info());
Handle<HeapObject> scope_info(shared->GetOuterScopeInfo());
if (!scope_info->IsTheHole(isolate) &&
Handle<ScopeInfo>::cast(scope_info)->length() > 0) {
p->set_outer_scope_info(Handle<ScopeInfo>::cast(scope_info));

View File

@ -1186,12 +1186,12 @@ void V8HeapExplorer::ExtractSharedFunctionInfoReferences(
SetInternalReference(obj, entry, "function_identifier",
shared->function_identifier(),
SharedFunctionInfo::kFunctionIdentifierOffset);
SetInternalReference(obj, entry, "feedback_metadata",
shared->feedback_metadata(),
SharedFunctionInfo::kFeedbackMetadataOffset);
SetInternalReference(
obj, entry, "raw_outer_scope_info_or_feedback_metadata",
shared->raw_outer_scope_info_or_feedback_metadata(),
SharedFunctionInfo::kOuterScopeInfoOrFeedbackMetadataOffset);
}
void V8HeapExplorer::ExtractScriptReferences(int entry, Script* script) {
HeapObject* obj = script;
SetInternalReference(obj, entry,

View File

@ -132,7 +132,7 @@ RUNTIME_FUNCTION(Runtime_InstantiateAsmJs) {
// Remove wasm data, mark as broken for asm->wasm, replace function code with
// CompileLazy, and return a smi 0 to indicate failure.
if (function->shared()->HasAsmWasmData()) {
function->shared()->ClearAsmWasmData();
function->shared()->FlushCompiled();
}
function->shared()->set_is_asm_wasm_broken(true);
DCHECK(function->code() ==

View File

@ -116,7 +116,8 @@ RUNTIME_FUNCTION(Runtime_SetCode) {
// of the target shared function info.
target_shared->set_function_data(source_shared->function_data());
target_shared->set_length(source_shared->GetLength());
target_shared->set_feedback_metadata(source_shared->feedback_metadata());
target_shared->set_raw_outer_scope_info_or_feedback_metadata(
source_shared->raw_outer_scope_info_or_feedback_metadata());
target_shared->set_internal_formal_parameter_count(
source_shared->internal_formal_parameter_count());
target_shared->set_raw_start_position_and_type(
@ -128,7 +129,6 @@ RUNTIME_FUNCTION(Runtime_SetCode) {
target_shared->set_function_literal_id(source_shared->function_literal_id());
target_shared->set_scope_info(source_shared->scope_info());
target_shared->set_outer_scope_info(source_shared->outer_scope_info());
Handle<Object> source_script(source_shared->script(), isolate);
if (source_script->IsScript()) {

View File

@ -138,9 +138,9 @@ Handle<JSFunction> FunctionTester::ForMachineGraph(Graph* graph,
Handle<JSFunction> FunctionTester::Compile(Handle<JSFunction> function) {
Handle<SharedFunctionInfo> shared(function->shared());
ParseInfo parse_info(shared);
OptimizedCompilationInfo info(parse_info.zone(), function->GetIsolate(),
shared, function);
Zone zone(function->GetIsolate()->allocator(), ZONE_NAME);
OptimizedCompilationInfo info(&zone, function->GetIsolate(), shared,
function);
if (flags_ & OptimizedCompilationInfo::kInliningEnabled) {
info.MarkAsInliningEnabled();
@ -164,9 +164,9 @@ Handle<JSFunction> FunctionTester::Compile(Handle<JSFunction> function) {
// and replace the JSFunction's code with the result.
Handle<JSFunction> FunctionTester::CompileGraph(Graph* graph) {
Handle<SharedFunctionInfo> shared(function->shared());
ParseInfo parse_info(shared);
OptimizedCompilationInfo info(parse_info.zone(), function->GetIsolate(),
shared, function);
Zone zone(function->GetIsolate()->allocator(), ZONE_NAME);
OptimizedCompilationInfo info(&zone, function->GetIsolate(), shared,
function);
Handle<Code> code =
Pipeline::GenerateCodeForTesting(&info, function->GetIsolate(), graph);

View File

@ -4941,7 +4941,7 @@ static void RemoveCodeAndGC(const v8::FunctionCallbackInfo<v8::Value>& args) {
Isolate* isolate = CcTest::i_isolate();
Handle<Object> obj = v8::Utils::OpenHandle(*args[0]);
Handle<JSFunction> fun = Handle<JSFunction>::cast(obj);
fun->shared()->ClearBytecodeArray(); // Bytecode is code too.
fun->shared()->FlushCompiled(); // Bytecode is code too.
fun->set_code(*BUILTIN_CODE(isolate, CompileLazy));
CcTest::CollectAllAvailableGarbage();
}

View File

@ -123,7 +123,9 @@ class InterpreterTester {
}
if (!feedback_metadata_.is_null()) {
function->set_feedback_cell(isolate_->heap()->many_closures_cell());
function->shared()->set_feedback_metadata(
// Set the raw feedback metadata to circumvent checks that we are not
// overwriting existing metadata.
function->shared()->set_raw_outer_scope_info_or_feedback_metadata(
*feedback_metadata_.ToHandleChecked());
JSFunction::EnsureFeedbackVector(function);
}

View File

@ -46,7 +46,9 @@ Handle<FeedbackVector> NewFeedbackVector(Isolate* isolate, Spec* spec) {
Handle<SharedFunctionInfo> shared =
isolate->factory()->NewSharedFunctionInfoForBuiltin(
isolate->factory()->empty_string(), Builtins::kIllegal);
shared->set_feedback_metadata(*metadata);
// Set the raw feedback metadata to circumvent checks that we are not
// overwriting existing metadata.
shared->set_raw_outer_scope_info_or_feedback_metadata(*metadata);
return FeedbackVector::New(isolate, shared);
}

View File

@ -26,12 +26,12 @@ namespace {
class BlockingCompilationJob : public OptimizedCompilationJob {
public:
BlockingCompilationJob(Isolate* isolate, Handle<JSFunction> function)
: OptimizedCompilationJob(isolate->stack_guard()->real_climit(),
&parse_info_, &info_, "BlockingCompilationJob",
: OptimizedCompilationJob(isolate->stack_guard()->real_climit(), &info_,
"BlockingCompilationJob",
State::kReadyToExecute),
shared_(function->shared()),
parse_info_(shared_),
info_(parse_info_.zone(), function->GetIsolate(), shared_, function),
zone_(isolate->allocator(), ZONE_NAME),
info_(&zone_, function->GetIsolate(), shared_, function),
blocking_(false),
semaphore_(0) {}
~BlockingCompilationJob() override = default;
@ -53,7 +53,7 @@ class BlockingCompilationJob : public OptimizedCompilationJob {
private:
Handle<SharedFunctionInfo> shared_;
ParseInfo parse_info_;
Zone zone_;
OptimizedCompilationInfo info_;
base::AtomicValue<bool> blocking_;
base::Semaphore semaphore_;

View File

@ -107,7 +107,9 @@ class JSCallReducerTest : public TypedGraphTest {
Handle<SharedFunctionInfo> shared =
isolate()->factory()->NewSharedFunctionInfoForBuiltin(
isolate()->factory()->empty_string(), Builtins::kIllegal);
shared->set_feedback_metadata(*metadata);
// Set the raw feedback metadata to circumvent checks that we are not
// overwriting existing metadata.
shared->set_raw_outer_scope_info_or_feedback_metadata(*metadata);
Handle<FeedbackVector> vector = FeedbackVector::New(isolate(), shared);
VectorSlotPair feedback(vector, FeedbackSlot(0));
return javascript()->Call(arity, CallFrequency(), feedback,

View File

@ -39,7 +39,9 @@ Handle<SharedFunctionInfo> CreateSharedFunctionInfo(
isolate->factory()->NewStringFromAsciiChecked("f"),
Builtins::kCompileLazy);
shared->set_raw_end_position(source->length());
shared->set_outer_scope_info(ScopeInfo::Empty(isolate));
// Make sure we have an outer scope info, even though it's empty
shared->set_raw_outer_scope_info_or_feedback_metadata(
ScopeInfo::Empty(isolate));
shared->set_function_literal_id(1);
SharedFunctionInfo::SetScript(shared, script);
return scope.CloseAndEscape(shared);