From 0f25e225504ffe31581b917c9d649fd9710a3c3f Mon Sep 17 00:00:00 2001 From: david <> Date: Tue, 2 Jul 2024 18:09:24 +0800 Subject: [PATCH] feat: delete some wtf --- bridge/CMakeLists.txt | 25 +- bridge/bindings/v8/base/check_op.h | 22 +- bridge/bindings/v8/base/feature_list.cc | 1014 -------- bridge/bindings/v8/base/feature_list.h | 666 ----- .../v8/base/feature_list_buildflags.h | 17 - bridge/bindings/v8/base/features.cc | 129 - bridge/bindings/v8/base/features.h | 55 - bridge/bindings/v8/base/location.h | 4 +- .../v8/base/metrics/field_trial_params.cc | 266 -- .../v8/base/metrics/field_trial_params.h | 354 --- .../bindings/v8/base/synchronization/lock.cc | 116 - .../bindings/v8/base/synchronization/lock.h | 145 -- .../v8/base/synchronization/lock_impl.h | 313 --- bridge/bindings/v8/gin/per_context_data.h | 4 +- .../bindings/v8/gin/public/isolate_holder.h | 2 +- .../heap/collection_support/heap_hash_map.h | 71 - .../heap_hash_table_backing.h | 369 --- .../collection_support/heap_vector_backing.h | 248 -- .../v8/platform/heap/heap_allocator_impl.h | 313 --- .../bindings/v8/platform/heap/trace_traits.h | 327 --- bridge/bindings/v8/platform/script_state.h | 1 + .../v8/platform/util/main_thread_util.cc | 2 - .../v8/platform/v8_per_context_data.cc | 106 +- .../v8/platform/v8_per_context_data.h | 56 +- .../v8/platform/v8_per_isolate_data.cc | 7 +- .../v8/platform/v8_per_isolate_data.h | 10 +- .../v8/platform/wtf/construct_traits.h | 5 +- bridge/bindings/v8/platform/wtf/hash_map.h | 580 ----- bridge/bindings/v8/platform/wtf/hash_table.cc | 6 - bridge/bindings/v8/platform/wtf/hash_table.h | 2289 ----------------- .../bindings/v8/platform/wtf/key_value_pair.h | 451 ---- .../v8/platform/wtf/thread_specific.h | 131 - bridge/bindings/v8/platform/wtf/threading.cc | 72 - bridge/bindings/v8/platform/wtf/threading.h | 84 - bridge/bindings/v8/script_value.h | 9 - bridge/bindings/v8/script_wrappable.cc | 6 - bridge/bindings/v8/script_wrappable.h | 189 -- bridge/bindings/v8/v8_initializer.cc | 18 +- bridge/bindings/v8/v8_interface_bridge_base.h | 3 +- bridge/bindings/v8/wrapper_type_info.h | 5 +- bridge/core/dart_isolate_context.cc | 16 +- bridge/foundation/native_value.h | 4 +- .../templates/idl_templates/v8/base.cc.tpl | 1 - bridge/webf_bridge.cc | 97 +- 44 files changed, 187 insertions(+), 8421 deletions(-) delete mode 100644 bridge/bindings/v8/base/feature_list.cc delete mode 100644 bridge/bindings/v8/base/feature_list.h delete mode 100644 bridge/bindings/v8/base/feature_list_buildflags.h delete mode 100644 bridge/bindings/v8/base/features.cc delete mode 100644 bridge/bindings/v8/base/features.h delete mode 100644 bridge/bindings/v8/base/metrics/field_trial_params.cc delete mode 100644 bridge/bindings/v8/base/metrics/field_trial_params.h delete mode 100644 bridge/bindings/v8/base/synchronization/lock.cc delete mode 100644 bridge/bindings/v8/base/synchronization/lock.h delete mode 100644 bridge/bindings/v8/base/synchronization/lock_impl.h delete mode 100644 bridge/bindings/v8/platform/heap/collection_support/heap_hash_map.h delete mode 100644 bridge/bindings/v8/platform/heap/collection_support/heap_hash_table_backing.h delete mode 100644 bridge/bindings/v8/platform/heap/collection_support/heap_vector_backing.h delete mode 100644 bridge/bindings/v8/platform/heap/heap_allocator_impl.h delete mode 100644 bridge/bindings/v8/platform/heap/trace_traits.h delete mode 100644 bridge/bindings/v8/platform/wtf/hash_map.h delete mode 100644 bridge/bindings/v8/platform/wtf/hash_table.cc delete mode 100644 bridge/bindings/v8/platform/wtf/hash_table.h delete mode 100644 bridge/bindings/v8/platform/wtf/key_value_pair.h delete mode 100644 bridge/bindings/v8/platform/wtf/thread_specific.h delete mode 100644 bridge/bindings/v8/platform/wtf/threading.cc delete mode 100644 bridge/bindings/v8/platform/wtf/threading.h delete mode 100644 bridge/bindings/v8/script_wrappable.cc delete mode 100644 bridge/bindings/v8/script_wrappable.h diff --git a/bridge/CMakeLists.txt b/bridge/CMakeLists.txt index aaddd641cb..b6055f3db2 100644 --- a/bridge/CMakeLists.txt +++ b/bridge/CMakeLists.txt @@ -430,8 +430,6 @@ elseif ($ENV{WEBF_JS_ENGINE} MATCHES "v8") bindings/v8/atomic_string.cc bindings/v8/native_string_utils.cc bindings/v8/script_value.cc -# bindings/v8/exception_state.cc - bindings/v8/script_wrappable.cc bindings/v8/wrapper_type_info.cc bindings/v8/v8_interface_bridge_base.cc bindings/v8/v8_initializer.cc @@ -445,12 +443,7 @@ elseif ($ENV{WEBF_JS_ENGINE} MATCHES "v8") bindings/v8/platform/heap/persistent.h bindings/v8/platform/heap/thread_state_storage.cc bindings/v8/platform/heap/write_barrier.h - bindings/v8/platform/heap/heap_allocator_impl.h - bindings/v8/platform/heap/trace_traits.h bindings/v8/platform/heap/custom_spaces.cc - bindings/v8/platform/heap/collection_support/heap_hash_map.h - bindings/v8/platform/heap/collection_support/heap_vector_backing.h - bindings/v8/platform/heap/collection_support/heap_hash_table_backing.h bindings/v8/platform/util/gc_plugin.h bindings/v8/platform/util/main_thread_util.cc bindings/v8/union_base.cc @@ -460,20 +453,15 @@ elseif ($ENV{WEBF_JS_ENGINE} MATCHES "v8") bindings/v8/for_build/build_config.h bindings/v8/for_build/buildflag.h bindings/v8/platform/platform_export.h - bindings/v8/platform/wtf/thread_specific.h bindings/v8/platform/wtf/dtoa.cc bindings/v8/platform/wtf/stack_util.cc bindings/v8/platform/wtf/atomic_operations.cc - bindings/v8/platform/wtf/threading.cc bindings/v8/platform/wtf/type_traits.cc bindings/v8/platform/wtf/vector_traits.cc bindings/v8/platform/wtf/hash_traits.h bindings/v8/platform/wtf/hash_functions.h bindings/v8/platform/wtf/hash_table_deleted_value_type.h - bindings/v8/platform/wtf/key_value_pair.h - bindings/v8/platform/wtf/hash_table.cc bindings/v8/platform/wtf/webf_size_t.h - bindings/v8/platform/wtf/hash_map.h bindings/v8/platform/wtf/conditional_destructor.h bindings/v8/platform/wtf/construct_traits.h bindings/v8/platform/wtf/sanitizers.h @@ -488,14 +476,11 @@ elseif ($ENV{WEBF_JS_ENGINE} MATCHES "v8") bindings/v8/base/containers/flat_set.h bindings/v8/base/containers/flat_tree.h bindings/v8/base/containers/util.h - bindings/v8/base/metrics/field_trial_params.cc bindings/v8/base/numerics/clamped_math.h bindings/v8/base/numerics/clamped_math_impl.h bindings/v8/base/ranges/algorithm.h bindings/v8/base/ranges/functional.h bindings/v8/base/ranges/ranges.h - bindings/v8/base/synchronization/lock.cc - bindings/v8/base/synchronization/lock_impl.h bindings/v8/base/time/time.cc bindings/v8/base/types/to_address.h bindings/v8/base/types/supports_ostream_operator.h @@ -506,9 +491,6 @@ elseif ($ENV{WEBF_JS_ENGINE} MATCHES "v8") bindings/v8/base/check.h bindings/v8/base/check_op.cc bindings/v8/base/dcheck_is_on.h - bindings/v8/base/feature_list.cc - bindings/v8/base/feature_list_buildflags.h - bindings/v8/base/features.cc bindings/v8/base/template_util.h bindings/v8/base/thread_annotations.h bindings/v8/base/location.cc @@ -520,7 +502,6 @@ elseif ($ENV{WEBF_JS_ENGINE} MATCHES "v8") bindings/v8/base/numerics/safe_math_shared_impl.h bindings/v8/base/numerics/safe_math_clang_gcc_impl.h bindings/v8/base/memory/raw_ptr.h - bindings/v8/base/memory/raw_ptr_exclusion.h bindings/v8/base/memory/scoped_refptr.h bindings/v8/base/memory/stack_allocated.h bindings/v8/base/compiler_specific.h @@ -554,14 +535,14 @@ endif() list(APPEND BRIDGE_SOURCE # Core sources -# webf_bridge.cc + webf_bridge.cc # core/api/api.cc # core/executing_context.cc # core/script_forbidden_scope.cc # core/script_state.cc # core/page.cc -# core/dart_methods.cc -# core/dart_isolate_context.cc + core/dart_methods.cc + core/dart_isolate_context.cc # core/dart_context_data.cc # core/executing_context_data.cc # core/fileapi/blob.cc diff --git a/bridge/bindings/v8/base/check_op.h b/bridge/bindings/v8/base/check_op.h index 31ffbd5388..1f175aa199 100644 --- a/bridge/bindings/v8/base/check_op.h +++ b/bridge/bindings/v8/base/check_op.h @@ -12,7 +12,7 @@ #include #include "bindings/v8/base/dcheck_is_on.h" -#include "bindings/v8/base/memory/raw_ptr_exclusion.h" +//#include "bindings/v8/base/memory/raw_ptr_exclusion.h" #include "bindings/v8/base/strings/to_string.h" #include "bindings/v8/base/types/supports_ostream_operator.h" #include "bindings/v8/base/check.h" @@ -150,21 +150,21 @@ char* CreateCheckOpLogMessageString(const char* expr_str, else \ check_failure_function(message_on_fail __VA_OPT__(, ) __VA_ARGS__) -#if !CHECK_WILL_STREAM() - -// Discard log strings to reduce code bloat. -#define CHECK_OP(name, op, val1, val2, ...) \ - BASE_IF(BASE_IS_EMPTY(__VA_ARGS__), CHECK((val1)op(val2)), \ - CHECK_OP_FUNCTION_IMPL(::logging::CheckError::CheckOp, name, op, \ - val1, val2, __VA_ARGS__)) - -#else +//#if !CHECK_WILL_STREAM() +// +//// Discard log strings to reduce code bloat. +//#define CHECK_OP(name, op, val1, val2, ...) \ +// BASE_IF(BASE_IS_EMPTY(__VA_ARGS__), CHECK((val1)op(val2)), \ +// CHECK_OP_FUNCTION_IMPL(::logging::CheckError::CheckOp, name, op, \ +// val1, val2, __VA_ARGS__)) +// +//#else #define CHECK_OP(name, op, val1, val2, ...) \ CHECK_OP_FUNCTION_IMPL(::logging::CheckError::CheckOp, name, op, val1, \ val2 __VA_OPT__(, ) __VA_ARGS__) -#endif +//#endif // The second overload avoids address-taking of static members for // fundamental types. diff --git a/bridge/bindings/v8/base/feature_list.cc b/bridge/bindings/v8/base/feature_list.cc deleted file mode 100644 index 76ab103fc4..0000000000 --- a/bridge/bindings/v8/base/feature_list.cc +++ /dev/null @@ -1,1014 +0,0 @@ -/* -* Copyright (C) 2019-2022 The Kraken authors. All rights reserved. -* Copyright (C) 2022-present The WebF authors. All rights reserved. -*/ - -#ifdef UNSAFE_BUFFERS_BUILD -// TODO(crbug.com/40284755): Remove this and spanify to fix the errors. -#pragma allow_unsafe_buffers -#endif - -#include "base/feature_list.h" - -#include - -#include -#include -#include - -#include "base/base_switches.h" -#include "base/containers/contains.h" -#include "base/containers/span.h" -#include "base/debug/crash_logging.h" -#include "base/debug/dump_without_crashing.h" -#include "base/logging.h" -#include "base/memory/ptr_util.h" -#include "base/memory/raw_ptr.h" -#include "base/metrics/field_trial.h" -#include "base/metrics/field_trial_param_associator.h" -#include "base/metrics/field_trial_params.h" -#include "base/metrics/persistent_memory_allocator.h" -#include "base/no_destructor.h" -#include "base/notreached.h" -#include "base/pickle.h" -#include "base/rand_util.h" -#include "base/strings/string_split.h" -#include "base/strings/string_util.h" -#include "base/strings/stringprintf.h" -#include "build/build_config.h" -#include "build/chromeos_buildflags.h" - -#if BUILDFLAG(IS_CHROMEOS_ASH) -#include "base/feature_visitor.h" -#endif // BUILDFLAG(IS_CHROMEOS_ASH) - -namespace base { - -namespace { - -// Pointer to the FeatureList instance singleton that was set via -// FeatureList::SetInstance(). Does not use base/memory/singleton.h in order to -// have more control over initialization timing. Leaky. -FeatureList* g_feature_list_instance = nullptr; - -// Tracks access to Feature state before FeatureList registration. -class EarlyFeatureAccessTracker { - public: - static EarlyFeatureAccessTracker* GetInstance() { - static NoDestructor instance; - return instance.get(); - } - - // Invoked when `feature` is accessed before FeatureList registration. - void AccessedFeature(const Feature& feature, - bool with_feature_allow_list = false) { - AutoLock lock(lock_); - if (fail_instantly_) { - Fail(&feature, with_feature_allow_list); - } else if (!feature_) { - feature_ = &feature; - feature_had_feature_allow_list_ = with_feature_allow_list; - } - } - - // Asserts that no feature was accessed before FeatureList registration. - void AssertNoAccess() { - AutoLock lock(lock_); - if (feature_) { - Fail(feature_, feature_had_feature_allow_list_); - } - } - - // Makes calls to AccessedFeature() fail instantly. - void FailOnFeatureAccessWithoutFeatureList() { - AutoLock lock(lock_); - if (feature_) { - Fail(feature_, feature_had_feature_allow_list_); - } - fail_instantly_ = true; - } - - // Resets the state of this tracker. - void Reset() { - AutoLock lock(lock_); - feature_ = nullptr; - fail_instantly_ = false; - } - - const Feature* GetFeature() { - AutoLock lock(lock_); - return feature_.get(); - } - - private: - void Fail(const Feature* feature, bool with_feature_allow_list) { - // TODO(crbug.com/40237050): Enable this check on all platforms. -#if !BUILDFLAG(IS_IOS) && !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_CHROMEOS) -#if !BUILDFLAG(IS_NACL) - // Create a crash key with the name of the feature accessed too early, to - // facilitate crash triage. - SCOPED_CRASH_KEY_STRING256("FeatureList", "feature-accessed-too-early", - feature->name); - SCOPED_CRASH_KEY_BOOL("FeatureList", "early-access-allow-list", - with_feature_allow_list); -#endif // !BUILDFLAG(IS_NACL) - CHECK(!feature) << "Accessed feature " << feature->name - << (with_feature_allow_list - ? " which is not on the allow list passed to " - "SetEarlyAccessInstance()." - : " before FeatureList registration."); -#endif // !BUILDFLAG(IS_IOS) && !BUILDFLAG(IS_ANDROID) && - // !BUILDFLAG(IS_CHROMEOS) - } - - friend class NoDestructor; - - EarlyFeatureAccessTracker() = default; - ~EarlyFeatureAccessTracker() = default; - - Lock lock_; - - // First feature to be accessed before FeatureList registration. - raw_ptr feature_ GUARDED_BY(lock_) = nullptr; - bool feature_had_feature_allow_list_ GUARDED_BY(lock_) = false; - - // Whether AccessedFeature() should fail instantly. - bool fail_instantly_ GUARDED_BY(lock_) = false; -}; - -#if DCHECK_IS_ON() -const char* g_reason_overrides_disallowed = nullptr; - -void DCheckOverridesAllowed() { - const bool feature_overrides_allowed = !g_reason_overrides_disallowed; - DCHECK(feature_overrides_allowed) << g_reason_overrides_disallowed; -} -#else -void DCheckOverridesAllowed() {} -#endif - -// An allocator entry for a feature in shared memory. The FeatureEntry is -// followed by a base::Pickle object that contains the feature and trial name. -struct FeatureEntry { - // SHA1(FeatureEntry): Increment this if structure changes! - static constexpr uint32_t kPersistentTypeId = 0x06567CA6 + 2; - - // Expected size for 32/64-bit check. - static constexpr size_t kExpectedInstanceSize = 16; - - // Specifies whether a feature override enables or disables the feature. Same - // values as the OverrideState enum in feature_list.h - uint32_t override_state; - - // On e.g. x86, alignof(uint64_t) is 4. Ensure consistent size and alignment - // of `pickle_size` across platforms. - uint32_t padding; - - // Size of the pickled structure, NOT the total size of this entry. - uint64_t pickle_size; - - // Return a pointer to the pickled data area immediately following the entry. - uint8_t* GetPickledDataPtr() { return reinterpret_cast(this + 1); } - const uint8_t* GetPickledDataPtr() const { - return reinterpret_cast(this + 1); - } - - // Reads the feature and trial name from the pickle. Calling this is only - // valid on an initialized entry that's in shared memory. - bool GetFeatureAndTrialName(std::string_view* feature_name, - std::string_view* trial_name) const { - Pickle pickle = Pickle::WithUnownedBuffer( - span(GetPickledDataPtr(), checked_cast(pickle_size))); - PickleIterator pickle_iter(pickle); - if (!pickle_iter.ReadStringPiece(feature_name)) { - return false; - } - // Return true because we are not guaranteed to have a trial name anyways. - std::ignore = pickle_iter.ReadStringPiece(trial_name); - return true; - } -}; - -// Splits |text| into two parts by the |separator| where the first part will be -// returned updated in |first| and the second part will be returned as |second|. -// This function returns false if there is more than one |separator| in |first|. -// If there is no |separator| presented in |first|, this function will not -// modify |first| and |second|. It's used for splitting the |enable_features| -// flag into feature name, field trial name and feature parameters. -bool SplitIntoTwo(std::string_view text, - std::string_view separator, - std::string_view* first, - std::string* second) { - std::vector parts = - SplitStringPiece(text, separator, TRIM_WHITESPACE, SPLIT_WANT_ALL); - if (parts.size() == 2) { - *second = std::string(parts[1]); - } else if (parts.size() > 2) { - DLOG(ERROR) << "Only one '" << separator - << "' is allowed but got: " << text; - return false; - } - *first = parts[0]; - return true; -} - -// Checks and parses the |enable_features| flag and sets -// |parsed_enable_features| to be a comma-separated list of features, -// |force_fieldtrials| to be a comma-separated list of field trials that each -// feature want to associate with and |force_fieldtrial_params| to be the field -// trial parameters for each field trial. -// Returns true if |enable_features| is parsable, otherwise false. -bool ParseEnableFeatures(const std::string& enable_features, - std::string* parsed_enable_features, - std::string* force_fieldtrials, - std::string* force_fieldtrial_params) { - std::vector enable_features_list; - std::vector force_fieldtrials_list; - std::vector force_fieldtrial_params_list; - for (const auto& enable_feature : - FeatureList::SplitFeatureListString(enable_features)) { - std::string feature_name; - std::string study; - std::string group; - std::string feature_params; - if (!FeatureList::ParseEnableFeatureString( - enable_feature, &feature_name, &study, &group, &feature_params)) { - return false; - } - - // If feature params were set but group and study weren't, associate the - // feature and its feature params to a synthetic field trial as the - // feature params only make sense when it's combined with a field trial. - if (!feature_params.empty()) { - force_fieldtrials_list.push_back(study + "/" + group); - force_fieldtrial_params_list.push_back(study + "." + group + ":" + - feature_params); - } - enable_features_list.push_back( - study.empty() ? feature_name : (feature_name + "<" + study)); - } - - *parsed_enable_features = JoinString(enable_features_list, ","); - // Field trial separator is currently a slash. See - // |kPersistentStringSeparator| in base/metrics/field_trial.cc. - *force_fieldtrials = JoinString(force_fieldtrials_list, "/"); - *force_fieldtrial_params = JoinString(force_fieldtrial_params_list, ","); - return true; -} - -std::pair UnpackFeatureCache( - uint32_t packed_cache_value) { - return std::make_pair( - static_cast(packed_cache_value >> 24), - packed_cache_value & 0xFFFF); -} - -uint32_t PackFeatureCache(FeatureList::OverrideState override_state, - uint32_t caching_context) { - return (static_cast(override_state) << 24) | - (caching_context & 0xFFFF); -} - -// A monotonically increasing id, passed to `FeatureList`s as they are created -// to invalidate the cache member of `base::Feature` objects that were queried -// with a different `FeatureList` installed. -uint16_t g_current_caching_context = 1; - -} // namespace - -#if BUILDFLAG(DCHECK_IS_CONFIGURABLE) -BASE_FEATURE(kDCheckIsFatalFeature, - "DcheckIsFatal", - FEATURE_DISABLED_BY_DEFAULT); -#endif // BUILDFLAG(DCHECK_IS_CONFIGURABLE) - -FeatureList::FeatureList() : caching_context_(g_current_caching_context++) {} - -FeatureList::~FeatureList() = default; - -FeatureList::ScopedDisallowOverrides::ScopedDisallowOverrides( - const char* reason) -#if DCHECK_IS_ON() - : previous_reason_(g_reason_overrides_disallowed) { - g_reason_overrides_disallowed = reason; -} -#else -{ -} -#endif - -FeatureList::ScopedDisallowOverrides::~ScopedDisallowOverrides() { -#if DCHECK_IS_ON() - g_reason_overrides_disallowed = previous_reason_; -#endif -} - -void FeatureList::InitFromCommandLine(const std::string& enable_features, - const std::string& disable_features) { - DCHECK(!initialized_); - - std::string parsed_enable_features; - std::string force_fieldtrials; - std::string force_fieldtrial_params; - bool parse_enable_features_result = - ParseEnableFeatures(enable_features, &parsed_enable_features, - &force_fieldtrials, &force_fieldtrial_params); - DCHECK(parse_enable_features_result) << StringPrintf( - "The --%s list is unparsable or invalid, please check the format.", - ::switches::kEnableFeatures); - - // Only create field trials when field_trial_list is available. Some tests - // don't have field trial list available. - if (FieldTrialList::GetInstance()) { - bool associate_params_result = AssociateFieldTrialParamsFromString( - force_fieldtrial_params, &UnescapeValue); - DCHECK(associate_params_result) << StringPrintf( - "The field trial parameters part of the --%s list is invalid. Make " - "sure " - "you %%-encode the following characters in param values: %%:/.,", - ::switches::kEnableFeatures); - - bool create_trials_result = - FieldTrialList::CreateTrialsFromString(force_fieldtrials); - DCHECK(create_trials_result) - << StringPrintf("Invalid field trials are specified in --%s.", - ::switches::kEnableFeatures); - } - - // Process disabled features first, so that disabled ones take precedence over - // enabled ones (since RegisterOverride() uses insert()). - RegisterOverridesFromCommandLine(disable_features, OVERRIDE_DISABLE_FEATURE); - RegisterOverridesFromCommandLine(parsed_enable_features, - OVERRIDE_ENABLE_FEATURE); - - initialized_from_command_line_ = true; -} - -void FeatureList::InitFromSharedMemory(PersistentMemoryAllocator* allocator) { - DCHECK(!initialized_); - - PersistentMemoryAllocator::Iterator iter(allocator); - const FeatureEntry* entry; - while ((entry = iter.GetNextOfObject()) != nullptr) { - OverrideState override_state = - static_cast(entry->override_state); - - std::string_view feature_name; - std::string_view trial_name; - if (!entry->GetFeatureAndTrialName(&feature_name, &trial_name)) - continue; - - FieldTrial* trial = FieldTrialList::Find(trial_name); - RegisterOverride(feature_name, override_state, trial); - } -} - -bool FeatureList::IsFeatureOverridden(const std::string& feature_name) const { - return GetOverrideEntryByFeatureName(feature_name); -} - -bool FeatureList::IsFeatureOverriddenFromCommandLine( - const std::string& feature_name) const { - const OverrideEntry* entry = GetOverrideEntryByFeatureName(feature_name); - return entry && !entry->overridden_by_field_trial; -} - -bool FeatureList::IsFeatureOverriddenFromCommandLine( - const std::string& feature_name, - OverrideState state) const { - const OverrideEntry* entry = GetOverrideEntryByFeatureName(feature_name); - return entry && !entry->overridden_by_field_trial && - entry->overridden_state == state; -} - -void FeatureList::AssociateReportingFieldTrial( - const std::string& feature_name, - OverrideState for_overridden_state, - FieldTrial* field_trial) { - DCHECK( - IsFeatureOverriddenFromCommandLine(feature_name, for_overridden_state)); - - // Only one associated field trial is supported per feature. This is generally - // enforced server-side. - OverrideEntry* entry = &overrides_.find(feature_name)->second; - if (entry->field_trial) { - NOTREACHED_IN_MIGRATION() - << "Feature " << feature_name - << " already has trial: " << entry->field_trial->trial_name() - << ", associating trial: " << field_trial->trial_name(); - return; - } - - entry->field_trial = field_trial; -} - -void FeatureList::RegisterFieldTrialOverride(const std::string& feature_name, - OverrideState override_state, - FieldTrial* field_trial) { - DCHECK(field_trial); - DCHECK(!HasAssociatedFieldTrialByFeatureName(feature_name)) - << "Feature " << feature_name << " is overriden multiple times in these " - << "trials: " - << overrides_.find(feature_name)->second.field_trial->trial_name() - << " and " << field_trial->trial_name() << ". " - << "Check the trial (study) in (1) the server config, " - << "(2) fieldtrial_testing_config.json, (3) about_flags.cc, and " - << "(4) client-side field trials."; - - RegisterOverride(feature_name, override_state, field_trial); -} - -void FeatureList::RegisterExtraFeatureOverrides( - const std::vector& extra_overrides) { - for (const FeatureOverrideInfo& override_info : extra_overrides) { - RegisterOverride(override_info.first.get().name, override_info.second, - /* field_trial = */ nullptr); - } -} - -void FeatureList::AddFeaturesToAllocator(PersistentMemoryAllocator* allocator) { - DCHECK(initialized_); - - for (const auto& override : overrides_) { - Pickle pickle; - pickle.WriteString(override.first); - if (override.second.field_trial) - pickle.WriteString(override.second.field_trial->trial_name()); - - size_t total_size = sizeof(FeatureEntry) + pickle.size(); - FeatureEntry* entry = allocator->New(total_size); - if (!entry) - return; - - entry->override_state = override.second.overridden_state; - entry->pickle_size = pickle.size(); - memcpy(entry->GetPickledDataPtr(), pickle.data(), pickle.size()); - - allocator->MakeIterable(entry); - } -} - -void FeatureList::GetFeatureOverrides(std::string* enable_overrides, - std::string* disable_overrides, - bool include_group_name) const { - GetFeatureOverridesImpl(enable_overrides, disable_overrides, false, - include_group_name); -} - -void FeatureList::GetCommandLineFeatureOverrides( - std::string* enable_overrides, - std::string* disable_overrides) const { - GetFeatureOverridesImpl(enable_overrides, disable_overrides, true); -} - -// static -bool FeatureList::IsEnabled(const Feature& feature) { - if (!g_feature_list_instance || - !g_feature_list_instance->AllowFeatureAccess(feature)) { - EarlyFeatureAccessTracker::GetInstance()->AccessedFeature( - feature, g_feature_list_instance && - g_feature_list_instance->IsEarlyAccessInstance()); - return feature.default_state == FEATURE_ENABLED_BY_DEFAULT; - } - return g_feature_list_instance->IsFeatureEnabled(feature); -} - -// static -bool FeatureList::IsValidFeatureOrFieldTrialName(std::string_view name) { - return IsStringASCII(name) && name.find_first_of(",<*") == std::string::npos; -} - -// static -std::optional FeatureList::GetStateIfOverridden(const Feature& feature) { - if (!g_feature_list_instance || - !g_feature_list_instance->AllowFeatureAccess(feature)) { - EarlyFeatureAccessTracker::GetInstance()->AccessedFeature( - feature, g_feature_list_instance && - g_feature_list_instance->IsEarlyAccessInstance()); - // If there is no feature list, there can be no overrides. - return std::nullopt; - } - return g_feature_list_instance->IsFeatureEnabledIfOverridden(feature); -} - -// static -FieldTrial* FeatureList::GetFieldTrial(const Feature& feature) { - if (!g_feature_list_instance || - !g_feature_list_instance->AllowFeatureAccess(feature)) { - EarlyFeatureAccessTracker::GetInstance()->AccessedFeature( - feature, g_feature_list_instance && - g_feature_list_instance->IsEarlyAccessInstance()); - return nullptr; - } - return g_feature_list_instance->GetAssociatedFieldTrial(feature); -} - -// static -std::vector FeatureList::SplitFeatureListString( - std::string_view input) { - return SplitStringPiece(input, ",", TRIM_WHITESPACE, SPLIT_WANT_NONEMPTY); -} - -// static -bool FeatureList::ParseEnableFeatureString(std::string_view enable_feature, - std::string* feature_name, - std::string* study_name, - std::string* group_name, - std::string* params) { - std::string_view first; - // First, check whether ":" is present. If true, feature parameters were - // set for this feature. - std::string feature_params; - if (!SplitIntoTwo(enable_feature, ":", &first, &feature_params)) - return false; - // Then, check whether "." is present. If true, a group was specified for - // this feature. - std::string group; - if (!SplitIntoTwo(first, ".", &first, &group)) - return false; - // Finally, check whether "<" is present. If true, a study was specified for - // this feature. - std::string study; - if (!SplitIntoTwo(first, "<", &first, &study)) - return false; - - std::string enable_feature_name(first); - // If feature params were set but group and study weren't, associate the - // feature and its feature params to a synthetic field trial as the - // feature params only make sense when it's combined with a field trial. - if (!feature_params.empty()) { - study = study.empty() ? "Study" + enable_feature_name : study; - group = group.empty() ? "Group" + enable_feature_name : group; - } - - feature_name->swap(enable_feature_name); - study_name->swap(study); - group_name->swap(group); - params->swap(feature_params); - return true; -} - -// static -bool FeatureList::InitInstance(const std::string& enable_features, - const std::string& disable_features) { - return InitInstance(enable_features, disable_features, - std::vector()); -} - -// static -bool FeatureList::InitInstance( - const std::string& enable_features, - const std::string& disable_features, - const std::vector& extra_overrides) { - // We want to initialize a new instance here to support command-line features - // in testing better. For example, we initialize a dummy instance in - // base/test/test_suite.cc, and override it in content/browser/ - // browser_main_loop.cc. - // On the other hand, we want to avoid re-initialization from command line. - // For example, we initialize an instance in chrome/browser/ - // chrome_browser_main.cc and do not override it in content/browser/ - // browser_main_loop.cc. - // If the singleton was previously initialized from within an accessor, we - // want to prevent callers from reinitializing the singleton and masking the - // accessor call(s) which likely returned incorrect information. - EarlyFeatureAccessTracker::GetInstance()->AssertNoAccess(); - bool instance_existed_before = false; - if (g_feature_list_instance) { - if (g_feature_list_instance->initialized_from_command_line_) - return false; - - delete g_feature_list_instance; - g_feature_list_instance = nullptr; - instance_existed_before = true; - } - - std::unique_ptr feature_list(new FeatureList); - feature_list->InitFromCommandLine(enable_features, disable_features); - feature_list->RegisterExtraFeatureOverrides(extra_overrides); - FeatureList::SetInstance(std::move(feature_list)); - return !instance_existed_before; -} - -// static -FeatureList* FeatureList::GetInstance() { - return g_feature_list_instance; -} - -// static -void FeatureList::SetInstance(std::unique_ptr instance) { - DCHECK(!g_feature_list_instance || - g_feature_list_instance->IsEarlyAccessInstance()); - // If there is an existing early-access instance, release it. - if (g_feature_list_instance) { - std::unique_ptr old_instance = - WrapUnique(g_feature_list_instance); - g_feature_list_instance = nullptr; - } - instance->FinalizeInitialization(); - - // Note: Intentional leak of global singleton. - g_feature_list_instance = instance.release(); - - EarlyFeatureAccessTracker::GetInstance()->AssertNoAccess(); - - // Don't configure random bytes field trials for a possibly early access - // FeatureList instance, as the state of the involved Features might change - // with the final FeatureList for this process. - if (!g_feature_list_instance->IsEarlyAccessInstance()) { -#if !BUILDFLAG(IS_NACL) - // Configured first because it takes precedence over the getrandom() trial. - internal::ConfigureBoringSSLBackedRandBytesFieldTrial(); -#endif - -#if BUILDFLAG(IS_ANDROID) - internal::ConfigureRandBytesFieldTrial(); -#endif - } - -#if BUILDFLAG(DCHECK_IS_CONFIGURABLE) - // Update the behaviour of LOGGING_DCHECK to match the Feature configuration. - // DCHECK is also forced to be FATAL if we are running a death-test. - // TODO(crbug.com/1057995#c11): --gtest_internal_run_death_test doesn't - // currently run through this codepath, mitigated in - // base::TestSuite::Initialize() for now. - // TODO(asvitkine): If we find other use-cases that need integrating here - // then define a proper API/hook for the purpose. - if (FeatureList::IsEnabled(kDCheckIsFatalFeature) || - CommandLine::ForCurrentProcess()->HasSwitch( - "gtest_internal_run_death_test")) { - logging::LOGGING_DCHECK = logging::LOGGING_FATAL; - } else { - logging::LOGGING_DCHECK = logging::LOGGING_ERROR; - } -#endif // BUILDFLAG(DCHECK_IS_CONFIGURABLE) -} - -// static -void FeatureList::SetEarlyAccessInstance( - std::unique_ptr instance, - base::flat_set allowed_feature_names) { - CHECK(!g_feature_list_instance); - CHECK(!allowed_feature_names.empty()); - instance->allowed_feature_names_ = std::move(allowed_feature_names); - SetInstance(std::move(instance)); -} - -// static -std::unique_ptr FeatureList::ClearInstanceForTesting() { - FeatureList* old_instance = g_feature_list_instance; - g_feature_list_instance = nullptr; - EarlyFeatureAccessTracker::GetInstance()->Reset(); - return WrapUnique(old_instance); -} - -// static -void FeatureList::RestoreInstanceForTesting( - std::unique_ptr instance) { - DCHECK(!g_feature_list_instance); - // Note: Intentional leak of global singleton. - g_feature_list_instance = instance.release(); -} - -// static -void FeatureList::FailOnFeatureAccessWithoutFeatureList() { - EarlyFeatureAccessTracker::GetInstance() - ->FailOnFeatureAccessWithoutFeatureList(); -} - -// static -const Feature* FeatureList::GetEarlyAccessedFeatureForTesting() { - return EarlyFeatureAccessTracker::GetInstance()->GetFeature(); -} - -// static -void FeatureList::ResetEarlyFeatureAccessTrackerForTesting() { - EarlyFeatureAccessTracker::GetInstance()->Reset(); -} - -void FeatureList::AddEarlyAllowedFeatureForTesting(std::string feature_name) { - CHECK(IsEarlyAccessInstance()); - allowed_feature_names_.insert(std::move(feature_name)); -} - -#if BUILDFLAG(IS_CHROMEOS_ASH) -// static -void FeatureList::VisitFeaturesAndParams(FeatureVisitor& visitor) { - CHECK(g_feature_list_instance); - FieldTrialParamAssociator* params_associator = - FieldTrialParamAssociator::GetInstance(); - - for (auto& feature_override : g_feature_list_instance->overrides_) { - FieldTrial* field_trial = feature_override.second.field_trial; - - std::string trial_name; - std::string group_name; - FieldTrialParams params; - if (field_trial) { - trial_name = field_trial->trial_name(); - group_name = field_trial->group_name(); - params_associator->GetFieldTrialParamsWithoutFallback( - trial_name, group_name, ¶ms); - } - - visitor.Visit(feature_override.first, - feature_override.second.overridden_state, params, trial_name, - group_name); - } -} -#endif // BULDFLAG(IS_CHROMEOS_ASH) - -void FeatureList::FinalizeInitialization() { - DCHECK(!initialized_); - // Store the field trial list pointer for DCHECKing. - field_trial_list_ = FieldTrialList::GetInstance(); - initialized_ = true; -} - -bool FeatureList::IsFeatureEnabled(const Feature& feature) const { - OverrideState overridden_state = GetOverrideState(feature); - - // If marked as OVERRIDE_USE_DEFAULT, simply return the default state below. - if (overridden_state != OVERRIDE_USE_DEFAULT) - return overridden_state == OVERRIDE_ENABLE_FEATURE; - - return feature.default_state == FEATURE_ENABLED_BY_DEFAULT; -} - -std::optional FeatureList::IsFeatureEnabledIfOverridden( - const Feature& feature) const { - OverrideState overridden_state = GetOverrideState(feature); - - // If marked as OVERRIDE_USE_DEFAULT, fall through to returning empty. - if (overridden_state != OVERRIDE_USE_DEFAULT) - return overridden_state == OVERRIDE_ENABLE_FEATURE; - - return std::nullopt; -} - -FeatureList::OverrideState FeatureList::GetOverrideState( - const Feature& feature) const { - DCHECK(initialized_); - DCHECK(IsValidFeatureOrFieldTrialName(feature.name)) << feature.name; - DCHECK(CheckFeatureIdentity(feature)) - << feature.name - << " has multiple definitions. Either it is defined more than once in " - "code or (for component builds) the code is built into multiple " - "components (shared libraries) without a corresponding export " - "statement"; - - uint32_t current_cache_value = - feature.cached_value.load(std::memory_order_relaxed); - - auto unpacked = UnpackFeatureCache(current_cache_value); - - if (unpacked.second == caching_context_) - return unpacked.first; - - OverrideState state = GetOverrideStateByFeatureName(feature.name); - uint32_t new_cache_value = PackFeatureCache(state, caching_context_); - - // Update the cache with the new value. - // In non-test code, this value can be in one of 2 states: either it's unset, - // or another thread has updated it to the same value we're about to write. - // Because of this, a plain `store` yields the correct result in all cases. - // In test code, it's possible for a different thread to have installed a new - // `ScopedFeatureList` and written a value that's different than the one we're - // about to write, although that would be a thread safety violation already - // and such tests should be fixed. - feature.cached_value.store(new_cache_value, std::memory_order_relaxed); - - return state; -} - -FeatureList::OverrideState FeatureList::GetOverrideStateByFeatureName( - std::string_view feature_name) const { - DCHECK(initialized_); - DCHECK(IsValidFeatureOrFieldTrialName(feature_name)) << feature_name; - - if (const OverrideEntry* entry = - GetOverrideEntryByFeatureName(feature_name)) { - // Activate the corresponding field trial, if necessary. - if (entry->field_trial) { - entry->field_trial->Activate(); - } - - // TODO(asvitkine) Expand this section as more support is added. - - return entry->overridden_state; - } - // Otherwise, report that we want to use the default state. - return OVERRIDE_USE_DEFAULT; -} - -FieldTrial* FeatureList::GetAssociatedFieldTrial(const Feature& feature) const { - DCHECK(initialized_); - DCHECK(CheckFeatureIdentity(feature)) << feature.name; - - return GetAssociatedFieldTrialByFeatureName(feature.name); -} - -const base::FeatureList::OverrideEntry* -FeatureList::GetOverrideEntryByFeatureName(std::string_view name) const { - DCHECK(IsValidFeatureOrFieldTrialName(name)) << name; - - auto it = overrides_.find(name); - if (it != overrides_.end()) { - const OverrideEntry& entry = it->second; - return &entry; - } - return nullptr; -} - -FieldTrial* FeatureList::GetAssociatedFieldTrialByFeatureName( - std::string_view name) const { - DCHECK(initialized_); - - if (const OverrideEntry* entry = GetOverrideEntryByFeatureName(name)) { - return entry->field_trial; - } - return nullptr; -} - -bool FeatureList::HasAssociatedFieldTrialByFeatureName( - std::string_view name) const { - DCHECK(!initialized_); - - const OverrideEntry* entry = GetOverrideEntryByFeatureName(name); - return entry && entry->field_trial; -} - -FieldTrial* FeatureList::GetEnabledFieldTrialByFeatureName( - std::string_view name) const { - DCHECK(initialized_); - - const base::FeatureList::OverrideEntry* entry = - GetOverrideEntryByFeatureName(name); - if (entry && - entry->overridden_state == base::FeatureList::OVERRIDE_ENABLE_FEATURE) { - return entry->field_trial; - } - return nullptr; -} - -std::unique_ptr FeatureList::ConstructAccessor() { - if (initialized_) { - // This function shouldn't be called after initialization. - NOTREACHED_IN_MIGRATION(); - return nullptr; - } - // Use new and WrapUnique because we want to restrict access to the Accessor's - // constructor. - return base::WrapUnique(new Accessor(this)); -} - -void FeatureList::RegisterOverridesFromCommandLine( - const std::string& feature_list, - OverrideState overridden_state) { - for (const auto& value : SplitFeatureListString(feature_list)) { - std::string_view feature_name = value; - FieldTrial* trial = nullptr; - - // The entry may be of the form FeatureNametrial_name())) - << field_trial->trial_name(); - } - if (StartsWith(feature_name, "*")) { - feature_name = feature_name.substr(1); - overridden_state = OVERRIDE_USE_DEFAULT; - } - - // Note: The semantics of emplace() is that it does not overwrite the entry if - // one already exists for the key. Thus, only the first override for a given - // feature name takes effect. - overrides_.emplace(std::string(feature_name), - OverrideEntry(overridden_state, field_trial)); -} - -void FeatureList::GetFeatureOverridesImpl(std::string* enable_overrides, - std::string* disable_overrides, - bool command_line_only, - bool include_group_name) const { - DCHECK(initialized_); - - // Check that the FieldTrialList this is associated with, if any, is the - // active one. If not, it likely indicates that this FeatureList has override - // entries from a freed FieldTrial, which may be caused by an incorrect test - // set up. - if (field_trial_list_) - DCHECK_EQ(field_trial_list_, FieldTrialList::GetInstance()); - - enable_overrides->clear(); - disable_overrides->clear(); - - // Note: Since |overrides_| is a std::map, iteration will be in alphabetical - // order. This is not guaranteed to users of this function, but is useful for - // tests to assume the order. - for (const auto& entry : overrides_) { - if (command_line_only && - (entry.second.field_trial != nullptr || - entry.second.overridden_state == OVERRIDE_USE_DEFAULT)) { - continue; - } - - std::string* target_list = nullptr; - switch (entry.second.overridden_state) { - case OVERRIDE_USE_DEFAULT: - case OVERRIDE_ENABLE_FEATURE: - target_list = enable_overrides; - break; - case OVERRIDE_DISABLE_FEATURE: - target_list = disable_overrides; - break; - } - - if (!target_list->empty()) - target_list->push_back(','); - if (entry.second.overridden_state == OVERRIDE_USE_DEFAULT) - target_list->push_back('*'); - target_list->append(entry.first); - if (entry.second.field_trial) { - auto* const field_trial = entry.second.field_trial.get(); - target_list->push_back('<'); - target_list->append(field_trial->trial_name()); - if (include_group_name) { - target_list->push_back('.'); - target_list->append(field_trial->GetGroupNameWithoutActivation()); - } - } - } -} - -bool FeatureList::CheckFeatureIdentity(const Feature& feature) const { - AutoLock auto_lock(feature_identity_tracker_lock_); - - auto it = feature_identity_tracker_.find(feature.name); - if (it == feature_identity_tracker_.end()) { - // If it's not tracked yet, register it. - feature_identity_tracker_[feature.name] = &feature; - return true; - } - // Compare address of |feature| to the existing tracked entry. - return it->second == &feature; -} - -bool FeatureList::IsEarlyAccessInstance() const { - return !allowed_feature_names_.empty(); -} - -bool FeatureList::AllowFeatureAccess(const Feature& feature) const { - DCHECK(initialized_); - // If this isn't an instance set with SetEarlyAccessInstance all features are - // allowed to be checked. - if (!IsEarlyAccessInstance()) { - return true; - } - return base::Contains(allowed_feature_names_, feature.name); -} - -FeatureList::OverrideEntry::OverrideEntry(OverrideState overridden_state, - FieldTrial* field_trial) - : overridden_state(overridden_state), - field_trial(field_trial), - overridden_by_field_trial(field_trial != nullptr) {} - -FeatureList::Accessor::Accessor(FeatureList* feature_list) - : feature_list_(feature_list) {} - -FeatureList::OverrideState FeatureList::Accessor::GetOverrideStateByFeatureName( - std::string_view feature_name) { - return feature_list_->GetOverrideStateByFeatureName(feature_name); -} - -bool FeatureList::Accessor::GetParamsByFeatureName( - std::string_view feature_name, - std::map* params) { - base::FieldTrial* trial = - feature_list_->GetAssociatedFieldTrialByFeatureName(feature_name); - return FieldTrialParamAssociator::GetInstance()->GetFieldTrialParams(trial, - params); -} - -} // namespace base - diff --git a/bridge/bindings/v8/base/feature_list.h b/bridge/bindings/v8/base/feature_list.h deleted file mode 100644 index 045a6a45bc..0000000000 --- a/bridge/bindings/v8/base/feature_list.h +++ /dev/null @@ -1,666 +0,0 @@ -/* -* Copyright (C) 2019-2022 The Kraken authors. All rights reserved. -* Copyright (C) 2022-present The WebF authors. All rights reserved. -*/ - -#ifndef BASE_FEATURE_LIST_H_ -#define BASE_FEATURE_LIST_H_ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "bindings/v8/base/base_export.h" -#include "bindings/v8/base/compiler_specific.h" -#include "bindings/v8/base/containers/flat_map.h" -#include "bindings/v8/base/containers/flat_set.h" -#include "bindings/v8/base/dcheck_is_on.h" -#include "bindings/v8/base/feature_list_buildflags.h" -//#include "bindings/v8/base/logging.h" -#include "bindings/v8/base/memory/raw_ptr.h" -#include "bindings/v8/base/synchronization/lock.h" -#include "bindings/v8/for_build/build_config.h" - -namespace base { - -class FieldTrial; -class FieldTrialList; -class PersistentMemoryAllocator; - -// Specifies whether a given feature is enabled or disabled by default. -// NOTE: The actual runtime state may be different, due to a field trial or a -// command line switch. -enum FeatureState { - FEATURE_DISABLED_BY_DEFAULT, - FEATURE_ENABLED_BY_DEFAULT, -}; - -// Recommended macros for declaring and defining features: -// -// - `kFeature` is the C++ identifier that will be used for the `base::Feature`. -// - `name` is the feature name, which must be globally unique. This name is -// used to enable/disable features via experiments and command-line flags. -// Names should use CamelCase-style naming, e.g. "MyGreatFeature". -// - `default_state` is the default state to use for the feature, i.e. -// `base::FEATURE_DISABLED_BY_DEFAULT` or `base::FEATURE_ENABLED_BY_DEFAULT`. -// As noted above, the actual runtime state may differ from the default state, -// due to field trials or command-line switches. - -// Provides a forward declaration for `kFeature` in a header file, e.g. -// -// BASE_DECLARE_FEATURE(kMyFeature); -// -// If the feature needs to be marked as exported, i.e. it is referenced by -// multiple components, then write: -// -// COMPONENT_EXPORT(MY_COMPONENT) BASE_DECLARE_FEATURE(kMyFeature); -#define BASE_DECLARE_FEATURE(kFeature) \ - extern constinit const base::Feature kFeature - -// Provides a definition for `kFeature` with `name` and `default_state`, e.g. -// -// BASE_FEATURE(kMyFeature, "MyFeature", base::FEATURE_DISABLED_BY_DEFAULT); -// -// Features should *not* be defined in header files; do not use this macro in -// header files. -#define BASE_FEATURE(feature, name, default_state) \ - constinit const base::Feature feature( \ - name, default_state, base::internal::FeatureMacroHandshake::kSecret) - -// Secret handshake to (try to) ensure all places that construct a base::Feature -// go through the helper `BASE_FEATURE()` macro above. -namespace internal { -enum class FeatureMacroHandshake { kSecret }; -} - -// The Feature struct is used to define the default state for a feature. There -// must only ever be one struct instance for a given feature name—generally -// defined as a constant global variable or file static. Declare and define -// features using the `BASE_DECLARE_FEATURE()` and `BASE_FEATURE()` macros -// above, as there are some subtleties involved. -// -// Feature constants are internally mutable, as this allows them to contain a -// mutable member to cache their override state, while still remaining declared -// as const. This cache member allows for significantly faster IsEnabled() -// checks. -// -// However, the "Mutable Constants" check [1] detects this as a regression, -// because this usually means that a readonly symbol is put in writable memory -// when readonly memory would be more efficient. -// -// The performance gains of the cache are large enough to offset the downsides -// to having the symbols in bssdata rather than rodata. Use LOGICALLY_CONST to -// suppress the "Mutable Constants" check. -// -// [1]: -// https://crsrc.org/c/docs/speed/binary_size/android_binary_size_trybot.md#Mutable-Constants -struct BASE_EXPORT LOGICALLY_CONST Feature { - constexpr Feature(const char* name, - FeatureState default_state, - internal::FeatureMacroHandshake) - : name(name), default_state(default_state) { -#if BUILDFLAG(ENABLE_BANNED_BASE_FEATURE_PREFIX) - if (std::string_view(name).find(BUILDFLAG(BANNED_BASE_FEATURE_PREFIX)) == - 0) { - LOG(FATAL) << "Invalid feature name " << name << " starts with " - << BUILDFLAG(BANNED_BASE_FEATURE_PREFIX); - } -#endif // BUILDFLAG(ENABLE_BANNED_BASE_FEATURE_PREFIX) - } - - // Non-copyable since: - // - there should be only one `Feature` instance per unique name. - // - a `Feature` contains internal cached state about the override state. - Feature(const Feature&) = delete; - Feature& operator=(const Feature&) = delete; - - // The name of the feature. This should be unique to each feature and is used - // for enabling/disabling features via command line flags and experiments. - // It is strongly recommended to use CamelCase style for feature names, e.g. - // "MyGreatFeature". - const char* const name; - - // The default state (i.e. enabled or disabled) for this feature. - // NOTE: The actual runtime state may be different, due to a field trial or a - // command line switch. - const FeatureState default_state; - - private: - friend class FeatureList; - - // A packed value where the first 8 bits represent the `OverrideState` of this - // feature, and the last 16 bits are a caching context ID used to allow - // ScopedFeatureLists to invalidate these cached values in testing. A value of - // 0 in the caching context ID field indicates that this value has never been - // looked up and cached, a value of 1 indicates this value contains the cached - // `OverrideState` that was looked up via `base::FeatureList`, and any other - // value indicate that this cached value is only valid for a particular - // ScopedFeatureList instance. - // - // Packing these values into a uint32_t makes it so that atomic operations - // performed on this fields can be lock free. - // - // The override state stored in this field is only used if the current - // `FeatureList::caching_context_` field is equal to the lower 16 bits of the - // packed cached value. Otherwise, the override state is looked up in the - // feature list and the cache is updated. - mutable std::atomic cached_value = 0; -}; - -#if BUILDFLAG(DCHECK_IS_CONFIGURABLE) -// DCHECKs have been built-in, and are configurable at run-time to be fatal, or -// not, via a DcheckIsFatal feature. We define the Feature here since it is -// checked in FeatureList::SetInstance(). See https://crbug.com/596231. -BASE_EXPORT BASE_DECLARE_FEATURE(kDCheckIsFatalFeature); -#endif // BUILDFLAG(DCHECK_IS_CONFIGURABLE) - -// The FeatureList class is used to determine whether a given feature is on or -// off. It provides an authoritative answer, taking into account command-line -// overrides and experimental control. -// -// The basic use case is for any feature that can be toggled (e.g. through -// command-line or an experiment) to have a defined Feature struct, e.g.: -// -// const base::Feature kMyGreatFeature { -// "MyGreatFeature", base::FEATURE_ENABLED_BY_DEFAULT -// }; -// -// Then, client code that wishes to query the state of the feature would check: -// -// if (base::FeatureList::IsEnabled(kMyGreatFeature)) { -// // Feature code goes here. -// } -// -// Behind the scenes, the above call would take into account any command-line -// flags to enable or disable the feature, any experiments that may control it -// and finally its default state (in that order of priority), to determine -// whether the feature is on. -// -// Features can be explicitly forced on or off by specifying a list of comma- -// separated feature names via the following command-line flags: -// -// --enable-features=Feature5,Feature7 -// --disable-features=Feature1,Feature2,Feature3 -// -// To enable/disable features in a test, do NOT append --enable-features or -// --disable-features to the command-line directly. Instead, use -// ScopedFeatureList. See base/test/scoped_feature_list.h for details. -// -// After initialization (which should be done single-threaded), the FeatureList -// API is thread safe. -// -// Note: This class is a singleton, but does not use base/memory/singleton.h in -// order to have control over its initialization sequence. Specifically, the -// intended use is to create an instance of this class and fully initialize it, -// before setting it as the singleton for a process, via SetInstance(). -class BASE_EXPORT FeatureList { - public: - FeatureList(); - FeatureList(const FeatureList&) = delete; - FeatureList& operator=(const FeatureList&) = delete; - ~FeatureList(); - - // Used by common test fixture classes to prevent abuse of ScopedFeatureList - // after multiple threads have started. - class BASE_EXPORT ScopedDisallowOverrides { - public: - explicit ScopedDisallowOverrides(const char* reason); - ScopedDisallowOverrides(const ScopedDisallowOverrides&) = delete; - ScopedDisallowOverrides& operator=(const ScopedDisallowOverrides&) = delete; - ~ScopedDisallowOverrides(); - - private: -#if DCHECK_IS_ON() - const char* const previous_reason_; -#endif - }; - - // Specifies whether a feature override enables or disables the feature. - enum OverrideState { - OVERRIDE_USE_DEFAULT, - OVERRIDE_DISABLE_FEATURE, - OVERRIDE_ENABLE_FEATURE, - }; - - // Accessor class, used to look up features by _name_ rather than by Feature - // object. - // Should only be used in limited cases. See ConstructAccessor() for details. - class BASE_EXPORT Accessor { - public: - Accessor(const Accessor&) = delete; - Accessor& operator=(const Accessor&) = delete; - - // Looks up the feature, returning only its override state, rather than - // falling back on a default value (since there is no default value given). - // Callers of this MUST ensure that there is a consistent, compile-time - // default value associated. - FeatureList::OverrideState GetOverrideStateByFeatureName( - std::string_view feature_name); - - // Look up the feature, and, if present, populate |params|. - // See GetFieldTrialParams in field_trial_params.h for more documentation. - bool GetParamsByFeatureName(std::string_view feature_name, - std::map* params); - - private: - // Allow FeatureList to construct this class. - friend class FeatureList; - - explicit Accessor(FeatureList* feature_list); - - // Unowned pointer to the FeatureList object we use to look up feature - // enablement. - raw_ptr feature_list_; - }; - - // Describes a feature override. The first member is a Feature that will be - // overridden with the state given by the second member. - using FeatureOverrideInfo = - std::pair, OverrideState>; - - // Initializes feature overrides via command-line flags `--enable-features=` - // and `--disable-features=`, each of which is a comma-separated list of - // features to enable or disable, respectively. This function also allows - // users to set a feature's field trial params via `--enable-features=`. Must - // only be invoked during the initialization phase (before - // FinalizeInitialization() has been called). - // - // If a feature appears on both lists, then it will be disabled. If - // a list entry has the format "FeatureName& extra_overrides); - - // Loops through feature overrides and serializes them all into |allocator|. - void AddFeaturesToAllocator(PersistentMemoryAllocator* allocator); - - // Returns comma-separated lists of feature names (in the same format that is - // accepted by InitFromCommandLine()) corresponding to features that - // have been overridden - either through command-line or via FieldTrials. For - // those features that have an associated FieldTrial, the output entry will be - // of the format "FeatureName ConstructAccessor(); - - // Returns whether the given `feature` is enabled. - // - // If no `FeatureList` instance is registered, this will: - // - DCHECK(), if FailOnFeatureAccessWithoutFeatureList() was called. - // TODO(crbug.com/40237050): Change the DCHECK to a CHECK when we're - // confident that all early accesses have been fixed. We don't want to - // get many crash reports from the field in the meantime. - // - Return the default state, otherwise. Registering a `FeatureList` later - // will fail. - // - // TODO(crbug.com/40237050): Make early FeatureList access fail on iOS, - // Android and ChromeOS. This currently only works on Windows, Mac and Linux. - // - // A feature with a given name must only have a single corresponding Feature - // instance, which is checked in builds with DCHECKs enabled. - static bool IsEnabled(const Feature& feature); - - // Some characters are not allowed to appear in feature names or the - // associated field trial names, as they are used as special characters for - // command-line serialization. This function checks that the strings are ASCII - // (since they are used in command-line API functions that require ASCII) and - // whether there are any reserved characters present, returning true if the - // string is valid. - static bool IsValidFeatureOrFieldTrialName(std::string_view name); - - // If the given |feature| is overridden, returns its enabled state; otherwise, - // returns an empty optional. Must only be called after the singleton instance - // has been registered via SetInstance(). Additionally, a feature with a given - // name must only have a single corresponding Feature struct, which is checked - // in builds with DCHECKs enabled. - static std::optional GetStateIfOverridden(const Feature& feature); - - // Returns the field trial associated with the given |feature|. Must only be - // called after the singleton instance has been registered via SetInstance(). - static FieldTrial* GetFieldTrial(const Feature& feature); - - // Splits a comma-separated string containing feature names into a vector. The - // resulting pieces point to parts of |input|. - static std::vector SplitFeatureListString( - std::string_view input); - - // Checks and parses the |enable_feature| (e.g. - // FeatureName& extra_overrides); - - // Returns the singleton instance of FeatureList. Will return null until an - // instance is registered via SetInstance(). - static FeatureList* GetInstance(); - - // Registers the given |instance| to be the singleton feature list for this - // process. This should only be called once and |instance| must not be null. - // Note: If you are considering using this for the purposes of testing, take - // a look at using base/test/scoped_feature_list.h instead. - static void SetInstance(std::unique_ptr instance); - - // Registers the given `instance` to be the temporary singleton feature list - // for this process. While the given `instance` is the singleton feature list, - // only the state of features matching `allowed_feature_names` can be checked. - // Attempting to query other feature will behave as if no feature list was set - // at all. It is expected that this instance is replaced using `SetInstance` - // with an instance without limitations as soon as practical. - static void SetEarlyAccessInstance( - std::unique_ptr instance, - base::flat_set allowed_feature_names); - - // Clears the previously-registered singleton instance for tests and returns - // the old instance. - // Note: Most tests should never call this directly. Instead consider using - // base::test::ScopedFeatureList. - static std::unique_ptr ClearInstanceForTesting(); - - // Sets a given (initialized) |instance| to be the singleton feature list, - // for testing. Existing instance must be null. This is primarily intended - // to support base::test::ScopedFeatureList helper class. - static void RestoreInstanceForTesting(std::unique_ptr instance); - - // After calling this, an attempt to access feature state when no FeatureList - // is registered will DCHECK. - // - // TODO(crbug.com/40237050): Change the DCHECK to a CHECK when we're confident - // that all early accesses have been fixed. We don't want to get many crash - // reports from the field in the meantime. - // - // Note: This isn't the default behavior because accesses are tolerated in - // processes that never register a FeatureList. - static void FailOnFeatureAccessWithoutFeatureList(); - - // Returns the first feature that was accessed before a FeatureList was - // registered that allows accessing the feature. - static const Feature* GetEarlyAccessedFeatureForTesting(); - - // Resets the state of the early feature access tracker. - static void ResetEarlyFeatureAccessTrackerForTesting(); - - // Adds a feature to the early allowed feature access list for tests. Should - // only be called on a FeatureList that was set with SetEarlyAccessInstance(). - void AddEarlyAllowedFeatureForTesting(std::string feature_name); - - - private: -// FRIEND_TEST_ALL_PREFIXES(FeatureListTest, CheckFeatureIdentity); -// FRIEND_TEST_ALL_PREFIXES(FeatureListTest, -// StoreAndRetrieveFeaturesFromSharedMemory); -// FRIEND_TEST_ALL_PREFIXES(FeatureListTest, -// StoreAndRetrieveAssociatedFeaturesFromSharedMemory); - // Allow Accessor to access GetOverrideStateByFeatureName(). - friend class Accessor; - - struct OverrideEntry { - // The overridden enable (on/off) state of the feature. - OverrideState overridden_state; - - // An optional associated field trial, which will be activated when the - // state of the feature is queried for the first time. Weak pointer to the - // FieldTrial object that is owned by the FieldTrialList singleton. - raw_ptr field_trial; - - // Specifies whether the feature's state is overridden by |field_trial|. - // If it's not, and |field_trial| is not null, it means it is simply an - // associated field trial for reporting purposes (and |overridden_state| - // came from the command-line). - bool overridden_by_field_trial; - - // TODO(asvitkine): Expand this as more support is added. - - // Constructs an OverrideEntry for the given |overridden_state|. If - // |field_trial| is not null, it implies that |overridden_state| comes from - // the trial, so |overridden_by_field_trial| will be set to true. - OverrideEntry(OverrideState overridden_state, FieldTrial* field_trial); - }; - - // Returns the override for the field trial associated with the given feature - // |name| or null if the feature is not found. - const base::FeatureList::OverrideEntry* GetOverrideEntryByFeatureName( - std::string_view name) const; - - // Finalizes the initialization state of the FeatureList, so that no further - // overrides can be registered. This is called by SetInstance() on the - // singleton feature list that is being registered. - void FinalizeInitialization(); - - // Returns whether the given |feature| is enabled. This is invoked by the - // public FeatureList::IsEnabled() static function on the global singleton. - // Requires the FeatureList to have already been fully initialized. - bool IsFeatureEnabled(const Feature& feature) const; - - // Returns whether the given |feature| is enabled. This is invoked by the - // public FeatureList::GetStateIfOverridden() static function on the global - // singleton. Requires the FeatureList to have already been fully initialized. - std::optional IsFeatureEnabledIfOverridden( - const Feature& feature) const; - - // Returns the override state of a given |feature|. If the feature was not - // overridden, returns OVERRIDE_USE_DEFAULT. Performs any necessary callbacks - // for when the feature state has been observed, e.g. activating field trials. - OverrideState GetOverrideState(const Feature& feature) const; - - // Same as GetOverrideState(), but without a default value. - OverrideState GetOverrideStateByFeatureName( - std::string_view feature_name) const; - - // Returns the field trial associated with the given |feature|. This is - // invoked by the public FeatureList::GetFieldTrial() static function on the - // global singleton. Requires the FeatureList to have already been fully - // initialized. - base::FieldTrial* GetAssociatedFieldTrial(const Feature& feature) const; - - // For each feature name in comma-separated list of strings |feature_list|, - // registers an override with the specified |overridden_state|. Also, will - // associate an optional named field trial if the entry is of the format - // "FeatureName overrides_; - - // Locked map that keeps track of seen features, to ensure a single feature is - // only defined once. This verification is only done in builds with DCHECKs - // enabled. This is mutable as it's not externally visible and needs to be - // usable from const getters. - mutable Lock feature_identity_tracker_lock_; - mutable std::map feature_identity_tracker_ - GUARDED_BY(feature_identity_tracker_lock_); - - // Tracks the associated FieldTrialList for DCHECKs. This is used to catch - // the scenario where multiple FieldTrialList are used with the same - // FeatureList - which can lead to overrides pointing to invalid FieldTrial - // objects. - raw_ptr field_trial_list_ = nullptr; - - // Whether this object has been fully initialized. This gets set to true as a - // result of FinalizeInitialization(). - bool initialized_ = false; - - // Whether this object has been initialized from command line. - bool initialized_from_command_line_ = false; - - // Used when querying `base::Feature` state to determine if the cached value - // in the `Feature` object is populated and valid. See the comment on - // `base::Feature::cached_value` for more details. - const uint16_t caching_context_; - - // If this instance was set with SetEarlyAccessInstance(), this set contains - // the names of the features whose state is allowed to be checked. Attempting - // to check the state of a feature not on this list will behave as if no - // feature list was initialized at all. - base::flat_set allowed_feature_names_; -}; - -} // namespace base - -#endif // BASE_FEATURE_LIST_H_ - diff --git a/bridge/bindings/v8/base/feature_list_buildflags.h b/bridge/bindings/v8/base/feature_list_buildflags.h deleted file mode 100644 index 2ac7f726fe..0000000000 --- a/bridge/bindings/v8/base/feature_list_buildflags.h +++ /dev/null @@ -1,17 +0,0 @@ -/* -* Copyright (C) 2019-2022 The Kraken authors. All rights reserved. -* Copyright (C) 2022-present The WebF authors. All rights reserved. -*/ - -#ifndef BASE_FEATURE_LIST_BUILDFLAGS_H_ -#define BASE_FEATURE_LIST_BUILDFLAGS_H_ - -#include "bindings/v8/for_build/buildflag.h" // IWYU pragma: export - -// IWYU pragma: always_keep - -#define BUILDFLAG_INTERNAL_ENABLE_BANNED_BASE_FEATURE_PREFIX() (0) -#define BUILDFLAG_INTERNAL_DCHECK_IS_CONFIGURABLE() (0) - -#endif // BASE_FEATURE_LIST_BUILDFLAGS_H_ - diff --git a/bridge/bindings/v8/base/features.cc b/bridge/bindings/v8/base/features.cc deleted file mode 100644 index 113807300e..0000000000 --- a/bridge/bindings/v8/base/features.cc +++ /dev/null @@ -1,129 +0,0 @@ -/* -* Copyright (C) 2019-2022 The Kraken authors. All rights reserved. -* Copyright (C) 2022-present The WebF authors. All rights reserved. -*/ - -#include "bindings/v8/base/features.h" - -#include "bindings/v8/base/cpu_reduction_experiment.h" -#include "bindings/v8/base/task/sequence_manager/sequence_manager_impl.h" -#include "bindings/v8/base/threading/platform_thread.h" -#include "bindings/v8/for_build/buildflag.h" - -#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID) -#include "base/message_loop/message_pump_epoll.h" -#include "base/message_loop/message_pump_libevent.h" -#endif - -#if BUILDFLAG(IS_APPLE) -#include "bindings/v8/base/files/file.h" -#include "bindings/v8/base/message_loop/message_pump_apple.h" -#include "bindings/v8/base/message_loop/message_pump_kqueue.h" -#include "bindings/v8/base/synchronization/condition_variable.h" -#endif - -#if BUILDFLAG(IS_ANDROID) -#include "base/android/input_hint_checker.h" -#endif - -#if BUILDFLAG(IS_WIN) -#include "base/task/sequence_manager/thread_controller_power_monitor.h" -#include "base/threading/platform_thread_win.h" -#endif - -namespace base::features { - -// Alphabetical: - -// Enforce that writeable file handles passed to untrusted processes are not -// backed by executable files. -BASE_FEATURE(kEnforceNoExecutableFileHandles, - "EnforceNoExecutableFileHandles", - FEATURE_ENABLED_BY_DEFAULT); - -// TODO(crbug.com/40580068): Roll out this to 100% before replacing existing -// NOTREACHED_IN_MIGRATION()s with NOTREACHED() as part of [[noreturn]] -// migration. Note that a prerequisite for rolling out this experiment is that -// existing NOTREACHED() reports are at a very low rate. Once this rolls out we -// should monitor that crash rates for the experiment population is within a -// 1-5% or lower than the control group. -BASE_FEATURE(kNotReachedIsFatal, - "NotReachedIsFatal", - FEATURE_ENABLED_BY_DEFAULT); - -// Optimizes parsing and loading of data: URLs. -BASE_FEATURE(kOptimizeDataUrls, "OptimizeDataUrls", FEATURE_ENABLED_BY_DEFAULT); - -BASE_FEATURE(kUseRustJsonParser, - "UseRustJsonParser", - FEATURE_DISABLED_BY_DEFAULT); - -#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_CHROMEOS) -// Force to enable LowEndDeviceMode partially on Android 3Gb devices. -// (see PartialLowEndModeOnMidRangeDevices below) -BASE_FEATURE(kPartialLowEndModeOn3GbDevices, - "PartialLowEndModeOn3GbDevices", - FEATURE_DISABLED_BY_DEFAULT); - -// Used to enable LowEndDeviceMode partially on Android and ChromeOS mid-range -// devices. Such devices aren't considered low-end, but we'd like experiment -// with a subset of low-end features to see if we get a good memory vs. -// performance tradeoff. -// -// TODO(crbug.com/40264947): |#if| out 32-bit before launching or going to -// high Stable %, because we will enable the feature only for <8GB 64-bit -// devices, where we didn't ship yet. However, we first need a larger -// population to collect data. -BASE_FEATURE(kPartialLowEndModeOnMidRangeDevices, - "PartialLowEndModeOnMidRangeDevices", -#if BUILDFLAG(IS_ANDROID) - FEATURE_ENABLED_BY_DEFAULT); -#elif BUILDFLAG(IS_CHROMEOS) - FEATURE_DISABLED_BY_DEFAULT); -#endif - -#endif // BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_CHROMEOS) - -#if BUILDFLAG(IS_ANDROID) -// Whether to report frame metrics to the Android.FrameTimeline.* histograms. -BASE_FEATURE(kCollectAndroidFrameTimelineMetrics, - "CollectAndroidFrameTimelineMetrics", - FEATURE_DISABLED_BY_DEFAULT); -#endif // BUILDFLAG(IS_ANDROID) - -void Init(EmitThreadControllerProfilerMetadata - emit_thread_controller_profiler_metadata) { - InitializeCpuReductionExperiment(); - sequence_manager::internal::SequenceManagerImpl::InitializeFeatures(); - sequence_manager::internal::ThreadController::InitializeFeatures( - emit_thread_controller_profiler_metadata); - -#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID) - MessagePumpLibevent::InitializeFeatures(); - MessagePumpEpoll::InitializeFeatures(); -#endif - -#if BUILDFLAG(IS_APPLE) || BUILDFLAG(IS_CHROMEOS) - PlatformThread::InitializeFeatures(); -#endif - -#if BUILDFLAG(IS_APPLE) - ConditionVariable::InitializeFeatures(); - File::InitializeFeatures(); - MessagePumpCFRunLoopBase::InitializeFeatures(); - MessagePumpKqueue::InitializeFeatures(); -#endif - -#if BUILDFLAG(IS_ANDROID) - android::InputHintChecker::InitializeFeatures(); -#endif - -#if BUILDFLAG(IS_WIN) - sequence_manager::internal::ThreadControllerPowerMonitor:: - InitializeFeatures(); - InitializePlatformThreadFeatures(); -#endif -} - -} // namespace base::features - diff --git a/bridge/bindings/v8/base/features.h b/bridge/bindings/v8/base/features.h deleted file mode 100644 index 81f998ce60..0000000000 --- a/bridge/bindings/v8/base/features.h +++ /dev/null @@ -1,55 +0,0 @@ -/* -* Copyright (C) 2019-2022 The Kraken authors. All rights reserved. -* Copyright (C) 2022-present The WebF authors. All rights reserved. -*/ - -#ifndef BASE_FEATURES_H_ -#define BASE_FEATURES_H_ - -#include "bindings/v8/base/base_export.h" -#include "bindings/v8/base/feature_list.h" -#include "bindings/v8/base/metrics/field_trial_params.h" - -namespace base::features { - -// All features in alphabetical order. The features should be documented -// alongside the definition of their values in the .cc file. - -// Alphabetical: -BASE_EXPORT BASE_DECLARE_FEATURE(kEnforceNoExecutableFileHandles); - -BASE_EXPORT BASE_DECLARE_FEATURE(kNotReachedIsFatal); - -BASE_EXPORT BASE_DECLARE_FEATURE(kOptimizeDataUrls); - -BASE_EXPORT BASE_DECLARE_FEATURE(kUseRustJsonParser); - -#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_CHROMEOS) -BASE_EXPORT BASE_DECLARE_FEATURE(kPartialLowEndModeOn3GbDevices); -BASE_EXPORT BASE_DECLARE_FEATURE(kPartialLowEndModeOnMidRangeDevices); -#endif - -#if BUILDFLAG(IS_ANDROID) -BASE_EXPORT BASE_DECLARE_FEATURE(kCollectAndroidFrameTimelineMetrics); -#endif - -// Policy for emitting profiler metadata from `ThreadController`. -enum class EmitThreadControllerProfilerMetadata { - // Always emit metadata. - kForce, - // Emit metadata only if enabled via the `FeatureList`. - kFeatureDependent, -}; - -// Initializes global variables that depend on `FeatureList`. Must be invoked -// early on process startup, but after `FeatureList` initialization. Different -// parts of //base read experiment state from global variables instead of -// directly from `FeatureList` to avoid data races (default values are used -// before this function is called to initialize the global variables). -BASE_EXPORT void Init(EmitThreadControllerProfilerMetadata - emit_thread_controller_profiler_metadata); - -} // namespace base::features - -#endif // BASE_FEATURES_H_ - diff --git a/bridge/bindings/v8/base/location.h b/bridge/bindings/v8/base/location.h index b00258d8bc..22691adf33 100644 --- a/bridge/bindings/v8/base/location.h +++ b/bridge/bindings/v8/base/location.h @@ -11,7 +11,7 @@ #include //#include "base/base_export.h" -#include "bindings/v8/base/memory/raw_ptr_exclusion.h" +//#include "bindings/v8/base/memory/raw_ptr_exclusion.h" //#include "base/trace_event/base_tracing_forward.h" #include "bindings/v8/for_build/build_config.h" @@ -101,7 +101,7 @@ class Location { // `program_counter_` is not a raw_ptr<...> for performance reasons (based on // analysis of sampling profiler data and tab_search:top100:2020). - RAW_PTR_EXCLUSION const void* program_counter_ = nullptr; + const void* program_counter_ = nullptr; }; const void* GetProgramCounter(); diff --git a/bridge/bindings/v8/base/metrics/field_trial_params.cc b/bridge/bindings/v8/base/metrics/field_trial_params.cc deleted file mode 100644 index c4f91196de..0000000000 --- a/bridge/bindings/v8/base/metrics/field_trial_params.cc +++ /dev/null @@ -1,266 +0,0 @@ -/* -* Copyright (C) 2019-2022 The Kraken authors. All rights reserved. -* Copyright (C) 2022-present The WebF authors. All rights reserved. -*/ - -#include "bindings/v8/base/metrics/field_trial_params.h" - -#include -#include -#include -#include -#include - -#include "bindings/v8/base/debug/crash_logging.h" -#include "bindings/v8/base/debug/dump_without_crashing.h" -#include "bindings/v8/base/feature_list.h" -#include "bindings/v8/base/metrics/field_trial.h" -#include "bindings/v8/base/metrics/field_trial_param_associator.h" -#include "bindings/v8/base/metrics/histogram_functions.h" -#include "bindings/v8/base/metrics/metrics_hashes.h" -#include "bindings/v8/base/notreached.h" -#include "bindings/v8/base/strings/escape.h" -#include "bindings/v8/base/strings/string_number_conversions.h" -#include "bindings/v8/base/strings/string_split.h" -#include "bindings/v8/base/strings/stringprintf.h" -#include "bindings/v8/base/time/time_delta_from_string.h" - -namespace base { - -void LogInvalidValue(const Feature& feature, - const char* type, - const std::string& param_name, - const std::string& value_as_string, - const std::string& default_value_as_string) { - UmaHistogramSparse("Variations.FieldTriamParamsLogInvalidValue", - static_cast(base::HashFieldTrialName( - FeatureList::GetFieldTrial(feature)->trial_name()))); - // To anyone noticing these crash dumps in the wild, these parameters come - // from server-side experiment configuration. If you're seeing an increase it - // is likely due to a bad experiment rollout rather than changes in the client - // code. - SCOPED_CRASH_KEY_STRING32("FieldTrialParams", "feature_name", feature.name); - SCOPED_CRASH_KEY_STRING32("FieldTrialParams", "param_name", param_name); - SCOPED_CRASH_KEY_STRING32("FieldTrialParams", "value", value_as_string); - SCOPED_CRASH_KEY_STRING32("FieldTrialParams", "default", - default_value_as_string); - LOG(ERROR) << "Failed to parse field trial param " << param_name - << " with string value " << value_as_string << " under feature " - << feature.name << " into " << type - << ". Falling back to default value of " - << default_value_as_string; - base::debug::DumpWithoutCrashing(); -} - -std::string UnescapeValue(const std::string& value) { - return UnescapeURLComponent( - value, UnescapeRule::PATH_SEPARATORS | - UnescapeRule::URL_SPECIAL_CHARS_EXCEPT_PATH_SEPARATORS); -} - -bool AssociateFieldTrialParams(const std::string& trial_name, - const std::string& group_name, - const FieldTrialParams& params) { - return FieldTrialParamAssociator::GetInstance()->AssociateFieldTrialParams( - trial_name, group_name, params); -} - -bool AssociateFieldTrialParamsFromString( - const std::string& params_string, - FieldTrialParamsDecodeStringFunc decode_data_func) { - // Format: Trial1.Group1:k1/v1/k2/v2,Trial2.Group2:k1/v1/k2/v2 - std::set> trial_groups; - for (std::string_view experiment_group : - SplitStringPiece(params_string, ",", TRIM_WHITESPACE, SPLIT_WANT_ALL)) { - std::vector experiment = SplitStringPiece( - experiment_group, ":", TRIM_WHITESPACE, SPLIT_WANT_ALL); - if (experiment.size() != 2) { - DLOG(ERROR) << "Experiment and params should be separated by ':'"; - return false; - } - - std::vector group_parts = - SplitString(experiment[0], ".", TRIM_WHITESPACE, SPLIT_WANT_ALL); - if (group_parts.size() != 2) { - DLOG(ERROR) << "Trial and group name should be separated by '.'"; - return false; - } - - std::vector key_values = - SplitString(experiment[1], "/", TRIM_WHITESPACE, SPLIT_WANT_ALL); - if (key_values.size() % 2 != 0) { - DLOG(ERROR) << "Param name and param value should be separated by '/'"; - return false; - } - std::string trial = decode_data_func(group_parts[0]); - std::string group = decode_data_func(group_parts[1]); - auto trial_group = std::make_pair(trial, group); - if (trial_groups.find(trial_group) != trial_groups.end()) { - DLOG(ERROR) << StringPrintf( - "A (trial, group) pair listed more than once. (%s, %s)", - trial.c_str(), group.c_str()); - return false; - } - trial_groups.insert(trial_group); - std::map params; - for (size_t i = 0; i < key_values.size(); i += 2) { - std::string key = decode_data_func(key_values[i]); - std::string value = decode_data_func(key_values[i + 1]); - params[key] = value; - } - bool result = AssociateFieldTrialParams(trial, group, params); - if (!result) { - DLOG(ERROR) << "Failed to associate field trial params for group \"" - << group << "\" in trial \"" << trial << "\""; - return false; - } - } - return true; -} - -bool GetFieldTrialParams(const std::string& trial_name, - FieldTrialParams* params) { - FieldTrial* trial = FieldTrialList::Find(trial_name); - return FieldTrialParamAssociator::GetInstance()->GetFieldTrialParams(trial, - params); -} - -bool GetFieldTrialParamsByFeature(const Feature& feature, - FieldTrialParams* params) { - if (!FeatureList::IsEnabled(feature)) - return false; - - FieldTrial* trial = FeatureList::GetFieldTrial(feature); - return FieldTrialParamAssociator::GetInstance()->GetFieldTrialParams(trial, - params); -} - -std::string GetFieldTrialParamValue(const std::string& trial_name, - const std::string& param_name) { - FieldTrialParams params; - if (GetFieldTrialParams(trial_name, ¶ms)) { - auto it = params.find(param_name); - if (it != params.end()) - return it->second; - } - return std::string(); -} - -std::string GetFieldTrialParamValueByFeature(const Feature& feature, - const std::string& param_name) { - FieldTrialParams params; - if (GetFieldTrialParamsByFeature(feature, ¶ms)) { - auto it = params.find(param_name); - if (it != params.end()) - return it->second; - } - return std::string(); -} - -int GetFieldTrialParamByFeatureAsInt(const Feature& feature, - const std::string& param_name, - int default_value) { - std::string value_as_string = - GetFieldTrialParamValueByFeature(feature, param_name); - int value_as_int = 0; - if (!StringToInt(value_as_string, &value_as_int)) { - if (!value_as_string.empty()) { - LogInvalidValue(feature, "an int", param_name, value_as_string, - base::NumberToString(default_value)); - } - value_as_int = default_value; - } - return value_as_int; -} - -double GetFieldTrialParamByFeatureAsDouble(const Feature& feature, - const std::string& param_name, - double default_value) { - std::string value_as_string = - GetFieldTrialParamValueByFeature(feature, param_name); - double value_as_double = 0; - if (!StringToDouble(value_as_string, &value_as_double)) { - if (!value_as_string.empty()) { - LogInvalidValue(feature, "a double", param_name, value_as_string, - base::NumberToString(default_value)); - } - value_as_double = default_value; - } - return value_as_double; -} - -bool GetFieldTrialParamByFeatureAsBool(const Feature& feature, - const std::string& param_name, - bool default_value) { - std::string value_as_string = - GetFieldTrialParamValueByFeature(feature, param_name); - if (value_as_string == "true") - return true; - if (value_as_string == "false") - return false; - - if (!value_as_string.empty()) { - LogInvalidValue(feature, "a bool", param_name, value_as_string, - default_value ? "true" : "false"); - } - return default_value; -} - -base::TimeDelta GetFieldTrialParamByFeatureAsTimeDelta( - const Feature& feature, - const std::string& param_name, - base::TimeDelta default_value) { - std::string value_as_string = - GetFieldTrialParamValueByFeature(feature, param_name); - - if (value_as_string.empty()) - return default_value; - - std::optional ret = TimeDeltaFromString(value_as_string); - if (!ret.has_value()) { - LogInvalidValue(feature, "a base::TimeDelta", param_name, value_as_string, - base::NumberToString(default_value.InSecondsF()) + " s"); - return default_value; - } - - return ret.value(); -} - -std::string FeatureParam::Get() const { - // We don't use `GetFieldTrialParamValueByFeature()` to handle empty values in - // the map. - FieldTrialParams params; - if (GetFieldTrialParamsByFeature(*feature, ¶ms)) { - auto it = params.find(name); - if (it != params.end()) { - return it->second; - } - } - return default_value; -} - -double FeatureParam::Get() const { - return GetFieldTrialParamByFeatureAsDouble(*feature, name, default_value); -} - -int FeatureParam::Get() const { - return GetFieldTrialParamByFeatureAsInt(*feature, name, default_value); -} - -bool FeatureParam::Get() const { - return GetFieldTrialParamByFeatureAsBool(*feature, name, default_value); -} - -base::TimeDelta FeatureParam::Get() const { - return GetFieldTrialParamByFeatureAsTimeDelta(*feature, name, default_value); -} - -void LogInvalidEnumValue(const Feature& feature, - const std::string& param_name, - const std::string& value_as_string, - int default_value_as_int) { - LogInvalidValue(feature, "an enum", param_name, value_as_string, - base::NumberToString(default_value_as_int)); -} - -} // namespace base diff --git a/bridge/bindings/v8/base/metrics/field_trial_params.h b/bridge/bindings/v8/base/metrics/field_trial_params.h deleted file mode 100644 index 7911548b33..0000000000 --- a/bridge/bindings/v8/base/metrics/field_trial_params.h +++ /dev/null @@ -1,354 +0,0 @@ -/* -* Copyright (C) 2019-2022 The Kraken authors. All rights reserved. -* Copyright (C) 2022-present The WebF authors. All rights reserved. -*/ - -#ifdef UNSAFE_BUFFERS_BUILD -// TODO(crbug.com/40284755): Remove this and spanify to fix the errors. -#pragma allow_unsafe_buffers -#endif - -#ifndef BASE_METRICS_FIELD_TRIAL_PARAMS_H_ -#define BASE_METRICS_FIELD_TRIAL_PARAMS_H_ - -#include -#include - -#include "bindings/v8/base/base_export.h" -#include "bindings/v8/base/feature_list.h" -//#include "bindings/v8/base/logging.h" -#include "bindings/v8/base/memory/raw_ptr_exclusion.h" -#include "bindings/v8/base/notreached.h" -#include "bindings/v8/base/time/time.h" - -namespace base { - -// Key-value mapping type for field trial parameters. -typedef std::map FieldTrialParams; - -// Param string decoding function for AssociateFieldTrialParamsFromString(). -typedef std::string (*FieldTrialParamsDecodeStringFunc)(const std::string& str); - -// Unescapes special characters from the given string. Used in -// AssociateFieldTrialParamsFromString() as one of the feature params decoding -// functions. -BASE_EXPORT std::string UnescapeValue(const std::string& value); - -// Associates the specified set of key-value |params| with the field trial -// specified by |trial_name| and |group_name|. Fails and returns false if the -// specified field trial already has params associated with it or the trial -// is already active (group() has been called on it). Thread safe. -BASE_EXPORT bool AssociateFieldTrialParams(const std::string& trial_name, - const std::string& group_name, - const FieldTrialParams& params); - -// Provides a mechanism to associate multiple set of params to multiple groups -// with a formatted string as returned by FieldTrialList::AllParamsToString(). -// |decode_data_func| allows specifying a custom decoding function. -BASE_EXPORT bool AssociateFieldTrialParamsFromString( - const std::string& params_string, - FieldTrialParamsDecodeStringFunc decode_data_func); - -// Retrieves the set of key-value |params| for the specified field trial, based -// on its selected group. If the field trial does not exist or its selected -// group does not have any parameters associated with it, returns false and -// does not modify |params|. Calling this function will result in the field -// trial being marked as active if found (i.e. group() will be called on it), -// if it wasn't already. Thread safe. -BASE_EXPORT bool GetFieldTrialParams(const std::string& trial_name, - FieldTrialParams* params); - -// Retrieves the set of key-value |params| for the field trial associated with -// the specified |feature|. A feature is associated with at most one field -// trial and selected group. See base/feature_list.h for more information on -// features. If the feature is not enabled, or if there's no associated params, -// returns false and does not modify |params|. Calling this function will -// result in the associated field trial being marked as active if found (i.e. -// group() will be called on it), if it wasn't already. Thread safe. -BASE_EXPORT bool GetFieldTrialParamsByFeature(const base::Feature& feature, - FieldTrialParams* params); - -// Retrieves a specific parameter value corresponding to |param_name| for the -// specified field trial, based on its selected group. If the field trial does -// not exist or the specified parameter does not exist, returns an empty -// string. Calling this function will result in the field trial being marked as -// active if found (i.e. group() will be called on it), if it wasn't already. -// Thread safe. -BASE_EXPORT std::string GetFieldTrialParamValue(const std::string& trial_name, - const std::string& param_name); - -// Retrieves a specific parameter value corresponding to |param_name| for the -// field trial associated with the specified |feature|. A feature is associated -// with at most one field trial and selected group. See base/feature_list.h for -// more information on features. If the feature is not enabled, or the -// specified parameter does not exist, returns an empty string. Calling this -// function will result in the associated field trial being marked as active if -// found (i.e. group() will be called on it), if it wasn't already. Thread safe. -BASE_EXPORT std::string GetFieldTrialParamValueByFeature( - const base::Feature& feature, - const std::string& param_name); - -// Same as GetFieldTrialParamValueByFeature(). On top of that, it converts the -// string value into an int using base::StringToInt() and returns it, if -// successful. Otherwise, it returns |default_value|. If the string value is not -// empty and the conversion does not succeed, it produces a warning to LOG. -BASE_EXPORT int GetFieldTrialParamByFeatureAsInt(const base::Feature& feature, - const std::string& param_name, - int default_value); - -// Same as GetFieldTrialParamValueByFeature(). On top of that, it converts the -// string value into a double using base::StringToDouble() and returns it, if -// successful. Otherwise, it returns |default_value|. If the string value is not -// empty and the conversion does not succeed, it produces a warning to LOG. -BASE_EXPORT double GetFieldTrialParamByFeatureAsDouble( - const base::Feature& feature, - const std::string& param_name, - double default_value); - -// Same as GetFieldTrialParamValueByFeature(). On top of that, it converts the -// string value into a boolean and returns it, if successful. Otherwise, it -// returns |default_value|. The only string representations accepted here are -// "true" and "false". If the string value is not empty and the conversion does -// not succeed, it produces a warning to LOG. -BASE_EXPORT bool GetFieldTrialParamByFeatureAsBool( - const base::Feature& feature, - const std::string& param_name, - bool default_value); - -// Same as GetFieldTrialParamValueByFeature(). On top of that, it converts the -// string value into a base::TimeDelta and returns it, if successful. Otherwise, -// it returns `default_value`. If the string value is not empty and the -// conversion does not succeed, it produces a warning to LOG. -BASE_EXPORT base::TimeDelta GetFieldTrialParamByFeatureAsTimeDelta( - const Feature& feature, - const std::string& param_name, - base::TimeDelta default_value); - -// Shared declaration for various FeatureParam types. -// -// This template is defined for the following types T: -// bool -// int -// double -// std::string -// enum types -// base::TimeDelta -// -// See the individual definitions below for the appropriate interfaces. -// Attempting to use it with any other type is a compile error. -// -// Getting a param value from a FeatureParam will have the same semantics as -// GetFieldTrialParamValueByFeature(), see that function's comments for details. -template > -struct FeatureParam { - // Prevent use of FeatureParam<> with unsupported types (e.g. void*). Uses T - // in its definition so that evaluation is deferred until the template is - // instantiated. - static_assert(!std::is_same_v, "unsupported FeatureParam<> type"); -}; - -// Declares a string-valued parameter. Example: -// -// constexpr FeatureParam kAssistantName = { -// &kAssistantFeature, "assistant_name", "HAL"}; -// -// If the feature is not enabled, the parameter is not set, or set to the empty -// string, then Get() will return the default value. -template <> -struct FeatureParam { - constexpr FeatureParam(const Feature* feature, - const char* name, - const char* default_value) - : feature(feature), name(name), default_value(default_value) {} - - // Calling Get() will activate the field trial associated with |feature|. See - // GetFieldTrialParamValueByFeature() for more details. - BASE_EXPORT std::string Get() const; - - // This field is not a raw_ptr<> because it was filtered by the rewriter for: - // #global-scope, #constexpr-ctor-field-initializer - RAW_PTR_EXCLUSION const Feature* const feature; - const char* const name; - const char* const default_value; -}; - -// Declares a double-valued parameter. Example: -// -// constexpr FeatureParam kAssistantTriggerThreshold = { -// &kAssistantFeature, "trigger_threshold", 0.10}; -// -// If the feature is not enabled, the parameter is not set, or set to an invalid -// double value, then Get() will return the default value. -template <> -struct FeatureParam { - constexpr FeatureParam(const Feature* feature, - const char* name, - double default_value) - : feature(feature), name(name), default_value(default_value) {} - - // Calling Get() will activate the field trial associated with |feature|. See - // GetFieldTrialParamValueByFeature() for more details. - BASE_EXPORT double Get() const; - - // This field is not a raw_ptr<> because it was filtered by the rewriter for: - // #global-scope, #constexpr-ctor-field-initializer - RAW_PTR_EXCLUSION const Feature* const feature; - const char* const name; - const double default_value; -}; - -// Declares an int-valued parameter. Example: -// -// constexpr FeatureParam kAssistantParallelism = { -// &kAssistantFeature, "parallelism", 4}; -// -// If the feature is not enabled, the parameter is not set, or set to an invalid -// int value, then Get() will return the default value. -template <> -struct FeatureParam { - constexpr FeatureParam(const Feature* feature, - const char* name, - int default_value) - : feature(feature), name(name), default_value(default_value) {} - - // Calling Get() will activate the field trial associated with |feature|. See - // GetFieldTrialParamValueByFeature() for more details. - BASE_EXPORT int Get() const; - - // This field is not a raw_ptr<> because it was filtered by the rewriter for: - // #global-scope, #constexpr-ctor-field-initializer - RAW_PTR_EXCLUSION const Feature* const feature; - const char* const name; - const int default_value; -}; - -// Declares a bool-valued parameter. Example: -// -// constexpr FeatureParam kAssistantIsHelpful = { -// &kAssistantFeature, "is_helpful", true}; -// -// If the feature is not enabled, the parameter is not set, or set to value -// other than "true" or "false", then Get() will return the default value. -template <> -struct FeatureParam { - constexpr FeatureParam(const Feature* feature, - const char* name, - bool default_value) - : feature(feature), name(name), default_value(default_value) {} - - // Calling Get() will activate the field trial associated with |feature|. See - // GetFieldTrialParamValueByFeature() for more details. - BASE_EXPORT bool Get() const; - - // This field is not a raw_ptr<> because it was filtered by the rewriter for: - // #global-scope, #constexpr-ctor-field-initializer - RAW_PTR_EXCLUSION const Feature* const feature; - const char* const name; - const bool default_value; -}; - -// Declares an TimeDelta-valued parameter. Example: -// -// constexpr base::FeatureParam kPerAgentDelay{ -// &kPerAgentSchedulingExperiments, "delay", base::TimeDelta()}; -// -// If the feature is not enabled, the parameter is not set, or set to an -// invalid value (as defined by base::TimeDeltaFromString()), then Get() will -// return the default value. -template <> -struct FeatureParam { - constexpr FeatureParam(const Feature* feature, - const char* name, - base::TimeDelta default_value) - : feature(feature), name(name), default_value(default_value) {} - - // Calling Get() will activate the field trial associated with |feature|. See - // GetFieldTrialParamValueByFeature() for more details. - BASE_EXPORT base::TimeDelta Get() const; - - // This field is not a raw_ptr<> because it was filtered by the rewriter for: - // #global-scope, #constexpr-ctor-field-initializer - RAW_PTR_EXCLUSION const Feature* const feature; - const char* const name; - const base::TimeDelta default_value; -}; - -BASE_EXPORT void LogInvalidEnumValue(const Feature& feature, - const std::string& param_name, - const std::string& value_as_string, - int default_value_as_int); - -// Feature param declaration for an enum, with associated options. Example: -// -// constexpr FeatureParam::Option kShapeParamOptions[] = { -// {SHAPE_CIRCLE, "circle"}, -// {SHAPE_CYLINDER, "cylinder"}, -// {SHAPE_PAPERCLIP, "paperclip"}}; -// constexpr FeatureParam kAssistantShapeParam = { -// &kAssistantFeature, "shape", SHAPE_CIRCLE, &kShapeParamOptions}; -// -// With this declaration, the parameter may be set to "circle", "cylinder", or -// "paperclip", and that will be translated to one of the three enum values. By -// default, or if the param is set to an unknown value, the parameter will be -// assumed to be SHAPE_CIRCLE. -template -struct FeatureParam { - struct Option { - constexpr Option(Enum value, const char* name) : value(value), name(name) {} - - const Enum value; - const char* const name; - }; - - template - constexpr FeatureParam(const Feature* feature, - const char* name, - const Enum default_value, - const Option (*options)[option_count]) - : feature(feature), - name(name), - default_value(default_value), - options(*options), - option_count(option_count) { - static_assert(option_count >= 1, "FeatureParam has no options"); - } - - // Calling Get() will activate the field trial associated with |feature|. See - // GetFieldTrialParamValueByFeature() for more details. - Enum Get() const { - std::string value = GetFieldTrialParamValueByFeature(*feature, name); - if (value.empty()) - return default_value; - for (size_t i = 0; i < option_count; ++i) { - if (value == options[i].name) - return options[i].value; - } - LogInvalidEnumValue(*feature, name, value, static_cast(default_value)); - return default_value; - } - - // Returns the param-string for the given enum value. - std::string GetName(Enum value) const { - for (size_t i = 0; i < option_count; ++i) { - if (value == options[i].value) - return options[i].name; - } - NOTREACHED_IN_MIGRATION(); - return ""; - } - - // This field is not a raw_ptr<> because it was filtered by the rewriter for: - // #global-scope, #constexpr-ctor-field-initializer - RAW_PTR_EXCLUSION const base::Feature* const feature; - const char* const name; - const Enum default_value; - // This field is not a raw_ptr<> because it was filtered by the rewriter for: - // #global-scope, #constexpr-ctor-field-initializer - RAW_PTR_EXCLUSION const Option* const options; - const size_t option_count; -}; - -} // namespace base - -#endif // BASE_METRICS_FIELD_TRIAL_PARAMS_H_ - diff --git a/bridge/bindings/v8/base/synchronization/lock.cc b/bridge/bindings/v8/base/synchronization/lock.cc deleted file mode 100644 index f47d16f92e..0000000000 --- a/bridge/bindings/v8/base/synchronization/lock.cc +++ /dev/null @@ -1,116 +0,0 @@ -/* -* Copyright (C) 2019-2022 The Kraken authors. All rights reserved. -* Copyright (C) 2022-present The WebF authors. All rights reserved. -*/ - -#ifdef UNSAFE_BUFFERS_BUILD -// TODO(crbug.com/40284755): Remove this and spanify to fix the errors. -#pragma allow_unsafe_buffers -#endif - -#include "bindings/v8/base/synchronization/lock.h" - -#include - -#if DCHECK_IS_ON() -#include - -#include "base/synchronization/lock_subtle.h" -#include "base/threading/platform_thread.h" - -namespace base { - -namespace { - -// List of locks held by a thread. -// -// As of May 2024, no more than 5 locks were held simultaneously by a thread in -// a test browsing session or while running the CQ (% locks acquired in unit -// tests "WaitSetTest.NoStarvation" and -// "MessagePipeTest.DataPipeConsumerHandlePingPong"). An array of size 10 is -// therefore considered sufficient to track all locks held by a thread. A -// dynamic-size array (e.g. owned by a `ThreadLocalOwnedPointer`) would require -// handling reentrancy issues with allocator shims that use `base::Lock`. -constexpr int kHeldLocksCapacity = 10; -thread_local std::array g_locks_held_by_thread; - -// Number of non-nullptr elements in `g_locks_held_by_thread`. -thread_local size_t g_num_locks_held_by_thread = 0; - -// Whether a lock is added to `g_locks_held_by_thread` when acquired. -thread_local bool g_track_locks = true; - -} // namespace - -Lock::~Lock() { - DCHECK(owning_thread_ref_.is_null()); -} - -void Lock::AssertAcquired() const { - DCHECK_EQ(owning_thread_ref_, PlatformThread::CurrentRef()); -} - -void Lock::AssertNotHeld() const { - DCHECK(owning_thread_ref_.is_null()); -} - -void Lock::CheckHeldAndUnmark() { - DCHECK_EQ(owning_thread_ref_, PlatformThread::CurrentRef()); - owning_thread_ref_ = PlatformThreadRef(); - - // Remove from the list of held locks. - for (size_t i = 0; i < g_num_locks_held_by_thread; ++i) { - // Traverse from the end since locks are typically acquired and released in - // opposite order. - const size_t index = g_num_locks_held_by_thread - i - 1; - if (g_locks_held_by_thread[index] == reinterpret_cast(this)) { - g_locks_held_by_thread[index] = - g_locks_held_by_thread[g_num_locks_held_by_thread - 1]; - g_locks_held_by_thread[g_num_locks_held_by_thread - 1] = - reinterpret_cast(nullptr); - --g_num_locks_held_by_thread; - break; - } - } -} - -void Lock::CheckUnheldAndMark() { - DCHECK(owning_thread_ref_.is_null()); - owning_thread_ref_ = PlatformThread::CurrentRef(); - - if (g_track_locks) { - // Check if capacity is exceeded. - if (g_num_locks_held_by_thread >= kHeldLocksCapacity) { - // Disable tracking of locks since logging may acquire a lock. - subtle::DoNotTrackLocks do_not_track_locks; - CHECK(false) - << "This thread holds more than " << kHeldLocksCapacity - << " locks simultaneously. Reach out to //base OWNERS to determine " - "whether it's preferable to increase `kHeldLocksCapacity` or to " - "use `DoNotTrackLocks` in this scope."; - } - - // Add to the list of held locks. - g_locks_held_by_thread[g_num_locks_held_by_thread] = - reinterpret_cast(this); - ++g_num_locks_held_by_thread; - } -} - -namespace subtle { - -span GetLocksHeldByCurrentThread() { - return span(g_locks_held_by_thread.begin(), - g_num_locks_held_by_thread); -} - -DoNotTrackLocks::DoNotTrackLocks() : auto_reset_(&g_track_locks, false) {} - -DoNotTrackLocks::~DoNotTrackLocks() = default; - -} // namespace subtle - -} // namespace base - -#endif // DCHECK_IS_ON() - diff --git a/bridge/bindings/v8/base/synchronization/lock.h b/bridge/bindings/v8/base/synchronization/lock.h deleted file mode 100644 index 0f5b8490ae..0000000000 --- a/bridge/bindings/v8/base/synchronization/lock.h +++ /dev/null @@ -1,145 +0,0 @@ -/* -* Copyright (C) 2019-2022 The Kraken authors. All rights reserved. -* Copyright (C) 2022-present The WebF authors. All rights reserved. -*/ - -#ifndef BASE_SYNCHRONIZATION_LOCK_H_ -#define BASE_SYNCHRONIZATION_LOCK_H_ - -#include "bindings/v8/base/base_export.h" -#include "bindings/v8/base/dcheck_is_on.h" -#include "bindings/v8/base/synchronization/lock_impl.h" -#include "bindings/v8/base/thread_annotations.h" -#include "bindings/v8/for_build/build_config.h" - -#if DCHECK_IS_ON() -#include "base/threading/platform_thread_ref.h" -#endif - -namespace base { - -// A convenient wrapper for an OS specific critical section. The only real -// intelligence in this class is in debug mode for the support for the -// AssertAcquired() method. -class LOCKABLE BASE_EXPORT Lock { - public: - Lock() = default; - - Lock(const Lock&) = delete; - Lock& operator=(const Lock&) = delete; - -#if !DCHECK_IS_ON() - ~Lock() = default; - - void Acquire() EXCLUSIVE_LOCK_FUNCTION() { lock_.Lock(); } - void Release() UNLOCK_FUNCTION() { lock_.Unlock(); } - - // If the lock is not held, take it and return true. If the lock is already - // held by another thread, immediately return false. This must not be called - // by a thread already holding the lock (what happens is undefined and an - // assertion may fail). - bool Try() EXCLUSIVE_TRYLOCK_FUNCTION(true) { return lock_.Try(); } - - // Null implementation if not debug. - void AssertAcquired() const ASSERT_EXCLUSIVE_LOCK() {} - void AssertNotHeld() const {} -#else - ~Lock(); - - // NOTE: We do not permit recursive locks and will commonly fire a DCHECK() if - // a thread attempts to acquire the lock a second time (while already holding - // it). - void Acquire() EXCLUSIVE_LOCK_FUNCTION() { - lock_.Lock(); - CheckUnheldAndMark(); - } - void Release() UNLOCK_FUNCTION() { - CheckHeldAndUnmark(); - lock_.Unlock(); - } - - bool Try() EXCLUSIVE_TRYLOCK_FUNCTION(true) { - bool rv = lock_.Try(); - if (rv) { - CheckUnheldAndMark(); - } - return rv; - } - - void AssertAcquired() const ASSERT_EXCLUSIVE_LOCK(); - void AssertNotHeld() const; -#endif // DCHECK_IS_ON() - - // Whether Lock mitigates priority inversion when used from different thread - // priorities. - static bool HandlesMultipleThreadPriorities() { -#if BUILDFLAG(IS_WIN) - // Windows mitigates priority inversion by randomly boosting the priority of - // ready threads. - // https://msdn.microsoft.com/library/windows/desktop/ms684831.aspx - return true; -#elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA) - // POSIX mitigates priority inversion by setting the priority of a thread - // holding a Lock to the maximum priority of any other thread waiting on it. - return internal::LockImpl::PriorityInheritanceAvailable(); -#else -#error Unsupported platform -#endif - } - - // Both Windows and POSIX implementations of ConditionVariable need to be - // able to see our lock and tweak our debugging counters, as they release and - // acquire locks inside of their condition variable APIs. - friend class ConditionVariable; - - private: -#if DCHECK_IS_ON() - // Members and routines taking care of locks assertions. - // Note that this checks for recursive locks and allows them - // if the variable is set. This is allowed by the underlying implementation - // on windows but not on Posix, so we're doing unneeded checks on Posix. - // It's worth it to share the code. - void CheckHeldAndUnmark(); - void CheckUnheldAndMark(); - - // All private data is implicitly protected by lock_. - // Be VERY careful to only access members under that lock. - base::PlatformThreadRef owning_thread_ref_; -#endif // DCHECK_IS_ON() - - // Platform specific underlying lock implementation. - internal::LockImpl lock_; -}; - -// A helper class that acquires the given Lock while the AutoLock is in scope. -using AutoLock = internal::BasicAutoLock; - -// A helper class that acquires the given Lock while the MovableAutoLock is in -// scope. Unlike AutoLock, the lock can be moved out of MovableAutoLock. Unlike -// AutoLockMaybe, the passed in lock is always valid, so need to check only on -// destruction. -using MovableAutoLock = internal::BasicMovableAutoLock; - -// A helper class that tries to acquire the given Lock while the AutoTryLock is -// in scope. -using AutoTryLock = internal::BasicAutoTryLock; - -// AutoUnlock is a helper that will Release() the |lock| argument in the -// constructor, and re-Acquire() it in the destructor. -using AutoUnlock = internal::BasicAutoUnlock; - -// Like AutoLock but is a no-op when the provided Lock* is null. Inspired from -// absl::MutexLockMaybe. Use this instead of std::optional to -// get around -Wthread-safety-analysis warnings for conditional locking. -using AutoLockMaybe = internal::BasicAutoLockMaybe; - -// Like AutoLock but permits Release() of its mutex before destruction. -// Release() may be called at most once. Inspired from -// absl::ReleasableMutexLock. Use this instead of std::optional -// to get around -Wthread-safety-analysis warnings for AutoLocks that are -// explicitly released early (prefer proper scoping to this). -using ReleasableAutoLock = internal::BasicReleasableAutoLock; - -} // namespace base - -#endif // BASE_SYNCHRONIZATION_LOCK_H_ diff --git a/bridge/bindings/v8/base/synchronization/lock_impl.h b/bridge/bindings/v8/base/synchronization/lock_impl.h deleted file mode 100644 index fb9f816bad..0000000000 --- a/bridge/bindings/v8/base/synchronization/lock_impl.h +++ /dev/null @@ -1,313 +0,0 @@ -/* -* Copyright (C) 2019-2022 The Kraken authors. All rights reserved. -* Copyright (C) 2022-present The WebF authors. All rights reserved. -*/ - -#ifndef BASE_SYNCHRONIZATION_LOCK_IMPL_H_ -#define BASE_SYNCHRONIZATION_LOCK_IMPL_H_ - -#include - -#include "bindings/v8/base/base_export.h" -#include "bindings/v8/base/check.h" -#include "bindings/v8/base/dcheck_is_on.h" -#include "bindings/v8/base/memory/raw_ptr_exclusion.h" -#include "bindings/v8/base/memory/stack_allocated.h" -#include "bindings/v8/base/thread_annotations.h" -#include "bindings/v8/for_build/build_config.h" - -#if BUILDFLAG(IS_WIN) -#include "base/win/windows_types.h" -#elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA) -#include -#include -#include -#endif - -namespace base { -class Lock; -class ConditionVariable; - -namespace win { -namespace internal { -class AutoNativeLock; -class ScopedHandleVerifier; -} // namespace internal -} // namespace win - -namespace internal { - -// This class implements the underlying platform-specific spin-lock mechanism -// used for the Lock class. Do not use, use Lock instead. -class BASE_EXPORT LockImpl { - public: - LockImpl(const LockImpl&) = delete; - LockImpl& operator=(const LockImpl&) = delete; - - private: - friend class base::Lock; - friend class base::ConditionVariable; - friend class base::win::internal::AutoNativeLock; - friend class base::win::internal::ScopedHandleVerifier; - -#if BUILDFLAG(IS_WIN) - using NativeHandle = CHROME_SRWLOCK; -#elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA) - using NativeHandle = pthread_mutex_t; -#endif - - LockImpl(); - ~LockImpl(); - - // If the lock is not held, take it and return true. If the lock is already - // held by something else, immediately return false. - inline bool Try(); - - // Take the lock, blocking until it is available if necessary. - inline void Lock(); - - // Release the lock. This must only be called by the lock's holder: after - // a successful call to Try, or a call to Lock. - inline void Unlock(); - - // Return the native underlying lock. - // TODO(awalker): refactor lock and condition variables so that this is - // unnecessary. - NativeHandle* native_handle() { return &native_handle_; } - -#if BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA) - // Whether this lock will attempt to use priority inheritance. - static bool PriorityInheritanceAvailable(); -#endif - - void LockInternal(); - NativeHandle native_handle_; -}; - -void LockImpl::Lock() { - // Try the lock first to acquire it cheaply if it's not contended. Try() is - // cheap on platforms with futex-type locks, as it doesn't call into the - // kernel. Not marked LIKELY(), as: - // 1. We don't know how much contention the lock would experience - // 2. This may lead to weird-looking code layout when inlined into a caller - // with (UN)LIKELY() annotations. - if (Try()) { - return; - } - - LockInternal(); -} - -#if BUILDFLAG(IS_WIN) -bool LockImpl::Try() { - return !!::TryAcquireSRWLockExclusive( - reinterpret_cast(&native_handle_)); -} - -void LockImpl::Unlock() { - ::ReleaseSRWLockExclusive(reinterpret_cast(&native_handle_)); -} - -#elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA) - -#if DCHECK_IS_ON() -BASE_EXPORT void dcheck_trylock_result(int rv); -BASE_EXPORT void dcheck_unlock_result(int rv); -#endif - -bool LockImpl::Try() { - int rv = pthread_mutex_trylock(&native_handle_); -#if DCHECK_IS_ON() - dcheck_trylock_result(rv); -#endif - return rv == 0; -} - -void LockImpl::Unlock() { - [[maybe_unused]] int rv = pthread_mutex_unlock(&native_handle_); -#if DCHECK_IS_ON() - dcheck_unlock_result(rv); -#endif -} -#endif - -// This is an implementation used for AutoLock templated on the lock type. -template -class SCOPED_LOCKABLE BasicAutoLock { - STACK_ALLOCATED(); - - public: - struct AlreadyAcquired {}; - - explicit BasicAutoLock(LockType& lock) EXCLUSIVE_LOCK_FUNCTION(lock) - : lock_(lock) { - lock_.Acquire(); - } - - BasicAutoLock(LockType& lock, const AlreadyAcquired&) - EXCLUSIVE_LOCKS_REQUIRED(lock) - : lock_(lock) { - lock_.AssertAcquired(); - } - - BasicAutoLock(const BasicAutoLock&) = delete; - BasicAutoLock& operator=(const BasicAutoLock&) = delete; - - ~BasicAutoLock() UNLOCK_FUNCTION() { - lock_.AssertAcquired(); - lock_.Release(); - } - - private: - LockType& lock_; -}; - -// This is an implementation used for MovableAutoLock templated on the lock -// type. -template -class SCOPED_LOCKABLE BasicMovableAutoLock { - public: - explicit BasicMovableAutoLock(LockType& lock) EXCLUSIVE_LOCK_FUNCTION(lock) - : lock_(&lock) { - lock_->Acquire(); - } - - BasicMovableAutoLock(const BasicMovableAutoLock&) = delete; - BasicMovableAutoLock& operator=(const BasicMovableAutoLock&) = delete; - BasicMovableAutoLock(BasicMovableAutoLock&& other) : - lock_(std::exchange(other.lock_, nullptr)) {} - BasicMovableAutoLock& operator=(BasicMovableAutoLock&& other) = delete; - - ~BasicMovableAutoLock() UNLOCK_FUNCTION() { - // The lock may have been moved out. - if (lock_) { - lock_->AssertAcquired(); - lock_->Release(); - } - } - - private: - // RAW_PTR_EXCLUSION: Stack-scoped. - RAW_PTR_EXCLUSION LockType* lock_; -}; - -// This is an implementation used for AutoTryLock templated on the lock type. -template -class SCOPED_LOCKABLE BasicAutoTryLock { - STACK_ALLOCATED(); - - public: - // The `LOCKS_EXCLUDED(lock)` annotation requires that the caller has not - // acquired `lock`. Without the annotation, Clang's Thread Safety Analysis - // would generate a false positive despite correct usage. For instance, a - // caller that checks `is_acquired()` before writing to guarded data would be - // flagged with "writing variable 'foo' requires holding 'lock' exclusively." - // See . - explicit BasicAutoTryLock(LockType& lock) LOCKS_EXCLUDED(lock) - : lock_(lock), is_acquired_(lock_.Try()) {} - - BasicAutoTryLock(const BasicAutoTryLock&) = delete; - BasicAutoTryLock& operator=(const BasicAutoTryLock&) = delete; - - ~BasicAutoTryLock() UNLOCK_FUNCTION() { - if (is_acquired_) { - lock_.AssertAcquired(); - lock_.Release(); - } - } - - bool is_acquired() const EXCLUSIVE_TRYLOCK_FUNCTION(true) { - return is_acquired_; - } - - private: - LockType& lock_; - const bool is_acquired_; -}; - -// This is an implementation used for AutoUnlock templated on the lock type. -template -class BasicAutoUnlock { - STACK_ALLOCATED(); - - public: - explicit BasicAutoUnlock(LockType& lock) : lock_(lock) { - // We require our caller to have the lock. - lock_.AssertAcquired(); - lock_.Release(); - } - - BasicAutoUnlock(const BasicAutoUnlock&) = delete; - BasicAutoUnlock& operator=(const BasicAutoUnlock&) = delete; - - ~BasicAutoUnlock() { lock_.Acquire(); } - - private: - LockType& lock_; -}; - -// This is an implementation used for AutoLockMaybe templated on the lock type. -template -class SCOPED_LOCKABLE BasicAutoLockMaybe { - STACK_ALLOCATED(); - - public: - explicit BasicAutoLockMaybe(LockType* lock) EXCLUSIVE_LOCK_FUNCTION(lock) - : lock_(lock) { - if (lock_) - lock_->Acquire(); - } - - BasicAutoLockMaybe(const BasicAutoLockMaybe&) = delete; - BasicAutoLockMaybe& operator=(const BasicAutoLockMaybe&) = delete; - - ~BasicAutoLockMaybe() UNLOCK_FUNCTION() { - if (lock_) { - lock_->AssertAcquired(); - lock_->Release(); - } - } - - private: - LockType* const lock_; -}; - -// This is an implementation used for ReleasableAutoLock templated on the lock -// type. -template -class SCOPED_LOCKABLE BasicReleasableAutoLock { - STACK_ALLOCATED(); - - public: - explicit BasicReleasableAutoLock(LockType* lock) EXCLUSIVE_LOCK_FUNCTION(lock) - : lock_(lock) { - DCHECK(lock_); - lock_->Acquire(); - } - - BasicReleasableAutoLock(const BasicReleasableAutoLock&) = delete; - BasicReleasableAutoLock& operator=(const BasicReleasableAutoLock&) = delete; - - ~BasicReleasableAutoLock() UNLOCK_FUNCTION() { - if (lock_) { - lock_->AssertAcquired(); - lock_->Release(); - } - } - - void Release() UNLOCK_FUNCTION() { - DCHECK(lock_); - lock_->AssertAcquired(); - lock_->Release(); - lock_ = nullptr; - } - - private: - LockType* lock_; -}; - -} // namespace internal -} // namespace base - -#endif // BASE_SYNCHRONIZATION_LOCK_IMPL_H_ - diff --git a/bridge/bindings/v8/gin/per_context_data.h b/bridge/bindings/v8/gin/per_context_data.h index 6b30068843..a4b63386c3 100644 --- a/bridge/bindings/v8/gin/per_context_data.h +++ b/bridge/bindings/v8/gin/per_context_data.h @@ -41,8 +41,8 @@ class GIN_EXPORT PerContextData { ContextHolder* context_holder() { return context_holder_; } private: - raw_ptr context_holder_; - raw_ptr runner_; + ContextHolder *context_holder_; + Runner *runner_; }; } // namespace gin diff --git a/bridge/bindings/v8/gin/public/isolate_holder.h b/bridge/bindings/v8/gin/public/isolate_holder.h index 747648d7b3..500b2adc32 100644 --- a/bridge/bindings/v8/gin/public/isolate_holder.h +++ b/bridge/bindings/v8/gin/public/isolate_holder.h @@ -156,7 +156,7 @@ class GIN_EXPORT IsolateHolder { void SetUp(scoped_refptr task_runner); std::unique_ptr snapshot_creator_; - raw_ptr isolate_; + v8::Isolate *isolate_; std::unique_ptr isolate_data_; std::unique_ptr isolate_memory_dump_provider_; AccessMode access_mode_; diff --git a/bridge/bindings/v8/platform/heap/collection_support/heap_hash_map.h b/bridge/bindings/v8/platform/heap/collection_support/heap_hash_map.h deleted file mode 100644 index a28b977ca4..0000000000 --- a/bridge/bindings/v8/platform/heap/collection_support/heap_hash_map.h +++ /dev/null @@ -1,71 +0,0 @@ -/* -* Copyright (C) 2019-2022 The Kraken authors. All rights reserved. -* Copyright (C) 2022-present The WebF authors. All rights reserved. -*/ - -#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_COLLECTION_SUPPORT_HEAP_HASH_MAP_H_ -#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_COLLECTION_SUPPORT_HEAP_HASH_MAP_H_ - -#include "bindings/v8/trace_wrapper_v8_reference.h" -#include "bindings/v8/platform/heap/garbage_collected.h" -#include "bindings/v8/platform/heap/heap_allocator_impl.h" -#include "bindings/v8/platform/wtf/hash_map.h" - -namespace webf { - -template , - typename MappedTraitsArg = HashTraits> -class HeapHashMap final - : public GarbageCollected< - HeapHashMap>, - public HashMap { - DISALLOW_NEW(); - - public: - HeapHashMap() = default; - - void Trace(Visitor* visitor) const { - HashMap::Trace(visitor); - } - - private: - template - static constexpr bool IsValidNonTraceableType() { - return !webf::IsTraceable::value && !webf::IsPointerToGced::value; - } - - struct TypeConstraints { - constexpr TypeConstraints() { - static_assert(std::is_trivially_destructible_v, - "HeapHashMap must be trivially destructible."); - static_assert( - webf::IsTraceable::value || webf::IsTraceable::value, - "For hash maps without traceable elements, use HashMap<> " - "instead of HeapHashMap<>."); - static_assert(webf::IsMemberOrWeakMemberType::value || - IsValidNonTraceableType(), - "HeapHashMap supports only Member, WeakMember and " - "non-traceable types as keys."); - static_assert( - webf::IsMemberOrWeakMemberType::value || - IsValidNonTraceableType() || - webf::IsSubclassOfTemplate::value, - "HeapHashMap supports only Member, WeakMember, " - "TraceWrapperV8Reference and " - "non-traceable types as values."); - } - }; - // NO_UNIQUE_ADDRESS TypeConstraints type_constraints_; -}; - -} // namespace webf - -#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_COLLECTION_SUPPORT_HEAP_HASH_MAP_H_ - diff --git a/bridge/bindings/v8/platform/heap/collection_support/heap_hash_table_backing.h b/bridge/bindings/v8/platform/heap/collection_support/heap_hash_table_backing.h deleted file mode 100644 index 005723e996..0000000000 --- a/bridge/bindings/v8/platform/heap/collection_support/heap_hash_table_backing.h +++ /dev/null @@ -1,369 +0,0 @@ -/* -* Copyright (C) 2019-2022 The Kraken authors. All rights reserved. -* Copyright (C) 2022-present The WebF authors. All rights reserved. -*/ - -#ifndef WEBF_HEAP_HASH_TABLE_BACKING_H_ -#define WEBF_HEAP_HASH_TABLE_BACKING_H_ - -#include - -//#include "bindings/v8/base/check_op.h" -#include "bindings/v8/platform/heap/custom_spaces.h" -#include "bindings/v8/platform/heap/garbage_collected.h" -#include "bindings/v8/platform/heap/thread_state_storage.h" -#include "bindings/v8/platform/wtf/conditional_destructor.h" -#include "bindings/v8/platform/wtf/hash_table.h" -#include "bindings/v8/platform/wtf/hash_traits.h" -#include "bindings/v8/platform/wtf/key_value_pair.h" -#include "bindings/v8/platform/wtf/sanitizers.h" -#include "bindings/v8/platform/wtf/type_traits.h" -#include -#include -#include -#include "bindings/v8/platform/heap/trace_traits.h" - -namespace webf { - -template -class HeapHashTableBacking final - : public GarbageCollected>, - public webf::ConditionalDestructor< - HeapHashTableBacking, - !std::is_trivially_destructible::value> { - using ClassType = HeapHashTableBacking
; - using ValueType = typename Table::ValueType; - - public: - // Although the HeapHashTableBacking is fully constructed, the array resulting - // from ToArray may not be fully constructed as the elements of the array are - // not initialized and may have null vtable pointers. Null vtable pointer - // violates CFI for polymorphic types. - ALWAYS_INLINE NO_SANITIZE_UNRELATED_CAST static ValueType* ToArray( - ClassType* backing) { - return reinterpret_cast(backing); - } - - ALWAYS_INLINE static ClassType* FromArray(ValueType* array) { - return reinterpret_cast(array); - } - - void Free(cppgc::HeapHandle& heap_handle) { - cppgc::subtle::FreeUnreferencedObject(heap_handle, *this); - } - - bool Resize(size_t new_size) { - return cppgc::subtle::Resize(*this, GetAdditionalBytes(new_size)); - } - - // Conditionally invoked via destructor. - void Finalize(); - - private: - static cppgc::AdditionalBytes GetAdditionalBytes(size_t wanted_array_size) { - // HHTB is an empty class that's purely used with inline storage. Since its - // sizeof(HHTB) == 1, we need to subtract its size to avoid wasting storage. - static_assert(sizeof(ClassType) == 1, "Class declaration changed"); -// DCHECK_GE(wanted_array_size, sizeof(ClassType)); - return cppgc::AdditionalBytes{wanted_array_size - sizeof(ClassType)}; - } -}; - -template -void HeapHashTableBacking
::Finalize() { - using Value = typename Table::ValueType; - static_assert( - !std::is_trivially_destructible::value, - "Finalization of trivially destructible classes should not happen."); - const size_t object_size = - cppgc::subtle::ObjectSizeTrait>::GetSize( - *this); - const size_t length = object_size / sizeof(Value); - Value* table = reinterpret_cast(this); - for (unsigned i = 0; i < length; ++i) { - if (!Table::IsEmptyOrDeletedBucket(table[i])) - table[i].~Value(); - } -} - -template -struct ThreadingTrait> { - STATIC_ONLY(ThreadingTrait); - using Key = typename Table::KeyType; - using Value = typename Table::ValueType; - static constexpr ThreadAffinity kAffinity = - (ThreadingTrait::kAffinity == kMainThreadOnly) && - (ThreadingTrait::kAffinity == kMainThreadOnly) - ? kMainThreadOnly - : kAnyThread; -}; - -template -struct ThreadingTrait> { - STATIC_ONLY(ThreadingTrait); - static constexpr ThreadAffinity kAffinity = - (ThreadingTrait::kAffinity == kMainThreadOnly) && - (ThreadingTrait::kAffinity == kMainThreadOnly) - ? kMainThreadOnly - : kAnyThread; -}; - -} // namespace webf - -namespace webf { - -namespace internal { - -// ConcurrentBucket is a wrapper for HashTable buckets for concurrent marking. -// It is used to provide a snapshot view of the bucket key and guarantee -// that the same key is used for checking empty/deleted buckets and tracing. -template -class ConcurrentBucket { - using KeyExtractionCallback = void (*)(const T&, void*); - - public: - using BucketType = T; - - ConcurrentBucket(const T& t, KeyExtractionCallback extract_key) { - extract_key(t, &buf_); - } - - // for HashTable that don't use KeyValuePair (i.e. *HashSets), the key - // and the value are the same. - const T* key() const { return reinterpret_cast(&buf_); } - const T* value() const { return key(); } - const T* bucket() const { return key(); } - - private: - // Alignment is needed for atomic accesses to |buf_| and to assure |buf_| - // can be accessed the same as objects of type T - static constexpr size_t boundary = std::max(alignof(T), sizeof(size_t)); - alignas(boundary) char buf_[sizeof(T)]; -}; - -template -class ConcurrentBucket> { - using KeyExtractionCallback = void (*)(const KeyValuePair&, - void*); - - public: - using BucketType = ConcurrentBucket; - - ConcurrentBucket(const KeyValuePair& pair, - KeyExtractionCallback extract_key) - : value_(&pair.value) { - extract_key(pair, &buf_); - } - - const Key* key() const { return reinterpret_cast(&buf_); } - const Value* value() const { return value_; } - const ConcurrentBucket* bucket() const { return this; } - - private: - // Alignment is needed for atomic accesses to |buf_| and to assure |buf_| - // can be accessed the same as objects of type Key - static constexpr size_t boundary = std::max(alignof(Key), sizeof(size_t)); - alignas(boundary) char buf_[sizeof(Key)]; - const Value* value_; -}; - -} // namespace webf - -template -struct TraceHashTableBackingInCollectionTrait { - using Value = typename Table::ValueType; - using Traits = typename Table::ValueTraits; - using Extractor = typename Table::ExtractorType; - - static void Trace(webf::Visitor* visitor, const void* self) { - static_assert(IsTraceable::value || webf::IsWeak::value, - "Table should not be traced"); - const Value* array = reinterpret_cast(self); - const size_t length = - cppgc::subtle:: - ObjectSizeTrait>::GetSize( - *reinterpret_cast*>( - self)) / - sizeof(Value); - for (size_t i = 0; i < length; ++i) { - internal::ConcurrentBucket concurrent_bucket( - array[i], Extractor::ExtractKeyToMemory); - if (!webf::IsHashTraitsEmptyOrDeletedValue( - *concurrent_bucket.key())) { - webf::TraceCollectionIfEnabled< - weak_handling, - typename internal::ConcurrentBucket::BucketType, - Traits>::Trace(visitor, concurrent_bucket.bucket()); - } - } - } -}; - -template -struct TraceInCollectionTrait, - void> { - static void Trace(webf::Visitor* visitor, const void* self) { - TraceHashTableBackingInCollectionTrait::Trace( - visitor, self); - } -}; - -template -struct TraceInCollectionTrait, - void> { - static void Trace(webf::Visitor* visitor, const void* self) { - TraceHashTableBackingInCollectionTrait::Trace(visitor, - self); - } -}; - -template -struct TraceInCollectionTrait< - kNoWeakHandling, - internal::ConcurrentBucket>, - Traits> { - static void Trace( - webf::Visitor* visitor, - const internal::ConcurrentBucket>& self) { - webf::internal::KeyValuePairInCollectionTrait::Trace(visitor, - self.key(), - self.value()); - } -}; - -template -struct TraceInCollectionTrait< - kWeakHandling, - internal::ConcurrentBucket>, - Traits> { - static void Trace( - webf::Visitor* visitor, - const internal::ConcurrentBucket>& self) { - webf::internal::KeyValuePairInCollectionTrait::Trace(visitor, - self.key(), - self.value()); - } -}; - -template -struct IsWeak> : IsWeak {}; - -template -struct IsTraceable> : IsTraceable {}; - -} // namespace webf - -namespace cppgc { - -template -struct SpaceTrait> { - using Space = webf::CompactableHeapHashTableBackingSpace; -}; - -// Custom allocation accounts for inlined storage of the actual elements of the -// backing table. -template -class MakeGarbageCollectedTrait> - : public MakeGarbageCollectedTraitBase> { - public: - using Backing = webf::HeapHashTableBacking
; - - template - static Backing* Call(AllocationHandle& handle, size_t num_elements) { - static_assert( - !std::is_polymorphic>::value, - "HeapHashTableBacking must not be polymorphic as it is converted to a " - "raw array of buckets for certain operation"); -// CHECK_GT(num_elements, 0u); - // Allocate automatically considers the custom space via SpaceTrait. - void* memory = MakeGarbageCollectedTraitBase::Allocate( - handle, sizeof(typename Table::ValueType) * num_elements); - Backing* object = ::new (memory) Backing(); - MakeGarbageCollectedTraitBase::MarkObjectAsFullyConstructed( - object); - return object; - } -}; - -template -struct TraceTrait> { - using Backing = webf::HeapHashTableBacking
; - using Traits = typename Table::ValueTraits; - using ValueType = typename Table::ValueTraits::TraitType; - - static TraceDescriptor GetTraceDescriptor(const void* self) { - return {self, Trace}; - } - - static TraceDescriptor GetWeakTraceDescriptor(const void* self) { - return GetWeakTraceDescriptorImpl::GetWeakTraceDescriptor(self); - } - - template - static void Trace(Visitor* visitor, const void* self) { - if (!Traits::kCanTraceConcurrently && self) { - if (visitor->DeferTraceToMutatorThreadIfConcurrent( - self, &Trace, - cppgc::subtle::ObjectSizeTrait::GetSize( - *reinterpret_cast(self)))) { - return; - } - } - - static_assert( - webf::IsTraceable::value || webf::IsWeak::value, - "T should not be traced"); - webf::TraceInCollectionTrait::Trace(visitor, - self); - } - - private: - // Default setting for HashTable is without weak trace descriptor. - template - struct GetWeakTraceDescriptorImpl { - static TraceDescriptor GetWeakTraceDescriptor(const void* self) { - return {self, nullptr}; - } - }; - - // Specialization for WTF::KeyValuePair, which is default bucket storage type. - template - struct GetWeakTraceDescriptorImpl> { - static TraceDescriptor GetWeakTraceDescriptor(const void* backing) { - return GetWeakTraceDescriptorKVPImpl::GetWeakTraceDescriptor( - backing); - } - - // Default setting for KVP without ephemeron semantics. - template ::value && - !webf::IsWeak::value && - webf::IsTraceable::value) || - (webf::IsWeak::value && - !webf::IsWeak::value && - webf::IsTraceable::value)> - struct GetWeakTraceDescriptorKVPImpl { - static TraceDescriptor GetWeakTraceDescriptor(const void* backing) { - return {backing, nullptr}; - } - }; - - // Specialization for KVP with ephemeron semantics. - template - struct GetWeakTraceDescriptorKVPImpl { - static TraceDescriptor GetWeakTraceDescriptor(const void* backing) { - return {backing, Trace}; - } - }; - }; -}; - -} // namespace cppgc - -#endif // WEBF_HEAP_HASH_TABLE_BACKING_H_ - diff --git a/bridge/bindings/v8/platform/heap/collection_support/heap_vector_backing.h b/bridge/bindings/v8/platform/heap/collection_support/heap_vector_backing.h deleted file mode 100644 index 72e9647e22..0000000000 --- a/bridge/bindings/v8/platform/heap/collection_support/heap_vector_backing.h +++ /dev/null @@ -1,248 +0,0 @@ -/* -* Copyright (C) 2019-2022 The Kraken authors. All rights reserved. -* Copyright (C) 2022-present The WebF authors. All rights reserved. -*/ - -#ifndef WEBF_HEAP_COLLECTION_SUPPORT_HEAP_VECTOR_BACKING_H_ -#define WEBF_HEAP_COLLECTION_SUPPORT_HEAP_VECTOR_BACKING_H_ - -#include -#include "bindings/v8/base/check_op.h" -#include "bindings/v8/platform/heap/custom_spaces.h" -#include "bindings/v8/platform/heap/garbage_collected.h" -#include "bindings/v8/platform/heap/member.h" -#include "bindings/v8/platform/heap/thread_state_storage.h" -#include "bindings/v8/platform/wtf/conditional_destructor.h" -#include "bindings/v8/platform/wtf/sanitizers.h" -#include "bindings/v8/platform/wtf/type_traits.h" -#include "bindings/v8/platform/wtf/vector_traits.h" -#include -#include -#include -#include -#include -#include - -namespace webf { -namespace internal { - -inline bool VTableInitialized(const void* object_payload) { - return !!(*reinterpret_cast(object_payload)); -} - -} // namespace internal - -template > -class HeapVectorBacking final - : public GarbageCollected>, - public webf::ConditionalDestructor, - Traits::kNeedsDestruction> { - public: - using ClassType = HeapVectorBacking; - using TraitsType = Traits; - - // Although the HeapVectorBacking is fully constructed, the array resulting - // from ToArray may not be fully constructed as the elements of the array are - // not initialized and may have null vtable pointers. Null vtable pointer - // violates CFI for polymorphic types. - ALWAYS_INLINE NO_SANITIZE_UNRELATED_CAST static T* ToArray( - ClassType* backing) { - return reinterpret_cast(backing); - } - - ALWAYS_INLINE static ClassType* FromArray(T* payload) { - return reinterpret_cast(payload); - } - - void Free(cppgc::HeapHandle& heap_handle) { - cppgc::subtle::FreeUnreferencedObject(heap_handle, *this); - } - - bool Resize(size_t new_size) { - return cppgc::subtle::Resize(*this, GetAdditionalBytes(new_size)); - } - - // Conditionally invoked via destructor. - void Finalize(); - - private: - static cppgc::AdditionalBytes GetAdditionalBytes(size_t wanted_array_size) { - // HVB is an empty class that's purely used with inline storage. Since its - // sizeof(HVB) == 1, we need to subtract its size to avoid wasting storage. - static_assert(sizeof(ClassType) == 1, "Class declaration changed"); - DCHECK_GE(wanted_array_size, sizeof(ClassType)); - return cppgc::AdditionalBytes{wanted_array_size - sizeof(ClassType)}; - } -}; - -template -void HeapVectorBacking::Finalize() { - static_assert(Traits::kNeedsDestruction, - "Only vector buffers with items requiring destruction should " - "be finalized"); - static_assert( - Traits::kCanClearUnusedSlotsWithMemset || std::is_polymorphic::value, - "HeapVectorBacking doesn't support objects that cannot be cleared as " - "unused with memset or don't have a vtable"); - static_assert( - !std::is_trivially_destructible::value, - "Finalization of trivially destructible classes should not happen."); - const size_t object_size = - cppgc::subtle::ObjectSizeTrait>::GetSize( - *this); - const size_t length = object_size / sizeof(T); - using ByteBuffer = uint8_t*; - ByteBuffer payload = reinterpret_cast(this); -#ifdef ANNOTATE_CONTIGUOUS_CONTAINER - ANNOTATE_CHANGE_SIZE(payload, length * sizeof(T), 0, length * sizeof(T)); -#endif // ANNOTATE_CONTIGUOUS_CONTAINER - // HeapVectorBacking calls finalizers for unused slots and expects them to be - // no-ops. - if (std::is_polymorphic::value) { - for (size_t i = 0; i < length; ++i) { - ByteBuffer element = payload + i * sizeof(T); - if (internal::VTableInitialized(element)) - reinterpret_cast(element)->~T(); - } - } else { - T* buffer = reinterpret_cast(payload); - for (size_t i = 0; i < length; ++i) - buffer[i].~T(); - } -} - -template -struct ThreadingTrait> { - STATIC_ONLY(ThreadingTrait); - static constexpr ThreadAffinity kAffinity = ThreadingTrait::kAffinity; -}; - -} // namespace webf - -namespace webf { - -// This trace method is used for all HeapVectorBacking objects. On-stack objects -// are found and dispatched using conservative stack scanning. HeapVector (i.e. -// Vector) dispatches all regular on-heap backings to this method. -template -struct TraceInCollectionTrait, - void> { - using Backing = webf::HeapVectorBacking; - - static void Trace(webf::Visitor* visitor, const void* self) { - // HeapVectorBacking does not know the exact size of the vector - // and just knows the capacity of the vector. Due to the constraint, - // HeapVectorBacking can support only the following objects: - // - // - An object that has a vtable. In this case, HeapVectorBacking - // traces only slots that are not zeroed out. This is because if - // the object has a vtable, the zeroed slot means that it is - // an unused slot (Remember that the unused slots are guaranteed - // to be zeroed out by VectorUnusedSlotClearer). - // - // - An object that can be initialized with memset. In this case, - // HeapVectorBacking traces all slots including unused slots. - // This is fine because the fact that the object can be initialized - // with memset indicates that it is safe to treat the zerod slot - // as a valid object. - static_assert( - Traits::kCanClearUnusedSlotsWithMemset || std::is_polymorphic::value, - "HeapVectorBacking doesn't support objects that cannot be " - "cleared as unused with memset."); - - // Bail out early if the contents are not actually traceable. - if constexpr (!IsTraceable::value) { - return; - } - - const T* array = reinterpret_cast(self); - const size_t length = - cppgc::subtle::ObjectSizeTrait::GetSize( - *reinterpret_cast(self)) / - sizeof(T); -#ifdef ANNOTATE_CONTIGUOUS_CONTAINER - // As commented above, HeapVectorBacking can trace unused slots (which are - // already zeroed out). - ANNOTATE_CHANGE_SIZE(array, length, 0, length); -#endif // ANNOTATE_CONTIGUOUS_CONTAINER - if constexpr (IsTraceable::value) { - for (unsigned i = 0; i < length; ++i) { - if (!std::is_polymorphic_v || - webf::internal::VTableInitialized(&array[i])) { - visitor->Trace(array[i]); - } - } - } - } -}; - -} // namespace webf - -namespace cppgc { - -// The space trait rewires allocations for HeapVector with `kCanMoveWithMemcpy` -// into a space supporting compaction. -template -struct SpaceTrait, - std::enable_if_t::TraitsType::kCanMoveWithMemcpy>> { - using Space = webf::CompactableHeapVectorBackingSpace; -}; - -// Custom allocation accounts for inlined storage of the actual elements of the -// backing array. -template -class MakeGarbageCollectedTrait> - : public MakeGarbageCollectedTraitBase> { - using Backing = webf::HeapVectorBacking; - - public: - template - static Backing* Call(AllocationHandle& handle, size_t num_elements) { - static_assert(!std::is_polymorphic>::value, - "HeapVectorBacking must not be polymorphic as it is " - "converted to a raw array of buckets for certain operation"); - CHECK_GT(num_elements, 0u); - // Allocate automatically considers the custom space via SpaceTrait. - void* memory = MakeGarbageCollectedTraitBase::Allocate( - handle, sizeof(T) * num_elements); - Backing* object = ::new (memory) Backing(); - MakeGarbageCollectedTraitBase::MarkObjectAsFullyConstructed( - object); - return object; - } -}; - -template -struct TraceTrait> { - using Backing = webf::HeapVectorBacking; - - static TraceDescriptor GetTraceDescriptor(const void* self) { - return {self, Trace}; - } - - static void Trace(Visitor* visitor, const void* self) { - if (!Traits::kCanTraceConcurrently && self) { - if (visitor->DeferTraceToMutatorThreadIfConcurrent( - self, &Trace, - cppgc::subtle::ObjectSizeTrait::GetSize( - *reinterpret_cast(self)))) { - return; - } - } - - static_assert(!webf::IsWeak::value, - "Weakness is not supported in HeapVector and HeapDeque"); - if (webf::IsTraceable::value) { - webf::TraceInCollectionTrait, - void>::Trace(visitor, self); - } - } -}; - -} // namespace cppgc - -#endif // WEBF_HEAP_COLLECTION_SUPPORT_HEAP_VECTOR_BACKING_H_ - diff --git a/bridge/bindings/v8/platform/heap/heap_allocator_impl.h b/bridge/bindings/v8/platform/heap/heap_allocator_impl.h deleted file mode 100644 index 8b58417e96..0000000000 --- a/bridge/bindings/v8/platform/heap/heap_allocator_impl.h +++ /dev/null @@ -1,313 +0,0 @@ -/* -* Copyright (C) 2019-2022 The Kraken authors. All rights reserved. -* Copyright (C) 2022-present The WebF authors. All rights reserved. -*/ - -#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_HEAP_ALLOCATOR_IMPL_H_ -#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_HEAP_ALLOCATOR_IMPL_H_ - -#include "bindings/v8/platform/platform_export.h" -#include "bindings/v8/platform/wtf/key_value_pair.h" -#include -#include -#include -#include -#include -#include "bindings/v8/platform/heap/garbage_collected.h" -#include "bindings/v8/platform/util/allocator/partition_allocator.h" -#include "bindings/v8/base/bits.h" -#include "bindings/v8/platform/heap/collection_support/heap_vector_backing.h" -#include "bindings/v8/platform/heap/collection_support/heap_hash_table_backing.h" - -namespace webf { - -template -void GenerationalBarrierForBacking( - const cppgc::subtle::HeapConsistency::WriteBarrierParams& params, - T* slot_in_backing); - -template -void GenerationalBarrierForBacking( - const cppgc::subtle::HeapConsistency::WriteBarrierParams& params, - std::pair* slot_in_backing); - -template -void GenerationalBarrierForBacking( - const cppgc::subtle::HeapConsistency::WriteBarrierParams& params, - webf::KeyValuePair* slot_in_backing); - -class PLATFORM_EXPORT HeapAllocator { - STATIC_ONLY(HeapAllocator); - - public: - using HeapConsistency = cppgc::subtle::HeapConsistency; - using LivenessBroker = webf::LivenessBroker; - using TraceCallback = cppgc::TraceCallback; - using WeakCallback = cppgc::WeakCallback; - - static constexpr bool kIsGarbageCollected = true; - - template - static size_t MaxElementCountInBackingStore() { - // Oilpan doesn't have a limit for supported capacity and instead supports - // arbitrary sized allocations. Delegate to PA to keep limits in sync which - // may be enforced for security reasons. E.g. PA may cap the limit below - // 32-bit sizes to avoid integer overflows in old code. - return util::PartitionAllocator::MaxElementCountInBackingStore(); - } - - template - static size_t QuantizedSize(size_t count) { - CHECK_LE(count, MaxElementCountInBackingStore()); - // Oilpan's internal size is independent of MaxElementCountInBackingStore() - // and the required size to match capacity needs. Align the size by Oilpan - // allocation granularity. This also helps us with ASAN API for container - // annotation, which requires 8-byte alignment for the range. - return base::bits::AlignUp( - count * sizeof(T), - cppgc::internal::api_constants::kAllocationGranularity); - } - - template - static T* AllocateVectorBacking(size_t size) { - return HeapVectorBacking::ToArray( - MakeGarbageCollected>(size / sizeof(T))); - } - - template - static void FreeVectorBacking(T* array) { - if (!array) - return; - - HeapVectorBacking::FromArray(array)->Free( - ThreadStateStorageFor::kAffinity>::GetState() - ->heap_handle()); - } - - template - static bool ExpandVectorBacking(T* array, size_t new_size) { - DCHECK(array); - return HeapVectorBacking::FromArray(array)->Resize(new_size); - } - - template - static bool ShrinkVectorBacking(T* array, size_t, size_t new_size) { - DCHECK(array); - return HeapVectorBacking::FromArray(array)->Resize(new_size); - } - - template - static T* AllocateHashTableBacking(size_t size) { - static_assert(sizeof(T) == sizeof(typename HashTable::ValueType), - "T must match ValueType."); - return HeapHashTableBacking::ToArray( - MakeGarbageCollected>(size / - sizeof(T))); - } - - template - static T* AllocateZeroedHashTableBacking(size_t size) { - return AllocateHashTableBacking(size); - } - - template - static void FreeHashTableBacking(T* array) { - if (!array) - return; - - HeapHashTableBacking::FromArray(array)->Free( - ThreadStateStorageFor>::kAffinity>::GetState() - ->heap_handle()); - } - - template - static bool ExpandHashTableBacking(T* array, size_t new_size) { - DCHECK(array); - return HeapHashTableBacking::FromArray(array)->Resize(new_size); - } - - static bool IsAllocationAllowed() { - return cppgc::subtle::DisallowGarbageCollectionScope:: - IsGarbageCollectionAllowed( - ThreadStateStorage::Current()->heap_handle()); - } - - static bool IsIncrementalMarking() { - auto& heap_handle = ThreadStateStorage::Current()->heap_handle(); - return cppgc::subtle::HeapState::IsMarking(heap_handle) && - !cppgc::subtle::HeapState::IsInAtomicPause(heap_handle); - } - - static void EnterGCForbiddenScope() { - cppgc::subtle::NoGarbageCollectionScope::Enter( - ThreadStateStorage::Current()->heap_handle()); - } - - static void LeaveGCForbiddenScope() { - cppgc::subtle::NoGarbageCollectionScope::Leave( - ThreadStateStorage::Current()->heap_handle()); - } - - template - static bool CanReuseHashTableDeletedBucket() { - if (Traits::kEmptyValueIsZero || !Traits::kCanTraceConcurrently) - return true; - return !IsIncrementalMarking(); - } - - template - static void BackingWriteBarrier(T** backing_pointer_slot) { - WriteBarrier::DispatchForUncompressedSlot(backing_pointer_slot, - *backing_pointer_slot); - } - - template - static void TraceBackingStoreIfMarked(T* object) { - HeapConsistency::WriteBarrierParams params; - if (HeapConsistency::GetWriteBarrierType(object, params) == - HeapConsistency::WriteBarrierType::kMarking) { - HeapConsistency::SteeleWriteBarrier(params, object); - } - } - - template - static void NotifyNewObject(T* slot_in_backing) { - HeapConsistency::WriteBarrierParams params; - // `slot_in_backing` points into a backing store and T is not necessarily a - // garbage collected type but may be kept inline. - switch (HeapConsistency::GetWriteBarrierType( - slot_in_backing, params, []() -> cppgc::HeapHandle& { - return ThreadStateStorageFor::kAffinity>::GetState() - ->heap_handle(); - })) { - case HeapConsistency::WriteBarrierType::kMarking: - HeapConsistency::DijkstraWriteBarrierRange( - params, slot_in_backing, sizeof(T), 1, - TraceCollectionIfEnabled::Trace); - break; - case HeapConsistency::WriteBarrierType::kGenerational: - GenerationalBarrierForBacking(params, slot_in_backing); - break; - case HeapConsistency::WriteBarrierType::kNone: - break; - default: - break; // TODO(1056170): Remove default case when API is stable. - } - } - - template - static void NotifyNewObjects(T* first_element, size_t length) { - HeapConsistency::WriteBarrierParams params; - // `first_element` points into a backing store and T is not necessarily a - // garbage collected type but may be kept inline. - switch (HeapConsistency::GetWriteBarrierType( - first_element, params, []() -> cppgc::HeapHandle& { - return ThreadStateStorageFor::kAffinity>::GetState() - ->heap_handle(); - })) { - case HeapConsistency::WriteBarrierType::kMarking: - HeapConsistency::DijkstraWriteBarrierRange( - params, first_element, sizeof(T), length, - TraceCollectionIfEnabled::Trace); - break; - case HeapConsistency::WriteBarrierType::kGenerational: - GenerationalBarrierForBacking(params, first_element); - break; - case HeapConsistency::WriteBarrierType::kNone: - break; - default: - break; // TODO(1056170): Remove default case when API is stable. - } - } - - template - static void Trace(Visitor* visitor, const T& t) { - TraceCollectionIfEnabled, T, Traits>::Trace( - visitor, &t); - } - - template - static void TraceVectorBacking(Visitor* visitor, - const T* backing, - const T* const* backing_slot) { - using BackingType = HeapVectorBacking; - - if constexpr (BackingType::TraitsType::kCanMoveWithMemcpy) { - visitor->RegisterMovableReference(const_cast( - reinterpret_cast(backing_slot))); - } - visitor->TraceStrongContainer( - reinterpret_cast(backing)); - } - - template - static void TraceHashTableBackingStrongly(Visitor* visitor, - const T* backing, - const T* const* backing_slot) { - visitor->RegisterMovableReference( - const_cast**>( - reinterpret_cast* const*>( - backing_slot))); - visitor->TraceStrongContainer( - reinterpret_cast*>(backing)); - } - - template - static void TraceHashTableBackingWeakly(Visitor* visitor, - const T* backing, - const T* const* backing_slot, - WeakCallback callback, - const void* parameter) { - visitor->RegisterMovableReference( - const_cast**>( - reinterpret_cast* const*>( - backing_slot))); - visitor->TraceWeakContainer( - reinterpret_cast*>(backing), - callback, parameter); - } - - static bool DeferTraceToMutatorThreadIfConcurrent(Visitor* visitor, - const void* object, - TraceCallback callback, - size_t deferred_size) { - return visitor->DeferTraceToMutatorThreadIfConcurrent(object, callback, - deferred_size); - } -}; - -template -void GenerationalBarrierForBacking( - const cppgc::subtle::HeapConsistency::WriteBarrierParams& params, - T* slot_in_backing) { - if constexpr (webf::IsMemberOrWeakMemberType>::value) { - // TODO(1029379): Provide Member::GetSlot() and call it here. - cppgc::subtle::HeapConsistency::GenerationalBarrier(params, - slot_in_backing); - } else if constexpr (webf::IsTraceable>::value) { - cppgc::subtle::HeapConsistency::GenerationalBarrierForSourceObject( - params, slot_in_backing); - } -} - -template -void GenerationalBarrierForBacking( - const cppgc::subtle::HeapConsistency::WriteBarrierParams& params, - std::pair* slot_in_backing) { - GenerationalBarrierForBacking(params, &slot_in_backing->first); - GenerationalBarrierForBacking(params, &slot_in_backing->second); -} - -template -void GenerationalBarrierForBacking( - const cppgc::subtle::HeapConsistency::WriteBarrierParams& params, - webf::KeyValuePair* slot_in_backing) { - GenerationalBarrierForBacking(params, &slot_in_backing->key); - GenerationalBarrierForBacking(params, &slot_in_backing->value); -} - -} // namespace webf - -#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_HEAP_ALLOCATOR_IMPL_H_ - diff --git a/bridge/bindings/v8/platform/heap/trace_traits.h b/bridge/bindings/v8/platform/heap/trace_traits.h deleted file mode 100644 index 2df4cd2b04..0000000000 --- a/bridge/bindings/v8/platform/heap/trace_traits.h +++ /dev/null @@ -1,327 +0,0 @@ -/* -* Copyright (C) 2019-2022 The Kraken authors. All rights reserved. -* Copyright (C) 2022-present The WebF authors. All rights reserved. -*/ - -#ifndef WEBF_HEAP_TRACE_TRAITS_H_ -#define WEBF_HEAP_TRACE_TRAITS_H_ - -#include - -#include "bindings/v8/base/notreached.h" -#include "bindings/v8/platform/heap/garbage_collected.h" -#include "bindings/v8/platform/heap/member.h" -//#include "third_party/blink/renderer/platform/heap/visitor.h" -#include "bindings/v8/platform/wtf/hash_table.h" -#include "bindings/v8/platform/wtf/key_value_pair.h" -#include "bindings/v8/platform/wtf/type_traits.h" -#include - -namespace webf { - -template -struct TraceIfNeeded { - STATIC_ONLY(TraceIfNeeded); - static void Trace(Visitor* visitor, const T& t) { - if constexpr (webf::IsTraceable::value) { - visitor->Trace(t); - } - } -}; - -// `WTF::IsWeak::value` is always false when used -// from vectors (on and off the GCed heap). -template ::value && - !webf::IsWeak::value, - webf::WeakHandlingFlag = webf::kWeakHandlingTrait> -struct TraceCollectionIfEnabled; - -template -struct TraceCollectionIfEnabled { - STATIC_ONLY(TraceCollectionIfEnabled); - - static bool IsAlive(const webf::LivenessBroker& info, const T&) { - return true; - } - - static void Trace(Visitor*, const void*) { - static_assert(!webf::IsTraceable::value || - webf::IsWeak::value, - "T should not be traced"); - } -}; - -template -struct TraceCollectionIfEnabled { - STATIC_ONLY(TraceCollectionIfEnabled); - - static void Trace(Visitor* visitor, const void* t) { - webf::TraceInCollectionTrait::Trace( - visitor, *reinterpret_cast(t)); - } -}; - -template -struct TraceCollectionIfEnabled { - STATIC_ONLY(TraceCollectionIfEnabled); - - static bool IsAlive(const webf::LivenessBroker& info, const T& traceable) { - return webf::TraceInCollectionTrait::IsAlive(info, - traceable); - } - - static void Trace(Visitor* visitor, const void* t) { - static_assert((webf::IsTraceable::value && - !webf::IsWeak::value) || - weakness == webf::kWeakHandling, - "Traits should be traced"); - webf::TraceInCollectionTrait::Trace( - visitor, *reinterpret_cast(t)); - } -}; - -namespace internal { - -// Helper for processing ephemerons represented as KeyValuePair. Reorders -// parameters if needed so that KeyType is always weak. -template ::value> -struct EphemeronKeyValuePair { - STACK_ALLOCATED(); - - public: - using KeyType = _KeyType; - using ValueType = _ValueType; - using KeyTraits = _KeyTraits; - using ValueTraits = _ValueTraits; - - // Ephemerons have different weakness for KeyType and ValueType. If weakness - // is equal, we either have Strong/Strong, or Weak/Weak, which would indicate - // a full strong or fully weak pair. - static constexpr bool kNeedsEphemeronSemantics = - webf::IsWeak::value != webf::IsWeak::value && - webf::IsTraceable::value; - - static_assert(!webf::IsWeak::value || - webf::IsWeakMemberType::value, - "Weakness must be encoded using WeakMember."); - static_assert(!webf::IsWeak::value || - webf::IsWeakMemberType::value, - "Weakness must be encoded using WeakMember."); - - EphemeronKeyValuePair(const KeyType& k, const ValueType& v) - : key(k), value(v) {} - - const KeyType& key; - const ValueType& value; -}; - -template -struct EphemeronKeyValuePair<_KeyType, - _ValueType, - _KeyTraits, - _ValueTraits, - true> : EphemeronKeyValuePair<_ValueType, - _KeyType, - _ValueTraits, - _KeyTraits, - false> { - EphemeronKeyValuePair(const _KeyType& k, const _ValueType& v) - : EphemeronKeyValuePair<_ValueType, - _KeyType, - _ValueTraits, - _KeyTraits, - false>(v, k) {} -}; - -template -struct KeyValuePairInCollectionTrait { - static bool IsAlive(const webf::LivenessBroker& info, - const webf::KeyValuePair& kvp) { - // Needed for Weak/Weak, Strong/Weak (reverse ephemeron), and Weak/Strong - // (ephemeron). Order of invocation does not matter as `IsAlive()` does not - // have any side effects. - return webf::TraceCollectionIfEnabled< - webf::kWeakHandlingTrait, Key, - typename Traits::KeyTraits>::IsAlive(info, kvp.key) && - webf::TraceCollectionIfEnabled< - webf::kWeakHandlingTrait, Value, - typename Traits::ValueTraits>::IsAlive(info, kvp.value); - } - - static void Trace(webf::Visitor* visitor, - const Key* key, - const Value* value) { - TraceImpl::Trace(visitor, key, value); - } - - static void Trace(webf::Visitor* visitor, - const webf::KeyValuePair& kvp) { - TraceImpl::Trace(visitor, &kvp.key, &kvp.value); - } - - private: - using EphemeronHelper = EphemeronKeyValuePair; - - struct WeakTrait { - static void Trace(webf::Visitor* visitor, - const Key* key, - const Value* value) { - // Strongification of ephemerons, i.e., Weak/Strong and Strong/Weak. - // The helper ensures that helper.key always refers to the weak part and - // helper.value always refers to the dependent part. - // We distinguish ephemeron from Weak/Weak and Strong/Strong to allow - // users to override visitation behavior. An example is creating a heap - // snapshot, where it is useful to annotate values as being kept alive - // from keys rather than the table. - EphemeronHelper helper(*key, *value); - if (WeakHandling == webf::kNoWeakHandling) { - // Strongify the weak part. - webf::TraceCollectionIfEnabled< - webf::kNoWeakHandling, typename EphemeronHelper::KeyType, - typename EphemeronHelper::KeyTraits>::Trace(visitor, &helper.key); - } - // The following passes on kNoWeakHandling for tracing value as the value - // callback is only invoked to keep value alive iff key is alive, - // following ephemeron semantics. - visitor->TraceEphemeron(helper.key, &helper.value); - } - }; - - struct StrongTrait { - static void Trace(webf::Visitor* visitor, - const Key* key, - const Value* value) { - // Strongification of non-ephemeron KVP, i.e., Strong/Strong or Weak/Weak. - // Order does not matter here. - webf::TraceCollectionIfEnabled< - webf::kNoWeakHandling, Key, typename Traits::KeyTraits>::Trace(visitor, - key); - webf::TraceCollectionIfEnabled< - webf::kNoWeakHandling, Value, - typename Traits::ValueTraits>::Trace(visitor, value); - } - }; - - using TraceImpl = - typename std::conditional::type; -}; - -} // namespace internal - -} // namespace blink - -namespace webf { - -// Trait for strong treatment of KeyValuePair. This is used to handle regular -// KVP but also for strongification of otherwise weakly handled KVPs. -template -struct TraceInCollectionTrait, Traits> - : public webf::internal:: - KeyValuePairInCollectionTrait {}; - -template -struct TraceInCollectionTrait, Traits> - : public webf::internal:: - KeyValuePairInCollectionTrait {}; - -// Catch-all for types that have a way to trace that don't have special -// handling for weakness in collections. This means that if this type -// contains WeakMember fields, they will simply be zeroed, but the entry -// will not be removed from the collection. This always happens for -// things in vectors, which don't currently support special handling of -// weak elements. -template -struct TraceInCollectionTrait { - static bool IsAlive(const webf::LivenessBroker& info, const T& t) { - return true; - } - - static void Trace(webf::Visitor* visitor, const T& t) { - static_assert(webf::IsTraceable::value && - !webf::IsWeak::value, - "T should be traceable"); - visitor->Trace(t); - } -}; - -template -struct TraceInCollectionTrait, Traits> { - static void Trace(webf::Visitor* visitor, const webf::WeakMember& t) { - // Extract raw pointer to avoid using the WeakMember<> overload in Visitor. - visitor->TraceStrongly(t); - } -}; - -// Catch-all for types that have HashTrait support for tracing with weakness. -// Empty to enforce specialization. -template -struct TraceInCollectionTrait {}; - -template -struct TraceInCollectionTrait, Traits> { - static bool IsAlive(const webf::LivenessBroker& info, - const webf::WeakMember& value) { - return info.IsHeapObjectAlive(value); - } -}; - -} // namespace webf - -namespace cppgc { - -// This trace trait for std::pair will clear WeakMember if their referent is -// collected. If you have a collection that contain weakness it does not remove -// entries from the collection that contain nulled WeakMember. -template -struct TraceTrait> { - STATIC_ONLY(TraceTrait); - - public: - static TraceDescriptor GetTraceDescriptor(const void* self) { - // The following code should never be reached as tracing through std::pair - // should always happen eagerly by directly invoking `Trace()` below. This - // happens e.g. when being used in HeapVector>. -// TODO NOTREACHED(); - return {nullptr, Trace}; - } - - static void Trace(Visitor* visitor, const std::pair* pair) { - webf::TraceIfNeeded::Trace(visitor, pair->second); - webf::TraceIfNeeded::Trace(visitor, pair->first); - } -}; - -} // namespace cppgc - -#endif // WEBF_HEAP_TRACE_TRAITS_H_ - diff --git a/bridge/bindings/v8/platform/script_state.h b/bridge/bindings/v8/platform/script_state.h index 0272b17d19..aa7cc7a064 100644 --- a/bridge/bindings/v8/platform/script_state.h +++ b/bridge/bindings/v8/platform/script_state.h @@ -8,6 +8,7 @@ #include +#include #include "bindings/v8/base/memory/stack_allocated.h" #include "bindings/v8/platform/heap/garbage_collected.h" #include "foundation/macros.h" diff --git a/bridge/bindings/v8/platform/util/main_thread_util.cc b/bridge/bindings/v8/platform/util/main_thread_util.cc index 2449d128d7..d217367527 100644 --- a/bridge/bindings/v8/platform/util/main_thread_util.cc +++ b/bridge/bindings/v8/platform/util/main_thread_util.cc @@ -16,8 +16,6 @@ //#include "bindings/v8/platform/wtf/text/atomic_string.h" //#include "bindings/v8/platform/wtf/text/copy_lchars_from_uchar_source.h" //#include "bindings/v8/platform/wtf/text/string_statics.h" -#include "bindings/v8/platform/wtf/thread_specific.h" -#include "bindings/v8/platform/wtf/threading.h" namespace webf { diff --git a/bridge/bindings/v8/platform/v8_per_context_data.cc b/bridge/bindings/v8/platform/v8_per_context_data.cc index 3a9b447dfc..6f3afe04de 100644 --- a/bridge/bindings/v8/platform/v8_per_context_data.cc +++ b/bridge/bindings/v8/platform/v8_per_context_data.cc @@ -73,7 +73,7 @@ v8::Local V8PerContextData::CreateWrapperFromCacheSlowCase( // TODO webf // DCHECK(!wrapper_boilerplates_.Contains(type)); v8::Context::Scope scope(GetContext()); - v8::Local interface_object = ConstructorForType(type); +// v8::Local interface_object = ConstructorForType(type); // if (UNLIKELY(interface_object.IsEmpty())) { // For investigation of crbug.com/1199223 // TODO webf not include crash_reporter for now @@ -102,28 +102,28 @@ v8::Local V8PerContextData::ConstructorForTypeSlowCase( v8::Local context = GetContext(); v8::Context::Scope scope(context); - v8::Local parent_interface_object; - if (auto* parent = type->parent_class) { - if (parent->is_skipped_in_interface_object_prototype_chain) { - // This is a special case for WindowProperties. - // We need to set up the inheritance of Window as the following: - // Window.__proto__ === EventTarget - // although the prototype chain is the following: - // Window.prototype.__proto__ === the named properties object - // Window.prototype.__proto__.__proto__ === EventTarget.prototype - // where the named properties object is WindowProperties.prototype in - // our implementation (although WindowProperties is not JS observable). - // Let WindowProperties be skipped and make - // Window.__proto__ == EventTarget. - - // TODO webf -// DCHECK(parent->parent_class); -// DCHECK(!parent->parent_class -// ->is_skipped_in_interface_object_prototype_chain); - parent = parent->parent_class; - } - parent_interface_object = ConstructorForType(parent); - } +// v8::Local parent_interface_object; +// if (auto* parent = type->parent_class) { +// if (parent->is_skipped_in_interface_object_prototype_chain) { +// // This is a special case for WindowProperties. +// // We need to set up the inheritance of Window as the following: +// // Window.__proto__ === EventTarget +// // although the prototype chain is the following: +// // Window.prototype.__proto__ === the named properties object +// // Window.prototype.__proto__.__proto__ === EventTarget.prototype +// // where the named properties object is WindowProperties.prototype in +// // our implementation (although WindowProperties is not JS observable). +// // Let WindowProperties be skipped and make +// // Window.__proto__ == EventTarget. +// +// // TODO webf +//// DCHECK(parent->parent_class); +//// DCHECK(!parent->parent_class +//// ->is_skipped_in_interface_object_prototype_chain); +// parent = parent->parent_class; +// } +// parent_interface_object = ConstructorForType(parent); +// } // const DOMWrapperWorld& world = DOMWrapperWorld::World(isolate_, context); // TODO webf not include V8ObjectConstructor for now @@ -142,46 +142,46 @@ v8::Local V8PerContextData::ConstructorForTypeSlowCase( v8::Local V8PerContextData::PrototypeForType( const WrapperTypeInfo* type) { - v8::Local constructor = ConstructorForType(type); - if (constructor.IsEmpty()) - return v8::Local(); +// v8::Local constructor = ConstructorForType(type); +// if (constructor.IsEmpty()) +// return v8::Local(); v8::Local prototype_value; - if (!constructor->Get(GetContext(), V8AtomicString(isolate_, "prototype")) - .ToLocal(&prototype_value) || - !prototype_value->IsObject()) - return v8::Local(); +// if (!constructor->Get(GetContext(), V8AtomicString(isolate_, "prototype")) +// .ToLocal(&prototype_value) || +// !prototype_value->IsObject()) +// return v8::Local(); return prototype_value.As(); } -bool V8PerContextData::GetExistingConstructorAndPrototypeForType( - const WrapperTypeInfo* type, - v8::Local* prototype_object, - v8::Local* interface_object) { - auto it = constructor_map_.find(type); - if (it == constructor_map_.end()) { - interface_object->Clear(); - prototype_object->Clear(); - return false; - } - *interface_object = it->value.Get(isolate_); - *prototype_object = PrototypeForType(type); - // TODO webf -// DCHECK(!prototype_object->IsEmpty()); - return true; -} +//bool V8PerContextData::GetExistingConstructorAndPrototypeForType( +// const WrapperTypeInfo* type, +// v8::Local* prototype_object, +// v8::Local* interface_object) { +// auto it = constructor_map_.find(type); +// if (it == constructor_map_.end()) { +// interface_object->Clear(); +// prototype_object->Clear(); +// return false; +// } +// *interface_object = it->value.Get(isolate_); +// *prototype_object = PrototypeForType(type); +// // TODO webf +//// DCHECK(!prototype_object->IsEmpty()); +// return true; +//} void V8PerContextData::AddData(const char* key, Data* data) { // TODO webf fix "In template: use of undeclared identifier 'AtomicMemzero'" // data_map_.Set(key, data); } -void V8PerContextData::ClearData(const char* key) { - data_map_.erase(key); -} +//void V8PerContextData::ClearData(const char* key) { +// data_map_.erase(key); +//} -V8PerContextData::Data* V8PerContextData::GetData(const char* key) { - auto it = data_map_.find(key); - return it != data_map_.end() ? it->value : nullptr; -} +//V8PerContextData::Data* V8PerContextData::GetData(const char* key) { +// auto it = data_map_.find(key); +// return it != data_map_.end() ? it->value : nullptr; +//} } // namespace webf diff --git a/bridge/bindings/v8/platform/v8_per_context_data.h b/bridge/bindings/v8/platform/v8_per_context_data.h index 9a423c350b..6e545b177c 100644 --- a/bridge/bindings/v8/platform/v8_per_context_data.h +++ b/bridge/bindings/v8/platform/v8_per_context_data.h @@ -13,7 +13,6 @@ #include "bindings/v8/platform/heap/garbage_collected.h" #include "bindings/v8/trace_wrapper_v8_reference.h" #include "bindings/v8/platform/scoped_persistent.h" -#include "bindings/v8/platform/heap/collection_support/heap_hash_map.h" #include "bindings/v8/gin/public/context_holder.h" #include "bindings/v8/platform/heap/member.h" @@ -42,22 +41,22 @@ class V8PerContextData final // To create JS Wrapper objects, we create a cache of a 'boiler plate' // object, and then simply Clone that object each time we need a new one. // This is faster than going through the full object creation process. - v8::Local CreateWrapperFromCache(const WrapperTypeInfo* type) { - if (auto it = wrapper_boilerplates_.find(type); - it != wrapper_boilerplates_.end()) { - v8::Local obj = it->value.Get(isolate_); - return obj->Clone(); - } - return CreateWrapperFromCacheSlowCase(type); - } +// v8::Local CreateWrapperFromCache(const WrapperTypeInfo* type) { +// if (auto it = wrapper_boilerplates_.find(type); +// it != wrapper_boilerplates_.end()) { +// v8::Local obj = it->value.Get(isolate_); +// return obj->Clone(); +// } +// return CreateWrapperFromCacheSlowCase(type); +// } // Returns the interface object that is appropriately initialized (e.g. // context-dependent properties are installed). - v8::Local ConstructorForType(const WrapperTypeInfo* type) { - auto it = constructor_map_.find(type); - return it != constructor_map_.end() ? it->value.Get(isolate_) - : ConstructorForTypeSlowCase(type); - } +// v8::Local ConstructorForType(const WrapperTypeInfo* type) { +// auto it = constructor_map_.find(type); +// return it != constructor_map_.end() ? it->value.Get(isolate_) +// : ConstructorForTypeSlowCase(type); +// } v8::Local PrototypeForType(const WrapperTypeInfo*); @@ -65,10 +64,10 @@ class V8PerContextData final // created. Returns true if they exist, and sets the existing values in // |prototypeObject| and |interfaceObject|. Otherwise, returns false, and the // values are set to empty objects (non-null). - bool GetExistingConstructorAndPrototypeForType( - const WrapperTypeInfo*, - v8::Local* prototype_object, - v8::Local* interface_object); +// bool GetExistingConstructorAndPrototypeForType( +// const WrapperTypeInfo*, +// v8::Local* prototype_object, +// v8::Local* interface_object); // V8DOMActivityLogger* ActivityLogger() const { return activity_logger_; } // void SetActivityLogger(V8DOMActivityLogger* activity_logger) { @@ -81,22 +80,23 @@ class V8PerContextData final class Data : public GarbageCollectedMixin {}; void AddData(const char* key, Data*); - void ClearData(const char* key); - Data* GetData(const char* key); +// void ClearData(const char* key); +// Data* GetData(const char* key); private: v8::Local CreateWrapperFromCacheSlowCase(const WrapperTypeInfo*); v8::Local ConstructorForTypeSlowCase(const WrapperTypeInfo*); - const raw_ptr isolate_; +// const raw_ptr isolate_; + v8::Isolate *isolate_; // For each possible type of wrapper, we keep a boilerplate object. // The boilerplate is used to create additional wrappers of the same type. - HeapHashMap> - wrapper_boilerplates_; - - HeapHashMap> - constructor_map_; +// HeapHashMap> +// wrapper_boilerplates_; +// +// HeapHashMap> +// constructor_map_; std::unique_ptr context_holder_; @@ -105,8 +105,8 @@ class V8PerContextData final // This is owned by a static hash map in V8DOMActivityLogger. // raw_ptr activity_logger_; - using DataMap = HeapHashMap>; - DataMap data_map_; +// using DataMap = HeapHashMap>; +// DataMap data_map_; }; } // namespace webf diff --git a/bridge/bindings/v8/platform/v8_per_isolate_data.cc b/bridge/bindings/v8/platform/v8_per_isolate_data.cc index 73ec46aded..83b2e31344 100644 --- a/bridge/bindings/v8/platform/v8_per_isolate_data.cc +++ b/bridge/bindings/v8/platform/v8_per_isolate_data.cc @@ -9,7 +9,6 @@ #include //#include "bindings/v8/base/debug/crash_logging.h" -//#include "bindings/v8/base/feature_list.h" //#include "bindings/v8/base/metrics/histogram_macros.h" //#include "bindings/v8/base/ranges/algorithm.h" //#include "bindings/v8/base/task/single_thread_task_runner.h" @@ -129,7 +128,7 @@ V8PerIsolateData::V8PerIsolateData( if (v8_context_snapshot_mode == V8ContextSnapshotMode::kTakeSnapshot) { // Snapshot should only execute on the main thread. SnapshotCreator enters // the isolate, so we don't call Isolate::Enter() here. - CHECK(IsMainThread()); +// CHECK(IsMainThread()); } else { // FIXME: Remove once all v8::Isolate::GetCurrent() calls are gone. // GetIsolate()->Enter(); @@ -163,7 +162,7 @@ v8::Isolate* V8PerIsolateData::Initialize( // std::move(task_runner), std::move(low_priority_task_runner), context_mode, create_histogram_callback, add_histogram_sample_callback); - DCHECK(data); +// DCHECK(data); v8::Isolate* isolate; // v8::Isolate* isolate = data->GetIsolate(); @@ -197,7 +196,7 @@ void V8PerIsolateData::WillBeDestroyed(v8::Isolate* isolate) { // data->active_script_wrappable_manager_.Clear(); // Callbacks can be removed as they only cover single events (e.g. atomic // pause) and they cannot get out of sync. - DCHECK_EQ(0u, data->gc_callback_depth_); +// DCHECK_EQ(0u, data->gc_callback_depth_); isolate->RemoveGCPrologueCallback(data->prologue_callback_); isolate->RemoveGCEpilogueCallback(data->epilogue_callback_); } diff --git a/bridge/bindings/v8/platform/v8_per_isolate_data.h b/bridge/bindings/v8/platform/v8_per_isolate_data.h index 661a7cb841..0dd8c60746 100644 --- a/bridge/bindings/v8/platform/v8_per_isolate_data.h +++ b/bridge/bindings/v8/platform/v8_per_isolate_data.h @@ -18,8 +18,6 @@ #include "bindings/v8/platform/heap/garbage_collected.h" #include "bindings/v8/platform/heap/persistent.h" #include "bindings/v8/platform/platform_export.h" -//#include "bindings/v8/platform/wtf/forward.h" -#include "bindings/v8/platform/wtf/hash_map.h" #include #include #include @@ -27,7 +25,7 @@ #include #include #include "bindings/v8/wrapper_type_info.h" -#include "bindings/v8/platform/util/allocator/partition_allocator.h" +//#include "bindings/v8/platform/util/allocator/partition_allocator.h" namespace base { //class SingleThreadTaskRunner; @@ -50,7 +48,7 @@ struct WrapperTypeInfo; // Used to hold data that is associated with a single v8::Isolate object, and // has a 1:1 relationship with v8::Isolate. class PLATFORM_EXPORT V8PerIsolateData final { - USING_FAST_MALLOC(V8PerIsolateData); +// USING_FAST_MALLOC(V8PerIsolateData); public: enum class V8ContextSnapshotMode { @@ -92,8 +90,8 @@ class PLATFORM_EXPORT V8PerIsolateData final { v8::AddHistogramSampleCallback); static V8PerIsolateData* From(v8::Isolate* isolate) { - DCHECK(isolate); - DCHECK(isolate->GetData(gin::kEmbedderWebf)); +// DCHECK(isolate); +// DCHECK(isolate->GetData(gin::kEmbedderWebf)); return static_cast( isolate->GetData(gin::kEmbedderWebf)); } diff --git a/bridge/bindings/v8/platform/wtf/construct_traits.h b/bridge/bindings/v8/platform/wtf/construct_traits.h index 45d571ea5e..4ee484d786 100644 --- a/bridge/bindings/v8/platform/wtf/construct_traits.h +++ b/bridge/bindings/v8/platform/wtf/construct_traits.h @@ -8,6 +8,7 @@ #include "bindings/v8/platform/wtf/type_traits.h" #include "bindings/v8/platform/wtf/vector_traits.h" +#include "foundation/macros.h" namespace webf { @@ -16,14 +17,14 @@ namespace webf { // dispatched through ConstructAndNotifyElement. template class ConstructTraits { - STATIC_ONLY(ConstructTraits); + WEBF_STATIC_ONLY(ConstructTraits); public: // Construct a single element that would otherwise be constructed using // placement new. template static T* Construct(void* location, Args&&... args) { - return ::new (NotNullTag::kNotNull, location) + return ::new (base::NotNullTag::kNotNull, location) T(std::forward(args)...); } diff --git a/bridge/bindings/v8/platform/wtf/hash_map.h b/bridge/bindings/v8/platform/wtf/hash_map.h deleted file mode 100644 index b9e0ef643d..0000000000 --- a/bridge/bindings/v8/platform/wtf/hash_map.h +++ /dev/null @@ -1,580 +0,0 @@ -/* -* Copyright (C) 2019-2022 The Kraken authors. All rights reserved. -* Copyright (C) 2022-present The WebF authors. All rights reserved. -*/ - -#ifndef WEBF_HASH_MAP_H_ -#define WEBF_HASH_MAP_H_ - -#include - -#include "bindings/v8/base/numerics/safe_conversions.h" -#include "bindings/v8/platform/wtf/construct_traits.h" -#include "bindings/v8/platform/wtf/hash_table.h" -#include "bindings/v8/platform/wtf/key_value_pair.h" -#include "bindings/v8/platform/wtf/type_traits.h" -#include "bindings/v8/platform/wtf/webf_size_t.h" -#include "bindings/v8/platform/wtf/atomic_operations.h" - -namespace webf { - -template -struct HashMapValueTraits; - -template -class HashCountedSet; - -struct KeyValuePairExtractor { - STATIC_ONLY(KeyValuePairExtractor); - template - static const typename T::KeyType& ExtractKey(const T& p) { - return p.key; - } - template - static typename T::KeyType& ExtractKey(T& p) { - return p.key; - } - // Assumes out points to a buffer of size at least sizeof(T::KeyType). - template - static void ExtractKeyToMemory(const T& p, void* out) { - AtomicReadMemcpy( - out, &p.key); - } - template - static void ClearValue(T& p) { - using ValueType = typename T::ValueType; - if (IsTraceable::value) { - AtomicMemzero(&p.value); - } else { - memset(static_cast(&p.value), 0, sizeof(p.value)); - } - } -}; - -// Note: empty or deleted key values are not allowed, using them may lead to -// undefined behavior. For pointer keys this means that null pointers are not -// allowed; for integer keys 0 or -1 can't be used as a key. You can change -// the restriction with a custom key hash traits. See hash_traits.h for how to -// define hash traits. -template , - typename MappedTraitsArg = HashTraits, - typename Allocator = util::PartitionAllocator> -class HashMap { - USE_ALLOCATOR(HashMap, Allocator); - template - friend class HashCountedSet; - - private: - typedef KeyTraitsArg KeyTraits; - typedef MappedTraitsArg MappedTraits; - typedef HashMapValueTraits ValueTraits; - - public: - typedef typename KeyTraits::TraitType KeyType; - typedef const typename KeyTraits::PeekInType& KeyPeekInType; - typedef typename MappedTraits::TraitType MappedType; - typedef typename ValueTraits::TraitType ValueType; - using value_type = ValueType; - - private: - typedef typename MappedTraits::PeekOutType MappedPeekType; - - typedef HashTable - HashTableType; - - class HashMapKeysProxy; - class HashMapValuesProxy; - - public: - HashMap() = default; - -#if DUMP_HASHTABLE_STATS_PER_TABLE - void DumpStats() { impl_.DumpStats(); } -#endif - HashMap(const HashMap&) = default; - HashMap& operator=(const HashMap&) = default; - HashMap(HashMap&&) = default; - HashMap& operator=(HashMap&&) = default; - - // For example, HashMap({{1, 11}, {2, 22}, {3, 33}}) will give you - // a HashMap containing a mapping {1 -> 11, 2 -> 22, 3 -> 33}. - HashMap(std::initializer_list elements); - HashMap& operator=(std::initializer_list elements); - - typedef HashTableIteratorAdapter iterator; - typedef HashTableConstIteratorAdapter - const_iterator; - typedef typename HashTableType::AddResult AddResult; - - void swap(HashMap& ref) { impl_.swap(ref.impl_); } - - unsigned size() const; - unsigned Capacity() const; - void ReserveCapacityForSize(unsigned size) { - impl_.ReserveCapacityForSize(size); - } - - bool empty() const; - - // iterators iterate over pairs of keys and values - iterator begin(); - iterator end(); - const_iterator begin() const; - const_iterator end() const; - - HashMapKeysProxy& Keys() { return static_cast(*this); } - const HashMapKeysProxy& Keys() const { - return static_cast(*this); - } - - HashMapValuesProxy& Values() { - return static_cast(*this); - } - const HashMapValuesProxy& Values() const { - return static_cast(*this); - } - - iterator find(KeyPeekInType); - const_iterator find(KeyPeekInType) const; - bool Contains(KeyPeekInType) const; - // Returns a reference to the mapped value. Crashes if no mapped value exists. - MappedPeekType at(KeyPeekInType) const; - - // Replaces value but not key if key is already present. Return value is a - // pair of the iterator to the key location, and a boolean that's true if a - // new value was actually added. - template - AddResult Set(IncomingKeyType&&, IncomingMappedType&&); - - // Does nothing if key is already present. Return value is a pair of the - // iterator to the key location, and a boolean that's true if a new value - // was actually added. - template - AddResult insert(IncomingKeyType&&, IncomingMappedType&&); - - void erase(KeyPeekInType); - void erase(iterator); - void clear(); - template - void RemoveAll(const Collection& to_be_removed) { - webf::RemoveAll(*this, to_be_removed); - } - - MappedType Take(KeyPeekInType); // efficient combination of get with remove - - // An alternate version of find() that finds the object by hashing and - // comparing with some other type, to avoid the cost of type conversion. - // HashTranslator must have the following function members: - // static unsigned GetHash(const T&); - // static bool Equal(const ValueType&, const T&); - template - iterator Find(const T&); - template - const_iterator Find(const T&) const; - template - bool Contains(const T&) const; - - template - static bool IsValidKey(const IncomingKeyType&); - - void Trace(auto visitor) const - requires Allocator::kIsGarbageCollected - { - impl_.Trace(visitor); - } - - protected: - ValueType** GetBufferSlot() { return impl_.GetBufferSlot(); } - - private: - template - AddResult InlineAdd(IncomingKeyType&&, IncomingMappedType&&); - - HashTableType impl_; - - struct TypeConstraints { - constexpr TypeConstraints() { - static_assert(!IsStackAllocatedType); - static_assert(!IsStackAllocatedType); - static_assert(Allocator::kIsGarbageCollected || - !IsPointerToGarbageCollectedType::value, - "Cannot put raw pointers to garbage-collected classes into " - "an off-heap HashMap. Use HeapHashMap<> instead."); - static_assert(Allocator::kIsGarbageCollected || - !IsPointerToGarbageCollectedType::value, - "Cannot put raw pointers to garbage-collected classes into " - "an off-heap HashMap. Use HeapHashMap<> instead."); - } - }; - NO_UNIQUE_ADDRESS TypeConstraints type_constraints_; -}; - -template -class HashMap:: - HashMapKeysProxy : private HashMap { - DISALLOW_NEW(); - - public: - typedef HashMap - HashMapType; - typedef typename HashMapType::iterator::KeysIterator iterator; - typedef typename HashMapType::const_iterator::KeysIterator const_iterator; - - iterator begin() { return HashMapType::begin().Keys(); } - - iterator end() { return HashMapType::end().Keys(); } - - const_iterator begin() const { return HashMapType::begin().Keys(); } - - const_iterator end() const { return HashMapType::end().Keys(); } - - private: - friend class HashMap; - - HashMapKeysProxy() = delete; - HashMapKeysProxy(const HashMapKeysProxy&) = delete; - HashMapKeysProxy& operator=(const HashMapKeysProxy&) = delete; - ~HashMapKeysProxy() = delete; -}; - -template -class HashMap:: - HashMapValuesProxy : private HashMap { - DISALLOW_NEW(); - - public: - typedef HashMap - HashMapType; - typedef typename HashMapType::iterator::ValuesIterator iterator; - typedef typename HashMapType::const_iterator::ValuesIterator const_iterator; - - iterator begin() { return HashMapType::begin().Values(); } - - iterator end() { return HashMapType::end().Values(); } - - const_iterator begin() const { return HashMapType::begin().Values(); } - - const_iterator end() const { return HashMapType::end().Values(); } - - private: - friend class HashMap; - - HashMapValuesProxy() = delete; - HashMapValuesProxy(const HashMapValuesProxy&) = delete; - HashMapValuesProxy& operator=(const HashMapValuesProxy&) = delete; - ~HashMapValuesProxy() = delete; -}; - -template -struct HashMapValueTraits : KeyValuePairHashTraits { - using P = typename KeyValuePairHashTraits::TraitType; - static bool IsEmptyValue(const P& value) { - return IsHashTraitsEmptyValue(value.key); - } - // HashTable should never use the following functions/flags of this traits - // type. They make sense in the KeyTraits only. - static bool Equal(const P&, const P&) = delete; - static void ConstructDeletedValue(P&) = delete; - static bool IsDeletedValue(const P&) = delete; - - private: - static const bool kSafeToCompareToEmptyOrDeleted; -}; - -template -struct HashMapTranslator { - STATIC_ONLY(HashMapTranslator); - template - static unsigned GetHash(const T& key) { - return KeyTraits::GetHash(key); - } - template - static bool Equal(const T& a, const U& b) { - return KeyTraits::Equal(a, b); - } - template - static void Store(T& location, U&& key, V&& mapped) { - location.key = std::forward(key); - location.value = std::forward(mapped); - } -}; - -template -HashMap::HashMap( - std::initializer_list elements) { - if (elements.size()) { - impl_.ReserveCapacityForSize( - base::checked_cast(elements.size())); - } - for (const ValueType& element : elements) - insert(element.key, element.value); -} - -template -auto HashMap::operator=( - std::initializer_list elements) -> HashMap& { - *this = HashMap(std::move(elements)); - return *this; -} - -template -inline unsigned HashMap::size() const { - return impl_.size(); -} - -template -inline unsigned HashMap::Capacity() const { - return impl_.Capacity(); -} - -template -inline bool HashMap::empty() const { - return impl_.empty(); -} - -template -inline typename HashMap::iterator -HashMap::begin() { - return impl_.begin(); -} - -template -inline typename HashMap::iterator HashMap::end() { - return impl_.end(); -} - -template -inline typename HashMap::const_iterator -HashMap::begin() const { - return impl_.begin(); -} - -template -inline typename HashMap::const_iterator -HashMap::end() const { - return impl_.end(); -} - -template -inline typename HashMap::iterator HashMap::find( - KeyPeekInType key) { - return impl_.find(key); -} - -template -inline typename HashMap::const_iterator -HashMap::find(KeyPeekInType key) const { - return impl_.find(key); -} - -template -inline bool HashMap::Contains(KeyPeekInType key) const { - return impl_.Contains(key); -} - -template -template -inline typename HashMap::iterator HashMap::Find( - const TYPE& value) { - return impl_.template Find(value); -} - -template -template -inline typename HashMap::const_iterator -HashMap::Find(const TYPE& value) const { - return impl_.template Find(value); -} - -template -template -inline bool HashMap::Contains(const TYPE& value) const { - return impl_.template Contains(value); -} - -template -template -typename HashMap::AddResult HashMap::InlineAdd( - IncomingKeyType&& key, - IncomingMappedType&& mapped) { - return impl_.template insert>( - std::forward(key), - std::forward(mapped)); -} - -template -template -typename HashMap::AddResult HashMap::Set( - IncomingKeyType&& key, - IncomingMappedType&& mapped) { - AddResult result = InlineAdd(std::forward(key), - std::forward(mapped)); - if (!result.is_new_entry) { - // The InlineAdd call above found an existing hash table entry; we need - // to set the mapped value. - // - // It's safe to call std::forward again, because |mapped| isn't moved if - // there's an existing entry. - result.stored_value->value = std::forward(mapped); - } - return result; -} - -template -template -typename HashMap::AddResult HashMap::insert( - IncomingKeyType&& key, - IncomingMappedType&& mapped) { - return InlineAdd(std::forward(key), - std::forward(mapped)); -} - -template -typename HashMap::MappedPeekType HashMap::at( - KeyPeekInType key) const { - const ValueType* entry = impl_.Lookup(key); -// CHECK(entry) << "HashMap::at found no value for the given key. See " -// "https://crbug.com/1058527."; - return MappedTraits::Peek(entry->value); -} - -template -inline void HashMap::erase(iterator it) { - impl_.erase(it.impl_); -} - -template -inline void HashMap::erase(KeyPeekInType key) { - erase(find(key)); -} - -template -inline void HashMap::clear() { - impl_.clear(); -} - -template -auto HashMap::Take(KeyPeekInType key) -> MappedType { - iterator it = find(key); - if (it == end()) - return MappedTraits::EmptyValue(); - MappedType result = std::move(it->value); - erase(it); - return result; -} - -template -template -inline bool HashMap::IsValidKey(const IncomingKeyType& key) { - return !IsHashTraitsEmptyOrDeletedValue(key); -} - -template -bool operator==(const HashMap& a, - const HashMap& b) { - if (a.size() != b.size()) - return false; - - typedef typename HashMap::const_iterator const_iterator; - - const_iterator a_end = a.end(); - const_iterator b_end = b.end(); - for (const_iterator it = a.begin(); it != a_end; ++it) { - const_iterator b_pos = b.find(it->key); - if (b_pos == b_end || it->value != b_pos->value) - return false; - } - - return true; -} - -template -inline bool operator!=(const HashMap& a, - const HashMap& b) { - return !(a == b); -} - -template -inline void CopyKeysToVector(const HashMap& collection, - Z& vector) { - typedef - typename HashMap::const_iterator::KeysIterator iterator; - - { - // Disallow GC during resize allocation; see crbugs 568173 and 823612. - // The element copy doesn't need to be in this scope because garbage - // collection can only remove elements from collection if its keys are - // WeakMembers, in which case copying them doesn't perform a heap - // allocation. - typename Z::GCForbiddenScope scope; - vector.resize(collection.size()); - } - - iterator it = collection.begin().Keys(); - iterator end = collection.end().Keys(); - for (unsigned i = 0; it != end; ++it, ++i) - vector[i] = *it; -} - -template -inline void CopyValuesToVector(const HashMap& collection, - Z& vector) { - typedef - typename HashMap::const_iterator::ValuesIterator iterator; - - // Disallow GC during resize allocation and copy operations (which may also - // perform allocations and therefore cause elements of collection to be - // removed); see crbugs 568173 and 823612. - typename Z::GCForbiddenScope scope; - - vector.resize(collection.size()); - - iterator it = collection.begin().Values(); - iterator end = collection.end().Values(); - for (unsigned i = 0; it != end; ++it, ++i) - vector[i] = *it; -} - -} // namespace WTF - -using webf::HashMap; - -#endif // WEBF_HASH_MAP_H_ - diff --git a/bridge/bindings/v8/platform/wtf/hash_table.cc b/bridge/bindings/v8/platform/wtf/hash_table.cc deleted file mode 100644 index dfb471519d..0000000000 --- a/bridge/bindings/v8/platform/wtf/hash_table.cc +++ /dev/null @@ -1,6 +0,0 @@ -/* -* Copyright (C) 2019-2022 The Kraken authors. All rights reserved. -* Copyright (C) 2022-present The WebF authors. All rights reserved. -*/ - -#include "hash_table.h" diff --git a/bridge/bindings/v8/platform/wtf/hash_table.h b/bridge/bindings/v8/platform/wtf/hash_table.h deleted file mode 100644 index 445ed1d108..0000000000 --- a/bridge/bindings/v8/platform/wtf/hash_table.h +++ /dev/null @@ -1,2289 +0,0 @@ -/* -* Copyright (C) 2019-2022 The Kraken authors. All rights reserved. -* Copyright (C) 2022-present The WebF authors. All rights reserved. -*/ - -#ifndef WEBF_HASH_TABLE_H_ -#define WEBF_HASH_TABLE_H_ - -#include - -#include "bindings/v8/platform/wtf/hash_traits.h" -#include "bindings/v8/platform/wtf/type_traits.h" -#include "bindings/v8/base/dcheck_is_on.h" -#include "bindings/v8/base/check_op.h" -#include "bindings/v8/base/check.h" -#include "bindings/v8/platform/wtf/conditional_destructor.h" -#include "bindings/v8/platform/wtf/construct_traits.h" - -#if !defined(DUMP_HASHTABLE_STATS) -#define DUMP_HASHTABLE_STATS 0 -#endif - -#if !defined(DUMP_HASHTABLE_STATS_PER_TABLE) -#define DUMP_HASHTABLE_STATS_PER_TABLE 0 -#endif - -#if DUMP_HASHTABLE_STATS -#include "third_party/blink/renderer/platform/wtf/threading.h" -#endif - -#if DUMP_HASHTABLE_STATS_PER_TABLE -#include -#include "third_party/blink/renderer/platform/wtf/DataLog.h" -#endif - -#if DUMP_HASHTABLE_STATS -#if DUMP_HASHTABLE_STATS_PER_TABLE - -#define UPDATE_PROBE_COUNTS() \ - ++probeCount; \ - HashTableStats::instance().recordCollisionAtCount(probeCount); \ - ++perTableProbeCount; \ - stats_->recordCollisionAtCount(perTableProbeCount) -#define UPDATE_ACCESS_COUNTS() \ - HashTableStats::instance().numAccesses.fetch_add(1, \ - std::memory_order_relaxed); \ - int probeCount = 0; \ - stats_->numAccesses.fetch_add(1, std::memory_order_relaxed); \ - int perTableProbeCount = 0 -#else -#define UPDATE_PROBE_COUNTS() \ - ++probeCount; \ - HashTableStats::instance().recordCollisionAtCount(probeCount) -#define UPDATE_ACCESS_COUNTS() \ - HashTableStats::instance().numAccesses.fetch_add(1, \ - std::memory_order_relaxed); \ - int probeCount = 0 -#endif -#else -#if DUMP_HASHTABLE_STATS_PER_TABLE -#define UPDATE_PROBE_COUNTS() \ - ++perTableProbeCount; \ - stats_->recordCollisionAtCount(perTableProbeCount) -#define UPDATE_ACCESS_COUNTS() \ - stats_->numAccesses.fetch_add(1, std::memory_order_relaxed); \ - int perTableProbeCount = 0 -#else -#define UPDATE_PROBE_COUNTS() \ - do { \ - } while (0) -#define UPDATE_ACCESS_COUNTS() \ - do { \ - } while (0) -#endif -#endif - -namespace webf { - -#if DUMP_HASHTABLE_STATS || DUMP_HASHTABLE_STATS_PER_TABLE -struct HashTableStats { - HashTableStats() - : numAccesses(0), - numRehashes(0), - numRemoves(0), - numReinserts(0), - maxCollisions(0), - numCollisions(0), - collisionGraph() {} - - // The following variables are all atomically incremented when modified. - std::atomic_int numAccesses; - std::atomic_int numRehashes; - std::atomic_int numRemoves; - std::atomic_int numReinserts; - - // The following variables are only modified in the recordCollisionAtCount - // method within a mutex. - int maxCollisions; - int numCollisions; - int collisionGraph[4096]; - - void copy(const HashTableStats* other); - void recordCollisionAtCount(int count); - void DumpStats(); - - static HashTableStats& instance(); - - template - void trace(VisitorDispatcher) const {} - - private: - void RecordCollisionAtCountWithoutLock(int count); - void DumpStatsWithoutLock(); -}; - -#if DUMP_HASHTABLE_STATS_PER_TABLE -template -class HashTableStatsPtr; - -template -class HashTableStatsPtr final { - STATIC_ONLY(HashTableStatsPtr); - - public: - static std::unique_ptr Create() { - return std::make_unique(); - } - - static std::unique_ptr copy( - const std::unique_ptr& other) { - if (!other) - return nullptr; - return std::make_unique(*other); - } - - static void swap(std::unique_ptr& stats, - std::unique_ptr& other) { - stats.swap(other); - } -}; - -template -class HashTableStatsPtr final { - STATIC_ONLY(HashTableStatsPtr); - - public: - static HashTableStats* Create() { - // TODO(cavalcantii): fix this. - return new HashTableStats; - } - - static HashTableStats* copy(const HashTableStats* other) { - if (!other) - return nullptr; - HashTableStats* obj = Create(); - obj->copy(other); - return obj; - } - - static void swap(HashTableStats*& stats, HashTableStats*& other) { - std::swap(stats, other); - } -}; -#endif -#endif - -template -class HashTable; -template -class HashTableIterator; -template -class HashTableConstIterator; -template -struct WeakProcessingHashTableHelper; - -typedef enum { kHashItemKnownGood } HashItemKnownGoodTag; - -template -class HashTableConstIterator final { - DISALLOW_NEW(); - - private: - typedef HashTable - HashTableType; - typedef HashTableIterator - iterator; - typedef HashTableConstIterator - const_iterator; - using value_type = Value; - typedef typename Traits::IteratorConstGetType GetType; - typedef const value_type* PointerType; - - friend class HashTable; - friend class HashTableIterator; - - void SkipEmptyBuckets() { - while (position_ != end_position_ && - HashTableType::IsEmptyOrDeletedBucket(*position_)) - ++position_; - } - - void ReverseSkipEmptyBuckets() { - // Don't need to check for out-of-bounds positions, as begin position is - // always going to be a non-empty bucket. - while (HashTableType::IsEmptyOrDeletedBucket(*position_)) { -#if DCHECK_IS_ON() - DCHECK_NE(position_, begin_position_); -#endif - --position_; - } - } - - HashTableConstIterator(PointerType position, - PointerType begin_position, - PointerType end_position, - const HashTableType* container) - : position_(position), - end_position_(end_position) -#if DCHECK_IS_ON() - , - begin_position_(begin_position), - container_(container), - container_modifications_(container->Modifications()) -#endif - { - SkipEmptyBuckets(); - } - - HashTableConstIterator(PointerType position, - PointerType begin_position, - PointerType end_position, - const HashTableType* container, - HashItemKnownGoodTag) - : position_(position), - end_position_(end_position) -#if DCHECK_IS_ON() - , - begin_position_(begin_position), - container_(container), - container_modifications_(container->Modifications()) -#endif - { -#if DCHECK_IS_ON() - DCHECK_EQ(container_modifications_, container_->Modifications()); -#endif - } - - void CheckModifications() const { -#if DCHECK_IS_ON() - // HashTable and collections that build on it do not support - // modifications while there is an iterator in use. The exception is - // LinkedHashSet, which has its own iterators that tolerate modification - // of the underlying set. - - DCHECK_EQ(container_modifications_, container_->Modifications()); - DCHECK(!container_->AccessForbidden()); -#endif - } - - public: - constexpr HashTableConstIterator() = default; - - GetType Get() const { - CheckModifications(); - return position_; - } - typename Traits::IteratorConstReferenceType operator*() const { - return *Get(); - } - GetType operator->() const { return Get(); } - - const_iterator& operator++() { - DCHECK_NE(position_, end_position_); - CheckModifications(); - ++position_; - SkipEmptyBuckets(); - return *this; - } - - const_iterator operator++(int) { - auto copy = this; - ++(*this); - return copy; - } - - const_iterator& operator--() { -#if DCHECK_IS_ON() - DCHECK_NE(position_, begin_position_); -#endif - CheckModifications(); - --position_; - ReverseSkipEmptyBuckets(); - return *this; - } - - const_iterator operator--(int) { - auto copy = *this; - --(*this); - return copy; - } - - // Comparison. - bool operator==(const const_iterator& other) const { - return position_ == other.position_; - } - bool operator!=(const const_iterator& other) const { - return position_ != other.position_; - } - bool operator==(const iterator& other) const { - return *this == static_cast(other); - } - bool operator!=(const iterator& other) const { - return *this != static_cast(other); - } - - std::ostream& PrintTo(std::ostream& stream) const { - if (position_ == end_position_) - return stream << "iterator representing "; - // TODO(tkent): Change |position_| to |*position_| to show the - // pointed object. It requires a lot of new stream printer functions. - return stream << "iterator pointing to " << position_; - } - - private: - PointerType position_ = nullptr; - PointerType end_position_ = nullptr; -#if DCHECK_IS_ON() - PointerType begin_position_ = nullptr; - const HashTableType* container_ = nullptr; - int64_t container_modifications_ = 0; -#endif -}; - -template -std::ostream& operator<<(std::ostream& stream, - const HashTableConstIterator& iterator) { - return iterator.PrintTo(stream); -} - -template -class HashTableIterator final { - DISALLOW_NEW(); - - private: - typedef HashTable - HashTableType; - typedef HashTableIterator - iterator; - typedef HashTableConstIterator - const_iterator; - using value_type = Value; - typedef typename Traits::IteratorGetType GetType; - typedef value_type* PointerType; - - friend class HashTable; - - HashTableIterator(PointerType pos, - PointerType begin, - PointerType end, - const HashTableType* container) - : iterator_(pos, begin, end, container) {} - HashTableIterator(PointerType pos, - PointerType begin, - PointerType end, - const HashTableType* container, - HashItemKnownGoodTag tag) - : iterator_(pos, begin, end, container, tag) {} - - public: - constexpr HashTableIterator() = default; - - // default copy, assignment and destructor are OK - - GetType Get() const { return const_cast(iterator_.Get()); } - typename Traits::IteratorReferenceType operator*() const { return *Get(); } - GetType operator->() const { return Get(); } - - iterator& operator++() { - ++iterator_; - return *this; - } - - iterator operator++(int) { - auto copy = *this; - ++(*this); - return copy; - } - - iterator& operator--() { - --iterator_; - return *this; - } - - iterator operator--(int) { - auto copy = *this; - --(*this); - return copy; - } - - // Comparison. - bool operator==(const iterator& other) const { - return iterator_ == other.iterator_; - } - bool operator!=(const iterator& other) const { - return iterator_ != other.iterator_; - } - bool operator==(const const_iterator& other) const { - return iterator_ == other; - } - bool operator!=(const const_iterator& other) const { - return iterator_ != other; - } - - operator const_iterator() const { return iterator_; } - std::ostream& PrintTo(std::ostream& stream) const { - return iterator_.PrintTo(stream); - } - - private: - const_iterator iterator_; -}; - -template -std::ostream& operator<<(std::ostream& stream, - const HashTableIterator& iterator) { - return iterator.PrintTo(stream); -} - -using std::swap; - -template -struct Mover { - STATIC_ONLY(Mover); - static void Move(T&& from, T& to) { - to.~T(); - new (NotNullTag::kNotNull, &to) T(std::move(from)); - } -}; - -template -struct Mover { - STATIC_ONLY(Mover); - static void Move(T&& from, T& to) { - Allocator::EnterGCForbiddenScope(); - to.~T(); - new (NotNullTag::kNotNull, &to) T(std::move(from)); - Allocator::LeaveGCForbiddenScope(); - } -}; - -template -class IdentityHashTranslator { - STATIC_ONLY(IdentityHashTranslator); - - public: - template - static unsigned GetHash(const T& key) { - return KeyTraits::GetHash(key); - } - template - static bool Equal(const T& a, const U& b) { - return KeyTraits::Equal(a, b); - } - template - static void Store(T& location, U&&, V&& value) { - location = std::forward(value); - } -}; - -template -struct HashTableAddResult final { - STACK_ALLOCATED(); - - public: - HashTableAddResult([[maybe_unused]] const HashTableType* container, - ValueType* stored_value, - bool is_new_entry) - : stored_value(stored_value), - is_new_entry(is_new_entry) -#if ENABLE_SECURITY_ASSERT - , - container_(container), - container_modifications_(container->Modifications()) -#endif - { - DCHECK(container); - } - - ValueType* stored_value; - bool is_new_entry; - -#if ENABLE_SECURITY_ASSERT - ~HashTableAddResult() { - // If rehash happened before accessing storedValue, it's - // use-after-free. Any modification may cause a rehash, so we check for - // modifications here. - - // Rehash after accessing storedValue is harmless but will assert if the - // AddResult destructor takes place after a modification. You may need - // to limit the scope of the AddResult. - SECURITY_DCHECK(container_modifications_ == container_->Modifications()); - } - - private: - const HashTableType* container_; - const int64_t container_modifications_; -#endif -}; - -template -struct HashTableKeyChecker { - STATIC_ONLY(HashTableKeyChecker); - // There's no simple generic way to make this check if - // safeToCompareToEmptyOrDeleted is false, so the check always passes. - template - static bool CheckKey(const T&) { - return true; - } -}; - -template -struct HashTableKeyChecker { - STATIC_ONLY(HashTableKeyChecker); - template - static bool CheckKey(const T& key) { - // FIXME : Check also equality to the deleted value. - return !HashTranslator::Equal(KeyTraits::EmptyValue(), key); - } -}; - -// Note: empty or deleted key values are not allowed, using them may lead to -// undefined behavior. For pointer keys this means that null pointers are not -// allowed unless you supply custom key traits. -template -class HashTable final - : public ConditionalDestructor< - HashTable, - !Allocator::kIsGarbageCollected> { - DISALLOW_NEW(); - - public: - typedef HashTableIterator - iterator; - typedef HashTableConstIterator - const_iterator; - typedef Traits ValueTraits; - typedef Key KeyType; - typedef typename KeyTraits::PeekInType KeyPeekInType; - typedef Value ValueType; - typedef Extractor ExtractorType; - typedef KeyTraits KeyTraitsType; - typedef IdentityHashTranslator IdentityTranslatorType; - typedef HashTableAddResult AddResult; - - HashTable(); - - void Finalize() { - static_assert(!Allocator::kIsGarbageCollected, - "GCed collections can't be finalized."); - if (LIKELY(!table_)) - return; - EnterAccessForbiddenScope(); - DeleteAllBucketsAndDeallocate(table_, table_size_); - LeaveAccessForbiddenScope(); - table_ = nullptr; - } - - HashTable(const HashTable&); - HashTable(HashTable&&); - void swap(HashTable&); - HashTable& operator=(const HashTable&); - HashTable& operator=(HashTable&&); - - // When the hash table is empty, just return the same iterator for end as - // for begin. This is more efficient because we don't have to skip all the - // empty and deleted buckets, and iterating an empty table is a common case - // that's worth optimizing. - iterator begin() { return empty() ? end() : MakeIterator(table_); } - iterator end() { return MakeKnownGoodIterator(table_ + table_size_); } - const_iterator begin() const { - return empty() ? end() : MakeConstIterator(table_); - } - const_iterator end() const { - return MakeKnownGoodConstIterator(table_ + table_size_); - } - - unsigned size() const { - DCHECK(!AccessForbidden()); - return key_count_; - } - unsigned Capacity() const { - DCHECK(!AccessForbidden()); - return table_size_; - } - bool empty() const { - DCHECK(!AccessForbidden()); - return !key_count_; - } - - void ReserveCapacityForSize(unsigned size); - - template - AddResult insert(IncomingValueType&& value) { - return insert( - Extractor::ExtractKey(value), std::forward(value)); - } - - // A special version of insert() that finds the object by hashing and - // comparing with some other type, to avoid the cost of type conversion if the - // object is already in the table. - // HashTranslator must have the following function members: - // static unsigned GetHash(const T&); - // static bool Equal(const ValueType&, const T&); - // static void Store(T& location, KeyType&&, ValueType&&); - template - AddResult insert(T&& key, Extra&&); - // Similar to the above, but passes additional `unsigned hash_code`, which - // is computed from `HashTranslator::GetHash(key)`, to HashTranslator method - // static Store(T&, KeyType&&, ValueType&&, unsigned hash_code); - // to avoid recomputation of the hash code when needed in the method. - template - AddResult InsertPassingHashCode(T&& key, Extra&&); - - iterator find(KeyPeekInType key) { return Find(key); } - const_iterator find(KeyPeekInType key) const { - return Find(key); - } - bool Contains(KeyPeekInType key) const { - return Contains(key); - } - - // A special version of find() that finds the object by hashing and - // comparing with some other type, to avoid the cost of type conversion. - // HashTranslator must have the following function members: - // static unsigned GetHash(const T&); - // static bool Equal(const ValueType&, const T&); - template - iterator Find(const T&); - template - const_iterator Find(const T&) const; - template - bool Contains(const T&) const; - - void erase(KeyPeekInType); - void erase(iterator); - void erase(const_iterator); - void clear(); - - static bool IsEmptyBucket(const ValueType& value) { - return IsHashTraitsEmptyValue(Extractor::ExtractKey(value)); - } - static bool IsDeletedBucket(const ValueType& value) { - return IsHashTraitsDeletedValue(Extractor::ExtractKey(value)); - } - static bool IsEmptyOrDeletedBucket(const ValueType& value) { - return IsHashTraitsEmptyOrDeletedValue( - Extractor::ExtractKey(value)); - } - - ValueType* Lookup(KeyPeekInType key) { - return Lookup(key); - } - const ValueType* Lookup(KeyPeekInType key) const { - return Lookup(key); - } - template - ValueType* Lookup(const T&); - template - const ValueType* Lookup(const T&) const; - - ValueType** GetBufferSlot() { return &table_; } - - void Trace(auto visitor) const - requires Allocator::kIsGarbageCollected; - -#if DCHECK_IS_ON() - void EnterAccessForbiddenScope() { - DCHECK(!access_forbidden_); - access_forbidden_ = true; - } - void LeaveAccessForbiddenScope() { access_forbidden_ = false; } - bool AccessForbidden() const { return access_forbidden_; } - int64_t Modifications() const { return modifications_; } - void RegisterModification() { modifications_++; } - // HashTable and collections that build on it do not support modifications - // while there is an iterator in use. The exception is - // LinkedHashSet, which has its own iterators that tolerate modification - // of the underlying set. - void CheckModifications(int64_t mods) const { - DCHECK_EQ(mods, modifications_); - } -#else - ALWAYS_INLINE void EnterAccessForbiddenScope() {} - ALWAYS_INLINE void LeaveAccessForbiddenScope() {} - ALWAYS_INLINE bool AccessForbidden() const { return false; } - ALWAYS_INLINE int64_t Modifications() const { return 0; } - ALWAYS_INLINE void RegisterModification() {} - ALWAYS_INLINE void CheckModifications(int64_t mods) const {} -#endif - - protected: - void TraceTable(auto visitor, const ValueType* table) const - requires Allocator::kIsGarbageCollected; - - private: - static ValueType* AllocateTable(unsigned size); - static void DeleteAllBucketsAndDeallocate(ValueType* table, unsigned size); - - struct LookupResult { - ValueType* entry; - bool found; - unsigned hash; - }; - template - LookupResult LookupForWriting(const T&); - - void erase(const ValueType*); - - bool ShouldExpand() const { - return (key_count_ + deleted_count_) * kMaxLoad >= table_size_; - } - bool MustRehashInPlace() const { - return key_count_ * kMinLoad < table_size_ * 2; - } - bool ShouldShrink() const { - // isAllocationAllowed check should be at the last because it's - // expensive. - return key_count_ * kMinLoad < table_size_ && - table_size_ > KeyTraits::kMinimumTableSize && - Allocator::IsAllocationAllowed(); - } - ValueType* Expand(ValueType* entry = nullptr); - void Shrink() { Rehash(table_size_ / 2, nullptr); } - - ValueType* ExpandBuffer(unsigned new_table_size, ValueType* entry, bool&); - ValueType* RehashTo(ValueType* new_table, - unsigned new_table_size, - ValueType* entry); - ValueType* Rehash(unsigned new_table_size, ValueType* entry); - ValueType* Reinsert(ValueType&&); - - static void ReinitializeBucket(ValueType& bucket); - static void DeleteBucket(ValueType& bucket) { - bucket.~ValueType(); - ConstructHashTraitsDeletedValue(Extractor::ExtractKey(bucket)); - // For GC collections the memory for the backing is zeroed when it is - // allocated, and the constructors may take advantage of that, - // especially if a GC occurs during insertion of an entry into the - // table. This slot is being marked deleted, but If the slot is reused - // at a later point, the same assumptions around memory zeroing must - // hold as they did at the initial allocation. Therefore we zero the - // value part of the slot here for GC collections. - if (Allocator::kIsGarbageCollected) { - Extractor::ClearValue(bucket); - } - } - - iterator MakeIterator(ValueType* pos) { - return iterator(pos, table_, table_ + table_size_, this); - } - const_iterator MakeConstIterator(const ValueType* pos) const { - return const_iterator(pos, table_, table_ + table_size_, this); - } - iterator MakeKnownGoodIterator(ValueType* pos) { - return iterator(pos, table_, table_ + table_size_, this, - kHashItemKnownGood); - } - const_iterator MakeKnownGoodConstIterator(const ValueType* pos) const { - return const_iterator(pos, table_, table_ + table_size_, this, - kHashItemKnownGood); - } - - static const unsigned kMaxLoad = 2; - static const unsigned kMinLoad = 6; - - unsigned TableSizeMask() const { - unsigned mask = table_size_ - 1; - DCHECK_EQ((mask & table_size_), 0u); - return mask; - } - - void SetEnqueued() { queue_flag_ = true; } - void ClearEnqueued() { queue_flag_ = false; } - bool Enqueued() { return queue_flag_; } - - // Constructor for hash tables with raw storage. - struct RawStorageTag {}; - HashTable(RawStorageTag, ValueType* table, unsigned size) - : table_(table), - table_size_(size), - key_count_(0), - deleted_count_(0), - queue_flag_(0) -#if DCHECK_IS_ON() - , - access_forbidden_(0), - modifications_(0) -#endif - { - } - - ValueType* table_; - unsigned table_size_; - unsigned key_count_; -#if DCHECK_IS_ON() - unsigned deleted_count_ : 30; - unsigned queue_flag_ : 1; - unsigned access_forbidden_ : 1; - unsigned modifications_; -#else - unsigned deleted_count_ : 31; - unsigned queue_flag_ : 1; -#endif - -#if DUMP_HASHTABLE_STATS_PER_TABLE - public: - mutable - typename std::conditional>::type stats_; - void DumpStats() { - if (stats_) { - stats_->DumpStats(); - } - } -#endif - - template - friend struct WeakProcessingHashTableHelper; - - struct TypeConstraints { - constexpr TypeConstraints() { - static_assert(!IsStackAllocatedType); - static_assert(!IsStackAllocatedType); - static_assert( - Allocator::kIsGarbageCollected || - (!IsPointerToGarbageCollectedType::value && - !IsPointerToGarbageCollectedType::value), - "Cannot put raw pointers to garbage-collected classes into an " - "off-heap collection."); - } - }; - NO_UNIQUE_ADDRESS TypeConstraints type_constraints_; -}; - -template -inline HashTable::HashTable() - : table_(nullptr), - table_size_(0), - key_count_(0), - deleted_count_(0), - queue_flag_(false) -#if DCHECK_IS_ON() - , - access_forbidden_(false), - modifications_(0) -#endif -#if DUMP_HASHTABLE_STATS_PER_TABLE - , - stats_(nullptr) -#endif -{ -} - -inline unsigned CalculateCapacity(unsigned size) { - for (unsigned mask = size; mask; mask >>= 1) - size |= mask; // 00110101010 -> 00111111111 - return (size + 1) * 2; // 00111111111 -> 10000000000 -} - -template -void HashTable::ReserveCapacityForSize(unsigned new_size) { - unsigned new_capacity = CalculateCapacity(new_size); - if (new_capacity < KeyTraits::kMinimumTableSize) - new_capacity = KeyTraits::kMinimumTableSize; - - if (new_capacity > Capacity()) { -// CHECK(!static_cast( -// new_capacity >> -// 31)); // HashTable capacity should not overflow 32bit int. - Rehash(new_capacity, nullptr); - } -} - -template -template -inline Value* -HashTable::Lookup( - const T& key) { - // Call the const version of Lookup(). - return const_cast( - const_cast(this)->Lookup(key)); -} - -template -template -inline const Value* -HashTable::Lookup( - const T& key) const { - DCHECK(!AccessForbidden()); - DCHECK((HashTableKeyChecker< - HashTranslator, KeyTraits, - KeyTraits::kSafeToCompareToEmptyOrDeleted>::CheckKey(key))); - const ValueType* table = table_; - if (!table) - return nullptr; - - size_t size_mask = TableSizeMask(); - unsigned h = HashTranslator::GetHash(key); - size_t i = h & size_mask; - size_t probe_count = 0; - - UPDATE_ACCESS_COUNTS(); - - while (true) { - const ValueType* entry = table + i; - - if (KeyTraits::kSafeToCompareToEmptyOrDeleted) { - if (HashTranslator::Equal(Extractor::ExtractKey(*entry), key)) { - return entry; - } - - if (IsEmptyBucket(*entry)) - return nullptr; - } else { - if (IsEmptyBucket(*entry)) - return nullptr; - - if (!IsDeletedBucket(*entry) && - HashTranslator::Equal(Extractor::ExtractKey(*entry), key)) { - return entry; - } - } - ++probe_count; - UPDATE_PROBE_COUNTS(); - i = (i + probe_count) & size_mask; - } -} - -template -template -inline typename HashTable:: - LookupResult - HashTable:: - LookupForWriting(const T& key) { - DCHECK(!AccessForbidden()); - DCHECK(table_); - RegisterModification(); - - ValueType* table = table_; - size_t size_mask = TableSizeMask(); - unsigned h = HashTranslator::GetHash(key); - size_t i = h & size_mask; - size_t probe_count = 0; - - UPDATE_ACCESS_COUNTS(); - - bool can_reuse_deleted_entry = - Allocator::template CanReuseHashTableDeletedBucket(); - - ValueType* deleted_entry = nullptr; - - while (true) { - ValueType* entry = table + i; - - if (IsEmptyBucket(*entry)) - return LookupResult{deleted_entry ? deleted_entry : entry, false, h}; - - if (KeyTraits::kSafeToCompareToEmptyOrDeleted) { - if (HashTranslator::Equal(Extractor::ExtractKey(*entry), key)) { - return LookupResult{entry, true, h}; - } - - if (can_reuse_deleted_entry && IsDeletedBucket(*entry)) { - deleted_entry = entry; - } - } else { - if (IsDeletedBucket(*entry)) { - if (can_reuse_deleted_entry) { - deleted_entry = entry; - } - } else if (HashTranslator::Equal(Extractor::ExtractKey(*entry), key)) { - return LookupResult{entry, true, h}; - } - } - ++probe_count; - UPDATE_PROBE_COUNTS(); - i = (i + probe_count) & size_mask; - } -} - -template -struct HashTableBucketInitializer { - STATIC_ONLY(HashTableBucketInitializer); - static_assert(!Traits::kEmptyValueIsZero); - - static void Reinitialize(Value& bucket) { - ConstructTraits::ConstructAndNotifyElement( - &bucket, Traits::EmptyValue()); - DCHECK(IsHashTraitsEmptyValue(bucket)); - } - - template - static Value* AllocateTable(unsigned size, size_t alloc_size) { - Value* result = - Allocator::template AllocateHashTableBacking( - alloc_size); - InitializeTable(result, size); - return result; - } - - static void InitializeTable(Value* table, unsigned size) { - for (unsigned i = 0; i < size; i++) { - Reinitialize(table[i]); - } - } -}; - -// Specialization when the hash traits for a type have kEmptyValueIsZero = true -// which indicate that all zero bytes represent an empty object. -template -struct HashTableBucketInitializer { - STATIC_ONLY(HashTableBucketInitializer); - static void Reinitialize(Value& bucket) { - // The memset to 0 looks like a slow operation but is optimized by the - // compilers. - if (!Allocator::kIsGarbageCollected) { - // NOLINTNEXTLINE(bugprone-undefined-memory-manipulation) - memset(&bucket, 0, sizeof(bucket)); - } else { - AtomicMemzero(&bucket); - } - CheckEmptyValues(&bucket, 1); - } - - template - static Value* AllocateTable(unsigned size, size_t alloc_size) { - Value* result = - Allocator::template AllocateZeroedHashTableBacking( - alloc_size); - CheckEmptyValues(result, size); - return result; - } - - static void InitializeTable(Value* table, unsigned size) { - AtomicMemzero(table, size * sizeof(Value)); - CheckEmptyValues(table, size); - } - - private: - static void CheckEmptyValues(Value* values, unsigned size) { -#if EXPENSIVE_DCHECKS_ARE_ON() - for (unsigned i = 0; i < size; i++) { - DCHECK(IsHashTraitsEmptyValue(values[i])); - } -#endif - } -}; - -template -inline void HashTable:: - ReinitializeBucket(ValueType& bucket) { - // Reinitialize is used when recycling a deleted bucket. - DCHECK(IsDeletedBucket(bucket)); - DCHECK(Allocator::template CanReuseHashTableDeletedBucket()); - HashTableBucketInitializer::Reinitialize(bucket); -} - -template -template -typename HashTable:: - AddResult - HashTable::insert( - T&& key, - Extra&& extra) { - DCHECK(!AccessForbidden()); - DCHECK(Allocator::IsAllocationAllowed()); - if (!table_) - Expand(); - - DCHECK(table_); - - ValueType* table = table_; - size_t size_mask = TableSizeMask(); - unsigned h = HashTranslator::GetHash(key); - size_t i = h & size_mask; - size_t probe_count = 0; - - UPDATE_ACCESS_COUNTS(); - - bool can_reuse_deleted_entry = - Allocator::template CanReuseHashTableDeletedBucket(); - - ValueType* deleted_entry = nullptr; - ValueType* entry; - while (true) { - entry = table + i; - - if (IsEmptyBucket(*entry)) - break; - - if (KeyTraits::kSafeToCompareToEmptyOrDeleted) { - if (HashTranslator::Equal(Extractor::ExtractKey(*entry), key)) { - return AddResult(this, entry, false); - } - - if (can_reuse_deleted_entry && IsDeletedBucket(*entry)) { - deleted_entry = entry; - } - } else { - if (IsDeletedBucket(*entry)) { - if (can_reuse_deleted_entry) { - deleted_entry = entry; - } - } else if (HashTranslator::Equal(Extractor::ExtractKey(*entry), key)) { - return AddResult(this, entry, false); - } - } - ++probe_count; - UPDATE_PROBE_COUNTS(); - i = (i + probe_count) & size_mask; - } - - RegisterModification(); - - if (deleted_entry) { - DCHECK(can_reuse_deleted_entry); - // Overwrite any data left over from last use, using placement new or - // memset. - ReinitializeBucket(*deleted_entry); - entry = deleted_entry; - --deleted_count_; - } - - HashTranslator::Store(*entry, std::forward(key), - std::forward(extra)); - DCHECK(!IsEmptyOrDeletedBucket(*entry)); - // Translate constructs an element so we need to notify using the trait. Avoid - // doing that in the translator so that they can be easily customized. - ConstructTraits::NotifyNewElement(entry); - - ++key_count_; - - if (ShouldExpand()) { - entry = Expand(entry); - } else if (webf::IsWeak::value && ShouldShrink()) { - // When weak hash tables are processed by the garbage collector, - // elements with no other strong references to them will have their - // table entries cleared. But no shrinking of the backing store is - // allowed at that time, as allocations are prohibited during that - // GC phase. - // - // With that weak processing taking care of removals, explicit - // erase()s of elements is rarely done. Which implies that the - // weak hash table will never be checked if it can be shrunk. - // - // To prevent weak hash tables with very low load factors from - // developing, we perform it when adding elements instead. - entry = Rehash(table_size_ / 2, entry); - } - - return AddResult(this, entry, true); -} - -template -template -typename HashTable:: - AddResult - HashTable:: - InsertPassingHashCode(T&& key, Extra&& extra) { - DCHECK(!AccessForbidden()); - DCHECK(Allocator::IsAllocationAllowed()); - if (!table_) - Expand(); - - LookupResult lookup_result = LookupForWriting(key); - ValueType* entry = lookup_result.entry; - if (lookup_result.found) { - return AddResult(this, entry, false); - } - - RegisterModification(); - - if (IsDeletedBucket(*entry)) { - ReinitializeBucket(*entry); - --deleted_count_; - } - - HashTranslator::Store(*entry, std::forward(key), - std::forward(extra), lookup_result.hash); - DCHECK(!IsEmptyOrDeletedBucket(*entry)); - // Translate constructs an element so we need to notify using the trait. Avoid - // doing that in the translator so that they can be easily customized. - ConstructTraits::NotifyNewElement(entry); - - ++key_count_; - if (ShouldExpand()) - entry = Expand(entry); - - return AddResult(this, entry, true); -} - -template -Value* HashTable::Reinsert( - ValueType&& entry) { - DCHECK(table_); - DCHECK(!AccessForbidden()); - RegisterModification(); -#if DUMP_HASHTABLE_STATS - HashTableStats::instance().numReinserts.fetch_add(1, - std::memory_order_relaxed); -#endif -#if DUMP_HASHTABLE_STATS_PER_TABLE - stats_->numReinserts.fetch_add(1, std::memory_order_relaxed); -#endif - - ValueType* table = table_; - size_t size_mask = TableSizeMask(); - const auto& key = Extractor::ExtractKey(entry); - unsigned h = KeyTraits::GetHash(key); - size_t i = h & size_mask; - size_t probe_count = 0; - - UPDATE_ACCESS_COUNTS(); - - ValueType* new_entry = table + i; - while (!IsEmptyBucket(*new_entry)) { - DCHECK(!IsDeletedBucket(*new_entry)); - DCHECK(!KeyTraits::Equal(Extractor::ExtractKey(*new_entry), key)); - - ++probe_count; - UPDATE_PROBE_COUNTS(); - i = (i + probe_count) & size_mask; - new_entry = table + i; - } - - Mover::value>::Move(std::move(entry), - *new_entry); - - return new_entry; -} - -template -template -inline typename HashTable:: - iterator - HashTable::Find( - const T& key) { - ValueType* entry = Lookup(key); - if (!entry) - return end(); - - return MakeKnownGoodIterator(entry); -} - -template -template -inline typename HashTable:: - const_iterator - HashTable::Find( - const T& key) const { - const ValueType* entry = Lookup(key); - if (!entry) - return end(); - - return MakeKnownGoodConstIterator(entry); -} - -template -template -bool HashTable::Contains( - const T& key) const { - return Lookup(key); -} - -template -void HashTable::erase( - const ValueType* pos) { - RegisterModification(); -#if DUMP_HASHTABLE_STATS - HashTableStats::instance().numRemoves.fetch_add(1, std::memory_order_relaxed); -#endif -#if DUMP_HASHTABLE_STATS_PER_TABLE - stats_->numRemoves.fetch_add(1, std::memory_order_relaxed); -#endif - - EnterAccessForbiddenScope(); - DeleteBucket(const_cast(*pos)); - LeaveAccessForbiddenScope(); - ++deleted_count_; - --key_count_; - - if (ShouldShrink()) - Shrink(); -} - -template -inline void -HashTable::erase( - iterator it) { - if (it == end()) - return; - erase(it.iterator_.position_); -} - -template -inline void -HashTable::erase( - const_iterator it) { - if (it == end()) - return; - erase(it.position_); -} - -template -inline void -HashTable::erase( - KeyPeekInType key) { - erase(find(key)); -} - -template -Value* -HashTable::AllocateTable( - unsigned size) { - // Assert that we will not use memset on things with a vtable entry. The - // compiler will also check this on some platforms. We would like to check - // this on the whole value (key-value pair), but std::is_polymorphic will - // return false for a pair of two types, even if one of the components is - // polymorphic. - static_assert( - !Traits::kEmptyValueIsZero || !std::is_polymorphic::value, - "empty value cannot be zero for things with a vtable"); - static_assert( - Allocator::kIsGarbageCollected || - ((!IsDisallowNew || !IsTraceable::value) && - (!IsDisallowNew || !IsTraceable::value)), - "Cannot put DISALLOW_NEW objects that " - "have trace methods into an off-heap HashTable"); - - size_t alloc_size = base::CheckMul(size, sizeof(ValueType)).ValueOrDie(); - return HashTableBucketInitializer< - Traits, Allocator, Value>::template AllocateTable(size, - alloc_size); -} - -template -void HashTable:: - DeleteAllBucketsAndDeallocate(ValueType* table, unsigned size) { - // We delete a bucket in the following cases: - // - It is not trivially destructible. - // - The table is weak (thus garbage collected) and we are currently marking. - // This is to handle the case where a backing store is removed from the - // HashTable after HashTable has been enqueued for processing. If we remove - // the backing in that case it stays unprocessed which upsets the marking - // verifier that checks that all backings are in consistent state. - const bool needs_bucket_deletion = - !std::is_trivially_destructible::value || - (webf::IsWeak::value && Allocator::IsIncrementalMarking()); - if (needs_bucket_deletion) { - for (unsigned i = 0; i < size; ++i) { - // This code is called when the hash table is cleared or resized. We - // have allocated a new backing store and we need to run the - // destructors on the old backing store, as it is being freed. If we - // are GCing we need to both call the destructor and mark the bucket - // as deleted, otherwise the destructor gets called again when the - // GC finds the backing store. With the default allocator it's - // enough to call the destructor, since we will free the memory - // explicitly and we won't see the memory with the bucket again. - if (Allocator::kIsGarbageCollected) { - if (!IsEmptyOrDeletedBucket(table[i])) - DeleteBucket(table[i]); - } else { - if (!IsDeletedBucket(table[i])) - table[i].~ValueType(); - } - } - } - Allocator::template FreeHashTableBacking(table); -} - -template -Value* HashTable::Expand( - Value* entry) { - unsigned new_size; - if (!table_size_) { - new_size = KeyTraits::kMinimumTableSize; - } else if (MustRehashInPlace()) { - new_size = table_size_; - } else { - new_size = table_size_ * 2; - CHECK_GT(new_size, table_size_); - } - - return Rehash(new_size, entry); -} - -template -Value* -HashTable::ExpandBuffer( - unsigned new_table_size, - Value* entry, - bool& success) { - success = false; - DCHECK_LT(table_size_, new_table_size); -// CHECK(Allocator::IsAllocationAllowed()); - if (!table_ || - !Allocator::template ExpandHashTableBacking( - table_, new_table_size * sizeof(ValueType))) - return nullptr; - - success = true; - - Value* new_entry = nullptr; - unsigned old_table_size = table_size_; - ValueType* original_table = table_; - - ValueType* temporary_table = AllocateTable(old_table_size); - for (unsigned i = 0; i < old_table_size; i++) { - if (&table_[i] == entry) - new_entry = &temporary_table[i]; - if (IsEmptyOrDeletedBucket(table_[i])) { - DCHECK_NE(&table_[i], entry); - // All entries are initially empty. See AllocateTable(). - DCHECK(IsEmptyBucket(temporary_table[i])); - } else { - Mover::value>:: - Move(std::move(table_[i]), temporary_table[i]); - table_[i].~ValueType(); - } - } - table_ = temporary_table; - Allocator::template BackingWriteBarrier(&table_); - - HashTableBucketInitializer::InitializeTable( - original_table, new_table_size); - new_entry = RehashTo(original_table, new_table_size, new_entry); - - return new_entry; -} - -template -Value* HashTable::RehashTo( - ValueType* new_table, - unsigned new_table_size, - Value* entry) { -#if DUMP_HASHTABLE_STATS - if (table_size_ != 0) { - HashTableStats::instance().numRehashes.fetch_add(1, - std::memory_order_relaxed); - } -#endif - -#if DUMP_HASHTABLE_STATS_PER_TABLE - if (table_size_ != 0) - stats_->numRehashes.fetch_add(1, std::memory_order_relaxed); -#endif - - HashTable new_hash_table(RawStorageTag{}, new_table, new_table_size); - - Value* new_entry = nullptr; - for (unsigned i = 0; i != table_size_; ++i) { - if (IsEmptyOrDeletedBucket(table_[i])) { - DCHECK_NE(&table_[i], entry); - continue; - } - Value* reinserted_entry = new_hash_table.Reinsert(std::move(table_[i])); - if (&table_[i] == entry) { - DCHECK(!new_entry); - new_entry = reinserted_entry; - } - } - - Allocator::TraceBackingStoreIfMarked(new_hash_table.table_); - - ValueType* old_table = table_; - unsigned old_table_size = table_size_; - - // This swaps the newly allocated buffer with the current one. The store to - // the current table has to be atomic to prevent races with concurrent marker. - AsAtomicPtr(&table_)->store(new_hash_table.table_, std::memory_order_relaxed); - Allocator::template BackingWriteBarrier(&table_); - table_size_ = new_table_size; - - new_hash_table.table_ = old_table; - new_hash_table.table_size_ = old_table_size; - - // Explicitly clear since garbage collected HashTables don't do this on - // destruction. - new_hash_table.clear(); - - deleted_count_ = 0; - -#if DUMP_HASHTABLE_STATS_PER_TABLE - if (!stats_) - stats_ = HashTableStatsPtr::Create(); -#endif - - return new_entry; -} - -template -Value* HashTable::Rehash( - unsigned new_table_size, - Value* entry) { - unsigned old_table_size = table_size_; - -#if DUMP_HASHTABLE_STATS - if (old_table_size != 0) { - HashTableStats::instance().numRehashes.fetch_add(1, - std::memory_order_relaxed); - } -#endif - -#if DUMP_HASHTABLE_STATS_PER_TABLE - if (old_table_size != 0) - stats_->numRehashes.fetch_add(1, std::memory_order_relaxed); -#endif - - // The Allocator::kIsGarbageCollected check is not needed. The check is just - // a static hint for a compiler to indicate that Base::expandBuffer returns - // false if Allocator is a PartitionAllocator. - if (Allocator::kIsGarbageCollected && new_table_size > old_table_size) { - bool success; - Value* new_entry = ExpandBuffer(new_table_size, entry, success); - if (success) - return new_entry; - } - - ValueType* new_table = AllocateTable(new_table_size); - Value* new_entry = RehashTo(new_table, new_table_size, entry); - - return new_entry; -} - -template -void HashTable::clear() { - RegisterModification(); - if (!table_) - return; - - EnterAccessForbiddenScope(); - DeleteAllBucketsAndDeallocate(table_, table_size_); - LeaveAccessForbiddenScope(); - AsAtomicPtr(&table_)->store(nullptr, std::memory_order_relaxed); - table_size_ = 0; - key_count_ = 0; -} - -template -HashTable::HashTable( - const HashTable& other) - : table_(nullptr), - table_size_(0), - key_count_(0), - deleted_count_(0), - queue_flag_(false) -#if DCHECK_IS_ON() - , - access_forbidden_(false), - modifications_(0) -#endif -#if DUMP_HASHTABLE_STATS_PER_TABLE - , - stats_(HashTableStatsPtr::copy(other.stats_)) -#endif -{ - if (other.size()) - ReserveCapacityForSize(other.size()); - // Copy the hash table the dumb way, by adding each element to the new - // table. It might be more efficient to copy the table slots, but it's not - // clear that efficiency is needed. - for (const auto& element : other) - insert(element); -} - -template -HashTable::HashTable( - HashTable&& other) - : table_(nullptr), - table_size_(0), - key_count_(0), - deleted_count_(0), - queue_flag_(false) -#if DCHECK_IS_ON() - , - access_forbidden_(false), - modifications_(0) -#endif -#if DUMP_HASHTABLE_STATS_PER_TABLE - , - stats_(HashTableStatsPtr::copy(other.stats_)) -#endif -{ - swap(other); -} - -template -void HashTable::swap( - HashTable& other) { - DCHECK(!AccessForbidden()); - // Following 3 lines swap table_ and other.table_ using atomic stores. These - // are needed for Oilpan concurrent marking which might trace the hash table - // while it is being swapped (i.e. the atomic stores are to avoid a data - // race). Atomic reads are not needed here because this method is only called - // on the mutator thread, which is also the only one that writes to them, so - // there is *no* risk of data races when reading. - AtomicWriteSwap(table_, other.table_); - Allocator::template BackingWriteBarrier(&table_); - Allocator::template BackingWriteBarrier(&other.table_); - if (IsWeak::value) { - // Weak processing is omitted when no backing store is present. In case such - // an empty table is later on used it needs to be strongified. - if (table_) - Allocator::TraceBackingStoreIfMarked(table_); - if (other.table_) - Allocator::TraceBackingStoreIfMarked(other.table_); - } - std::swap(table_size_, other.table_size_); - std::swap(key_count_, other.key_count_); - // std::swap does not work for bit fields. - unsigned deleted = deleted_count_; - deleted_count_ = other.deleted_count_; - other.deleted_count_ = deleted; - DCHECK(!queue_flag_); - DCHECK(!other.queue_flag_); - -#if DCHECK_IS_ON() - std::swap(modifications_, other.modifications_); -#endif - -#if DUMP_HASHTABLE_STATS_PER_TABLE - HashTableStatsPtr::swap(stats_, other.stats_); -#endif -} - -template -HashTable& -HashTable::operator=( - const HashTable& other) { - HashTable tmp(other); - swap(tmp); - return *this; -} - -template -HashTable& -HashTable::operator=( - HashTable&& other) { - swap(other); - return *this; -} - -template -struct WeakProcessingHashTableHelper { - STATIC_ONLY(WeakProcessingHashTableHelper); - static void Process(const typename Allocator::LivenessBroker&, const void*) {} -}; - -template -struct WeakProcessingHashTableHelper { - STATIC_ONLY(WeakProcessingHashTableHelper); - - using HashTableType = - HashTable; - using ValueType = typename HashTableType::ValueType; - - // Used for purely weak and for weak-and-strong tables (ephemerons). - static void Process(const typename Allocator::LivenessBroker& info, - const void* parameter) { - HashTableType* table = - reinterpret_cast(const_cast(parameter)); - // During incremental marking, the table may be freed after the callback has - // been registered. - if (!table->table_) - return; - - // Weak processing: If the backing was accessible through an iterator and - // thus marked strongly this loop will find all buckets as non-empty. - for (ValueType* element = table->table_ + table->table_size_ - 1; - element >= table->table_; element--) { - if (!HashTableType::IsEmptyOrDeletedBucket(*element)) { - if (!TraceInCollectionTrait::IsAlive( - info, *element)) { - table->RegisterModification(); - HashTableType::DeleteBucket(*element); // Also calls the destructor. - table->deleted_count_++; - table->key_count_--; - // We don't rehash the backing until the next add or delete, - // because that would cause allocation during GC. - } - } - } - } -}; - -template -void HashTable::Trace( - auto visitor) const - requires Allocator::kIsGarbageCollected -{ - static_assert(webf::IsWeak::value || IsTraceable::value, - "Value should not be traced"); - TraceTable(visitor, AsAtomicPtr(&table_)->load(std::memory_order_relaxed)); -} - -template -void HashTable::TraceTable( - auto visitor, - const ValueType* table) const - requires Allocator::kIsGarbageCollected -{ - if (!webf::IsWeak::value) { - // Strong HashTable. - Allocator::template TraceHashTableBackingStrongly( - visitor, table, &table_); - } else { - // Weak HashTable. The HashTable may be held alive strongly from somewhere - // else, e.g., an iterator. - - // Trace the table weakly. For marking this will result in delaying the - // processing until the end of the atomic pause. It is safe to trace - // weakly multiple times. - Allocator::template TraceHashTableBackingWeakly( - visitor, table, &table_, - WeakProcessingHashTableHelper, Key, Value, - Extractor, Traits, KeyTraits, - Allocator>::Process, - this); - } -} - -// iterator adapters - -template -struct HashTableConstIteratorAdapter { - static_assert(!IsTraceable::value); - - using iterator_category = std::bidirectional_iterator_tag; - using value_type = HashTableType::ValueType; - using difference_type = ptrdiff_t; - using pointer = value_type*; - using reference = value_type&; - - HashTableConstIteratorAdapter() = default; - HashTableConstIteratorAdapter( - const typename HashTableType::const_iterator& impl) - : impl_(impl) {} - typedef typename Traits::IteratorConstGetType GetType; - typedef - typename HashTableType::ValueTraits::IteratorConstGetType SourceGetType; - - GetType Get() const { - return const_cast(SourceGetType(impl_.Get())); - } - typename Traits::IteratorConstReferenceType operator*() const { - return *Get(); - } - GetType operator->() const { return Get(); } - - HashTableConstIteratorAdapter& operator++() { - ++impl_; - return *this; - } - HashTableConstIteratorAdapter operator++(int) { - HashTableConstIteratorAdapter copy = *this; - ++*this; - return copy; - } - HashTableConstIteratorAdapter& operator--() { - --impl_; - return *this; - } - HashTableConstIteratorAdapter operator--(int) { - HashTableConstIteratorAdapter copy = *this; - --*this; - return copy; - } - typename HashTableType::const_iterator impl_; -}; - -template -struct HashTableConstIteratorAdapter< - HashTableType, - Traits, - typename std::enable_if_t::value>> { - static_assert(IsTraceable::value); - STACK_ALLOCATED(); - - public: - using iterator_category = std::bidirectional_iterator_tag; - using value_type = HashTableType::ValueType; - using difference_type = ptrdiff_t; - using pointer = value_type*; - using reference = value_type&; - - HashTableConstIteratorAdapter() = default; - HashTableConstIteratorAdapter( - const typename HashTableType::const_iterator& impl) - : impl_(impl) {} - typedef typename Traits::IteratorConstGetType GetType; - typedef - typename HashTableType::ValueTraits::IteratorConstGetType SourceGetType; - - GetType Get() const { - return const_cast(SourceGetType(impl_.Get())); - } - typename Traits::IteratorConstReferenceType operator*() const { - return *Get(); - } - GetType operator->() const { return Get(); } - - HashTableConstIteratorAdapter& operator++() { - ++impl_; - return *this; - } - HashTableConstIteratorAdapter operator++(int) { - HashTableConstIteratorAdapter copy = *this; - ++*this; - return copy; - } - HashTableConstIteratorAdapter& operator--() { - --impl_; - return *this; - } - HashTableConstIteratorAdapter operator--(int) { - HashTableConstIteratorAdapter copy = *this; - --*this; - return copy; - } - typename HashTableType::const_iterator impl_; -}; - -template -std::ostream& operator<<( - std::ostream& stream, - const HashTableConstIteratorAdapter& iterator) { - return stream << iterator.impl_; -} - -template -struct HashTableIteratorAdapter { - static_assert(!IsTraceable::value); - - using iterator_category = std::bidirectional_iterator_tag; - using value_type = HashTableType::ValueType; - using difference_type = ptrdiff_t; - using pointer = value_type*; - using reference = value_type&; - - typedef typename Traits::IteratorGetType GetType; - typedef typename HashTableType::ValueTraits::IteratorGetType SourceGetType; - - constexpr HashTableIteratorAdapter() = default; - HashTableIteratorAdapter(const typename HashTableType::iterator& impl) - : impl_(impl) {} - - GetType Get() const { - return const_cast(SourceGetType(impl_.get())); - } - typename Traits::IteratorReferenceType operator*() const { return *Get(); } - GetType operator->() const { return Get(); } - - HashTableIteratorAdapter& operator++() { - ++impl_; - return *this; - } - HashTableIteratorAdapter operator++(int) { - auto copy = *this; - ++(*this); - return copy; - } - - HashTableIteratorAdapter& operator--() { - --impl_; - return *this; - } - HashTableIteratorAdapter operator--(int) { - auto copy = *this; - --(*this); - return copy; - } - - operator HashTableConstIteratorAdapter() { - typename HashTableType::const_iterator i = impl_; - return i; - } - - typename HashTableType::iterator impl_; -}; - -template -struct HashTableIteratorAdapter< - HashTableType, - Traits, - typename std::enable_if_t::value>> { - static_assert(IsTraceable::value); - STACK_ALLOCATED(); - - public: - using iterator_category = std::bidirectional_iterator_tag; - using value_type = HashTableType::ValueType; - using difference_type = ptrdiff_t; - using pointer = value_type*; - using reference = value_type&; - - typedef typename Traits::IteratorGetType GetType; - typedef typename HashTableType::ValueTraits::IteratorGetType SourceGetType; - - constexpr HashTableIteratorAdapter() = default; - HashTableIteratorAdapter(const typename HashTableType::iterator& impl) - : impl_(impl) {} - - GetType Get() const { - return const_cast(SourceGetType(impl_.get())); - } - typename Traits::IteratorReferenceType operator*() const { return *Get(); } - GetType operator->() const { return Get(); } - - HashTableIteratorAdapter& operator++() { - ++impl_; - return *this; - } - HashTableIteratorAdapter operator++(int) { - auto copy = *this; - ++(*this); - return copy; - } - - HashTableIteratorAdapter& operator--() { - --impl_; - return *this; - } - HashTableIteratorAdapter operator--(int) { - auto copy = *this; - --(*this); - return copy; - } - - operator HashTableConstIteratorAdapter() { - typename HashTableType::const_iterator i = impl_; - return i; - } - - typename HashTableType::iterator impl_; -}; - -template -std::ostream& operator<<( - std::ostream& stream, - const HashTableIteratorAdapter& iterator) { - return stream << iterator.impl_; -} - -template -inline bool operator==(const HashTableConstIteratorAdapter& a, - const HashTableConstIteratorAdapter& b) { - return a.impl_ == b.impl_; -} - -template -inline bool operator!=(const HashTableConstIteratorAdapter& a, - const HashTableConstIteratorAdapter& b) { - return a.impl_ != b.impl_; -} - -template -inline bool operator==(const HashTableIteratorAdapter& a, - const HashTableIteratorAdapter& b) { - return a.impl_ == b.impl_; -} - -template -inline bool operator!=(const HashTableIteratorAdapter& a, - const HashTableIteratorAdapter& b) { - return a.impl_ != b.impl_; -} - -// All 4 combinations of ==, != and Const,non const. -template -inline bool operator==(const HashTableConstIteratorAdapter& a, - const HashTableIteratorAdapter& b) { - return a.impl_ == b.impl_; -} - -template -inline bool operator!=(const HashTableConstIteratorAdapter& a, - const HashTableIteratorAdapter& b) { - return a.impl_ != b.impl_; -} - -template -inline bool operator==(const HashTableIteratorAdapter& a, - const HashTableConstIteratorAdapter& b) { - return a.impl_ == b.impl_; -} - -template -inline bool operator!=(const HashTableIteratorAdapter& a, - const HashTableConstIteratorAdapter& b) { - return a.impl_ != b.impl_; -} - -template -inline void RemoveAll(Collection1& collection, - const Collection2& to_be_removed) { - if (collection.empty() || to_be_removed.empty()) - return; - typedef typename Collection2::const_iterator CollectionIterator; - CollectionIterator end(to_be_removed.end()); - for (CollectionIterator it(to_be_removed.begin()); it != end; ++it) - collection.erase(*it); -} - -} // namespace webf - -#endif // WEBF_HASH_TABLE_H_ - diff --git a/bridge/bindings/v8/platform/wtf/key_value_pair.h b/bridge/bindings/v8/platform/wtf/key_value_pair.h deleted file mode 100644 index 693600e56e..0000000000 --- a/bridge/bindings/v8/platform/wtf/key_value_pair.h +++ /dev/null @@ -1,451 +0,0 @@ -/* -* Copyright (C) 2019-2022 The Kraken authors. All rights reserved. -* Copyright (C) 2022-present The WebF authors. All rights reserved. -*/ - -#ifndef WEBF_KEY_VALUE_PAIR_H_ -#define WEBF_KEY_VALUE_PAIR_H_ - -#include - -#include "bindings/v8/platform/wtf/type_traits.h" -#include "bindings/v8/platform/wtf/hash_traits.h" -#include "bindings/v8/platform/wtf/hash_table.h" - -namespace webf { - -template -struct KeyValuePair { - using KeyType = KeyTypeArg; - using ValueType = ValueTypeArg; - - template - KeyValuePair(IncomingKeyType&& key, IncomingValueType&& value) - : key(std::forward(key)), - value(std::forward(value)) {} - - template - KeyValuePair(KeyValuePair&& other) - : key(std::move(other.key)), value(std::move(other.value)) {} - - KeyTypeArg key; - ValueTypeArg value; -}; - -template -struct IsWeak> - : std::integral_constant::value || IsWeak::value> {}; - -template -struct IsTraceable> - : std::integral_constant::value || IsTraceable::value> {}; - -template > -struct KeyValuePairHashTraits - : TwoFieldsHashTraits { - using TraitType = P; - using KeyTraits = KeyTraitsArg; - using ValueTraits = ValueTraitsArg; - - // Even non-traceable keys need to have their trait set. This is because - // non-traceable keys still need to be processed concurrently for checking - // empty/deleted state. - static constexpr bool kCanTraceConcurrently = - KeyTraits::kCanTraceConcurrently && - (ValueTraits::kCanTraceConcurrently || - !IsTraceable::value); -}; - -template -struct HashTraits> - : public KeyValuePairHashTraits, HashTraits> {}; - -namespace internal { - -template ::value> -class IteratorAdapterBase {}; - -template -struct IteratorAdapterBase { - STACK_ALLOCATED(); -}; - -} // namespace internal - -template -struct HashTableConstKeysIterator; -template -struct HashTableConstValuesIterator; -template -struct HashTableKeysIterator; -template -struct HashTableValuesIterator; - -template -struct HashTableConstIteratorAdapter> - : internal::IteratorAdapterBase> { - typedef KeyValuePair ValueType; - typedef HashTableConstKeysIterator - KeysIterator; - typedef HashTableConstValuesIterator - ValuesIterator; - - using iterator_category = std::bidirectional_iterator_tag; - using value_type = ValueType; - using difference_type = ptrdiff_t; - using pointer = const ValueType*; - using reference = const ValueType&; - - HashTableConstIteratorAdapter() = default; - HashTableConstIteratorAdapter( - const typename HashTableType::const_iterator& impl) - : impl_(impl) {} - - const ValueType* Get() const { return (const ValueType*)impl_.Get(); } - const ValueType& operator*() const { return *Get(); } - const ValueType* operator->() const { return Get(); } - - HashTableConstIteratorAdapter& operator++() { - ++impl_; - return *this; - } - HashTableConstIteratorAdapter operator++(int) { - HashTableConstIteratorAdapter copy(*this); - ++*this; - return copy; - } - - HashTableConstIteratorAdapter& operator--() { - --impl_; - return *this; - } - HashTableConstIteratorAdapter operator--(int) { - HashTableConstIteratorAdapter copy(*this); - --*this; - return copy; - } - - KeysIterator Keys() { return KeysIterator(*this); } - ValuesIterator Values() { return ValuesIterator(*this); } - - typename HashTableType::const_iterator impl_; -}; - -template -struct HashTableIteratorAdapter> - : internal::IteratorAdapterBase> { - typedef KeyValuePair ValueType; - typedef HashTableKeysIterator - KeysIterator; - typedef HashTableValuesIterator - ValuesIterator; - - using iterator_category = std::bidirectional_iterator_tag; - using value_type = ValueType; - using difference_type = ptrdiff_t; - using pointer = ValueType*; - using reference = ValueType&; - - HashTableIteratorAdapter() = default; - HashTableIteratorAdapter(const typename HashTableType::iterator& impl) - : impl_(impl) {} - - ValueType* Get() const { return (ValueType*)impl_.Get(); } - ValueType& operator*() const { return *Get(); } - ValueType* operator->() const { return Get(); } - - HashTableIteratorAdapter& operator++() { - ++impl_; - return *this; - } - HashTableIteratorAdapter operator++(int) { - HashTableIteratorAdapter copy(*this); - ++*this; - return copy; - } - - HashTableIteratorAdapter& operator--() { - --impl_; - return *this; - } - HashTableIteratorAdapter operator--(int) { - HashTableIteratorAdapter copy(*this); - --*this; - return copy; - } - - operator HashTableConstIteratorAdapter() { - typename HashTableType::const_iterator i = impl_; - return i; - } - - KeysIterator Keys() { return KeysIterator(*this); } - ValuesIterator Values() { return ValuesIterator(*this); } - - typename HashTableType::iterator impl_; -}; - -template -struct HashTableConstKeysIterator - : internal::IteratorAdapterBase> { - private: - typedef HashTableConstIteratorAdapter> - ConstIterator; - - public: - using iterator_category = typename ConstIterator::iterator_category; - using value_type = KeyType; - using difference_type = typename ConstIterator::difference_type; - using pointer = const KeyType*; - using reference = const KeyType&; - - HashTableConstKeysIterator(const ConstIterator& impl) : impl_(impl) {} - - const KeyType* Get() const { return &(impl_.Get()->key); } - const KeyType& operator*() const { return *Get(); } - const KeyType* operator->() const { return Get(); } - - HashTableConstKeysIterator& operator++() { - ++impl_; - return *this; - } - HashTableConstKeysIterator operator++(int) { - HashTableConstKeysIterator copy(*this); - ++*this; - return copy; - } - - HashTableConstKeysIterator& operator--() { - --impl_; - return *this; - } - HashTableConstKeysIterator operator--(int) { - HashTableConstKeysIterator copy(*this); - --*this; - return copy; - } - - ConstIterator impl_; -}; - -template -struct HashTableConstValuesIterator - : internal::IteratorAdapterBase> { - private: - typedef HashTableConstIteratorAdapter> - ConstIterator; - - public: - using iterator_category = typename ConstIterator::iterator_category; - using value_type = MappedType; - using difference_type = typename ConstIterator::difference_type; - using pointer = const MappedType*; - using reference = const MappedType&; - - HashTableConstValuesIterator(const ConstIterator& impl) : impl_(impl) {} - - const MappedType* Get() const { return &(impl_.Get()->value); } - const MappedType& operator*() const { return *Get(); } - const MappedType* operator->() const { return Get(); } - - HashTableConstValuesIterator& operator++() { - ++impl_; - return *this; - } - HashTableConstValuesIterator operator++(int) { - HashTableConstValuesIterator copy(*this); - ++*this; - return copy; - } - - HashTableConstValuesIterator& operator--() { - --impl_; - return *this; - } - HashTableConstValuesIterator operator--(int) { - HashTableConstValuesIterator copy(*this); - --*this; - return copy; - } - - ConstIterator impl_; -}; - -template -struct HashTableKeysIterator - : internal::IteratorAdapterBase> { - private: - typedef HashTableIteratorAdapter> - Iterator; - typedef HashTableConstIteratorAdapter> - ConstIterator; - - public: - using iterator_category = typename Iterator::iterator_category; - using value_type = KeyType; - using difference_type = typename Iterator::difference_type; - using pointer = KeyType*; - using reference = KeyType&; - - HashTableKeysIterator(const Iterator& impl) : impl_(impl) {} - - KeyType* Get() const { return &(impl_.Get()->key); } - KeyType& operator*() const { return *Get(); } - KeyType* operator->() const { return Get(); } - - HashTableKeysIterator& operator++() { - ++impl_; - return *this; - } - HashTableKeysIterator operator++(int) { - HashTableKeysIterator copy(*this); - ++*this; - return copy; - } - - HashTableKeysIterator& operator--() { - --impl_; - return *this; - } - HashTableKeysIterator operator--(int) { - HashTableKeysIterator copy(*this); - --*this; - return copy; - } - - operator HashTableConstKeysIterator() { - ConstIterator i = impl_; - return i; - } - - Iterator impl_; -}; - -template -struct HashTableValuesIterator - : internal::IteratorAdapterBase> { - private: - typedef HashTableIteratorAdapter> - Iterator; - typedef HashTableConstIteratorAdapter> - ConstIterator; - - public: - using iterator_category = typename Iterator::iterator_category; - using value_type = MappedType; - using difference_type = typename Iterator::difference_type; - using pointer = MappedType*; - using reference = MappedType&; - - constexpr HashTableValuesIterator() = default; - - HashTableValuesIterator(const Iterator& impl) : impl_(impl) {} - - MappedType* Get() const { return &(impl_.Get()->value); } - MappedType& operator*() const { return *Get(); } - MappedType* operator->() const { return Get(); } - - HashTableValuesIterator& operator++() { - ++impl_; - return *this; - } - HashTableValuesIterator operator++(int) { - HashTableValuesIterator copy(*this); - ++*this; - return copy; - } - - HashTableValuesIterator& operator--() { - --impl_; - return *this; - } - HashTableValuesIterator operator--(int) { - HashTableValuesIterator copy(*this); - --*this; - return copy; - } - - operator HashTableConstValuesIterator() { - ConstIterator i = impl_; - return i; - } - - Iterator impl_; -}; - -template -inline bool operator==(const HashTableConstKeysIterator& a, - const HashTableConstKeysIterator& b) { - return a.impl_ == b.impl_; -} - -template -inline bool operator!=(const HashTableConstKeysIterator& a, - const HashTableConstKeysIterator& b) { - return a.impl_ != b.impl_; -} - -template -inline bool operator==(const HashTableConstValuesIterator& a, - const HashTableConstValuesIterator& b) { - return a.impl_ == b.impl_; -} - -template -inline bool operator!=(const HashTableConstValuesIterator& a, - const HashTableConstValuesIterator& b) { - return a.impl_ != b.impl_; -} - -template -inline bool operator==(const HashTableKeysIterator& a, - const HashTableKeysIterator& b) { - return a.impl_ == b.impl_; -} - -template -inline bool operator!=(const HashTableKeysIterator& a, - const HashTableKeysIterator& b) { - return a.impl_ != b.impl_; -} - -template -inline bool operator==(const HashTableValuesIterator& a, - const HashTableValuesIterator& b) { - return a.impl_ == b.impl_; -} - -template -inline bool operator!=(const HashTableValuesIterator& a, - const HashTableValuesIterator& b) { - return a.impl_ != b.impl_; -} - -} // namespace webf - -#endif // WEBF_KEY_VALUE_PAIR_H_ - diff --git a/bridge/bindings/v8/platform/wtf/thread_specific.h b/bridge/bindings/v8/platform/wtf/thread_specific.h deleted file mode 100644 index c0c2f4d39b..0000000000 --- a/bridge/bindings/v8/platform/wtf/thread_specific.h +++ /dev/null @@ -1,131 +0,0 @@ -/* -* Copyright (C) 2019-2022 The Kraken authors. All rights reserved. -* Copyright (C) 2022-present The WebF authors. All rights reserved. -*/ - -#ifndef PLATFORM_WEBF_THREAD_SPECIFIC_H_ -#define PLATFORM_WEBF_THREAD_SPECIFIC_H_ - -#include "bindings/v8/base/threading/thread_local_storage.h" -#include "bindings/v8/for_build/build_config.h" -//#include "bindings/v8/platform/wtf/allocator/allocator.h" - -#include "bindings/v8/platform/util/allocator/partition_allocator.h" -//#include "bindings/v8/platform/wtf/allocator/partitions.h" -#include "bindings/v8/platform/wtf/stack_util.h" -#include "bindings/v8/platform/util/main_thread_util.h" - -namespace webf { - -template -class ThreadSpecific { - USING_FAST_MALLOC(ThreadSpecific); - - public: - ThreadSpecific() : slot_(&Destroy) {} - ThreadSpecific(const ThreadSpecific&) = delete; - ThreadSpecific& operator=(const ThreadSpecific&) = delete; - bool - IsSet(); // Useful as a fast check to see if this thread has set this value. - T* operator->(); - operator T*(); - T& operator*(); - - private: - // Not implemented. It's technically possible to destroy a thread specific - // key, but one would need to make sure that all values have been destroyed - // already (usually, that all threads that used it have exited). It's - // unlikely that any user of this call will be in that situation - and having - // a destructor defined can be confusing, given that it has such strong - // pre-requisites to work correctly. - ~ThreadSpecific() = delete; - - T* Get() { return static_cast(slot_.Get()); } - - void Set(T* ptr) { - DCHECK(!Get()); - slot_.Set(ptr); - } - - void static Destroy(void* ptr); - - // This member must only be accessed or modified on the main thread. - T* main_thread_storage_ = nullptr; - base::ThreadLocalStorage::Slot slot_; -}; - -template -inline void ThreadSpecific::Destroy(void* ptr) { - // Never call destructors on the main thread. This is fine because Blink no - // longer has a graceful shutdown sequence. Be careful to call this function - // (which can be re-entrant) while the pointer is still set, to avoid lazily - // allocating Threading after it is destroyed. - if (IsMainThread()) - return; - - // The memory was allocated via Partitions::FastZeroedMalloc, and then the - // object was placement-newed. To destroy, we must call the delete expression, - // and then free the memory manually. - T* instance = static_cast(ptr); - instance->~T(); - Partitions::FastFree(ptr); -} - -template -inline bool ThreadSpecific::IsSet() { - return !!Get(); -} - -template -inline ThreadSpecific::operator T*() { - T* off_thread_ptr; -#if defined(__GLIBC__) || BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_FREEBSD) - // TLS is fast on these platforms. - // TODO(csharrison): Qualify this statement for Android. - const bool kMainThreadAlwaysChecksTLS = true; - T** ptr = &off_thread_ptr; - off_thread_ptr = static_cast(Get()); -#else - const bool kMainThreadAlwaysChecksTLS = false; - T** ptr = &main_thread_storage_; - if (UNLIKELY(MayNotBeMainThread())) { - off_thread_ptr = static_cast(Get()); - ptr = &off_thread_ptr; - } -#endif - // Set up thread-specific value's memory pointer before invoking constructor, - // in case any function it calls needs to access the value, to avoid - // recursion. - if (UNLIKELY(!*ptr)) { - *ptr = static_cast(Partitions::FastZeroedMalloc( - sizeof(T), nullptr)); - - // Even if we didn't realize we're on the main thread, we might still be. - // We need to double-check so that |main_thread_storage_| is populated. - if (!kMainThreadAlwaysChecksTLS && UNLIKELY(ptr != &main_thread_storage_) && - IsMainThread()) { - main_thread_storage_ = *ptr; - } - - Set(*ptr); - ::new (NotNullTag::kNotNull, *ptr) T; - } - return *ptr; -} - -template -inline T* ThreadSpecific::operator->() { - return operator T*(); -} - -template -inline T& ThreadSpecific::operator*() { - return *operator T*(); -} - -} // namespace webf - -using webf::ThreadSpecific; - -#endif // PLATFORM_WEBF_THREAD_SPECIFIC_H_ - diff --git a/bridge/bindings/v8/platform/wtf/threading.cc b/bridge/bindings/v8/platform/wtf/threading.cc deleted file mode 100644 index 351ee39e11..0000000000 --- a/bridge/bindings/v8/platform/wtf/threading.cc +++ /dev/null @@ -1,72 +0,0 @@ -/* -* Copyright (C) 2019-2022 The Kraken authors. All rights reserved. -* Copyright (C) 2022-present The WebF authors. All rights reserved. -*/ - -#include "bindings/v8/platform/wtf/threading.h" - -#include -#include "bindings/v8/for_build/build_config.h" -#include "bindings/v8/platform/wtf/stack_util.h" -//#include "bindings/v8/platform/wtf/text/text_codec_icu.h" - -namespace webf { - -#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_WIN) -base::PlatformThreadId CurrentThread() { - // TODO webf -// thread_local base::PlatformThreadId g_id = base::PlatformThread::CurrentId(); - thread_local base::PlatformThreadId g_id; - return g_id; -} -#endif // !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_WIN) - -// For debugging only -- whether a non-main thread has been created. - -#if DCHECK_IS_ON() -static std::atomic_bool g_thread_created(false); - -bool IsBeforeThreadCreated() { - return !g_thread_created; -} - -void WillCreateThread() { - g_thread_created = true; -} - -void SetIsBeforeThreadCreatedForTest() { - g_thread_created = false; -} -#endif - -ThreadSpecific* Threading::static_data_; - -// TODO webf -//Threading::Threading() -// : cached_converter_icu_(new ICUConverterWrapper), -// thread_id_(CurrentThread()) {} -// -//Threading::~Threading() = default; - -void Threading::Initialize() { - // TODO webf -// DCHECK(!Threading::static_data_); -// Threading::static_data_ = new ThreadSpecific; -// WtfThreading(); -} - -#if BUILDFLAG(IS_WIN) && defined(COMPILER_MSVC) -size_t Threading::ThreadStackSize() { - // Needed to bootstrap Threading on Windows, because this value is needed - // before the main thread data is fully initialized. - if (!Threading::static_data_->IsSet()) - return internal::ThreadStackSize(); - - Threading& data = WtfThreading(); - if (!data.thread_stack_size_) - data.thread_stack_size_ = internal::ThreadStackSize(); - return data.thread_stack_size_; -} -#endif - -} // namespace webf diff --git a/bridge/bindings/v8/platform/wtf/threading.h b/bridge/bindings/v8/platform/wtf/threading.h deleted file mode 100644 index 2467e6ce2c..0000000000 --- a/bridge/bindings/v8/platform/wtf/threading.h +++ /dev/null @@ -1,84 +0,0 @@ -/* -* Copyright (C) 2019-2022 The Kraken authors. All rights reserved. -* Copyright (C) 2022-present The WebF authors. All rights reserved. -*/ - -#ifndef PLATFORM_WEBF_THREADING_H_ -#define PLATFORM_WEBF_THREADING_H_ - -#include -#include - -#include "bindings/v8/base/check_op.h" -#include "bindings/v8/base/dcheck_is_on.h" -#include "bindings/v8/base/threading/platform_thread.h" -#include "bindings/v8/for_build//build_config.h" -#include "bindings/v8/platform/wtf/thread_specific.h" -#include "bindings/v8/platform/wtf/type_traits.h" - -namespace webf { - -#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_WIN) -base::PlatformThreadId CurrentThread(); -#else -// On Android gettid(3) uses a faster TLS model than thread_local. -// On Windows GetCurrentThreadId() directly pick TID from TEB. -inline base::PlatformThreadId CurrentThread() { - return base::PlatformThread::CurrentId(); -} -#endif // !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_WIN) - -#if DCHECK_IS_ON() -bool IsBeforeThreadCreated(); -void WillCreateThread(); -void SetIsBeforeThreadCreatedForTest(); -#endif - -struct ICUConverterWrapper; - -class Threading { - DISALLOW_NEW(); - - public: - Threading(); - Threading(const Threading&) = delete; - Threading& operator=(const Threading&) = delete; - ~Threading(); - - ICUConverterWrapper& CachedConverterICU() { return *cached_converter_icu_; } - - base::PlatformThreadId ThreadId() const { return thread_id_; } - - // Must be called on the main thread before any callers to wtfThreadData(). - static void Initialize(); - -#if BUILDFLAG(IS_WIN) && defined(COMPILER_MSVC) - static size_t ThreadStackSize(); -#endif - - private: - std::unique_ptr cached_converter_icu_; - - base::PlatformThreadId thread_id_; - -#if BUILDFLAG(IS_WIN) && defined(COMPILER_MSVC) - size_t thread_stack_size_ = 0u; -#endif - - static ThreadSpecific* static_data_; - friend Threading& WtfThreading(); -}; - -inline Threading& WtfThreading() { - DCHECK(Threading::static_data_); - return **Threading::static_data_; -} - -} // namespace webf - -using webf::CurrentThread; -using webf::Threading; -using webf::WtfThreading; - -#endif // PLATFORM_WEBF_THREADING_H_ - diff --git a/bridge/bindings/v8/script_value.h b/bridge/bindings/v8/script_value.h index 08fc525a03..32d2062734 100644 --- a/bridge/bindings/v8/script_value.h +++ b/bridge/bindings/v8/script_value.h @@ -16,7 +16,6 @@ #include "platform/script_state.h" #include "union_base.h" //#include "bindings/v8/platform/wtf/vector_traits.h" -//#include "script_wrappable.h" #include "foundation/macros.h" #include "bindings/v8/trace_wrapper_v8_reference.h" @@ -97,14 +96,6 @@ class ScriptValue final { bool operator!=(const ScriptValue& value) const { return !operator==(value); } - // This creates a new local Handle; Don't use this in performance-sensitive - // places. - bool IsFunction() const { - assert_m(!IsEmpty(), "ScriptValue is empty"); - v8::Local value = V8Value(); - return !value.IsEmpty() && value->IsFunction(); - } - // This creates a new local Handle; Don't use this in performance-sensitive // places. bool IsNull() const { diff --git a/bridge/bindings/v8/script_wrappable.cc b/bridge/bindings/v8/script_wrappable.cc deleted file mode 100644 index 9bd207635b..0000000000 --- a/bridge/bindings/v8/script_wrappable.cc +++ /dev/null @@ -1,6 +0,0 @@ -/* -* Copyright (C) 2019-2022 The Kraken authors. All rights reserved. -* Copyright (C) 2022-present The WebF authors. All rights reserved. -*/ - -#include "script_wrappable.h" diff --git a/bridge/bindings/v8/script_wrappable.h b/bridge/bindings/v8/script_wrappable.h deleted file mode 100644 index 1200a7dd4f..0000000000 --- a/bridge/bindings/v8/script_wrappable.h +++ /dev/null @@ -1,189 +0,0 @@ -/* -* Copyright (C) 2019-2022 The Kraken authors. All rights reserved. -* Copyright (C) 2022-present The WebF authors. All rights reserved. -*/ - -#ifndef WEBF_SCRIPT_WRAPPABLE_H -#define WEBF_SCRIPT_WRAPPABLE_H - -#include -#include "platform/heap/garbage_collected.h" -#include "name_client.h" -#include "base/memory/stack_allocated.h" -#include "bindings/v8/platform/wtf/vector_traits.h" -#include "bindings/v8/trace_wrapper_v8_reference.h" -#include "bindings/v8/wrapper_type_info.h" - -namespace webf { - -class DOMDataStore; -class ScriptState; - -// ScriptWrappable provides a way to map from/to C++ DOM implementation to/from -// JavaScript object (platform object). ToV8() converts a ScriptWrappable to -// a v8::Object and toScriptWrappable() converts a v8::Object back to -// a ScriptWrappable. v8::Object as platform object is called "wrapper object". -// The wrapper object for the main world is stored in ScriptWrappable. Wrapper -// objects for other worlds are stored in DOMDataStore. -class ScriptWrappable - : public GarbageCollected, - public NameClient { - public: - // This is a type dispatcher from ScriptWrappable* to a subtype, optimized for - // use cases that perform downcasts multiple times. If you perform a downcast - // only once, ScriptWrappable::DowncastTo or ScriptWrappable::ToMostDerived - // would be a better choice. - class TypeDispatcher final { - STACK_ALLOCATED(); - - public: - // The input parameter `script_wrappable` must not be null. - explicit TypeDispatcher(ScriptWrappable* script_wrappable) - : script_wrappable_(script_wrappable), - wrapper_type_info_(script_wrappable->GetWrapperTypeInfo()) {} - ~TypeDispatcher() = default; - - TypeDispatcher(const TypeDispatcher&) = delete; - TypeDispatcher& operator=(const TypeDispatcher&) = delete; - - // Downcasts the ScriptWrappable to the given template parameter type or - // nullptr if the ScriptWrappable doesn't implement the given type. The - // inheritance is checked with WrapperTypeInfo, i.e. the check is based on - // the IDL definitions in *.idl files, not based on C++ class inheritance. - template - T* DowncastTo() { - if (wrapper_type_info_->IsSubclass(T::GetStaticWrapperTypeInfo())) - return static_cast(script_wrappable_); - return nullptr; - } - - // Downcasts the ScriptWrappable to the given template parameter type iff - // the ScriptWrappable implements the type as the most derived class (i.e. - // the ScriptWrappable does _not_ implement a subtype of the given type). - // Otherwise, returns nullptr. The inheritance is checked with - // WrapperTypeInfo, i.e. the check is based on the IDL definitions in *.idl - // files, not based on C++ class inheritance. - template - T* ToMostDerived() { - if (wrapper_type_info_ == T::GetStaticWrapperTypeInfo()) - return static_cast(script_wrappable_); - return nullptr; - } - - private: - ScriptWrappable* script_wrappable_ = nullptr; - const WrapperTypeInfo* wrapper_type_info_ = nullptr; - }; - - ScriptWrappable(const ScriptWrappable&) = delete; - ScriptWrappable& operator=(const ScriptWrappable&) = delete; - ~ScriptWrappable() override = default; - - const char* NameInHeapSnapshot() const override; - - virtual void Trace(Visitor*) const; - - // Downcasts this instance to the given template parameter type or nullptr if - // this instance doesn't implement the given type. The inheritance is checked - // with WrapperTypeInfo, i.e. the check is based on the IDL definitions in - // *.idl files, not based on C++ class inheritance. - template - T* DowncastTo() { - if (GetWrapperTypeInfo()->IsSubclass(T::GetStaticWrapperTypeInfo())) - return static_cast(this); - return nullptr; - } - - // Downcasts this instance to the given template parameter type iff this - // instance implements the type as the most derived class (i.e. this instance - // does _not_ implement a subtype of the given type). Otherwise, returns - // nullptr. The inheritance is checked with WrapperTypeInfo, i.e. the check is - // based on the IDL definitions in *.idl files, not based on C++ class - // inheritance. - template - T* ToMostDerived() { - if (GetWrapperTypeInfo() == T::GetStaticWrapperTypeInfo()) - return static_cast(this); - return nullptr; - } - - template - T* ToImpl() { // DEPRECATED - // All ScriptWrappables are managed by the Blink GC heap; check that - // |T| is a garbage collected type. - static_assert( - sizeof(T) && webf::IsGarbageCollectedType::value, - "Classes implementing ScriptWrappable must be garbage collected."); - - // Check if T* is castable to ScriptWrappable*, which means T doesn't - // have two or more ScriptWrappable as superclasses. If T has two - // ScriptWrappable as superclasses, conversions from T* to - // ScriptWrappable* are ambiguous. - static_assert(!static_cast(static_cast(nullptr)), - "Class T must not have two or more ScriptWrappable as its " - "superclasses."); - - return static_cast(this); - } - - // Returns the WrapperTypeInfo of the instance. - // - // This method must be overridden by DEFINE_WRAPPERTYPEINFO macro. - virtual const WrapperTypeInfo* GetWrapperTypeInfo() const = 0; - - // Returns a wrapper object, creating it if needed. - v8::Local ToV8(ScriptState*); - v8::Local ToV8(v8::Isolate*, - v8::Local creation_context_object); - - // Creates and returns a new wrapper object. This DCHECKs that a wrapper does - // not exist yet. Use ToV8() if a wrapper might already exist. - virtual v8::Local Wrap(ScriptState*); - - // Associates the instance with the given |wrapper| if this instance is not - // yet associated with any wrapper. Returns the wrapper already associated - // or |wrapper| if not yet associated. - // The caller should always use the returned value rather than |wrapper|. - [[nodiscard]] virtual v8::Local AssociateWithWrapper( - v8::Isolate*, - const WrapperTypeInfo*, - v8::Local wrapper); - - protected: - ScriptWrappable() = default; - - private: - static_assert( - std::is_trivially_destructible< - TraceWrapperV8Reference>::value, - "TraceWrapperV8Reference should be trivially destructible."); - - // Inline storage for the a single wrapper reference. Only - // `DOMDataStore::UncheckedInlineStorageForWrappable()` should access this - // field. - TraceWrapperV8Reference wrapper_; - friend class DOMDataStore; -}; - -// Defines |GetWrapperTypeInfo| virtual method which returns the WrapperTypeInfo -// of the instance. Also declares a static member of type WrapperTypeInfo, of -// which the definition is given by the IDL code generator. -// -// All the derived classes of ScriptWrappable, regardless of directly or -// indirectly, must write this macro in the class definition as long as the -// class has a corresponding .idl file. -#define DEFINE_WRAPPERTYPEINFO() \ - public: \ - const WrapperTypeInfo* GetWrapperTypeInfo() const override { \ - return &wrapper_type_info_; \ - } \ - static const WrapperTypeInfo* GetStaticWrapperTypeInfo() { \ - return &wrapper_type_info_; \ - } \ - \ - private: \ - static const WrapperTypeInfo& wrapper_type_info_ - -} // namespace webf - -#endif // WEBF_SCRIPT_WRAPPABLE_H diff --git a/bridge/bindings/v8/v8_initializer.cc b/bridge/bindings/v8/v8_initializer.cc index 000b66a1e2..237681fc32 100644 --- a/bridge/bindings/v8/v8_initializer.cc +++ b/bridge/bindings/v8/v8_initializer.cc @@ -143,13 +143,13 @@ struct PrintV8OOM { }; std::ostream& operator<<(std::ostream& os, const PrintV8OOM& oom_details) { - const auto [location, details] = oom_details; - os << "V8 " << (details.is_heap_oom ? "javascript" : "process") << " OOM (" - << location; - if (details.detail) { - os << "; detail: " << details.detail; - } - os << ")."; +// const auto [location, details] = oom_details; +// os << "V8 " << (details.is_heap_oom ? "javascript" : "process") << " OOM (" +// << location; +// if (details.detail) { +// os << "; detail: " << details.detail; +// } +// os << ")."; return os; } @@ -293,7 +293,7 @@ void V8Initializer::InitializeIsolateHolder( } v8::Isolate* V8Initializer::InitializeMainThread() { - DCHECK(IsMainThread()); +// DCHECK(IsMainThread()); // ThreadScheduler* scheduler = ThreadScheduler::Current(); V8PerIsolateData::V8ContextSnapshotMode snapshot_mode = @@ -313,7 +313,7 @@ v8::Isolate* V8Initializer::InitializeMainThread() { // ThreadState::isolate_ needs to be set before setting the EmbedderHeapTracer // as setting the tracer indicates that a V8 garbage collection should trace // over to Blink. - DCHECK(ThreadStateStorage::MainThreadStateStorage()); +// DCHECK(ThreadStateStorage::MainThreadStateStorage()); InitializeV8Common(isolate); diff --git a/bridge/bindings/v8/v8_interface_bridge_base.h b/bridge/bindings/v8/v8_interface_bridge_base.h index 78113e71d0..545683f3ed 100644 --- a/bridge/bindings/v8/v8_interface_bridge_base.h +++ b/bridge/bindings/v8/v8_interface_bridge_base.h @@ -13,6 +13,7 @@ #include #include "platform/platform_export.h" +#include "foundation/macros.h" namespace webf { @@ -23,7 +24,7 @@ namespace bindings { // The common base class of code-generated V8-Blink bridge class of IDL // interfaces and namespaces. class PLATFORM_EXPORT V8InterfaceBridgeBase { - STATIC_ONLY(V8InterfaceBridgeBase); + WEBF_STATIC_ONLY(V8InterfaceBridgeBase); public: // Selects properties to be installed according to origin trial features. diff --git a/bridge/bindings/v8/wrapper_type_info.h b/bridge/bindings/v8/wrapper_type_info.h index d5cc587457..1ff5335640 100644 --- a/bridge/bindings/v8/wrapper_type_info.h +++ b/bridge/bindings/v8/wrapper_type_info.h @@ -11,6 +11,7 @@ #include "gin/public/wrapper_info.h" #include "platform/platform_export.h" #include "v8_interface_bridge_base.h" +#include "foundation/macros.h" namespace webf { @@ -32,7 +33,7 @@ static const int kV8PrototypeInternalFieldcount = 1; // WrapperTypeInfo member, so comparing pointers is a safe way to determine if // types match. struct PLATFORM_EXPORT WrapperTypeInfo final { - DISALLOW_NEW(); + WEBF_DISALLOW_NEW(); enum WrapperTypePrototype { kWrapperTypeObjectPrototype, @@ -124,7 +125,7 @@ struct PLATFORM_EXPORT WrapperTypeInfo final { // This field must be the first member of the struct WrapperTypeInfo. // See also static_assert() in .cpp file. - const gin::GinEmbedder gin_embedder; +// const gin::GinEmbedder gin_embedder; bindings::V8InterfaceBridgeBase::InstallInterfaceTemplateFuncType install_interface_template_func; diff --git a/bridge/core/dart_isolate_context.cc b/bridge/core/dart_isolate_context.cc index 443448a8e5..663e37bc9a 100644 --- a/bridge/core/dart_isolate_context.cc +++ b/bridge/core/dart_isolate_context.cc @@ -8,10 +8,10 @@ #endif #include #include "dart_isolate_context.h" -#include "event_factory.h" +//#include "event_factory.h" #include "html_element_factory.h" -#include "names_installer.h" -#include "page.h" +//#include "names_installer.h" +//#include "page.h" #include "svg_element_factory.h" namespace webf { @@ -46,6 +46,7 @@ void DeleteDartWire(DartWireContext* wire) { delete wire; } +#if WEBF_QUICKJS_JS_ENGINE static void ClearUpWires(JSRuntime* runtime) { for (auto& wire : alive_wires) { JS_FreeValueRT(runtime, wire->jsObject.QJSValue()); @@ -53,6 +54,7 @@ static void ClearUpWires(JSRuntime* runtime) { } alive_wires.clear(); } +#endif const std::unique_ptr& DartIsolateContext::EnsureData() const { if (data_ == nullptr) { @@ -116,13 +118,13 @@ void DartIsolateContext::FinalizeJSRuntime() { return; // Prebuilt strings stored in JSRuntime. Only needs to dispose when runtime disposed. - names_installer::Dispose(); +// names_installer::Dispose(); HTMLElementFactory::Dispose(); SVGElementFactory::Dispose(); - EventFactory::Dispose(); - ClearUpWires(runtime_); +// EventFactory::Dispose(); #if WEBF_QUICKJS_JS_ENGINE + ClearUpWires(runtime_); JS_TurnOnGC(runtime_); JS_FreeRuntime(runtime_); runtime_ = nullptr; @@ -136,7 +138,7 @@ void DartIsolateContext::FinalizeJSRuntime() { DartIsolateContext::DartIsolateContext(const uint64_t* dart_methods, int32_t dart_methods_length, bool profile_enabled) : is_valid_(true), running_thread_(std::this_thread::get_id()), - profiler_(std::make_unique(profile_enabled)), +// profiler_(std::make_unique(profile_enabled)), dart_method_ptr_(std::make_unique(this, dart_methods, dart_methods_length)) { is_valid_ = true; running_dart_isolates++; diff --git a/bridge/foundation/native_value.h b/bridge/foundation/native_value.h index fc801bd994..4af865cd80 100644 --- a/bridge/foundation/native_value.h +++ b/bridge/foundation/native_value.h @@ -9,10 +9,12 @@ #if WEBF_QUICKJS_JS_ENGINE #include #include +#include "bindings/qjs/native_string_utils.h" +#elif WEBF_V8_JS_ENGINE + #endif #include #include -#include "bindings/qjs/native_string_utils.h" #include "foundation/dart_readable.h" namespace webf { diff --git a/bridge/scripts/code_generator/templates/idl_templates/v8/base.cc.tpl b/bridge/scripts/code_generator/templates/idl_templates/v8/base.cc.tpl index f87ef82338..5cf5632131 100644 --- a/bridge/scripts/code_generator/templates/idl_templates/v8/base.cc.tpl +++ b/bridge/scripts/code_generator/templates/idl_templates/v8/base.cc.tpl @@ -9,7 +9,6 @@ #include "bindings/v8/member_installer.h" #include "bindings/v8/qjs_function.h" #include "bindings/v8/converter_impl.h" -#include "bindings/v8/script_wrappable.h" #include "bindings/v8/script_promise.h" #include "bindings/v8/cppgc/mutation_scope.h" #include "core/executing_context.h" diff --git a/bridge/webf_bridge.cc b/bridge/webf_bridge.cc index 2cf6e3b950..ecc20e800b 100644 --- a/bridge/webf_bridge.cc +++ b/bridge/webf_bridge.cc @@ -6,7 +6,7 @@ #include "core/api/api.h" #include "core/dart_isolate_context.h" #include "core/html/parser/html_parser.h" -#include "core/page.h" +//#include "core/page.h" #include "foundation/native_type.h" #include "include/dart_api.h" #include "multiple_threading/dispatcher.h" @@ -67,14 +67,14 @@ void* allocateNewPageSync(double thread_identity, void* ptr) { auto* dart_isolate_context = (webf::DartIsolateContext*)ptr; assert(dart_isolate_context != nullptr); - dart_isolate_context->profiler()->StartTrackInitialize(); +// dart_isolate_context->profiler()->StartTrackInitialize(); void* result = static_cast(dart_isolate_context)->AddNewPageSync(thread_identity); #if ENABLE_LOG WEBF_LOG(INFO) << "[Dispatcher]: allocateNewPageSync Call END"; #endif - dart_isolate_context->profiler()->FinishTrackInitialize(); +// dart_isolate_context->profiler()->FinishTrackInitialize(); return result; } @@ -143,11 +143,11 @@ void evaluateScripts(void* page_, #if ENABLE_LOG WEBF_LOG(VERBOSE) << "[Dart] evaluateScriptsWrapper call" << std::endl; #endif - auto page = reinterpret_cast(page_); - Dart_PersistentHandle persistent_handle = Dart_NewPersistentHandle_DL(dart_handle); - page->executingContext()->dartIsolateContext()->dispatcher()->PostToJs( - page->isDedicated(), page->contextId(), webf::evaluateScriptsInternal, page_, code, code_len, parsed_bytecodes, - bytecode_len, bundleFilename, start_line, profile_id, persistent_handle, result_callback); +// auto page = reinterpret_cast(page_); +// Dart_PersistentHandle persistent_handle = Dart_NewPersistentHandle_DL(dart_handle); +// page->executingContext()->dartIsolateContext()->dispatcher()->PostToJs( +// page->isDedicated(), page->contextId(), webf::evaluateScriptsInternal, page_, code, code_len, parsed_bytecodes, +// bytecode_len, bundleFilename, start_line, profile_id, persistent_handle, result_callback); } void dumpQuickjsByteCode(void* page_, @@ -163,11 +163,11 @@ void dumpQuickjsByteCode(void* page_, WEBF_LOG(VERBOSE) << "[Dart] dumpQuickjsByteCode call" << std::endl; #endif - auto page = reinterpret_cast(page_); - Dart_PersistentHandle persistent_handle = Dart_NewPersistentHandle_DL(dart_handle); - page->dartIsolateContext()->dispatcher()->PostToJs( - page->isDedicated(), page->contextId(), webf::dumpQuickJsByteCodeInternal, page, profile_id, code, code_len, - parsed_bytecodes, bytecode_len, url, persistent_handle, result_callback); +// auto page = reinterpret_cast(page_); +// Dart_PersistentHandle persistent_handle = Dart_NewPersistentHandle_DL(dart_handle); +// page->dartIsolateContext()->dispatcher()->PostToJs( +// page->isDedicated(), page->contextId(), webf::dumpQuickJsByteCodeInternal, page, profile_id, code, code_len, +// parsed_bytecodes, bytecode_len, url, persistent_handle, result_callback); } void evaluateQuickjsByteCode(void* page_, @@ -179,11 +179,11 @@ void evaluateQuickjsByteCode(void* page_, #if ENABLE_LOG WEBF_LOG(VERBOSE) << "[Dart] evaluateQuickjsByteCodeWrapper call" << std::endl; #endif - auto page = reinterpret_cast(page_); - Dart_PersistentHandle persistent_handle = Dart_NewPersistentHandle_DL(dart_handle); - page->dartIsolateContext()->dispatcher()->PostToJs(page->isDedicated(), page->contextId(), - webf::evaluateQuickjsByteCodeInternal, page_, bytes, byteLen, - profile_id, persistent_handle, result_callback); +// auto page = reinterpret_cast(page_); +// Dart_PersistentHandle persistent_handle = Dart_NewPersistentHandle_DL(dart_handle); +// page->dartIsolateContext()->dispatcher()->PostToJs(page->isDedicated(), page->contextId(), +// webf::evaluateQuickjsByteCodeInternal, page_, bytes, byteLen, +// profile_id, persistent_handle, result_callback); } void parseHTML(void* page_, @@ -195,19 +195,19 @@ void parseHTML(void* page_, #if ENABLE_LOG WEBF_LOG(VERBOSE) << "[Dart] parseHTMLWrapper call" << std::endl; #endif - auto page = reinterpret_cast(page_); - Dart_PersistentHandle persistent_handle = Dart_NewPersistentHandle_DL(dart_handle); - page->executingContext()->dartIsolateContext()->dispatcher()->PostToJs( - page->isDedicated(), page->contextId(), webf::parseHTMLInternal, page_, code, length, profile_id, - persistent_handle, result_callback); +// auto page = reinterpret_cast(page_); +// Dart_PersistentHandle persistent_handle = Dart_NewPersistentHandle_DL(dart_handle); +// page->executingContext()->dartIsolateContext()->dispatcher()->PostToJs( +// page->isDedicated(), page->contextId(), webf::parseHTMLInternal, page_, code, length, profile_id, +// persistent_handle, result_callback); } void registerPluginByteCode(uint8_t* bytes, int32_t length, const char* pluginName) { - webf::ExecutingContext::plugin_byte_code[pluginName] = webf::NativeByteCode{bytes, length}; +// webf::ExecutingContext::plugin_byte_code[pluginName] = webf::NativeByteCode{bytes, length}; } void registerPluginCode(const char* code, int32_t length, const char* pluginName) { - webf::ExecutingContext::plugin_string_code[pluginName] = std::string(code, length); +// webf::ExecutingContext::plugin_string_code[pluginName] = std::string(code, length); } static WebFInfo* webfInfo{nullptr}; @@ -241,26 +241,26 @@ void invokeModuleEvent(void* page_, Dart_Handle dart_handle, InvokeModuleEventCallback result_callback) { Dart_PersistentHandle persistent_handle = Dart_NewPersistentHandle_DL(dart_handle); - auto page = reinterpret_cast(page_); - auto dart_isolate_context = page->executingContext()->dartIsolateContext(); - auto is_dedicated = page->executingContext()->isDedicated(); - auto context_id = page->contextId(); - dart_isolate_context->dispatcher()->PostToJs(is_dedicated, context_id, webf::invokeModuleEventInternal, page_, module, - eventType, event, extra, persistent_handle, result_callback); +// auto page = reinterpret_cast(page_); +// auto dart_isolate_context = page->executingContext()->dartIsolateContext(); +// auto is_dedicated = page->executingContext()->isDedicated(); +// auto context_id = page->contextId(); +// dart_isolate_context->dispatcher()->PostToJs(is_dedicated, context_id, webf::invokeModuleEventInternal, page_, module, +// eventType, event, extra, persistent_handle, result_callback); } void collectNativeProfileData(void* ptr, const char** data, uint32_t* len) { - auto* dart_isolate_context = static_cast(ptr); - std::string result = dart_isolate_context->profiler()->ToJSON(); - - *data = static_cast(webf::dart_malloc(sizeof(char) * result.size() + 1)); - memcpy((void*)*data, result.c_str(), sizeof(char) * result.size() + 1); - *len = result.size(); +// auto* dart_isolate_context = static_cast(ptr); +// std::string result = dart_isolate_context->profiler()->ToJSON(); +// +// *data = static_cast(webf::dart_malloc(sizeof(char) * result.size() + 1)); +// memcpy((void*)*data, result.c_str(), sizeof(char) * result.size() + 1); +// *len = result.size(); } void clearNativeProfileData(void* ptr) { - auto* dart_isolate_context = static_cast(ptr); - dart_isolate_context->profiler()->clear(); +// auto* dart_isolate_context = static_cast(ptr); +// dart_isolate_context->profiler()->clear(); } void dispatchUITask(void* page_, void* context, void* callback) { @@ -269,23 +269,26 @@ void dispatchUITask(void* page_, void* context, void* callback) { } void* getUICommandItems(void* page_) { - auto page = reinterpret_cast(page_); - return page->executingContext()->uiCommandBuffer()->data(); +// auto page = reinterpret_cast(page_); +// return page->executingContext()->uiCommandBuffer()->data(); + return nullptr; } uint32_t getUICommandKindFlag(void* page_) { - auto page = reinterpret_cast(page_); - return page->executingContext()->uiCommandBuffer()->kindFlag(); +// auto page = reinterpret_cast(page_); +// return page->executingContext()->uiCommandBuffer()->kindFlag(); + return 0; } int64_t getUICommandItemSize(void* page_) { - auto page = reinterpret_cast(page_); - return page->executingContext()->uiCommandBuffer()->size(); +// auto page = reinterpret_cast(page_); +// return page->executingContext()->uiCommandBuffer()->size(); + return 0; } void clearUICommandItems(void* page_) { - auto page = reinterpret_cast(page_); - page->executingContext()->uiCommandBuffer()->clear(); +// auto page = reinterpret_cast(page_); +// page->executingContext()->uiCommandBuffer()->clear(); } // Callbacks when dart context object was finalized by Dart GC.