@@ -2022,18 +2022,39 @@ class ConstantPoolPointerForwarder {
20222022 }
20232023
20242024 void RecordScopeInfos (Tagged<MaybeObject> maybe_old_info) {
2025+ RecordScopeInfos (maybe_old_info.GetHeapObjectAssumeWeak ());
2026+ }
2027+
2028+ // Record all scope infos relevant for a shared function info or scope info
2029+ // (recorded for eval).
2030+ void RecordScopeInfos (Tagged<HeapObject> info) {
20252031 Tagged<ScopeInfo> scope_info;
2026- Tagged<HeapObject> info = maybe_old_info.GetHeapObjectAssumeWeak ();
20272032 if (Is<SharedFunctionInfo>(info)) {
20282033 Tagged<SharedFunctionInfo> old_sfi = Cast<SharedFunctionInfo>(info);
2029- if (!old_sfi->HasOuterScopeInfo ()) return ;
2030- scope_info = old_sfi->GetOuterScopeInfo ();
2034+ // Also record context-having own scope infos for SFIs.
2035+ if (!old_sfi->scope_info ()->IsEmpty () &&
2036+ old_sfi->scope_info ()->HasContext ()) {
2037+ scope_info = old_sfi->scope_info ();
2038+ } else if (old_sfi->HasOuterScopeInfo ()) {
2039+ scope_info = old_sfi->GetOuterScopeInfo ();
2040+ } else {
2041+ return ;
2042+ }
20312043 } else {
20322044 scope_info = Cast<ScopeInfo>(info);
20332045 }
2046+
20342047 while (true ) {
2035- if (scope_infos_to_update_.find (scope_info->UniqueIdInScript ()) !=
2036- scope_infos_to_update_.end ()) {
2048+ auto it = scope_infos_to_update_.find (scope_info->UniqueIdInScript ());
2049+ if (it != scope_infos_to_update_.end ()) {
2050+ // Once we find an already recorded scope info, it need to match the one
2051+ // on the chain.
2052+ if (V8_UNLIKELY (*it->second != scope_info)) {
2053+ info->Print ();
2054+ (*it->second )->Print ();
2055+ scope_info->Print ();
2056+ UNREACHABLE ();
2057+ }
20372058 return ;
20382059 }
20392060 scope_infos_to_update_[scope_info->UniqueIdInScript ()] =
@@ -2062,17 +2083,51 @@ class ConstantPoolPointerForwarder {
20622083 !scope_infos_to_update_.empty ();
20632084 }
20642085
2065- void UpdateOuterScopeInfo (Tagged<SharedFunctionInfo> sfi) {
2086+ // Find an own scope info for the sfi based on the UniqueIdInScript that the
2087+ // own scope info would have. This works even if the SFI doesn't yet have a
2088+ // scope info attached by computing UniqueIdInScript from the SFI position.
2089+ //
2090+ // This should only directly be used for SFIs that already existed on the
2091+ // script. Their outer scope info will already be correct.
2092+ bool InstallOwnScopeInfo (Tagged<SharedFunctionInfo> sfi) {
2093+ auto it = scope_infos_to_update_.find (sfi->UniqueIdInScript ());
2094+ if (it == scope_infos_to_update_.end ()) return false ;
2095+ sfi->SetScopeInfo (*it->second );
2096+ return true ;
2097+ }
2098+
2099+ // Either replace the own scope info of the sfi, or the first outer scope info
2100+ // that was recorded.
2101+ //
2102+ // This has to be used for all newly created SFIs since their outer scope info
2103+ // also may need to be reattached.
2104+ void UpdateScopeInfo (Tagged<SharedFunctionInfo> sfi) {
2105+ // This should not be called on already existing SFIs. Their scope infos are
2106+ // already correct.
2107+ DCHECK_NE (MakeWeak (sfi),
2108+ old_script_->infos ()->get (sfi->function_literal_id ()));
2109+ if (InstallOwnScopeInfo (sfi)) return ;
20662110 if (!sfi->HasOuterScopeInfo ()) return ;
2111+
2112+ Tagged<ScopeInfo> parent =
2113+ sfi->scope_info ()->IsEmpty () ? Tagged<ScopeInfo>() : sfi->scope_info ();
20672114 Tagged<ScopeInfo> outer_info = sfi->GetOuterScopeInfo ();
2115+
20682116 auto it = scope_infos_to_update_.find (outer_info->UniqueIdInScript ());
2069- if (it == scope_infos_to_update_.end ()) return ;
2117+ while (it == scope_infos_to_update_.end ()) {
2118+ if (!outer_info->HasOuterScopeInfo ()) return ;
2119+ parent = outer_info;
2120+ outer_info = outer_info->OuterScopeInfo ();
2121+ it = scope_infos_to_update_.find (outer_info->UniqueIdInScript ());
2122+ }
20702123 if (outer_info == *it->second ) return ;
2124+
20712125 VerifyScopeInfo (outer_info, *it->second );
2072- if (sfi->is_compiled ()) {
2073- sfi->scope_info ()->set_outer_scope_info (*it->second );
2074- } else {
2126+
2127+ if (parent.is_null ()) {
20752128 sfi->set_raw_outer_scope_info_or_feedback_metadata (*it->second );
2129+ } else {
2130+ parent->set_outer_scope_info (*it->second );
20762131 }
20772132 }
20782133
@@ -2254,6 +2309,16 @@ void BackgroundMergeTask::BeginMergeInBackground(
22542309 new_compiled_data_for_cached_sfis_.push_back (
22552310 {local_heap->NewPersistentHandle (old_sfi),
22562311 local_heap->NewPersistentHandle (new_sfi)});
2312+ // Pick up existing scope infos from the old sfi. The new sfi will be
2313+ // copied over the old sfi later. This will ensure that we'll keep
2314+ // using the old sfis. This will also allow us check later whether new
2315+ // scope infos have appeared that need to be reused.
2316+ if (!old_sfi->scope_info ()->IsEmpty ()) {
2317+ new_sfi->SetScopeInfo (old_sfi->scope_info ());
2318+ } else if (old_sfi->HasOuterScopeInfo ()) {
2319+ new_sfi->scope_info ()->set_outer_scope_info (
2320+ old_sfi->GetOuterScopeInfo ());
2321+ }
22572322 forwarder.AddBytecodeArray (new_sfi->GetBytecodeArray (isolate));
22582323 }
22592324 } else {
@@ -2278,13 +2343,23 @@ void BackgroundMergeTask::BeginMergeInBackground(
22782343
22792344 if (forwarder.HasAnythingToForward ()) {
22802345 for (DirectHandle<SharedFunctionInfo> new_sfi : used_new_sfis_) {
2281- forwarder.UpdateOuterScopeInfo (*new_sfi);
2346+ forwarder.UpdateScopeInfo (*new_sfi);
2347+ }
2348+ for (const auto & new_compiled_data : new_compiled_data_for_cached_sfis_) {
2349+ // It's possible that new_compiled_data.cached_sfi had
2350+ // scope_info()->IsEmpty() while an inner function has scope info if the
2351+ // cached_sfi was recreated when an outer function was recompiled. If so,
2352+ // new_compiled_data.new_sfi does not have a reused scope info yet, and
2353+ // we'll have found it when we visited the inner function. Try to pick it
2354+ // up here.
2355+ forwarder.InstallOwnScopeInfo (*new_compiled_data.new_sfi );
22822356 }
22832357 forwarder.IterateAndForwardPointers ();
22842358 }
22852359 persistent_handles_ = local_heap->DetachPersistentHandles ();
22862360 state_ = kPendingForegroundWork ;
22872361}
2362+
22882363Handle<SharedFunctionInfo> BackgroundMergeTask::CompleteMergeInForeground (
22892364 Isolate* isolate, DirectHandle<Script> new_script) {
22902365 DCHECK_EQ (state_, kPendingForegroundWork );
@@ -2295,8 +2370,8 @@ Handle<SharedFunctionInfo> BackgroundMergeTask::CompleteMergeInForeground(
22952370 isolate, isolate->main_thread_local_heap (), old_script);
22962371
22972372 for (const auto & new_compiled_data : new_compiled_data_for_cached_sfis_) {
2298- if (! new_compiled_data.cached_sfi -> is_compiled () &&
2299- new_compiled_data.new_sfi ->is_compiled ()) {
2373+ Tagged<SharedFunctionInfo> sfi = * new_compiled_data.cached_sfi ;
2374+ if (!sfi-> is_compiled () && new_compiled_data.new_sfi ->is_compiled ()) {
23002375 // Updating existing DebugInfos is not supported, but we don't expect
23012376 // uncompiled SharedFunctionInfos to contain DebugInfos.
23022377 DCHECK (!new_compiled_data.cached_sfi ->HasDebugInfo (isolate));
@@ -2306,8 +2381,7 @@ Handle<SharedFunctionInfo> BackgroundMergeTask::CompleteMergeInForeground(
23062381 // cached_sfi to new_sfi, and then copy every field using CopyFrom.
23072382 new_compiled_data.new_sfi ->set_script (
23082383 new_compiled_data.cached_sfi ->script (kAcquireLoad ), kReleaseStore );
2309- new_compiled_data.cached_sfi ->CopyFrom (*new_compiled_data.new_sfi ,
2310- isolate);
2384+ sfi->CopyFrom (*new_compiled_data.new_sfi , isolate);
23112385 }
23122386 }
23132387
@@ -2336,12 +2410,17 @@ Handle<SharedFunctionInfo> BackgroundMergeTask::CompleteMergeInForeground(
23362410 // pools is required.
23372411 if (forwarder.HasAnythingToForward ()) {
23382412 for (DirectHandle<SharedFunctionInfo> new_sfi : used_new_sfis_) {
2339- forwarder.UpdateOuterScopeInfo (*new_sfi);
2413+ forwarder.UpdateScopeInfo (*new_sfi);
23402414 if (new_sfi->HasBytecodeArray (isolate)) {
23412415 forwarder.AddBytecodeArray (new_sfi->GetBytecodeArray (isolate));
23422416 }
23432417 }
23442418 for (const auto & new_compiled_data : new_compiled_data_for_cached_sfis_) {
2419+ // It's possible that cached_sfi wasn't compiled, but an inner function
2420+ // existed that didn't exist when be background merged. In that case, pick
2421+ // up the relevant scope infos.
2422+ Tagged<SharedFunctionInfo> sfi = *new_compiled_data.cached_sfi ;
2423+ forwarder.InstallOwnScopeInfo (sfi);
23452424 if (new_compiled_data.cached_sfi ->HasBytecodeArray (isolate)) {
23462425 forwarder.AddBytecodeArray (
23472426 new_compiled_data.cached_sfi ->GetBytecodeArray (isolate));
@@ -2364,6 +2443,45 @@ Handle<SharedFunctionInfo> BackgroundMergeTask::CompleteMergeInForeground(
23642443 SharedFunctionInfo::EnsureSourcePositionsAvailable (isolate, result);
23652444 }
23662445
2446+ if (v8_flags.verify_code_merge ) {
2447+ // Check that there aren't any duplicate scope infos. Every scope/context
2448+ // should correspond to at most one scope info.
2449+ std::unordered_map<int , Tagged<ScopeInfo>> scope_infos;
2450+ for (int i = 0 ; i < old_script->infos ()->length (); i++) {
2451+ Tagged<ScopeInfo> scope_info;
2452+ if (!old_script->infos ()->get (i).IsWeak ()) continue ;
2453+ Tagged<HeapObject> info =
2454+ old_script->infos ()->get (i).GetHeapObjectAssumeWeak ();
2455+ if (Is<SharedFunctionInfo>(info)) {
2456+ Tagged<SharedFunctionInfo> old_sfi = Cast<SharedFunctionInfo>(info);
2457+ if (!old_sfi->scope_info ()->IsEmpty ()) {
2458+ scope_info = old_sfi->scope_info ();
2459+ } else if (old_sfi->HasOuterScopeInfo ()) {
2460+ scope_info = old_sfi->GetOuterScopeInfo ();
2461+ } else {
2462+ continue ;
2463+ }
2464+ } else {
2465+ scope_info = Cast<ScopeInfo>(info);
2466+ }
2467+ while (true ) {
2468+ auto it = scope_infos.find (scope_info->UniqueIdInScript ());
2469+ if (it != scope_infos.end ()) {
2470+ if (*it->second != scope_info) {
2471+ old_script->infos ()->get (i).GetHeapObjectAssumeWeak ()->Print ();
2472+ (*it->second )->Print ();
2473+ scope_info->Print ();
2474+ UNREACHABLE ();
2475+ }
2476+ break ;
2477+ }
2478+ scope_infos[scope_info->UniqueIdInScript ()] = scope_info;
2479+ if (!scope_info->HasOuterScopeInfo ()) break ;
2480+ scope_info = scope_info->OuterScopeInfo ();
2481+ }
2482+ }
2483+ }
2484+
23672485 return handle_scope.CloseAndEscape (result);
23682486}
23692487
0 commit comments