diff options
author | 2017-12-08 14:09:45 +0000 | |
---|---|---|
committer | 2017-12-08 17:54:25 +0000 | |
commit | e11dd50ac2b5ccbf3b02213b7361f55b1f1a90da (patch) | |
tree | ea958df5f757369119cc84968f3b77210faf593f | |
parent | 2ba3557b6d2ea65956f7a98e6f0fd921f35792a5 (diff) |
Do not pass DexFile to ClassLinker::ResolveField*().
The DexFile can be easily retrieved from the DexCache,
so reduce the number of arguments that need to be passed.
Test: m test-art-host-gtest
Test: testrunner.py --host --optimizing
Change-Id: I0579db64c63afea789c7c9ad8db81e37c9248e97
-rw-r--r-- | compiler/driver/compiler_driver-inl.h | 21 | ||||
-rw-r--r-- | compiler/driver/compiler_driver.cc | 30 | ||||
-rw-r--r-- | compiler/driver/compiler_driver.h | 22 | ||||
-rw-r--r-- | compiler/optimizing/instruction_builder.cc | 3 | ||||
-rw-r--r-- | runtime/class_linker-inl.h | 3 | ||||
-rw-r--r-- | runtime/class_linker.cc | 17 | ||||
-rw-r--r-- | runtime/class_linker.h | 23 | ||||
-rw-r--r-- | runtime/dex_file_annotations.cc | 9 | ||||
-rw-r--r-- | runtime/dex_file_annotations.h | 17 | ||||
-rw-r--r-- | runtime/entrypoints/entrypoint_utils-inl.h | 3 | ||||
-rw-r--r-- | runtime/verifier/method_verifier.cc | 4 |
11 files changed, 64 insertions, 88 deletions
diff --git a/compiler/driver/compiler_driver-inl.h b/compiler/driver/compiler_driver-inl.h index 7e118d5d85..42fc4aa5ba 100644 --- a/compiler/driver/compiler_driver-inl.h +++ b/compiler/driver/compiler_driver-inl.h @@ -58,13 +58,13 @@ inline ObjPtr<mirror::Class> CompilerDriver::ResolveCompilingMethodsClass( return ResolveClass(soa, dex_cache, class_loader, referrer_method_id.class_idx_, mUnit); } -inline ArtField* CompilerDriver::ResolveFieldWithDexFile( - const ScopedObjectAccess& soa, Handle<mirror::DexCache> dex_cache, - Handle<mirror::ClassLoader> class_loader, const DexFile* dex_file, - uint32_t field_idx, bool is_static) { - DCHECK_EQ(dex_cache->GetDexFile(), dex_file); +inline ArtField* CompilerDriver::ResolveField(const ScopedObjectAccess& soa, + Handle<mirror::DexCache> dex_cache, + Handle<mirror::ClassLoader> class_loader, + uint32_t field_idx, + bool is_static) { ArtField* resolved_field = Runtime::Current()->GetClassLinker()->ResolveField( - *dex_file, field_idx, dex_cache, class_loader, is_static); + field_idx, dex_cache, class_loader, is_static); DCHECK_EQ(resolved_field == nullptr, soa.Self()->IsExceptionPending()); if (UNLIKELY(resolved_field == nullptr)) { // Clean up any exception left by type resolution. @@ -79,15 +79,6 @@ inline ArtField* CompilerDriver::ResolveFieldWithDexFile( return resolved_field; } -inline ArtField* CompilerDriver::ResolveField( - const ScopedObjectAccess& soa, Handle<mirror::DexCache> dex_cache, - Handle<mirror::ClassLoader> class_loader, const DexCompilationUnit* mUnit, - uint32_t field_idx, bool is_static) { - DCHECK_EQ(class_loader.Get(), mUnit->GetClassLoader().Get()); - return ResolveFieldWithDexFile(soa, dex_cache, class_loader, mUnit->GetDexFile(), field_idx, - is_static); -} - inline std::pair<bool, bool> CompilerDriver::IsFastInstanceField( ObjPtr<mirror::DexCache> dex_cache, ObjPtr<mirror::Class> referrer_class, diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc index f49d119900..2d43476d5a 100644 --- a/compiler/driver/compiler_driver.cc +++ b/compiler/driver/compiler_driver.cc @@ -1368,17 +1368,18 @@ void CompilerDriver::ProcessedStaticField(bool resolved, bool local) { } ArtField* CompilerDriver::ComputeInstanceFieldInfo(uint32_t field_idx, - const DexCompilationUnit* mUnit, bool is_put, + const DexCompilationUnit* mUnit, + bool is_put, const ScopedObjectAccess& soa) { // Try to resolve the field and compiling method's class. ArtField* resolved_field; ObjPtr<mirror::Class> referrer_class; Handle<mirror::DexCache> dex_cache(mUnit->GetDexCache()); { - Handle<mirror::ClassLoader> class_loader_handle = mUnit->GetClassLoader(); - resolved_field = ResolveField(soa, dex_cache, class_loader_handle, mUnit, field_idx, false); + Handle<mirror::ClassLoader> class_loader = mUnit->GetClassLoader(); + resolved_field = ResolveField(soa, dex_cache, class_loader, field_idx, /* is_static */ false); referrer_class = resolved_field != nullptr - ? ResolveCompilingMethodsClass(soa, dex_cache, class_loader_handle, mUnit) : nullptr; + ? ResolveCompilingMethodsClass(soa, dex_cache, class_loader, mUnit) : nullptr; } bool can_link = false; if (resolved_field != nullptr && referrer_class != nullptr) { @@ -1664,8 +1665,8 @@ class ResolveClassFieldsAndMethodsVisitor : public CompilationVisitor { ClassDataItemIterator it(dex_file, class_data); while (it.HasNextStaticField()) { if (resolve_fields_and_methods) { - ArtField* field = class_linker->ResolveField(dex_file, it.GetMemberIndex(), - dex_cache, class_loader, true); + ArtField* field = class_linker->ResolveField( + it.GetMemberIndex(), dex_cache, class_loader, /* is_static */ true); if (field == nullptr) { CheckAndClearResolveException(soa.Self()); } @@ -1679,8 +1680,8 @@ class ResolveClassFieldsAndMethodsVisitor : public CompilationVisitor { requires_constructor_barrier = true; } if (resolve_fields_and_methods) { - ArtField* field = class_linker->ResolveField(dex_file, it.GetMemberIndex(), - dex_cache, class_loader, false); + ArtField* field = class_linker->ResolveField( + it.GetMemberIndex(), dex_cache, class_loader, /* is_static */ false); if (field == nullptr) { CheckAndClearResolveException(soa.Self()); } @@ -2329,22 +2330,21 @@ class InitializeClassVisitor : public CompilationVisitor { DCHECK(!klass->IsInitialized()); StackHandleScope<1> hs(Thread::Current()); - Handle<mirror::DexCache> h_dex_cache = hs.NewHandle(klass->GetDexCache()); + Handle<mirror::DexCache> dex_cache = hs.NewHandle(klass->GetDexCache()); const DexFile* dex_file = manager_->GetDexFile(); const DexFile::ClassDef* class_def = klass->GetClassDef(); ClassLinker* class_linker = manager_->GetClassLinker(); // Check encoded final field values for strings and intern. - annotations::RuntimeEncodedStaticFieldValueIterator value_it(*dex_file, - &h_dex_cache, - &class_loader, + annotations::RuntimeEncodedStaticFieldValueIterator value_it(dex_cache, + class_loader, manager_->GetClassLinker(), *class_def); for ( ; value_it.HasNext(); value_it.Next()) { if (value_it.GetValueType() == annotations::RuntimeEncodedStaticFieldValueIterator::kString) { // Resolve the string. This will intern the string. art::ObjPtr<mirror::String> resolved = class_linker->ResolveString( - *dex_file, dex::StringIndex(value_it.GetJavaValue().i), h_dex_cache); + *dex_file, dex::StringIndex(value_it.GetJavaValue().i), dex_cache); CHECK(resolved != nullptr); } } @@ -2357,11 +2357,11 @@ class InitializeClassVisitor : public CompilationVisitor { for (const DexInstructionPcPair& inst : code_item->Instructions()) { if (inst->Opcode() == Instruction::CONST_STRING) { ObjPtr<mirror::String> s = class_linker->ResolveString( - *dex_file, dex::StringIndex(inst->VRegB_21c()), h_dex_cache); + *dex_file, dex::StringIndex(inst->VRegB_21c()), dex_cache); CHECK(s != nullptr); } else if (inst->Opcode() == Instruction::CONST_STRING_JUMBO) { ObjPtr<mirror::String> s = class_linker->ResolveString( - *dex_file, dex::StringIndex(inst->VRegB_31c()), h_dex_cache); + *dex_file, dex::StringIndex(inst->VRegB_31c()), dex_cache); CHECK(s != nullptr); } } diff --git a/compiler/driver/compiler_driver.h b/compiler/driver/compiler_driver.h index ce7ec4520d..ab788e326f 100644 --- a/compiler/driver/compiler_driver.h +++ b/compiler/driver/compiler_driver.h @@ -232,17 +232,11 @@ class CompilerDriver { // Resolve a field. Returns null on failure, including incompatible class change. // NOTE: Unlike ClassLinker's ResolveField(), this method enforces is_static. - ArtField* ResolveField( - const ScopedObjectAccess& soa, Handle<mirror::DexCache> dex_cache, - Handle<mirror::ClassLoader> class_loader, const DexCompilationUnit* mUnit, - uint32_t field_idx, bool is_static) - REQUIRES_SHARED(Locks::mutator_lock_); - - // Resolve a field with a given dex file. - ArtField* ResolveFieldWithDexFile( - const ScopedObjectAccess& soa, Handle<mirror::DexCache> dex_cache, - Handle<mirror::ClassLoader> class_loader, const DexFile* dex_file, - uint32_t field_idx, bool is_static) + ArtField* ResolveField(const ScopedObjectAccess& soa, + Handle<mirror::DexCache> dex_cache, + Handle<mirror::ClassLoader> class_loader, + uint32_t field_idx, + bool is_static) REQUIRES_SHARED(Locks::mutator_lock_); // Can we fast-path an IGET/IPUT access to an instance field? If yes, compute the field offset. @@ -271,9 +265,9 @@ class CompilerDriver { REQUIRES(!Locks::mutator_lock_); ArtField* ComputeInstanceFieldInfo(uint32_t field_idx, - const DexCompilationUnit* mUnit, - bool is_put, - const ScopedObjectAccess& soa) + const DexCompilationUnit* mUnit, + bool is_put, + const ScopedObjectAccess& soa) REQUIRES_SHARED(Locks::mutator_lock_); diff --git a/compiler/optimizing/instruction_builder.cc b/compiler/optimizing/instruction_builder.cc index 4485f064c6..bce4de32d5 100644 --- a/compiler/optimizing/instruction_builder.cc +++ b/compiler/optimizing/instruction_builder.cc @@ -1484,8 +1484,7 @@ ArtField* HInstructionBuilder::ResolveField(uint16_t field_idx, bool is_static, Handle<mirror::ClassLoader> class_loader = dex_compilation_unit_->GetClassLoader(); Handle<mirror::Class> compiling_class(hs.NewHandle(GetCompilingClass())); - ArtField* resolved_field = class_linker->ResolveField(*dex_compilation_unit_->GetDexFile(), - field_idx, + ArtField* resolved_field = class_linker->ResolveField(field_idx, dex_compilation_unit_->GetDexCache(), class_loader, is_static); diff --git a/runtime/class_linker-inl.h b/runtime/class_linker-inl.h index 648b455e50..2d8d4b41a0 100644 --- a/runtime/class_linker-inl.h +++ b/runtime/class_linker-inl.h @@ -299,8 +299,7 @@ inline ArtField* ClassLinker::ResolveField(uint32_t field_idx, StackHandleScope<2> hs(Thread::Current()); Handle<mirror::DexCache> dex_cache(hs.NewHandle(referrer->GetDexCache())); Handle<mirror::ClassLoader> class_loader(hs.NewHandle(declaring_class->GetClassLoader())); - const DexFile& dex_file = *dex_cache->GetDexFile(); - resolved_field = ResolveField(dex_file, field_idx, dex_cache, class_loader, is_static); + resolved_field = ResolveField(field_idx, dex_cache, class_loader, is_static); // Note: We cannot check here to see whether we added the field to the cache. The type // might be an erroneous class, which results in it being hidden from us. } diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc index 81aa371fcb..095cb30a04 100644 --- a/runtime/class_linker.cc +++ b/runtime/class_linker.cc @@ -4818,7 +4818,6 @@ bool ClassLinker::InitializeClass(Thread* self, Handle<mirror::Class> klass, if (num_static_fields > 0) { const DexFile::ClassDef* dex_class_def = klass->GetClassDef(); CHECK(dex_class_def != nullptr); - const DexFile& dex_file = klass->GetDexFile(); StackHandleScope<3> hs(self); Handle<mirror::ClassLoader> class_loader(hs.NewHandle(klass->GetClassLoader())); Handle<mirror::DexCache> dex_cache(hs.NewHandle(klass->GetDexCache())); @@ -4836,11 +4835,11 @@ bool ClassLinker::InitializeClass(Thread* self, Handle<mirror::Class> klass, } } - annotations::RuntimeEncodedStaticFieldValueIterator value_it(dex_file, - &dex_cache, - &class_loader, + annotations::RuntimeEncodedStaticFieldValueIterator value_it(dex_cache, + class_loader, this, *dex_class_def); + const DexFile& dex_file = *dex_cache->GetDexFile(); const uint8_t* class_data = dex_file.GetClassData(*dex_class_def); ClassDataItemIterator field_it(dex_file, class_data); if (value_it.HasNext()) { @@ -4848,7 +4847,7 @@ bool ClassLinker::InitializeClass(Thread* self, Handle<mirror::Class> klass, CHECK(can_init_statics); for ( ; value_it.HasNext(); value_it.Next(), field_it.Next()) { ArtField* field = ResolveField( - dex_file, field_it.GetMemberIndex(), dex_cache, class_loader, true); + field_it.GetMemberIndex(), dex_cache, class_loader, /* is_static */ true); if (Runtime::Current()->IsActiveTransaction()) { value_it.ReadValueToField<true>(field); } else { @@ -8114,8 +8113,7 @@ ArtField* ClassLinker::LookupResolvedField(uint32_t field_idx, return resolved_field; } -ArtField* ClassLinker::ResolveField(const DexFile& dex_file, - uint32_t field_idx, +ArtField* ClassLinker::ResolveField(uint32_t field_idx, Handle<mirror::DexCache> dex_cache, Handle<mirror::ClassLoader> class_loader, bool is_static) { @@ -8125,6 +8123,7 @@ ArtField* ClassLinker::ResolveField(const DexFile& dex_file, if (resolved != nullptr) { return resolved; } + const DexFile& dex_file = *dex_cache->GetDexFile(); const DexFile::FieldId& field_id = dex_file.GetFieldId(field_idx); Thread* const self = Thread::Current(); ObjPtr<mirror::Class> klass = ResolveType(dex_file, field_id.class_idx_, dex_cache, class_loader); @@ -8156,8 +8155,7 @@ ArtField* ClassLinker::ResolveField(const DexFile& dex_file, return resolved; } -ArtField* ClassLinker::ResolveFieldJLS(const DexFile& dex_file, - uint32_t field_idx, +ArtField* ClassLinker::ResolveFieldJLS(uint32_t field_idx, Handle<mirror::DexCache> dex_cache, Handle<mirror::ClassLoader> class_loader) { DCHECK(dex_cache != nullptr); @@ -8166,6 +8164,7 @@ ArtField* ClassLinker::ResolveFieldJLS(const DexFile& dex_file, if (resolved != nullptr) { return resolved; } + const DexFile& dex_file = *dex_cache->GetDexFile(); const DexFile::FieldId& field_id = dex_file.GetFieldId(field_idx); Thread* self = Thread::Current(); ObjPtr<mirror::Class> klass(ResolveType(dex_file, field_id.class_idx_, dex_cache, class_loader)); diff --git a/runtime/class_linker.h b/runtime/class_linker.h index 16255f4542..6a8c7c1d05 100644 --- a/runtime/class_linker.h +++ b/runtime/class_linker.h @@ -345,23 +345,22 @@ class ClassLinker { REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!Locks::dex_lock_, !Roles::uninterruptible_); - // Resolve a field with a given ID from the DexFile, storing the - // result in DexCache. The ClassLinker and ClassLoader are used as - // in ResolveType. What is unique is the is_static argument which is - // used to determine if we are resolving a static or non-static - // field. - ArtField* ResolveField(const DexFile& dex_file, uint32_t field_idx, + // Resolve a field with a given ID from the DexFile associated with the given DexCache + // and ClassLoader, storing the result in DexCache. The ClassLinker and ClassLoader + // are used as in ResolveType. What is unique is the is_static argument which is used + // to determine if we are resolving a static or non-static field. + ArtField* ResolveField(uint32_t field_idx, Handle<mirror::DexCache> dex_cache, - Handle<mirror::ClassLoader> class_loader, bool is_static) + Handle<mirror::ClassLoader> class_loader, + bool is_static) REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!Locks::dex_lock_, !Roles::uninterruptible_); - // Resolve a field with a given ID from the DexFile, storing the - // result in DexCache. The ClassLinker and ClassLoader are used as - // in ResolveType. No is_static argument is provided so that Java + // Resolve a field with a given ID from the DexFile associated with the given DexCache + // and ClassLoader, storing the result in DexCache. The ClassLinker and ClassLoader + // are used as in ResolveType. No is_static argument is provided so that Java // field resolution semantics are followed. - ArtField* ResolveFieldJLS(const DexFile& dex_file, - uint32_t field_idx, + ArtField* ResolveFieldJLS(uint32_t field_idx, Handle<mirror::DexCache> dex_cache, Handle<mirror::ClassLoader> class_loader) REQUIRES_SHARED(Locks::mutator_lock_) diff --git a/runtime/dex_file_annotations.cc b/runtime/dex_file_annotations.cc index 27b9202d25..437347403b 100644 --- a/runtime/dex_file_annotations.cc +++ b/runtime/dex_file_annotations.cc @@ -540,7 +540,6 @@ bool ProcessAnnotationValue(const ClassData& klass, } else { StackHandleScope<2> hs(self); ArtField* field = Runtime::Current()->GetClassLinker()->ResolveFieldJLS( - klass.GetDexFile(), index, hs.NewHandle(klass.GetDexCache()), hs.NewHandle(klass.GetClassLoader())); @@ -569,7 +568,6 @@ bool ProcessAnnotationValue(const ClassData& klass, } else { StackHandleScope<3> hs(self); ArtField* enum_field = Runtime::Current()->GetClassLinker()->ResolveField( - klass.GetDexFile(), index, hs.NewHandle(klass.GetDexCache()), hs.NewHandle(klass.GetClassLoader()), @@ -1580,7 +1578,6 @@ int32_t GetLineNumFromPC(const DexFile* dex_file, ArtMethod* method, uint32_t re template<bool kTransactionActive> void RuntimeEncodedStaticFieldValueIterator::ReadValueToField(ArtField* field) const { DCHECK(dex_cache_ != nullptr); - DCHECK(class_loader_ != nullptr); switch (type_) { case kBoolean: field->SetBoolean<kTransactionActive>(field->GetDeclaringClass(), jval_.z); break; @@ -1595,15 +1592,15 @@ void RuntimeEncodedStaticFieldValueIterator::ReadValueToField(ArtField* field) c case kString: { ObjPtr<mirror::String> resolved = linker_->ResolveString(dex_file_, dex::StringIndex(jval_.i), - *dex_cache_); + dex_cache_); field->SetObject<kTransactionActive>(field->GetDeclaringClass(), resolved); break; } case kType: { ObjPtr<mirror::Class> resolved = linker_->ResolveType(dex_file_, dex::TypeIndex(jval_.i), - *dex_cache_, - *class_loader_); + dex_cache_, + class_loader_); field->SetObject<kTransactionActive>(field->GetDeclaringClass(), resolved); break; } diff --git a/runtime/dex_file_annotations.h b/runtime/dex_file_annotations.h index a934a4f99c..9ff0929176 100644 --- a/runtime/dex_file_annotations.h +++ b/runtime/dex_file_annotations.h @@ -19,18 +19,18 @@ #include "dex_file.h" +#include "handle.h" +#include "mirror/dex_cache.h" #include "mirror/object_array.h" namespace art { namespace mirror { class ClassLoader; -class DexCache; } // namespace mirror class ArtField; class ArtMethod; class ClassLinker; -template<class T> class MutableHandle; namespace annotations { @@ -116,13 +116,12 @@ int32_t GetLineNumFromPC(const DexFile* dex_file, ArtMethod* method, uint32_t re class RuntimeEncodedStaticFieldValueIterator : public EncodedStaticFieldValueIterator { public: // A constructor meant to be called from runtime code. - RuntimeEncodedStaticFieldValueIterator(const DexFile& dex_file, - Handle<mirror::DexCache>* dex_cache, - Handle<mirror::ClassLoader>* class_loader, + RuntimeEncodedStaticFieldValueIterator(Handle<mirror::DexCache> dex_cache, + Handle<mirror::ClassLoader> class_loader, ClassLinker* linker, const DexFile::ClassDef& class_def) REQUIRES_SHARED(Locks::mutator_lock_) - : EncodedStaticFieldValueIterator(dex_file, class_def), + : EncodedStaticFieldValueIterator(*dex_cache->GetDexFile(), class_def), dex_cache_(dex_cache), class_loader_(class_loader), linker_(linker) { @@ -132,9 +131,9 @@ class RuntimeEncodedStaticFieldValueIterator : public EncodedStaticFieldValueIte void ReadValueToField(ArtField* field) const REQUIRES_SHARED(Locks::mutator_lock_); private: - Handle<mirror::DexCache>* const dex_cache_; // Dex cache to resolve literal objects. - Handle<mirror::ClassLoader>* const class_loader_; // ClassLoader to resolve types. - ClassLinker* linker_; // Linker to resolve literal objects. + const Handle<mirror::DexCache> dex_cache_; // Dex cache to resolve literal objects. + const Handle<mirror::ClassLoader> class_loader_; // ClassLoader to resolve types. + ClassLinker* const linker_; // Linker to resolve literal objects. DISALLOW_IMPLICIT_CONSTRUCTORS(RuntimeEncodedStaticFieldValueIterator); }; diff --git a/runtime/entrypoints/entrypoint_utils-inl.h b/runtime/entrypoints/entrypoint_utils-inl.h index 475c1e7e90..df17b30580 100644 --- a/runtime/entrypoints/entrypoint_utils-inl.h +++ b/runtime/entrypoints/entrypoint_utils-inl.h @@ -349,8 +349,7 @@ inline ArtField* FindFieldFromCode(uint32_t field_idx, Handle<mirror::DexCache> h_dex_cache(hs.NewHandle(method->GetDexCache())); Handle<mirror::ClassLoader> h_class_loader(hs.NewHandle(method->GetClassLoader())); - resolved_field = class_linker->ResolveFieldJLS(*method->GetDexFile(), - field_idx, + resolved_field = class_linker->ResolveFieldJLS(field_idx, h_dex_cache, h_class_loader); } else { diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc index 3ca34a70f3..8bd00b802c 100644 --- a/runtime/verifier/method_verifier.cc +++ b/runtime/verifier/method_verifier.cc @@ -4883,7 +4883,7 @@ ArtField* MethodVerifier::GetStaticField(int field_idx) { return nullptr; // Can't resolve Class so no more to do here, will do checking at runtime. } ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); - ArtField* field = class_linker->ResolveFieldJLS(*dex_file_, field_idx, dex_cache_, class_loader_); + ArtField* field = class_linker->ResolveFieldJLS(field_idx, dex_cache_, class_loader_); // Record result of the field resolution attempt. VerifierDeps::MaybeRecordFieldResolution(*dex_file_, field_idx, field); @@ -4924,7 +4924,7 @@ ArtField* MethodVerifier::GetInstanceField(const RegType& obj_type, int field_id return nullptr; // Can't resolve Class so no more to do here } ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); - ArtField* field = class_linker->ResolveFieldJLS(*dex_file_, field_idx, dex_cache_, class_loader_); + ArtField* field = class_linker->ResolveFieldJLS(field_idx, dex_cache_, class_loader_); // Record result of the field resolution attempt. VerifierDeps::MaybeRecordFieldResolution(*dex_file_, field_idx, field); |