8319999: Refactor MetaspaceShared::use_full_module_graph()

Reviewed-by: dholmes, ccheung
This commit is contained in:
Ioi Lam 2023-11-15 05:09:10 +00:00
parent d9a89c59da
commit a6343c0b7b
16 changed files with 111 additions and 76 deletions

@ -188,10 +188,6 @@ ArchiveBuilder::~ArchiveBuilder() {
}
}
bool ArchiveBuilder::is_dumping_full_module_graph() {
return DumpSharedSpaces && MetaspaceShared::use_full_module_graph();
}
class GatherKlassesAndSymbols : public UniqueMetaspaceClosure {
ArchiveBuilder* _builder;
@ -237,7 +233,7 @@ void ArchiveBuilder::gather_klasses_and_symbols() {
GatherKlassesAndSymbols doit(this);
iterate_roots(&doit);
#if INCLUDE_CDS_JAVA_HEAP
if (is_dumping_full_module_graph()) {
if (CDSConfig::is_dumping_full_module_graph()) {
ClassLoaderDataShared::iterate_symbols(&doit);
}
#endif
@ -586,7 +582,7 @@ void ArchiveBuilder::dump_rw_metadata() {
make_shallow_copies(&_rw_region, &_rw_src_objs);
#if INCLUDE_CDS_JAVA_HEAP
if (is_dumping_full_module_graph()) {
if (CDSConfig::is_dumping_full_module_graph()) {
// Archive the ModuleEntry's and PackageEntry's of the 3 built-in loaders
char* start = rw_region()->top();
ClassLoaderDataShared::allocate_archived_tables();
@ -603,7 +599,7 @@ void ArchiveBuilder::dump_ro_metadata() {
make_shallow_copies(&_ro_region, &_ro_src_objs);
#if INCLUDE_CDS_JAVA_HEAP
if (is_dumping_full_module_graph()) {
if (CDSConfig::is_dumping_full_module_graph()) {
char* start = ro_region()->top();
ClassLoaderDataShared::init_archived_tables();
alloc_stats()->record_modules(ro_region()->top() - start, /*read_only*/true);

@ -237,7 +237,6 @@ public:
};
private:
bool is_dumping_full_module_graph();
FollowMode get_follow_mode(MetaspaceClosure::Ref *ref);
void iterate_sorted_roots(MetaspaceClosure* it);

@ -24,6 +24,7 @@
#include "precompiled.hpp"
#include "cds/archiveHeapLoader.inline.hpp"
#include "cds/cdsConfig.hpp"
#include "cds/heapShared.hpp"
#include "cds/metaspaceShared.hpp"
#include "classfile/classLoaderDataShared.hpp"
@ -87,7 +88,7 @@ void ArchiveHeapLoader::fixup_region() {
fill_failed_loaded_heap();
}
if (is_in_use()) {
if (!MetaspaceShared::use_full_module_graph()) {
if (!CDSConfig::is_loading_full_module_graph()) {
// Need to remove all the archived java.lang.Module objects from HeapShared::roots().
ClassLoaderDataShared::clear_archived_oops();
}

@ -23,11 +23,20 @@
*/
#include "precompiled.hpp"
#include "cds/archiveHeapLoader.hpp"
#include "cds/cdsConfig.hpp"
#include "cds/heapShared.hpp"
#include "classfile/classLoaderDataShared.hpp"
#include "logging/log.hpp"
bool CDSConfig::_is_dumping_dynamic_archive = false;
// The ability to dump the FMG depends on many factors checked by
// is_dumping_full_module_graph(), but can be unconditionally disabled by
// _dumping_full_module_graph_disabled. (Ditto for loading the FMG).
bool CDSConfig::_dumping_full_module_graph_disabled = false;
bool CDSConfig::_loading_full_module_graph_disabled = false;
bool CDSConfig::is_dumping_static_archive() {
return DumpSharedSpaces;
}
@ -37,4 +46,51 @@ bool CDSConfig::is_dumping_heap() {
// heap dump is not supported in dynamic dump
return is_dumping_static_archive() && HeapShared::can_write();
}
bool CDSConfig::is_dumping_full_module_graph() {
if (!_dumping_full_module_graph_disabled &&
is_dumping_heap() &&
MetaspaceShared::use_optimized_module_handling()) {
return true;
} else {
return false;
}
}
bool CDSConfig::is_loading_full_module_graph() {
if (ClassLoaderDataShared::is_full_module_graph_loaded()) {
return true;
}
if (!_loading_full_module_graph_disabled &&
UseSharedSpaces &&
ArchiveHeapLoader::can_use() &&
MetaspaceShared::use_optimized_module_handling()) {
// Classes used by the archived full module graph are loaded in JVMTI early phase.
assert(!(JvmtiExport::should_post_class_file_load_hook() && JvmtiExport::has_early_class_hook_env()),
"CDS should be disabled if early class hooks are enabled");
return true;
} else {
return false;
}
}
void CDSConfig::disable_dumping_full_module_graph(const char* reason) {
if (!_dumping_full_module_graph_disabled) {
_dumping_full_module_graph_disabled = true;
if (reason != nullptr) {
log_info(cds)("full module graph cannot be dumped: %s", reason);
}
}
}
void CDSConfig::disable_loading_full_module_graph(const char* reason) {
assert(!ClassLoaderDataShared::is_full_module_graph_loaded(), "you call this function too late!");
if (!_loading_full_module_graph_disabled) {
_loading_full_module_graph_disabled = true;
if (reason != nullptr) {
log_info(cds)("full module graph cannot be loaded: %s", reason);
}
}
}
#endif // INCLUDE_CDS_JAVA_HEAP

@ -31,6 +31,8 @@
class CDSConfig : public AllStatic {
#if INCLUDE_CDS
static bool _is_dumping_dynamic_archive;
static bool _dumping_full_module_graph_disabled;
static bool _loading_full_module_graph_disabled;
#endif
public:
@ -43,6 +45,11 @@ public:
// CDS archived heap
static bool is_dumping_heap() NOT_CDS_JAVA_HEAP_RETURN_(false);
static void disable_dumping_full_module_graph(const char* reason = nullptr) NOT_CDS_JAVA_HEAP_RETURN;
static bool is_dumping_full_module_graph() NOT_CDS_JAVA_HEAP_RETURN_(false);
static void disable_loading_full_module_graph(const char* reason = nullptr) NOT_CDS_JAVA_HEAP_RETURN;
static bool is_loading_full_module_graph() NOT_CDS_JAVA_HEAP_RETURN_(false);
};
#endif // SHARE_CDS_CDSCONFIG_HPP

@ -23,6 +23,7 @@
*/
#include "precompiled.hpp"
#include "cds/cdsConfig.hpp"
#include "cds/cdsProtectionDomain.hpp"
#include "classfile/classLoader.hpp"
#include "classfile/classLoaderData.inline.hpp"
@ -118,7 +119,7 @@ Handle CDSProtectionDomain::get_package_name(Symbol* class_name, TRAPS) {
PackageEntry* CDSProtectionDomain::get_package_entry_from_class(InstanceKlass* ik, Handle class_loader) {
PackageEntry* pkg_entry = ik->package();
if (MetaspaceShared::use_full_module_graph() && ik->is_shared() && pkg_entry != nullptr) {
if (CDSConfig::is_loading_full_module_graph() && ik->is_shared() && pkg_entry != nullptr) {
assert(MetaspaceShared::is_in_shared_metaspace(pkg_entry), "must be");
assert(!ik->is_shared_unregistered_class(), "unexpected archived package entry for an unregistered class");
assert(ik->module()->is_named(), "unexpected archived package entry for a class in an unnamed module");

@ -213,7 +213,7 @@ void FileMapHeader::populate(FileMapInfo *info, size_t core_region_alignment,
_compressed_class_ptrs = UseCompressedClassPointers;
_max_heap_size = MaxHeapSize;
_use_optimized_module_handling = MetaspaceShared::use_optimized_module_handling();
_use_full_module_graph = MetaspaceShared::use_full_module_graph();
_has_full_module_graph = CDSConfig::is_dumping_full_module_graph();
// The following fields are for sanity checks for whether this archive
// will function correctly with this JVM and the bootclasspath it's
@ -291,7 +291,7 @@ void FileMapHeader::print(outputStream* st) {
st->print_cr("- heap_roots_offset: " SIZE_FORMAT, _heap_roots_offset);
st->print_cr("- allow_archiving_with_java_agent:%d", _allow_archiving_with_java_agent);
st->print_cr("- use_optimized_module_handling: %d", _use_optimized_module_handling);
st->print_cr("- use_full_module_graph %d", _use_full_module_graph);
st->print_cr("- has_full_module_graph %d", _has_full_module_graph);
st->print_cr("- ptrmap_size_in_bits: " SIZE_FORMAT, _ptrmap_size_in_bits);
}
@ -1968,7 +1968,7 @@ void FileMapInfo::map_or_load_heap_region() {
}
if (!success) {
MetaspaceShared::disable_full_module_graph();
CDSConfig::disable_loading_full_module_graph();
}
}
@ -2387,9 +2387,9 @@ bool FileMapHeader::validate() {
log_info(cds)("optimized module handling: disabled because archive was created without optimized module handling");
}
if (!_use_full_module_graph) {
MetaspaceShared::disable_full_module_graph();
log_info(cds)("full module graph: disabled because archive was created without full module graph");
if (is_static() && !_has_full_module_graph) {
// Only the static archive can contain the full module graph.
CDSConfig::disable_loading_full_module_graph("archive was created without full module graph");
}
return true;

@ -223,7 +223,7 @@ private:
bool _allow_archiving_with_java_agent; // setting of the AllowArchivingWithJavaAgent option
bool _use_optimized_module_handling;// No module-relation VM options were specified, so we can skip
// some expensive operations.
bool _use_full_module_graph; // Can we use the full archived module graph?
bool _has_full_module_graph; // Does this CDS archive contain the full archived module graph?
size_t _ptrmap_size_in_bits; // Size of pointer relocation bitmap
size_t _heap_roots_offset; // Offset of the HeapShared::roots() object, from the bottom
// of the archived heap objects, in bytes.
@ -249,6 +249,7 @@ public:
void set_base_archive_name_size(unsigned int s) { _generic_header._base_archive_name_size = s; }
void set_common_app_classpath_prefix_size(unsigned int s) { _common_app_classpath_prefix_size = s; }
bool is_static() const { return magic() == CDS_ARCHIVE_MAGIC; }
size_t core_region_alignment() const { return _core_region_alignment; }
int obj_alignment() const { return _obj_alignment; }
address narrow_oop_base() const { return _narrow_oop_base; }

@ -583,7 +583,7 @@ void HeapShared::copy_objects() {
archive_object_subgraphs(archive_subgraph_entry_fields,
false /* is_full_module_graph */);
if (MetaspaceShared::use_full_module_graph()) {
if (CDSConfig::is_dumping_full_module_graph()) {
archive_object_subgraphs(fmg_archive_subgraph_entry_fields,
true /* is_full_module_graph */);
Modules::verify_archived_modules();
@ -972,7 +972,7 @@ HeapShared::resolve_or_init_classes_for_subgraph_of(Klass* k, bool do_init, TRAP
}
return nullptr;
} else {
if (record->is_full_module_graph() && !MetaspaceShared::use_full_module_graph()) {
if (record->is_full_module_graph() && !CDSConfig::is_loading_full_module_graph()) {
if (log_is_enabled(Info, cds, heap)) {
ResourceMark rm(THREAD);
log_info(cds, heap)("subgraph %s cannot be used because full module graph is disabled",
@ -1513,7 +1513,7 @@ void HeapShared::init_subgraph_entry_fields(TRAPS) {
assert(HeapShared::can_write(), "must be");
_dump_time_subgraph_info_table = new (mtClass)DumpTimeKlassSubGraphInfoTable();
init_subgraph_entry_fields(archive_subgraph_entry_fields, CHECK);
if (MetaspaceShared::use_full_module_graph()) {
if (CDSConfig::is_dumping_full_module_graph()) {
init_subgraph_entry_fields(fmg_archive_subgraph_entry_fields, CHECK);
}
}

@ -97,7 +97,6 @@ void* MetaspaceShared::_shared_metaspace_static_top = nullptr;
intx MetaspaceShared::_relocation_delta;
char* MetaspaceShared::_requested_base_address;
bool MetaspaceShared::_use_optimized_module_handling = true;
bool MetaspaceShared::_use_full_module_graph = true;
// The CDS archive is divided into the following regions:
// rw - read-write metadata
@ -782,11 +781,11 @@ void MetaspaceShared::preload_and_dump_impl(TRAPS) {
StringTable::allocate_shared_strings_array(CHECK);
if (!HeapShared::is_archived_boot_layer_available(THREAD)) {
log_info(cds)("archivedBootLayer not available, disabling full module graph");
disable_full_module_graph();
CDSConfig::disable_dumping_full_module_graph();
}
HeapShared::init_for_dumping(CHECK);
ArchiveHeapWriter::init();
if (use_full_module_graph()) {
if (CDSConfig::is_dumping_full_module_graph()) {
HeapShared::reset_archived_object_states(CHECK);
}
}
@ -1171,7 +1170,7 @@ MapArchiveResult MetaspaceShared::map_archives(FileMapInfo* static_mapinfo, File
}
#endif // _LP64
log_info(cds)("initial optimized module handling: %s", MetaspaceShared::use_optimized_module_handling() ? "enabled" : "disabled");
log_info(cds)("initial full module graph: %s", MetaspaceShared::use_full_module_graph() ? "enabled" : "disabled");
log_info(cds)("initial full module graph: %s", CDSConfig::is_loading_full_module_graph() ? "enabled" : "disabled");
} else {
unmap_archive(static_mapinfo);
unmap_archive(dynamic_mapinfo);
@ -1545,29 +1544,6 @@ bool MetaspaceShared::remap_shared_readonly_as_readwrite() {
return true;
}
bool MetaspaceShared::use_full_module_graph() {
#if INCLUDE_CDS_JAVA_HEAP
if (ClassLoaderDataShared::is_full_module_graph_loaded()) {
return true;
}
#endif
bool result = _use_optimized_module_handling && _use_full_module_graph;
if (DumpSharedSpaces) {
result &= HeapShared::can_write();
} else if (UseSharedSpaces) {
result &= ArchiveHeapLoader::can_use();
} else {
result = false;
}
if (result && UseSharedSpaces) {
// Classes used by the archived full module graph are loaded in JVMTI early phase.
assert(!(JvmtiExport::should_post_class_file_load_hook() && JvmtiExport::has_early_class_hook_env()),
"CDS should be disabled if early class hooks are enabled");
}
return result;
}
void MetaspaceShared::print_on(outputStream* st) {
if (UseSharedSpaces) {
st->print("CDS archive(s) mapped at: ");

@ -53,7 +53,6 @@ class MetaspaceShared : AllStatic {
static intx _relocation_delta;
static char* _requested_base_address;
static bool _use_optimized_module_handling;
static bool _use_full_module_graph;
public:
enum {
// core archive spaces
@ -164,10 +163,6 @@ public:
static bool use_optimized_module_handling() { return NOT_CDS(false) CDS_ONLY(_use_optimized_module_handling); }
static void disable_optimized_module_handling() { _use_optimized_module_handling = false; }
// Can we use the full archived module graph?
static bool use_full_module_graph() NOT_CDS_RETURN_(false);
static void disable_full_module_graph() { _use_full_module_graph = false; }
private:
static void read_extra_data(JavaThread* current, const char* filename) NOT_CDS_RETURN;
static FileMapInfo* open_static_archive();

@ -23,7 +23,7 @@
*/
#include "precompiled.hpp"
#include "cds/metaspaceShared.hpp"
#include "cds/cdsConfig.hpp"
#include "cds/serializeClosure.hpp"
#include "classfile/classLoaderData.inline.hpp"
#include "classfile/classLoaderDataShared.hpp"
@ -145,21 +145,21 @@ static ClassLoaderData* java_system_loader_data_or_null() {
}
void ClassLoaderDataShared::iterate_symbols(MetaspaceClosure* closure) {
assert(DumpSharedSpaces && MetaspaceShared::use_full_module_graph(), "must be");
assert(CDSConfig::is_dumping_full_module_graph(), "must be");
_archived_boot_loader_data.iterate_symbols (null_class_loader_data(), closure);
_archived_platform_loader_data.iterate_symbols(java_platform_loader_data_or_null(), closure);
_archived_system_loader_data.iterate_symbols (java_system_loader_data_or_null(), closure);
}
void ClassLoaderDataShared::allocate_archived_tables() {
assert(DumpSharedSpaces && MetaspaceShared::use_full_module_graph(), "must be");
assert(CDSConfig::is_dumping_full_module_graph(), "must be");
_archived_boot_loader_data.allocate (null_class_loader_data());
_archived_platform_loader_data.allocate(java_platform_loader_data_or_null());
_archived_system_loader_data.allocate (java_system_loader_data_or_null());
}
void ClassLoaderDataShared::init_archived_tables() {
assert(DumpSharedSpaces && MetaspaceShared::use_full_module_graph(), "must be");
assert(CDSConfig::is_dumping_full_module_graph(), "must be");
_archived_boot_loader_data.init_archived_entries (null_class_loader_data());
_archived_platform_loader_data.init_archived_entries(java_platform_loader_data_or_null());
_archived_system_loader_data.init_archived_entries (java_system_loader_data_or_null());
@ -172,7 +172,7 @@ void ClassLoaderDataShared::serialize(SerializeClosure* f) {
_archived_system_loader_data.serialize(f);
f->do_ptr(&_archived_javabase_moduleEntry);
if (f->reading() && MetaspaceShared::use_full_module_graph()) {
if (f->reading() && CDSConfig::is_loading_full_module_graph()) {
// Must be done before ClassLoader::create_javabase()
_archived_boot_loader_data.restore(null_class_loader_data(), true, false);
ModuleEntryTable::set_javabase_moduleEntry(_archived_javabase_moduleEntry);
@ -182,25 +182,25 @@ void ClassLoaderDataShared::serialize(SerializeClosure* f) {
}
void ClassLoaderDataShared::clear_archived_oops() {
assert(UseSharedSpaces && !MetaspaceShared::use_full_module_graph(), "must be");
assert(!CDSConfig::is_loading_full_module_graph(), "must be");
_archived_boot_loader_data.clear_archived_oops();
_archived_platform_loader_data.clear_archived_oops();
_archived_system_loader_data.clear_archived_oops();
}
oop ClassLoaderDataShared::restore_archived_oops_for_null_class_loader_data() {
assert(UseSharedSpaces && MetaspaceShared::use_full_module_graph(), "must be");
assert(CDSConfig::is_loading_full_module_graph(), "must be");
_archived_boot_loader_data.restore(null_class_loader_data(), false, true);
return _archived_javabase_moduleEntry->module();
}
void ClassLoaderDataShared::restore_java_platform_loader_from_archive(ClassLoaderData* loader_data) {
assert(UseSharedSpaces && MetaspaceShared::use_full_module_graph(), "must be");
assert(CDSConfig::is_loading_full_module_graph(), "must be");
_archived_platform_loader_data.restore(loader_data, true, true);
}
void ClassLoaderDataShared::restore_java_system_loader_from_archive(ClassLoaderData* loader_data) {
assert(UseSharedSpaces && MetaspaceShared::use_full_module_graph(), "must be");
assert(CDSConfig::is_loading_full_module_graph(), "must be");
_archived_system_loader_data.restore(loader_data, true, true);
_full_module_graph_loaded = true;
}

@ -24,6 +24,7 @@
#include "precompiled.hpp"
#include "cds/archiveBuilder.hpp"
#include "cds/cdsConfig.hpp"
#include "cds/metaspaceShared.hpp"
#include "classfile/classFileParser.hpp"
#include "classfile/classLoader.hpp"
@ -486,7 +487,7 @@ static bool _seen_system_unnamed_module = false;
// Returns true iff the oop has an archived ModuleEntry.
bool Modules::check_archived_module_oop(oop orig_module_obj) {
assert(DumpSharedSpaces, "must be");
assert(MetaspaceShared::use_full_module_graph(), "must be");
assert(CDSConfig::is_dumping_full_module_graph(), "must be");
assert(java_lang_Module::is_instance(orig_module_obj), "must be");
ModuleEntry* orig_module_ent = java_lang_Module::module_entry_raw(orig_module_obj);
@ -599,12 +600,12 @@ void Modules::serialize(SerializeClosure* soc) {
MetaspaceShared::disable_optimized_module_handling();
}
log_info(cds)("optimized module handling: %s", MetaspaceShared::use_optimized_module_handling() ? "enabled" : "disabled");
log_info(cds)("full module graph: %s", MetaspaceShared::use_full_module_graph() ? "enabled" : "disabled");
log_info(cds)("full module graph: %s", CDSConfig::is_loading_full_module_graph() ? "enabled" : "disabled");
}
}
void Modules::define_archived_modules(Handle h_platform_loader, Handle h_system_loader, TRAPS) {
assert(UseSharedSpaces && MetaspaceShared::use_full_module_graph(), "must be");
assert(CDSConfig::is_loading_full_module_graph(), "must be");
// We don't want the classes used by the archived full module graph to be redefined by JVMTI.
// Luckily, such classes are loaded in the JVMTI "early" phase, and CDS is disabled if a JVMTI
@ -640,7 +641,7 @@ void Modules::define_archived_modules(Handle h_platform_loader, Handle h_system_
}
void Modules::check_cds_restrictions(TRAPS) {
if (DumpSharedSpaces && Universe::is_module_initialized() && MetaspaceShared::use_full_module_graph()) {
if (DumpSharedSpaces && Universe::is_module_initialized() && CDSConfig::is_dumping_full_module_graph()) {
THROW_MSG(vmSymbols::java_lang_UnsupportedOperationException(),
"During -Xshare:dump, module system cannot be modified after it's initialized");
}

@ -140,7 +140,7 @@ void SystemDictionary::compute_java_loaders(TRAPS) {
} else {
// It must have been restored from the archived module graph
assert(UseSharedSpaces, "must be");
assert(MetaspaceShared::use_full_module_graph(), "must be");
assert(CDSConfig::is_loading_full_module_graph(), "must be");
DEBUG_ONLY(
oop system_loader = get_system_class_loader_impl(CHECK);
assert(_java_system_loader.resolve() == system_loader, "must be");
@ -153,7 +153,7 @@ void SystemDictionary::compute_java_loaders(TRAPS) {
} else {
// It must have been restored from the archived module graph
assert(UseSharedSpaces, "must be");
assert(MetaspaceShared::use_full_module_graph(), "must be");
assert(CDSConfig::is_loading_full_module_graph(), "must be");
DEBUG_ONLY(
oop platform_loader = get_platform_class_loader_impl(CHECK);
assert(_java_platform_loader.resolve() == platform_loader, "must be");

@ -2691,21 +2691,22 @@ void InstanceKlass::remove_java_mirror() {
}
void InstanceKlass::init_shared_package_entry() {
assert(CDSConfig::is_dumping_archive(), "must be");
#if !INCLUDE_CDS_JAVA_HEAP
_package_entry = nullptr;
#else
if (!MetaspaceShared::use_full_module_graph()) {
_package_entry = nullptr;
} else if (CDSConfig::is_dumping_dynamic_archive()) {
if (!MetaspaceShared::is_in_shared_metaspace(_package_entry)) {
_package_entry = nullptr;
}
} else {
if (CDSConfig::is_dumping_full_module_graph()) {
if (is_shared_unregistered_class()) {
_package_entry = nullptr;
} else {
_package_entry = PackageEntry::get_archived_entry(_package_entry);
}
} else if (CDSConfig::is_dumping_dynamic_archive() &&
CDSConfig::is_loading_full_module_graph() &&
MetaspaceShared::is_in_shared_metaspace(_package_entry)) {
// _package_entry is an archived package in the base archive. Leave it as is.
} else {
_package_entry = nullptr;
}
ArchivePtrMarker::mark_pointer((address**)&_package_entry);
#endif
@ -3027,7 +3028,7 @@ void InstanceKlass::set_package(ClassLoaderData* loader_data, PackageEntry* pkg_
}
if (is_shared() && _package_entry != nullptr) {
if (MetaspaceShared::use_full_module_graph() && _package_entry == pkg_entry) {
if (CDSConfig::is_loading_full_module_graph() && _package_entry == pkg_entry) {
// we can use the saved package
assert(MetaspaceShared::is_in_shared_metaspace(_package_entry), "must be");
return;

@ -1269,7 +1269,8 @@ bool Arguments::add_property(const char* prop, PropertyWriteable writeable, Prop
if (strcmp(key, "jdk.module.showModuleResolution") == 0 ||
strcmp(key, "jdk.module.validation") == 0 ||
strcmp(key, "java.system.class.loader") == 0) {
MetaspaceShared::disable_full_module_graph();
CDSConfig::disable_loading_full_module_graph();
CDSConfig::disable_dumping_full_module_graph();
log_info(cds)("full module graph: disabled due to incompatible property: %s=%s", key, value);
}
#endif