Merge "Revert "Invoke dex2oat explictly before dalvikvm""
diff --git a/cmdline/cmdline_parser_test.cc b/cmdline/cmdline_parser_test.cc
index 5b331bc..1a2b9cd 100644
--- a/cmdline/cmdline_parser_test.cc
+++ b/cmdline/cmdline_parser_test.cc
@@ -300,6 +300,13 @@
log_verbosity.oat = true;
EXPECT_SINGLE_PARSE_VALUE(log_verbosity, log_args, M::Verbose);
}
+
+ {
+ const char* log_args = "-verbose:dex";
+ LogVerbosity log_verbosity = LogVerbosity();
+ log_verbosity.dex = true;
+ EXPECT_SINGLE_PARSE_VALUE(log_verbosity, log_args, M::Verbose);
+ }
} // TEST_F
// TODO: Enable this b/19274810
diff --git a/cmdline/cmdline_types.h b/cmdline/cmdline_types.h
index cd19fa4..e33a207 100644
--- a/cmdline/cmdline_types.h
+++ b/cmdline/cmdline_types.h
@@ -656,6 +656,8 @@
log_verbosity.systrace_lock_logging = true;
} else if (verbose_options[j] == "agents") {
log_verbosity.agents = true;
+ } else if (verbose_options[j] == "dex") {
+ log_verbosity.dex = true;
} else {
return Result::Usage(std::string("Unknown -verbose option ") + verbose_options[j]);
}
diff --git a/compiler/compiled_method.h b/compiler/compiled_method.h
index aa529f8..d0f66e2 100644
--- a/compiler/compiled_method.h
+++ b/compiler/compiled_method.h
@@ -121,14 +121,15 @@
enum class Type : uint8_t {
kMethod,
kCall,
- kCallRelative, // NOTE: Actual patching is instruction_set-dependent.
+ kCallRelative, // NOTE: Actual patching is instruction_set-dependent.
kType,
- kTypeRelative, // NOTE: Actual patching is instruction_set-dependent.
- kTypeBssEntry, // NOTE: Actual patching is instruction_set-dependent.
+ kTypeRelative, // NOTE: Actual patching is instruction_set-dependent.
+ kTypeBssEntry, // NOTE: Actual patching is instruction_set-dependent.
kString,
- kStringRelative, // NOTE: Actual patching is instruction_set-dependent.
- kStringBssEntry, // NOTE: Actual patching is instruction_set-dependent.
- kDexCacheArray, // NOTE: Actual patching is instruction_set-dependent.
+ kStringRelative, // NOTE: Actual patching is instruction_set-dependent.
+ kStringBssEntry, // NOTE: Actual patching is instruction_set-dependent.
+ kDexCacheArray, // NOTE: Actual patching is instruction_set-dependent.
+ kBakerReadBarrierBranch, // NOTE: Actual patching is instruction_set-dependent.
};
static LinkerPatch MethodPatch(size_t literal_offset,
@@ -215,13 +216,21 @@
const DexFile* target_dex_file,
uint32_t pc_insn_offset,
uint32_t element_offset) {
- DCHECK(IsUint<32>(element_offset));
LinkerPatch patch(literal_offset, Type::kDexCacheArray, target_dex_file);
patch.pc_insn_offset_ = pc_insn_offset;
patch.element_offset_ = element_offset;
return patch;
}
+ static LinkerPatch BakerReadBarrierBranchPatch(size_t literal_offset,
+ uint32_t custom_value1 = 0u,
+ uint32_t custom_value2 = 0u) {
+ LinkerPatch patch(literal_offset, Type::kBakerReadBarrierBranch, nullptr);
+ patch.baker_custom_value1_ = custom_value1;
+ patch.baker_custom_value2_ = custom_value2;
+ return patch;
+ }
+
LinkerPatch(const LinkerPatch& other) = default;
LinkerPatch& operator=(const LinkerPatch& other) = default;
@@ -241,6 +250,7 @@
case Type::kStringRelative:
case Type::kStringBssEntry:
case Type::kDexCacheArray:
+ case Type::kBakerReadBarrierBranch:
return true;
default:
return false;
@@ -301,6 +311,16 @@
return pc_insn_offset_;
}
+ uint32_t GetBakerCustomValue1() const {
+ DCHECK(patch_type_ == Type::kBakerReadBarrierBranch);
+ return baker_custom_value1_;
+ }
+
+ uint32_t GetBakerCustomValue2() const {
+ DCHECK(patch_type_ == Type::kBakerReadBarrierBranch);
+ return baker_custom_value2_;
+ }
+
private:
LinkerPatch(size_t literal_offset, Type patch_type, const DexFile* target_dex_file)
: target_dex_file_(target_dex_file),
@@ -314,6 +334,7 @@
}
const DexFile* target_dex_file_;
+ // TODO: Clean up naming. Some patched locations are literals but others are not.
uint32_t literal_offset_ : 24; // Method code size up to 16MiB.
Type patch_type_ : 8;
union {
@@ -322,10 +343,12 @@
uint32_t type_idx_; // Type index for Type patches.
uint32_t string_idx_; // String index for String patches.
uint32_t element_offset_; // Element offset in the dex cache arrays.
+ uint32_t baker_custom_value1_;
static_assert(sizeof(method_idx_) == sizeof(cmp1_), "needed by relational operators");
static_assert(sizeof(type_idx_) == sizeof(cmp1_), "needed by relational operators");
static_assert(sizeof(string_idx_) == sizeof(cmp1_), "needed by relational operators");
static_assert(sizeof(element_offset_) == sizeof(cmp1_), "needed by relational operators");
+ static_assert(sizeof(baker_custom_value1_) == sizeof(cmp1_), "needed by relational operators");
};
union {
// Note: To avoid uninitialized padding on 64-bit systems, we use `size_t` for `cmp2_`.
@@ -334,7 +357,9 @@
// Literal offset of the insn loading PC (same as literal_offset if it's the same insn,
// may be different if the PC-relative addressing needs multiple insns).
uint32_t pc_insn_offset_;
+ uint32_t baker_custom_value2_;
static_assert(sizeof(pc_insn_offset_) <= sizeof(cmp2_), "needed by relational operators");
+ static_assert(sizeof(baker_custom_value2_) <= sizeof(cmp2_), "needed by relational operators");
};
friend bool operator==(const LinkerPatch& lhs, const LinkerPatch& rhs);
diff --git a/compiler/linker/arm/relative_patcher_arm_base.cc b/compiler/linker/arm/relative_patcher_arm_base.cc
index 2471f79..f55d5a6 100644
--- a/compiler/linker/arm/relative_patcher_arm_base.cc
+++ b/compiler/linker/arm/relative_patcher_arm_base.cc
@@ -24,6 +24,118 @@
namespace art {
namespace linker {
+class ArmBaseRelativePatcher::ThunkData {
+ public:
+ ThunkData(std::vector<uint8_t> code, uint32_t max_next_offset)
+ : code_(code),
+ offsets_(),
+ max_next_offset_(max_next_offset),
+ pending_offset_(0u) {
+ DCHECK(NeedsNextThunk()); // The data is constructed only when we expect to need the thunk.
+ }
+
+ ThunkData(ThunkData&& src) = default;
+
+ size_t CodeSize() const {
+ return code_.size();
+ }
+
+ ArrayRef<const uint8_t> GetCode() const {
+ return ArrayRef<const uint8_t>(code_);
+ }
+
+ bool NeedsNextThunk() const {
+ return max_next_offset_ != 0u;
+ }
+
+ uint32_t MaxNextOffset() const {
+ DCHECK(NeedsNextThunk());
+ return max_next_offset_;
+ }
+
+ void ClearMaxNextOffset() {
+ DCHECK(NeedsNextThunk());
+ max_next_offset_ = 0u;
+ }
+
+ void SetMaxNextOffset(uint32_t max_next_offset) {
+ DCHECK(!NeedsNextThunk());
+ max_next_offset_ = max_next_offset;
+ }
+
+ // Adjust the MaxNextOffset() down if needed to fit the code before the next thunk.
+ // Returns true if it was adjusted, false if the old value was kept.
+ bool MakeSpaceBefore(const ThunkData& next_thunk, size_t alignment) {
+ DCHECK(NeedsNextThunk());
+ DCHECK(next_thunk.NeedsNextThunk());
+ DCHECK_ALIGNED_PARAM(MaxNextOffset(), alignment);
+ DCHECK_ALIGNED_PARAM(next_thunk.MaxNextOffset(), alignment);
+ if (next_thunk.MaxNextOffset() - CodeSize() < MaxNextOffset()) {
+ max_next_offset_ = RoundDown(next_thunk.MaxNextOffset() - CodeSize(), alignment);
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ uint32_t ReserveOffset(size_t offset) {
+ DCHECK(NeedsNextThunk());
+ DCHECK_LE(offset, max_next_offset_);
+ max_next_offset_ = 0u; // The reserved offset should satisfy all pending references.
+ offsets_.push_back(offset);
+ return offset + CodeSize();
+ }
+
+ bool HasReservedOffset() const {
+ return !offsets_.empty();
+ }
+
+ uint32_t LastReservedOffset() const {
+ DCHECK(HasReservedOffset());
+ return offsets_.back();
+ }
+
+ bool HasPendingOffset() const {
+ return pending_offset_ != offsets_.size();
+ }
+
+ uint32_t GetPendingOffset() const {
+ DCHECK(HasPendingOffset());
+ return offsets_[pending_offset_];
+ }
+
+ void MarkPendingOffsetAsWritten() {
+ DCHECK(HasPendingOffset());
+ ++pending_offset_;
+ }
+
+ bool HasWrittenOffset() const {
+ return pending_offset_ != 0u;
+ }
+
+ uint32_t LastWrittenOffset() const {
+ DCHECK(HasWrittenOffset());
+ return offsets_[pending_offset_ - 1u];
+ }
+
+ private:
+ std::vector<uint8_t> code_; // The code of the thunk.
+ std::vector<uint32_t> offsets_; // Offsets at which the thunk needs to be written.
+ uint32_t max_next_offset_; // The maximum offset at which the next thunk can be placed.
+ uint32_t pending_offset_; // The index of the next offset to write.
+};
+
+class ArmBaseRelativePatcher::PendingThunkComparator {
+ public:
+ bool operator()(const ThunkData* lhs, const ThunkData* rhs) const {
+ DCHECK(lhs->HasPendingOffset());
+ DCHECK(rhs->HasPendingOffset());
+ // The top of the heap is defined to contain the highest element and we want to pick
+ // the thunk with the smallest pending offset, so use the reverse ordering, i.e. ">".
+ return lhs->GetPendingOffset() > rhs->GetPendingOffset();
+ }
+};
+
uint32_t ArmBaseRelativePatcher::ReserveSpace(uint32_t offset,
const CompiledMethod* compiled_method,
MethodReference method_ref) {
@@ -31,151 +143,305 @@
}
uint32_t ArmBaseRelativePatcher::ReserveSpaceEnd(uint32_t offset) {
- uint32_t aligned_offset = CompiledMethod::AlignCode(offset, instruction_set_);
- bool needs_thunk = ReserveSpaceProcessPatches(aligned_offset,
- MethodReference(nullptr, 0u),
- aligned_offset);
- if (needs_thunk) {
- // All remaining patches will be handled by this thunk.
- DCHECK(!unprocessed_patches_.empty());
- DCHECK_LE(aligned_offset - unprocessed_patches_.front().second, max_positive_displacement_);
- unprocessed_patches_.clear();
-
- thunk_locations_.push_back(aligned_offset);
- offset = aligned_offset + thunk_code_.size();
+ // For multi-oat compilations (boot image), ReserveSpaceEnd() is called for each oat file.
+ // Since we do not know here whether this is the last file or whether the next opportunity
+ // to place thunk will be soon enough, we need to reserve all needed thunks now. Code for
+ // subsequent oat files can still call back to them.
+ if (!unprocessed_method_call_patches_.empty()) {
+ ResolveMethodCalls(offset, MethodReference(nullptr, DexFile::kDexNoIndex));
}
+ for (ThunkData* data : unreserved_thunks_) {
+ uint32_t thunk_offset = CompiledCode::AlignCode(offset, instruction_set_);
+ offset = data->ReserveOffset(thunk_offset);
+ }
+ unreserved_thunks_.clear();
+ // We also need to delay initiating the pending_thunks_ until the call to WriteThunks().
+ // Check that the `pending_thunks_.capacity()` indicates that no WriteThunks() has taken place.
+ DCHECK_EQ(pending_thunks_.capacity(), 0u);
return offset;
}
uint32_t ArmBaseRelativePatcher::WriteThunks(OutputStream* out, uint32_t offset) {
- if (current_thunk_to_write_ == thunk_locations_.size()) {
- return offset;
+ if (pending_thunks_.capacity() == 0u) {
+ if (thunks_.empty()) {
+ return offset;
+ }
+ // First call to WriteThunks(), prepare the thunks for writing.
+ pending_thunks_.reserve(thunks_.size());
+ for (auto& entry : thunks_) {
+ ThunkData* data = &entry.second;
+ if (data->HasPendingOffset()) {
+ pending_thunks_.push_back(data);
+ }
+ }
+ std::make_heap(pending_thunks_.begin(), pending_thunks_.end(), PendingThunkComparator());
}
uint32_t aligned_offset = CompiledMethod::AlignCode(offset, instruction_set_);
- if (UNLIKELY(aligned_offset == thunk_locations_[current_thunk_to_write_])) {
- ++current_thunk_to_write_;
+ while (!pending_thunks_.empty() &&
+ pending_thunks_.front()->GetPendingOffset() == aligned_offset) {
+ // Write alignment bytes and code.
uint32_t aligned_code_delta = aligned_offset - offset;
- if (aligned_code_delta != 0u && !WriteCodeAlignment(out, aligned_code_delta)) {
+ if (aligned_code_delta != 0u && UNLIKELY(!WriteCodeAlignment(out, aligned_code_delta))) {
return 0u;
}
- if (UNLIKELY(!WriteRelCallThunk(out, ArrayRef<const uint8_t>(thunk_code_)))) {
+ if (UNLIKELY(!WriteThunk(out, pending_thunks_.front()->GetCode()))) {
return 0u;
}
- offset = aligned_offset + thunk_code_.size();
+ offset = aligned_offset + pending_thunks_.front()->CodeSize();
+ // Mark the thunk as written at the pending offset and update the `pending_thunks_` heap.
+ std::pop_heap(pending_thunks_.begin(), pending_thunks_.end(), PendingThunkComparator());
+ pending_thunks_.back()->MarkPendingOffsetAsWritten();
+ if (pending_thunks_.back()->HasPendingOffset()) {
+ std::push_heap(pending_thunks_.begin(), pending_thunks_.end(), PendingThunkComparator());
+ } else {
+ pending_thunks_.pop_back();
+ }
+ aligned_offset = CompiledMethod::AlignCode(offset, instruction_set_);
}
+ DCHECK(pending_thunks_.empty() || pending_thunks_.front()->GetPendingOffset() > aligned_offset);
return offset;
}
ArmBaseRelativePatcher::ArmBaseRelativePatcher(RelativePatcherTargetProvider* provider,
- InstructionSet instruction_set,
- std::vector<uint8_t> thunk_code,
- uint32_t max_positive_displacement,
- uint32_t max_negative_displacement)
- : provider_(provider), instruction_set_(instruction_set), thunk_code_(thunk_code),
- max_positive_displacement_(max_positive_displacement),
- max_negative_displacement_(max_negative_displacement),
- thunk_locations_(), current_thunk_to_write_(0u), unprocessed_patches_() {
+ InstructionSet instruction_set)
+ : provider_(provider),
+ instruction_set_(instruction_set),
+ thunks_(),
+ unprocessed_method_call_patches_(),
+ method_call_thunk_(nullptr),
+ pending_thunks_() {
+}
+
+ArmBaseRelativePatcher::~ArmBaseRelativePatcher() {
+ // All work done by member destructors.
}
uint32_t ArmBaseRelativePatcher::ReserveSpaceInternal(uint32_t offset,
const CompiledMethod* compiled_method,
MethodReference method_ref,
uint32_t max_extra_space) {
- uint32_t quick_code_size = compiled_method->GetQuickCode().size();
- uint32_t quick_code_offset = compiled_method->AlignCode(offset + sizeof(OatQuickMethodHeader));
- uint32_t next_aligned_offset = compiled_method->AlignCode(quick_code_offset + quick_code_size);
- // Adjust for extra space required by the subclass.
- next_aligned_offset = compiled_method->AlignCode(next_aligned_offset + max_extra_space);
- // TODO: ignore unprocessed patches targeting this method if they can reach quick_code_offset.
- // We need the MethodReference for that.
- if (!unprocessed_patches_.empty() &&
- next_aligned_offset - unprocessed_patches_.front().second > max_positive_displacement_) {
- bool needs_thunk = ReserveSpaceProcessPatches(quick_code_offset,
- method_ref,
- next_aligned_offset);
- if (needs_thunk) {
- // A single thunk will cover all pending patches.
- unprocessed_patches_.clear();
- uint32_t thunk_location = CompiledMethod::AlignCode(offset, instruction_set_);
- thunk_locations_.push_back(thunk_location);
- offset = thunk_location + thunk_code_.size();
+ // Adjust code size for extra space required by the subclass.
+ uint32_t max_code_size = compiled_method->GetQuickCode().size() + max_extra_space;
+ uint32_t code_offset;
+ uint32_t next_aligned_offset;
+ while (true) {
+ code_offset = compiled_method->AlignCode(offset + sizeof(OatQuickMethodHeader));
+ next_aligned_offset = compiled_method->AlignCode(code_offset + max_code_size);
+ if (unreserved_thunks_.empty() ||
+ unreserved_thunks_.front()->MaxNextOffset() >= next_aligned_offset) {
+ break;
+ }
+ ThunkData* thunk = unreserved_thunks_.front();
+ if (thunk == method_call_thunk_) {
+ ResolveMethodCalls(code_offset, method_ref);
+ // This may have changed `method_call_thunk_` data, so re-check if we need to reserve.
+ if (unreserved_thunks_.empty() ||
+ unreserved_thunks_.front()->MaxNextOffset() >= next_aligned_offset) {
+ break;
+ }
+ // We need to process the new `front()` whether it's still the `method_call_thunk_` or not.
+ thunk = unreserved_thunks_.front();
+ }
+ unreserved_thunks_.pop_front();
+ uint32_t thunk_offset = CompiledCode::AlignCode(offset, instruction_set_);
+ offset = thunk->ReserveOffset(thunk_offset);
+ if (thunk == method_call_thunk_) {
+ // All remaining method call patches will be handled by this thunk.
+ DCHECK(!unprocessed_method_call_patches_.empty());
+ DCHECK_LE(thunk_offset - unprocessed_method_call_patches_.front().GetPatchOffset(),
+ MaxPositiveDisplacement(ThunkType::kMethodCall));
+ unprocessed_method_call_patches_.clear();
}
}
- for (const LinkerPatch& patch : compiled_method->GetPatches()) {
- if (patch.GetType() == LinkerPatch::Type::kCallRelative) {
- unprocessed_patches_.emplace_back(patch.TargetMethod(),
- quick_code_offset + patch.LiteralOffset());
- }
- }
+
+ // Process patches and check that adding thunks for the current method did not push any
+ // thunks (previously existing or newly added) before `next_aligned_offset`. This is
+ // essentially a check that we never compile a method that's too big. The calls or branches
+ // from the method should be able to reach beyond the end of the method and over any pending
+ // thunks. (The number of different thunks should be relatively low and their code short.)
+ ProcessPatches(compiled_method, code_offset);
+ CHECK(unreserved_thunks_.empty() ||
+ unreserved_thunks_.front()->MaxNextOffset() >= next_aligned_offset);
+
return offset;
}
-uint32_t ArmBaseRelativePatcher::CalculateDisplacement(uint32_t patch_offset,
- uint32_t target_offset) {
+uint32_t ArmBaseRelativePatcher::CalculateMethodCallDisplacement(uint32_t patch_offset,
+ uint32_t target_offset) {
+ DCHECK(method_call_thunk_ != nullptr);
// Unsigned arithmetic with its well-defined overflow behavior is just fine here.
uint32_t displacement = target_offset - patch_offset;
+ uint32_t max_positive_displacement = MaxPositiveDisplacement(ThunkType::kMethodCall);
+ uint32_t max_negative_displacement = MaxNegativeDisplacement(ThunkType::kMethodCall);
// NOTE: With unsigned arithmetic we do mean to use && rather than || below.
- if (displacement > max_positive_displacement_ && displacement < -max_negative_displacement_) {
+ if (displacement > max_positive_displacement && displacement < -max_negative_displacement) {
// Unwritten thunks have higher offsets, check if it's within range.
- DCHECK(current_thunk_to_write_ == thunk_locations_.size() ||
- thunk_locations_[current_thunk_to_write_] > patch_offset);
- if (current_thunk_to_write_ != thunk_locations_.size() &&
- thunk_locations_[current_thunk_to_write_] - patch_offset < max_positive_displacement_) {
- displacement = thunk_locations_[current_thunk_to_write_] - patch_offset;
+ DCHECK(!method_call_thunk_->HasPendingOffset() ||
+ method_call_thunk_->GetPendingOffset() > patch_offset);
+ if (method_call_thunk_->HasPendingOffset() &&
+ method_call_thunk_->GetPendingOffset() - patch_offset <= max_positive_displacement) {
+ displacement = method_call_thunk_->GetPendingOffset() - patch_offset;
} else {
// We must have a previous thunk then.
- DCHECK_NE(current_thunk_to_write_, 0u);
- DCHECK_LT(thunk_locations_[current_thunk_to_write_ - 1], patch_offset);
- displacement = thunk_locations_[current_thunk_to_write_ - 1] - patch_offset;
- DCHECK(displacement >= -max_negative_displacement_);
+ DCHECK(method_call_thunk_->HasWrittenOffset());
+ DCHECK_LT(method_call_thunk_->LastWrittenOffset(), patch_offset);
+ displacement = method_call_thunk_->LastWrittenOffset() - patch_offset;
+ DCHECK_GE(displacement, -max_negative_displacement);
}
}
return displacement;
}
-bool ArmBaseRelativePatcher::ReserveSpaceProcessPatches(uint32_t quick_code_offset,
- MethodReference method_ref,
- uint32_t next_aligned_offset) {
- // Process as many patches as possible, stop only on unresolved targets or calls too far back.
- while (!unprocessed_patches_.empty()) {
- MethodReference patch_ref = unprocessed_patches_.front().first;
- uint32_t patch_offset = unprocessed_patches_.front().second;
- DCHECK(thunk_locations_.empty() || thunk_locations_.back() <= patch_offset);
- if (patch_ref.dex_file == method_ref.dex_file &&
- patch_ref.dex_method_index == method_ref.dex_method_index) {
- DCHECK_GT(quick_code_offset, patch_offset);
- if (quick_code_offset - patch_offset > max_positive_displacement_) {
- return true;
- }
- } else {
- auto result = provider_->FindMethodOffset(patch_ref);
- if (!result.first) {
- // If still unresolved, check if we have a thunk within range.
- if (thunk_locations_.empty() ||
- patch_offset - thunk_locations_.back() > max_negative_displacement_) {
- // No thunk in range, we need a thunk if the next aligned offset
- // is out of range, or if we're at the end of all code.
- return (next_aligned_offset - patch_offset > max_positive_displacement_) ||
- (quick_code_offset == next_aligned_offset); // End of code.
- }
+uint32_t ArmBaseRelativePatcher::GetThunkTargetOffset(const ThunkKey& key, uint32_t patch_offset) {
+ auto it = thunks_.find(key);
+ CHECK(it != thunks_.end());
+ const ThunkData& data = it->second;
+ if (data.HasWrittenOffset()) {
+ uint32_t offset = data.LastWrittenOffset();
+ DCHECK_LT(offset, patch_offset);
+ if (patch_offset - offset <= MaxNegativeDisplacement(key.GetType())) {
+ return offset;
+ }
+ }
+ DCHECK(data.HasPendingOffset());
+ uint32_t offset = data.GetPendingOffset();
+ DCHECK_GT(offset, patch_offset);
+ DCHECK_LE(offset - patch_offset, MaxPositiveDisplacement(key.GetType()));
+ return offset;
+}
+
+void ArmBaseRelativePatcher::ProcessPatches(const CompiledMethod* compiled_method,
+ uint32_t code_offset) {
+ for (const LinkerPatch& patch : compiled_method->GetPatches()) {
+ uint32_t patch_offset = code_offset + patch.LiteralOffset();
+ ThunkType key_type = static_cast<ThunkType>(-1);
+ ThunkData* old_data = nullptr;
+ if (patch.GetType() == LinkerPatch::Type::kCallRelative) {
+ key_type = ThunkType::kMethodCall;
+ unprocessed_method_call_patches_.emplace_back(patch_offset, patch.TargetMethod());
+ if (method_call_thunk_ == nullptr) {
+ ThunkKey key(key_type, ThunkParams{{ 0u, 0u }}); // NOLINT(whitespace/braces)
+ uint32_t max_next_offset = CalculateMaxNextOffset(patch_offset, key_type);
+ auto it = thunks_.Put(key, ThunkData(CompileThunk(key), max_next_offset));
+ method_call_thunk_ = &it->second;
+ AddUnreservedThunk(method_call_thunk_);
} else {
- uint32_t target_offset = result.second - CompiledCode::CodeDelta(instruction_set_);
- if (target_offset >= patch_offset) {
- DCHECK_LE(target_offset - patch_offset, max_positive_displacement_);
- } else {
- // When calling back, check if we have a thunk that's closer than the actual target.
- if (!thunk_locations_.empty()) {
- target_offset = std::max(target_offset, thunk_locations_.back());
- }
- if (patch_offset - target_offset > max_negative_displacement_) {
- return true;
- }
+ old_data = method_call_thunk_;
+ }
+ } else if (patch.GetType() == LinkerPatch::Type::kBakerReadBarrierBranch) {
+ ThunkKey key = GetBakerReadBarrierKey(patch);
+ key_type = key.GetType();
+ auto lb = thunks_.lower_bound(key);
+ if (lb == thunks_.end() || thunks_.key_comp()(key, lb->first)) {
+ uint32_t max_next_offset = CalculateMaxNextOffset(patch_offset, key_type);
+ auto it = thunks_.PutBefore(lb, key, ThunkData(CompileThunk(key), max_next_offset));
+ AddUnreservedThunk(&it->second);
+ } else {
+ old_data = &lb->second;
+ }
+ }
+ if (old_data != nullptr) {
+ // Shared path where an old thunk may need an update.
+ DCHECK(key_type != static_cast<ThunkType>(-1));
+ DCHECK(!old_data->HasReservedOffset() || old_data->LastReservedOffset() < patch_offset);
+ if (old_data->NeedsNextThunk()) {
+ // Patches for a method are ordered by literal offset, so if we still need to place
+ // this thunk for a previous patch, that thunk shall be in range for this patch.
+ DCHECK_LE(old_data->MaxNextOffset(), CalculateMaxNextOffset(patch_offset, key_type));
+ } else {
+ if (!old_data->HasReservedOffset() ||
+ patch_offset - old_data->LastReservedOffset() > MaxNegativeDisplacement(key_type)) {
+ old_data->SetMaxNextOffset(CalculateMaxNextOffset(patch_offset, key_type));
+ AddUnreservedThunk(old_data);
}
}
}
- unprocessed_patches_.pop_front();
}
- return false;
+}
+
+void ArmBaseRelativePatcher::AddUnreservedThunk(ThunkData* data) {
+ DCHECK(data->NeedsNextThunk());
+ size_t index = unreserved_thunks_.size();
+ while (index != 0u && data->MaxNextOffset() < unreserved_thunks_[index - 1u]->MaxNextOffset()) {
+ --index;
+ }
+ unreserved_thunks_.insert(unreserved_thunks_.begin() + index, data);
+ // We may need to update the max next offset(s) if the thunk code would not fit.
+ size_t alignment = GetInstructionSetAlignment(instruction_set_);
+ if (index + 1u != unreserved_thunks_.size()) {
+ // Note: Ignore the return value as we need to process previous thunks regardless.
+ data->MakeSpaceBefore(*unreserved_thunks_[index + 1u], alignment);
+ }
+ // Make space for previous thunks. Once we find a pending thunk that does
+ // not need an adjustment, we can stop.
+ while (index != 0u && unreserved_thunks_[index - 1u]->MakeSpaceBefore(*data, alignment)) {
+ --index;
+ data = unreserved_thunks_[index];
+ }
+}
+
+void ArmBaseRelativePatcher::ResolveMethodCalls(uint32_t quick_code_offset,
+ MethodReference method_ref) {
+ DCHECK(!unreserved_thunks_.empty());
+ DCHECK(!unprocessed_method_call_patches_.empty());
+ DCHECK(method_call_thunk_ != nullptr);
+ uint32_t max_positive_displacement = MaxPositiveDisplacement(ThunkType::kMethodCall);
+ uint32_t max_negative_displacement = MaxNegativeDisplacement(ThunkType::kMethodCall);
+ // Process as many patches as possible, stop only on unresolved targets or calls too far back.
+ while (!unprocessed_method_call_patches_.empty()) {
+ MethodReference target_method = unprocessed_method_call_patches_.front().GetTargetMethod();
+ uint32_t patch_offset = unprocessed_method_call_patches_.front().GetPatchOffset();
+ DCHECK(!method_call_thunk_->HasReservedOffset() ||
+ method_call_thunk_->LastReservedOffset() <= patch_offset);
+ if (!method_call_thunk_->HasReservedOffset() ||
+ patch_offset - method_call_thunk_->LastReservedOffset() > max_negative_displacement) {
+ // No previous thunk in range, check if we can reach the target directly.
+ if (target_method.dex_file == method_ref.dex_file &&
+ target_method.dex_method_index == method_ref.dex_method_index) {
+ DCHECK_GT(quick_code_offset, patch_offset);
+ if (quick_code_offset - patch_offset > max_positive_displacement) {
+ break;
+ }
+ } else {
+ auto result = provider_->FindMethodOffset(target_method);
+ if (!result.first) {
+ break;
+ }
+ uint32_t target_offset = result.second - CompiledCode::CodeDelta(instruction_set_);
+ if (target_offset >= patch_offset) {
+ DCHECK_LE(target_offset - patch_offset, max_positive_displacement);
+ } else if (patch_offset - target_offset > max_negative_displacement) {
+ break;
+ }
+ }
+ }
+ unprocessed_method_call_patches_.pop_front();
+ }
+ if (!unprocessed_method_call_patches_.empty()) {
+ // Try to adjust the max next offset in `method_call_thunk_`. Do this conservatively only if
+ // the thunk shall be at the end of the `unreserved_thunks_` to avoid dealing with overlaps.
+ uint32_t new_max_next_offset =
+ unprocessed_method_call_patches_.front().GetPatchOffset() + max_positive_displacement;
+ if (new_max_next_offset >
+ unreserved_thunks_.back()->MaxNextOffset() + unreserved_thunks_.back()->CodeSize()) {
+ method_call_thunk_->ClearMaxNextOffset();
+ method_call_thunk_->SetMaxNextOffset(new_max_next_offset);
+ if (method_call_thunk_ != unreserved_thunks_.back()) {
+ RemoveElement(unreserved_thunks_, method_call_thunk_);
+ unreserved_thunks_.push_back(method_call_thunk_);
+ }
+ }
+ } else {
+ // We have resolved all method calls, we do not need a new thunk anymore.
+ method_call_thunk_->ClearMaxNextOffset();
+ RemoveElement(unreserved_thunks_, method_call_thunk_);
+ }
+}
+
+inline uint32_t ArmBaseRelativePatcher::CalculateMaxNextOffset(uint32_t patch_offset,
+ ThunkType type) {
+ return RoundDown(patch_offset + MaxPositiveDisplacement(type),
+ GetInstructionSetAlignment(instruction_set_));
}
} // namespace linker
diff --git a/compiler/linker/arm/relative_patcher_arm_base.h b/compiler/linker/arm/relative_patcher_arm_base.h
index 25fd35e..2cb1b6c 100644
--- a/compiler/linker/arm/relative_patcher_arm_base.h
+++ b/compiler/linker/arm/relative_patcher_arm_base.h
@@ -18,9 +18,11 @@
#define ART_COMPILER_LINKER_ARM_RELATIVE_PATCHER_ARM_BASE_H_
#include <deque>
+#include <vector>
#include "linker/relative_patcher.h"
#include "method_reference.h"
+#include "safe_map.h"
namespace art {
namespace linker {
@@ -35,32 +37,138 @@
protected:
ArmBaseRelativePatcher(RelativePatcherTargetProvider* provider,
- InstructionSet instruction_set,
- std::vector<uint8_t> thunk_code,
- uint32_t max_positive_displacement,
- uint32_t max_negative_displacement);
+ InstructionSet instruction_set);
+ ~ArmBaseRelativePatcher();
+
+ enum class ThunkType {
+ kMethodCall, // Method call thunk.
+ kBakerReadBarrierField, // Baker read barrier, load field or array element at known offset.
+ kBakerReadBarrierRoot, // Baker read barrier, GC root load.
+ };
+
+ struct BakerReadBarrierOffsetParams {
+ uint32_t holder_reg; // Holder object for reading lock word.
+ uint32_t base_reg; // Base register, different from holder for large offset.
+ // If base differs from holder, it should be a pre-defined
+ // register to limit the number of thunks we need to emit.
+ // The offset is retrieved using introspection.
+ };
+
+ struct BakerReadBarrierRootParams {
+ uint32_t root_reg; // The register holding the GC root.
+ uint32_t dummy;
+ };
+
+ struct RawThunkParams {
+ uint32_t first;
+ uint32_t second;
+ };
+
+ union ThunkParams {
+ RawThunkParams raw_params;
+ BakerReadBarrierOffsetParams offset_params;
+ BakerReadBarrierRootParams root_params;
+ };
+
+ class ThunkKey {
+ public:
+ ThunkKey(ThunkType type, ThunkParams params) : type_(type), params_(params) { }
+
+ ThunkType GetType() const {
+ return type_;
+ }
+
+ BakerReadBarrierOffsetParams GetOffsetParams() const {
+ DCHECK(type_ == ThunkType::kBakerReadBarrierField);
+ return params_.offset_params;
+ }
+
+ BakerReadBarrierRootParams GetRootParams() const {
+ DCHECK(type_ == ThunkType::kBakerReadBarrierRoot);
+ return params_.root_params;
+ }
+
+ RawThunkParams GetRawParams() const {
+ return params_.raw_params;
+ }
+
+ private:
+ ThunkType type_;
+ ThunkParams params_;
+ };
+
+ class ThunkKeyCompare {
+ public:
+ bool operator()(const ThunkKey& lhs, const ThunkKey& rhs) const {
+ if (lhs.GetType() != rhs.GetType()) {
+ return lhs.GetType() < rhs.GetType();
+ }
+ if (lhs.GetRawParams().first != rhs.GetRawParams().first) {
+ return lhs.GetRawParams().first < rhs.GetRawParams().first;
+ }
+ return lhs.GetRawParams().second < rhs.GetRawParams().second;
+ }
+ };
uint32_t ReserveSpaceInternal(uint32_t offset,
const CompiledMethod* compiled_method,
MethodReference method_ref,
uint32_t max_extra_space);
- uint32_t CalculateDisplacement(uint32_t patch_offset, uint32_t target_offset);
+ uint32_t GetThunkTargetOffset(const ThunkKey& key, uint32_t patch_offset);
+
+ uint32_t CalculateMethodCallDisplacement(uint32_t patch_offset,
+ uint32_t target_offset);
+
+ virtual ThunkKey GetBakerReadBarrierKey(const LinkerPatch& patch) = 0;
+ virtual std::vector<uint8_t> CompileThunk(const ThunkKey& key) = 0;
+ virtual uint32_t MaxPositiveDisplacement(ThunkType type) = 0;
+ virtual uint32_t MaxNegativeDisplacement(ThunkType type) = 0;
private:
- bool ReserveSpaceProcessPatches(uint32_t quick_code_offset, MethodReference method_ref,
- uint32_t next_aligned_offset);
+ class ThunkData;
+
+ void ProcessPatches(const CompiledMethod* compiled_method, uint32_t code_offset);
+ void AddUnreservedThunk(ThunkData* data);
+
+ void ResolveMethodCalls(uint32_t quick_code_offset, MethodReference method_ref);
+
+ uint32_t CalculateMaxNextOffset(uint32_t patch_offset, ThunkType type);
RelativePatcherTargetProvider* const provider_;
const InstructionSet instruction_set_;
- const std::vector<uint8_t> thunk_code_;
- const uint32_t max_positive_displacement_;
- const uint32_t max_negative_displacement_;
- std::vector<uint32_t> thunk_locations_;
- size_t current_thunk_to_write_;
- // ReserveSpace() tracks unprocessed patches.
- typedef std::pair<MethodReference, uint32_t> UnprocessedPatch;
- std::deque<UnprocessedPatch> unprocessed_patches_;
+ // The data for all thunks.
+ // SafeMap<> nodes don't move after being inserted, so we can use direct pointers to the data.
+ using ThunkMap = SafeMap<ThunkKey, ThunkData, ThunkKeyCompare>;
+ ThunkMap thunks_;
+
+ // ReserveSpace() tracks unprocessed method call patches. These may be resolved later.
+ class UnprocessedMethodCallPatch {
+ public:
+ UnprocessedMethodCallPatch(uint32_t patch_offset, MethodReference target_method)
+ : patch_offset_(patch_offset), target_method_(target_method) { }
+
+ uint32_t GetPatchOffset() const {
+ return patch_offset_;
+ }
+
+ MethodReference GetTargetMethod() const {
+ return target_method_;
+ }
+
+ private:
+ uint32_t patch_offset_;
+ MethodReference target_method_;
+ };
+ std::deque<UnprocessedMethodCallPatch> unprocessed_method_call_patches_;
+ // Once we have compiled a method call thunk, cache pointer to the data.
+ ThunkData* method_call_thunk_;
+
+ // Thunks
+ std::deque<ThunkData*> unreserved_thunks_;
+
+ class PendingThunkComparator;
+ std::vector<ThunkData*> pending_thunks_; // Heap with the PendingThunkComparator.
friend class Arm64RelativePatcherTest;
friend class Thumb2RelativePatcherTest;
diff --git a/compiler/linker/arm/relative_patcher_thumb2.cc b/compiler/linker/arm/relative_patcher_thumb2.cc
index fa49fc4..1a5d79c 100644
--- a/compiler/linker/arm/relative_patcher_thumb2.cc
+++ b/compiler/linker/arm/relative_patcher_thumb2.cc
@@ -23,9 +23,17 @@
namespace art {
namespace linker {
+// PC displacement from patch location; Thumb2 PC is always at instruction address + 4.
+static constexpr int32_t kPcDisplacement = 4;
+
+// Maximum positive and negative displacement for method call measured from the patch location.
+// (Signed 25 bit displacement with the last bit 0 has range [-2^24, 2^24-2] measured from
+// the Thumb2 PC pointing right after the BL, i.e. 4 bytes later than the patch location.)
+constexpr uint32_t kMaxMethodCallPositiveDisplacement = (1u << 24) - 2 + kPcDisplacement;
+constexpr uint32_t kMaxMethodCallNegativeDisplacement = (1u << 24) - kPcDisplacement;
+
Thumb2RelativePatcher::Thumb2RelativePatcher(RelativePatcherTargetProvider* provider)
- : ArmBaseRelativePatcher(provider, kThumb2, CompileThunkCode(),
- kMaxPositiveDisplacement, kMaxNegativeDisplacement) {
+ : ArmBaseRelativePatcher(provider, kThumb2) {
}
void Thumb2RelativePatcher::PatchCall(std::vector<uint8_t>* code,
@@ -36,7 +44,7 @@
DCHECK_EQ(literal_offset & 1u, 0u);
DCHECK_EQ(patch_offset & 1u, 0u);
DCHECK_EQ(target_offset & 1u, 1u); // Thumb2 mode bit.
- uint32_t displacement = CalculateDisplacement(patch_offset, target_offset & ~1u);
+ uint32_t displacement = CalculateMethodCallDisplacement(patch_offset, target_offset & ~1u);
displacement -= kPcDisplacement; // The base PC is at the end of the 4-byte patch.
DCHECK_EQ(displacement & 1u, 0u);
DCHECK((displacement >> 24) == 0u || (displacement >> 24) == 255u); // 25-bit signed.
@@ -76,7 +84,20 @@
SetInsn32(code, literal_offset, insn);
}
-std::vector<uint8_t> Thumb2RelativePatcher::CompileThunkCode() {
+void Thumb2RelativePatcher::PatchBakerReadBarrierBranch(std::vector<uint8_t>* code ATTRIBUTE_UNUSED,
+ const LinkerPatch& patch ATTRIBUTE_UNUSED,
+ uint32_t patch_offset ATTRIBUTE_UNUSED) {
+ LOG(FATAL) << "UNIMPLEMENTED";
+}
+
+ArmBaseRelativePatcher::ThunkKey Thumb2RelativePatcher::GetBakerReadBarrierKey(
+ const LinkerPatch& patch ATTRIBUTE_UNUSED) {
+ LOG(FATAL) << "UNIMPLEMENTED";
+ UNREACHABLE();
+}
+
+std::vector<uint8_t> Thumb2RelativePatcher::CompileThunk(const ThunkKey& key) {
+ DCHECK(key.GetType() == ThunkType::kMethodCall);
// The thunk just uses the entry point in the ArtMethod. This works even for calls
// to the generic JNI and interpreter trampolines.
ArenaPool pool;
@@ -93,6 +114,16 @@
return thunk_code;
}
+uint32_t Thumb2RelativePatcher::MaxPositiveDisplacement(ThunkType type) {
+ DCHECK(type == ThunkType::kMethodCall);
+ return kMaxMethodCallPositiveDisplacement;
+}
+
+uint32_t Thumb2RelativePatcher::MaxNegativeDisplacement(ThunkType type) {
+ DCHECK(type == ThunkType::kMethodCall);
+ return kMaxMethodCallNegativeDisplacement;
+}
+
void Thumb2RelativePatcher::SetInsn32(std::vector<uint8_t>* code, uint32_t offset, uint32_t value) {
DCHECK_LE(offset + 4u, code->size());
DCHECK_EQ(offset & 1u, 0u);
diff --git a/compiler/linker/arm/relative_patcher_thumb2.h b/compiler/linker/arm/relative_patcher_thumb2.h
index d85739c..ab37802 100644
--- a/compiler/linker/arm/relative_patcher_thumb2.h
+++ b/compiler/linker/arm/relative_patcher_thumb2.h
@@ -34,24 +34,24 @@
const LinkerPatch& patch,
uint32_t patch_offset,
uint32_t target_offset) OVERRIDE;
+ void PatchBakerReadBarrierBranch(std::vector<uint8_t>* code,
+ const LinkerPatch& patch,
+ uint32_t patch_offset) OVERRIDE;
+
+ protected:
+ ThunkKey GetBakerReadBarrierKey(const LinkerPatch& patch) OVERRIDE;
+ std::vector<uint8_t> CompileThunk(const ThunkKey& key) OVERRIDE;
+ uint32_t MaxPositiveDisplacement(ThunkType type) OVERRIDE;
+ uint32_t MaxNegativeDisplacement(ThunkType type) OVERRIDE;
private:
- static std::vector<uint8_t> CompileThunkCode();
-
void SetInsn32(std::vector<uint8_t>* code, uint32_t offset, uint32_t value);
static uint32_t GetInsn32(ArrayRef<const uint8_t> code, uint32_t offset);
template <typename Vector>
static uint32_t GetInsn32(Vector* code, uint32_t offset);
- // PC displacement from patch location; Thumb2 PC is always at instruction address + 4.
- static constexpr int32_t kPcDisplacement = 4;
-
- // Maximum positive and negative displacement measured from the patch location.
- // (Signed 25 bit displacement with the last bit 0 has range [-2^24, 2^24-2] measured from
- // the Thumb2 PC pointing right after the BL, i.e. 4 bytes later than the patch location.)
- static constexpr uint32_t kMaxPositiveDisplacement = (1u << 24) - 2 + kPcDisplacement;
- static constexpr uint32_t kMaxNegativeDisplacement = (1u << 24) - kPcDisplacement;
+ friend class Thumb2RelativePatcherTest;
DISALLOW_COPY_AND_ASSIGN(Thumb2RelativePatcher);
};
diff --git a/compiler/linker/arm/relative_patcher_thumb2_test.cc b/compiler/linker/arm/relative_patcher_thumb2_test.cc
index eace3d4..f08270d 100644
--- a/compiler/linker/arm/relative_patcher_thumb2_test.cc
+++ b/compiler/linker/arm/relative_patcher_thumb2_test.cc
@@ -63,7 +63,7 @@
const uint32_t method2_size = (method3_offset - sizeof(OatQuickMethodHeader) - method2_offset);
std::vector<uint8_t> method2_raw_code(method2_size);
ArrayRef<const uint8_t> method2_code(method2_raw_code);
- AddCompiledMethod(MethodRef(2u), method2_code, ArrayRef<const LinkerPatch>());
+ AddCompiledMethod(MethodRef(2u), method2_code);
AddCompiledMethod(MethodRef(3u), method3_code, method3_patches);
@@ -80,7 +80,7 @@
} else {
uint32_t thunk_end =
CompiledCode::AlignCode(method3_offset - sizeof(OatQuickMethodHeader), kThumb2) +
- ThunkSize();
+ MethodCallThunkSize();
uint32_t header_offset = thunk_end + CodeAlignmentSize(thunk_end);
CHECK_EQ(result3.second, header_offset + sizeof(OatQuickMethodHeader) + 1 /* thumb mode */);
return true; // Thunk present.
@@ -94,24 +94,30 @@
return result.second - 1 /* thumb mode */;
}
- uint32_t ThunkSize() {
- return static_cast<Thumb2RelativePatcher*>(patcher_.get())->thunk_code_.size();
+ std::vector<uint8_t> CompileMethodCallThunk() {
+ ArmBaseRelativePatcher::ThunkKey key(
+ ArmBaseRelativePatcher::ThunkType::kMethodCall,
+ ArmBaseRelativePatcher::ThunkParams{{ 0, 0 }}); // NOLINT(whitespace/braces)
+ return static_cast<Thumb2RelativePatcher*>(patcher_.get())->CompileThunk(key);
+ }
+
+ uint32_t MethodCallThunkSize() {
+ return CompileMethodCallThunk().size();
}
bool CheckThunk(uint32_t thunk_offset) {
- Thumb2RelativePatcher* patcher = static_cast<Thumb2RelativePatcher*>(patcher_.get());
- ArrayRef<const uint8_t> expected_code(patcher->thunk_code_);
+ const std::vector<uint8_t> expected_code = CompileMethodCallThunk();
if (output_.size() < thunk_offset + expected_code.size()) {
LOG(ERROR) << "output_.size() == " << output_.size() << " < "
<< "thunk_offset + expected_code.size() == " << (thunk_offset + expected_code.size());
return false;
}
ArrayRef<const uint8_t> linked_code(&output_[thunk_offset], expected_code.size());
- if (linked_code == expected_code) {
+ if (linked_code == ArrayRef<const uint8_t>(expected_code)) {
return true;
}
// Log failure info.
- DumpDiff(expected_code, linked_code);
+ DumpDiff(ArrayRef<const uint8_t>(expected_code), linked_code);
return false;
}
@@ -357,9 +363,10 @@
uint32_t method3_offset = GetMethodOffset(3u);
ASSERT_TRUE(IsAligned<kArmAlignment>(method3_offset));
uint32_t method3_header_offset = method3_offset - sizeof(OatQuickMethodHeader);
+ uint32_t thunk_size = MethodCallThunkSize();
uint32_t thunk_offset =
- RoundDown(method3_header_offset - ThunkSize(), GetInstructionSetAlignment(kThumb2));
- DCHECK_EQ(thunk_offset + ThunkSize() + CodeAlignmentSize(thunk_offset + ThunkSize()),
+ RoundDown(method3_header_offset - thunk_size, GetInstructionSetAlignment(kThumb2));
+ DCHECK_EQ(thunk_offset + thunk_size + CodeAlignmentSize(thunk_offset + thunk_size),
method3_header_offset);
ASSERT_TRUE(IsAligned<kArmAlignment>(thunk_offset));
uint32_t diff = thunk_offset - (method1_offset + bl_offset_in_method1 + 4u /* PC adjustment */);
diff --git a/compiler/linker/arm64/relative_patcher_arm64.cc b/compiler/linker/arm64/relative_patcher_arm64.cc
index 9ddf200..53797d2 100644
--- a/compiler/linker/arm64/relative_patcher_arm64.cc
+++ b/compiler/linker/arm64/relative_patcher_arm64.cc
@@ -16,11 +16,17 @@
#include "linker/arm64/relative_patcher_arm64.h"
+#include "arch/arm64/asm_support_arm64.h"
#include "arch/arm64/instruction_set_features_arm64.h"
#include "art_method.h"
+#include "base/bit_utils.h"
#include "compiled_method.h"
#include "driver/compiler_driver.h"
+#include "entrypoints/quick/quick_entrypoints_enum.h"
#include "linker/output_stream.h"
+#include "lock_word.h"
+#include "mirror/object.h"
+#include "mirror/array-inl.h"
#include "oat.h"
#include "oat_quick_method_header.h"
#include "utils/arm64/assembler_arm64.h"
@@ -30,17 +36,52 @@
namespace {
+// Maximum positive and negative displacement for method call measured from the patch location.
+// (Signed 28 bit displacement with the last two bits 0 has range [-2^27, 2^27-4] measured from
+// the ARM64 PC pointing to the BL.)
+constexpr uint32_t kMaxMethodCallPositiveDisplacement = (1u << 27) - 4u;
+constexpr uint32_t kMaxMethodCallNegativeDisplacement = (1u << 27);
+
+// Maximum positive and negative displacement for a conditional branch measured from the patch
+// location. (Signed 21 bit displacement with the last two bits 0 has range [-2^20, 2^20-4]
+// measured from the ARM64 PC pointing to the B.cond.)
+constexpr uint32_t kMaxBcondPositiveDisplacement = (1u << 20) - 4u;
+constexpr uint32_t kMaxBcondNegativeDisplacement = (1u << 20);
+
+// The ADRP thunk for erratum 843419 is 2 instructions, i.e. 8 bytes.
+constexpr uint32_t kAdrpThunkSize = 8u;
+
inline bool IsAdrpPatch(const LinkerPatch& patch) {
- return (patch.IsPcRelative() && patch.GetType() != LinkerPatch::Type::kCallRelative) &&
- patch.LiteralOffset() == patch.PcInsnOffset();
+ switch (patch.GetType()) {
+ case LinkerPatch::Type::kMethod:
+ case LinkerPatch::Type::kCall:
+ case LinkerPatch::Type::kCallRelative:
+ case LinkerPatch::Type::kType:
+ case LinkerPatch::Type::kString:
+ case LinkerPatch::Type::kBakerReadBarrierBranch:
+ return false;
+ case LinkerPatch::Type::kTypeRelative:
+ case LinkerPatch::Type::kTypeBssEntry:
+ case LinkerPatch::Type::kStringRelative:
+ case LinkerPatch::Type::kStringBssEntry:
+ case LinkerPatch::Type::kDexCacheArray:
+ return patch.LiteralOffset() == patch.PcInsnOffset();
+ }
+}
+
+inline uint32_t MaxExtraSpace(size_t num_adrp, size_t code_size) {
+ if (num_adrp == 0u) {
+ return 0u;
+ }
+ uint32_t alignment_bytes = CompiledMethod::AlignCode(code_size, kArm64) - code_size;
+ return kAdrpThunkSize * num_adrp + alignment_bytes;
}
} // anonymous namespace
Arm64RelativePatcher::Arm64RelativePatcher(RelativePatcherTargetProvider* provider,
const Arm64InstructionSetFeatures* features)
- : ArmBaseRelativePatcher(provider, kArm64, CompileThunkCode(),
- kMaxPositiveDisplacement, kMaxNegativeDisplacement),
+ : ArmBaseRelativePatcher(provider, kArm64),
fix_cortex_a53_843419_(features->NeedFixCortexA53_843419()),
reserved_adrp_thunks_(0u),
processed_adrp_thunks_(0u) {
@@ -74,7 +115,9 @@
++num_adrp;
}
}
- offset = ReserveSpaceInternal(offset, compiled_method, method_ref, kAdrpThunkSize * num_adrp);
+ ArrayRef<const uint8_t> code = compiled_method->GetQuickCode();
+ uint32_t max_extra_space = MaxExtraSpace(num_adrp, code.size());
+ offset = ReserveSpaceInternal(offset, compiled_method, method_ref, max_extra_space);
if (num_adrp == 0u) {
return offset;
}
@@ -82,7 +125,6 @@
// Now that we have the actual offset where the code will be placed, locate the ADRP insns
// that actually require the thunk.
uint32_t quick_code_offset = compiled_method->AlignCode(offset + sizeof(OatQuickMethodHeader));
- ArrayRef<const uint8_t> code = compiled_method->GetQuickCode();
uint32_t thunk_offset = compiled_method->AlignCode(quick_code_offset + code.size());
DCHECK(compiled_method != nullptr);
for (const LinkerPatch& patch : compiled_method->GetPatches()) {
@@ -146,7 +188,7 @@
DCHECK_EQ(literal_offset & 3u, 0u);
DCHECK_EQ(patch_offset & 3u, 0u);
DCHECK_EQ(target_offset & 3u, 0u);
- uint32_t displacement = CalculateDisplacement(patch_offset, target_offset & ~1u);
+ uint32_t displacement = CalculateMethodCallDisplacement(patch_offset, target_offset & ~1u);
DCHECK_EQ(displacement & 3u, 0u);
DCHECK((displacement >> 27) == 0u || (displacement >> 27) == 31u); // 28-bit signed.
uint32_t insn = (displacement & 0x0fffffffu) >> 2;
@@ -253,15 +295,184 @@
}
}
-std::vector<uint8_t> Arm64RelativePatcher::CompileThunkCode() {
- // The thunk just uses the entry point in the ArtMethod. This works even for calls
- // to the generic JNI and interpreter trampolines.
+void Arm64RelativePatcher::PatchBakerReadBarrierBranch(std::vector<uint8_t>* code,
+ const LinkerPatch& patch,
+ uint32_t patch_offset) {
+ DCHECK_ALIGNED(patch_offset, 4u);
+ uint32_t literal_offset = patch.LiteralOffset();
+ DCHECK_ALIGNED(literal_offset, 4u);
+ DCHECK_LT(literal_offset, code->size());
+ uint32_t insn = GetInsn(code, literal_offset);
+ DCHECK_EQ(insn & 0xffffffe0u, 0xb5000000); // CBNZ Xt, +0 (unpatched)
+ ThunkKey key = GetBakerReadBarrierKey(patch);
+ if (kIsDebugBuild) {
+ // Check that the next instruction matches the expected LDR.
+ switch (key.GetType()) {
+ case ThunkType::kBakerReadBarrierField: {
+ DCHECK_GE(code->size() - literal_offset, 8u);
+ uint32_t next_insn = GetInsn(code, literal_offset + 4u);
+ // LDR (immediate) with correct base_reg.
+ CheckValidReg(next_insn & 0x1fu); // Check destination register.
+ CHECK_EQ(next_insn & 0xffc003e0u, 0xb9400000u | (key.GetOffsetParams().base_reg << 5));
+ break;
+ }
+ case ThunkType::kBakerReadBarrierRoot: {
+ DCHECK_GE(literal_offset, 4u);
+ uint32_t prev_insn = GetInsn(code, literal_offset - 4u);
+ // LDR (immediate) with correct root_reg.
+ CHECK_EQ(prev_insn & 0xffc0001fu, 0xb9400000u | key.GetRootParams().root_reg);
+ break;
+ }
+ default:
+ LOG(FATAL) << "Unexpected type: " << static_cast<uint32_t>(key.GetType());
+ UNREACHABLE();
+ }
+ }
+ uint32_t target_offset = GetThunkTargetOffset(key, patch_offset);
+ DCHECK_ALIGNED(target_offset, 4u);
+ uint32_t disp = target_offset - patch_offset;
+ DCHECK((disp >> 20) == 0u || (disp >> 20) == 4095u); // 21-bit signed.
+ insn |= (disp << (5 - 2)) & 0x00ffffe0u; // Shift bits 2-20 to 5-23.
+ SetInsn(code, literal_offset, insn);
+}
+
+ArmBaseRelativePatcher::ThunkKey Arm64RelativePatcher::GetBakerReadBarrierKey(
+ const LinkerPatch& patch) {
+ DCHECK_EQ(patch.GetType(), LinkerPatch::Type::kBakerReadBarrierBranch);
+ uint32_t value = patch.GetBakerCustomValue1();
+ BakerReadBarrierKind type = BakerReadBarrierKindField::Decode(value);
+ ThunkParams params;
+ switch (type) {
+ case BakerReadBarrierKind::kField:
+ params.offset_params.base_reg = BakerReadBarrierFirstRegField::Decode(value);
+ CheckValidReg(params.offset_params.base_reg);
+ params.offset_params.holder_reg = BakerReadBarrierSecondRegField::Decode(value);
+ CheckValidReg(params.offset_params.holder_reg);
+ break;
+ case BakerReadBarrierKind::kGcRoot:
+ params.root_params.root_reg = BakerReadBarrierFirstRegField::Decode(value);
+ CheckValidReg(params.root_params.root_reg);
+ params.root_params.dummy = 0u;
+ DCHECK_EQ(BakerReadBarrierSecondRegField::Decode(value), kInvalidEncodedReg);
+ break;
+ default:
+ LOG(FATAL) << "Unexpected type: " << static_cast<uint32_t>(type);
+ UNREACHABLE();
+ }
+ constexpr uint8_t kTypeTranslationOffset = 1u;
+ static_assert(static_cast<uint32_t>(BakerReadBarrierKind::kField) + kTypeTranslationOffset ==
+ static_cast<uint32_t>(ThunkType::kBakerReadBarrierField),
+ "Thunk type translation check.");
+ static_assert(static_cast<uint32_t>(BakerReadBarrierKind::kGcRoot) + kTypeTranslationOffset ==
+ static_cast<uint32_t>(ThunkType::kBakerReadBarrierRoot),
+ "Thunk type translation check.");
+ return ThunkKey(static_cast<ThunkType>(static_cast<uint32_t>(type) + kTypeTranslationOffset),
+ params);
+}
+
+#define __ assembler.GetVIXLAssembler()->
+
+static void EmitGrayCheckAndFastPath(arm64::Arm64Assembler& assembler,
+ vixl::aarch64::Register base_reg,
+ vixl::aarch64::MemOperand& lock_word,
+ vixl::aarch64::Label* slow_path) {
+ using namespace vixl::aarch64; // NOLINT(build/namespaces)
+ // Load the lock word containing the rb_state.
+ __ Ldr(ip0.W(), lock_word);
+ // Given the numeric representation, it's enough to check the low bit of the rb_state.
+ static_assert(ReadBarrier::WhiteState() == 0, "Expecting white to have value 0");
+ static_assert(ReadBarrier::GrayState() == 1, "Expecting gray to have value 1");
+ __ Tbnz(ip0.W(), LockWord::kReadBarrierStateShift, slow_path);
+ static_assert(BAKER_MARK_INTROSPECTION_FIELD_LDR_OFFSET == -4, "Check field LDR offset");
+ static_assert(BAKER_MARK_INTROSPECTION_ARRAY_LDR_OFFSET == -4, "Check array LDR offset");
+ __ Sub(lr, lr, 4); // Adjust the return address one instruction back to the LDR.
+ // Introduce a dependency on the lock_word including rb_state,
+ // to prevent load-load reordering, and without using
+ // a memory barrier (which would be more expensive).
+ __ Add(base_reg, base_reg, Operand(vixl::aarch64::ip0, LSR, 32));
+ __ Br(lr); // And return back to the function.
+ // Note: The fake dependency is unnecessary for the slow path.
+}
+
+std::vector<uint8_t> Arm64RelativePatcher::CompileThunk(const ThunkKey& key) {
+ using namespace vixl::aarch64; // NOLINT(build/namespaces)
ArenaPool pool;
ArenaAllocator arena(&pool);
arm64::Arm64Assembler assembler(&arena);
- Offset offset(ArtMethod::EntryPointFromQuickCompiledCodeOffset(
- kArm64PointerSize).Int32Value());
- assembler.JumpTo(ManagedRegister(arm64::X0), offset, ManagedRegister(arm64::IP0));
+
+ switch (key.GetType()) {
+ case ThunkType::kMethodCall: {
+ // The thunk just uses the entry point in the ArtMethod. This works even for calls
+ // to the generic JNI and interpreter trampolines.
+ Offset offset(ArtMethod::EntryPointFromQuickCompiledCodeOffset(
+ kArm64PointerSize).Int32Value());
+ assembler.JumpTo(ManagedRegister(arm64::X0), offset, ManagedRegister(arm64::IP0));
+ break;
+ }
+ case ThunkType::kBakerReadBarrierField: {
+ // Check if the holder is gray and, if not, add fake dependency to the base register
+ // and return to the LDR instruction to load the reference. Otherwise, use introspection
+ // to load the reference and call the entrypoint (in IP1) that performs further checks
+ // on the reference and marks it if needed.
+ auto holder_reg = Register::GetXRegFromCode(key.GetOffsetParams().holder_reg);
+ auto base_reg = Register::GetXRegFromCode(key.GetOffsetParams().base_reg);
+ UseScratchRegisterScope temps(assembler.GetVIXLAssembler());
+ temps.Exclude(ip0, ip1);
+ // If base_reg differs from holder_reg, the offset was too large and we must have
+ // emitted an explicit null check before the load. Otherwise, we need to null-check
+ // the holder as we do not necessarily do that check before going to the thunk.
+ vixl::aarch64::Label throw_npe;
+ if (holder_reg.Is(base_reg)) {
+ __ Cbz(holder_reg.W(), &throw_npe);
+ }
+ vixl::aarch64::Label slow_path;
+ MemOperand lock_word(holder_reg, mirror::Object::MonitorOffset().Int32Value());
+ EmitGrayCheckAndFastPath(assembler, base_reg, lock_word, &slow_path);
+ __ Bind(&slow_path);
+ MemOperand ldr_address(lr, BAKER_MARK_INTROSPECTION_FIELD_LDR_OFFSET);
+ __ Ldr(ip0.W(), ldr_address); // Load the LDR (immediate) unsigned offset.
+ __ Ubfx(ip0, ip0, 10, 12); // Extract the offset.
+ __ Ldr(ip0.W(), MemOperand(base_reg, ip0, LSL, 2)); // Load the reference.
+ __ Br(ip1); // Jump to the entrypoint.
+ if (holder_reg.Is(base_reg)) {
+ // Add null check slow path. The stack map is at the address pointed to by LR.
+ __ Bind(&throw_npe);
+ int32_t offset = GetThreadOffset<kArm64PointerSize>(kQuickThrowNullPointer).Int32Value();
+ __ Ldr(ip0, MemOperand(vixl::aarch64::x19, offset));
+ __ Br(ip0);
+ }
+ break;
+ }
+ case ThunkType::kBakerReadBarrierRoot: {
+ // Check if the reference needs to be marked and if so (i.e. not null, not marked yet
+ // and it does not have a forwarding address), call the correct introspection entrypoint;
+ // otherwise return the reference (or the extracted forwarding address).
+ // There is no gray bit check for GC roots.
+ auto root_reg = Register::GetWRegFromCode(key.GetRootParams().root_reg);
+ UseScratchRegisterScope temps(assembler.GetVIXLAssembler());
+ temps.Exclude(ip0, ip1);
+ vixl::aarch64::Label return_label, not_marked, forwarding_address;
+ __ Cbz(root_reg, &return_label);
+ MemOperand lock_word(root_reg.X(), mirror::Object::MonitorOffset().Int32Value());
+ __ Ldr(ip0.W(), lock_word);
+ __ Tbz(ip0.W(), LockWord::kMarkBitStateShift, ¬_marked);
+ __ Bind(&return_label);
+ __ Br(lr);
+ __ Bind(¬_marked);
+ __ Tst(ip0.W(), Operand(ip0.W(), LSL, 1));
+ __ B(&forwarding_address, mi);
+ // Adjust the art_quick_read_barrier_mark_introspection address in IP1 to
+ // art_quick_read_barrier_mark_introspection_gc_roots.
+ __ Add(ip1, ip1, Operand(BAKER_MARK_INTROSPECTION_GC_ROOT_ENTRYPOINT_OFFSET));
+ __ Mov(ip0.W(), root_reg);
+ __ Br(ip1);
+ __ Bind(&forwarding_address);
+ __ Lsl(root_reg, ip0.W(), LockWord::kForwardingAddressShift);
+ __ Br(lr);
+ break;
+ }
+ }
+
// Ensure we emit the literal pool.
assembler.FinalizeCode();
std::vector<uint8_t> thunk_code(assembler.CodeSize());
@@ -270,6 +481,28 @@
return thunk_code;
}
+#undef __
+
+uint32_t Arm64RelativePatcher::MaxPositiveDisplacement(ThunkType type) {
+ switch (type) {
+ case ThunkType::kMethodCall:
+ return kMaxMethodCallPositiveDisplacement;
+ case ThunkType::kBakerReadBarrierField:
+ case ThunkType::kBakerReadBarrierRoot:
+ return kMaxBcondPositiveDisplacement;
+ }
+}
+
+uint32_t Arm64RelativePatcher::MaxNegativeDisplacement(ThunkType type) {
+ switch (type) {
+ case ThunkType::kMethodCall:
+ return kMaxMethodCallNegativeDisplacement;
+ case ThunkType::kBakerReadBarrierField:
+ case ThunkType::kBakerReadBarrierRoot:
+ return kMaxBcondNegativeDisplacement;
+ }
+}
+
uint32_t Arm64RelativePatcher::PatchAdrp(uint32_t adrp, uint32_t disp) {
return (adrp & 0x9f00001fu) | // Clear offset bits, keep ADRP with destination reg.
// Bottom 12 bits are ignored, the next 2 lowest bits are encoded in bits 29-30.
diff --git a/compiler/linker/arm64/relative_patcher_arm64.h b/compiler/linker/arm64/relative_patcher_arm64.h
index a4a8018..7887cea 100644
--- a/compiler/linker/arm64/relative_patcher_arm64.h
+++ b/compiler/linker/arm64/relative_patcher_arm64.h
@@ -18,6 +18,7 @@
#define ART_COMPILER_LINKER_ARM64_RELATIVE_PATCHER_ARM64_H_
#include "base/array_ref.h"
+#include "base/bit_field.h"
#include "linker/arm/relative_patcher_arm_base.h"
namespace art {
@@ -25,6 +26,27 @@
class Arm64RelativePatcher FINAL : public ArmBaseRelativePatcher {
public:
+ enum class BakerReadBarrierKind : uint8_t {
+ kField, // Field get or array get with constant offset (i.e. constant index).
+ kGcRoot, // GC root load.
+ kLast
+ };
+
+ static uint32_t EncodeBakerReadBarrierFieldData(uint32_t base_reg, uint32_t holder_reg) {
+ CheckValidReg(base_reg);
+ CheckValidReg(holder_reg);
+ return BakerReadBarrierKindField::Encode(BakerReadBarrierKind::kField) |
+ BakerReadBarrierFirstRegField::Encode(base_reg) |
+ BakerReadBarrierSecondRegField::Encode(holder_reg);
+ }
+
+ static uint32_t EncodeBakerReadBarrierGcRootData(uint32_t root_reg) {
+ CheckValidReg(root_reg);
+ return BakerReadBarrierKindField::Encode(BakerReadBarrierKind::kGcRoot) |
+ BakerReadBarrierFirstRegField::Encode(root_reg) |
+ BakerReadBarrierSecondRegField::Encode(kInvalidEncodedReg);
+ }
+
Arm64RelativePatcher(RelativePatcherTargetProvider* provider,
const Arm64InstructionSetFeatures* features);
@@ -41,9 +63,33 @@
const LinkerPatch& patch,
uint32_t patch_offset,
uint32_t target_offset) OVERRIDE;
+ void PatchBakerReadBarrierBranch(std::vector<uint8_t>* code,
+ const LinkerPatch& patch,
+ uint32_t patch_offset) OVERRIDE;
+
+ protected:
+ static constexpr uint32_t kInvalidEncodedReg = /* sp/zr is invalid */ 31u;
+
+ ThunkKey GetBakerReadBarrierKey(const LinkerPatch& patch) OVERRIDE;
+ std::vector<uint8_t> CompileThunk(const ThunkKey& key) OVERRIDE;
+ uint32_t MaxPositiveDisplacement(ThunkType type) OVERRIDE;
+ uint32_t MaxNegativeDisplacement(ThunkType type) OVERRIDE;
private:
- static std::vector<uint8_t> CompileThunkCode();
+ static constexpr size_t kBitsForBakerReadBarrierKind =
+ MinimumBitsToStore(static_cast<size_t>(BakerReadBarrierKind::kLast));
+ static constexpr size_t kBitsForRegister = 5u;
+ using BakerReadBarrierKindField =
+ BitField<BakerReadBarrierKind, 0, kBitsForBakerReadBarrierKind>;
+ using BakerReadBarrierFirstRegField =
+ BitField<uint32_t, kBitsForBakerReadBarrierKind, kBitsForRegister>;
+ using BakerReadBarrierSecondRegField =
+ BitField<uint32_t, kBitsForBakerReadBarrierKind + kBitsForRegister, kBitsForRegister>;
+
+ static void CheckValidReg(uint32_t reg) {
+ DCHECK(reg < 30u && reg != 16u && reg != 17u);
+ }
+
static uint32_t PatchAdrp(uint32_t adrp, uint32_t disp);
static bool NeedsErratum843419Thunk(ArrayRef<const uint8_t> code, uint32_t literal_offset,
@@ -54,15 +100,6 @@
template <typename Alloc>
static uint32_t GetInsn(std::vector<uint8_t, Alloc>* code, uint32_t offset);
- // Maximum positive and negative displacement measured from the patch location.
- // (Signed 28 bit displacement with the last bit 0 has range [-2^27, 2^27-4] measured from
- // the ARM64 PC pointing to the BL.)
- static constexpr uint32_t kMaxPositiveDisplacement = (1u << 27) - 4u;
- static constexpr uint32_t kMaxNegativeDisplacement = (1u << 27);
-
- // The ADRP thunk for erratum 843419 is 2 instructions, i.e. 8 bytes.
- static constexpr uint32_t kAdrpThunkSize = 8u;
-
const bool fix_cortex_a53_843419_;
// Map original patch_offset to thunk offset.
std::vector<std::pair<uint32_t, uint32_t>> adrp_thunk_locations_;
@@ -70,6 +107,8 @@
size_t processed_adrp_thunks_;
std::vector<uint8_t> current_method_thunks_;
+ friend class Arm64RelativePatcherTest;
+
DISALLOW_COPY_AND_ASSIGN(Arm64RelativePatcher);
};
diff --git a/compiler/linker/arm64/relative_patcher_arm64_test.cc b/compiler/linker/arm64/relative_patcher_arm64_test.cc
index 9932c79..b4d35ab 100644
--- a/compiler/linker/arm64/relative_patcher_arm64_test.cc
+++ b/compiler/linker/arm64/relative_patcher_arm64_test.cc
@@ -14,8 +14,11 @@
* limitations under the License.
*/
+#include "base/casts.h"
#include "linker/relative_patcher_test.h"
#include "linker/arm64/relative_patcher_arm64.h"
+#include "lock_word.h"
+#include "mirror/object.h"
#include "oat_quick_method_header.h"
namespace art {
@@ -32,6 +35,9 @@
static const uint8_t kNopRawCode[];
static const ArrayRef<const uint8_t> kNopCode;
+ // NOP instruction.
+ static constexpr uint32_t kNopInsn = 0xd503201f;
+
// All branches can be created from kBlPlus0 or kBPlus0 by adding the low 26 bits.
static constexpr uint32_t kBlPlus0 = 0x94000000u;
static constexpr uint32_t kBPlus0 = 0x14000000u;
@@ -40,7 +46,7 @@
static constexpr uint32_t kBlPlusMax = 0x95ffffffu;
static constexpr uint32_t kBlMinusMax = 0x96000000u;
- // LDR immediate, 32-bit.
+ // LDR immediate, unsigned offset.
static constexpr uint32_t kLdrWInsn = 0xb9400000u;
// ADD/ADDS/SUB/SUBS immediate, 64-bit.
@@ -61,6 +67,34 @@
static constexpr uint32_t kLdrWSpRelInsn = 0xb94003edu;
static constexpr uint32_t kLdrXSpRelInsn = 0xf94003edu;
+ // CBNZ x17, +0. Bits 5-23 are a placeholder for target offset from PC in units of 4-bytes.
+ static constexpr uint32_t kCbnzIP1Plus0Insn = 0xb5000011;
+
+ void InsertInsn(std::vector<uint8_t>* code, size_t pos, uint32_t insn) {
+ CHECK_LE(pos, code->size());
+ const uint8_t insn_code[] = {
+ static_cast<uint8_t>(insn),
+ static_cast<uint8_t>(insn >> 8),
+ static_cast<uint8_t>(insn >> 16),
+ static_cast<uint8_t>(insn >> 24),
+ };
+ static_assert(sizeof(insn_code) == 4u, "Invalid sizeof(insn_code).");
+ code->insert(code->begin() + pos, insn_code, insn_code + sizeof(insn_code));
+ }
+
+ void PushBackInsn(std::vector<uint8_t>* code, uint32_t insn) {
+ InsertInsn(code, code->size(), insn);
+ }
+
+ std::vector<uint8_t> RawCode(std::initializer_list<uint32_t> insns) {
+ std::vector<uint8_t> raw_code;
+ raw_code.reserve(insns.size() * 4u);
+ for (uint32_t insn : insns) {
+ PushBackInsn(&raw_code, insn);
+ }
+ return raw_code;
+ }
+
uint32_t Create2MethodsWithGap(const ArrayRef<const uint8_t>& method1_code,
const ArrayRef<const LinkerPatch>& method1_patches,
const ArrayRef<const uint8_t>& last_method_code,
@@ -93,8 +127,7 @@
uint32_t chunk_code_size =
chunk_size - CodeAlignmentSize(chunk_start) - sizeof(OatQuickMethodHeader);
gap_code.resize(chunk_code_size, 0u);
- AddCompiledMethod(MethodRef(method_idx), ArrayRef<const uint8_t>(gap_code),
- ArrayRef<const LinkerPatch>());
+ AddCompiledMethod(MethodRef(method_idx), ArrayRef<const uint8_t>(gap_code));
method_idx += 1u;
chunk_start += chunk_size;
chunk_size = kSmallChunkSize; // For all but the first chunk.
@@ -112,7 +145,7 @@
// There may be a thunk before method2.
if (last_result.second != last_method_offset) {
// Thunk present. Check that there's only one.
- uint32_t thunk_end = CompiledCode::AlignCode(gap_end, kArm64) + ThunkSize();
+ uint32_t thunk_end = CompiledCode::AlignCode(gap_end, kArm64) + MethodCallThunkSize();
uint32_t header_offset = thunk_end + CodeAlignmentSize(thunk_end);
CHECK_EQ(last_result.second, header_offset + sizeof(OatQuickMethodHeader));
}
@@ -126,37 +159,49 @@
return result.second;
}
- uint32_t ThunkSize() {
- return static_cast<Arm64RelativePatcher*>(patcher_.get())->thunk_code_.size();
+ std::vector<uint8_t> CompileMethodCallThunk() {
+ ArmBaseRelativePatcher::ThunkKey key(
+ ArmBaseRelativePatcher::ThunkType::kMethodCall,
+ ArmBaseRelativePatcher::ThunkParams{{ 0, 0 }}); // NOLINT(whitespace/braces)
+ return down_cast<Arm64RelativePatcher*>(patcher_.get())->CompileThunk(key);
+ }
+
+ uint32_t MethodCallThunkSize() {
+ return CompileMethodCallThunk().size();
}
bool CheckThunk(uint32_t thunk_offset) {
- Arm64RelativePatcher* patcher = static_cast<Arm64RelativePatcher*>(patcher_.get());
- ArrayRef<const uint8_t> expected_code(patcher->thunk_code_);
+ const std::vector<uint8_t> expected_code = CompileMethodCallThunk();
if (output_.size() < thunk_offset + expected_code.size()) {
LOG(ERROR) << "output_.size() == " << output_.size() << " < "
<< "thunk_offset + expected_code.size() == " << (thunk_offset + expected_code.size());
return false;
}
ArrayRef<const uint8_t> linked_code(&output_[thunk_offset], expected_code.size());
- if (linked_code == expected_code) {
+ if (linked_code == ArrayRef<const uint8_t>(expected_code)) {
return true;
}
// Log failure info.
- DumpDiff(expected_code, linked_code);
+ DumpDiff(ArrayRef<const uint8_t>(expected_code), linked_code);
return false;
}
+ std::vector<uint8_t> GenNops(size_t num_nops) {
+ std::vector<uint8_t> result;
+ result.reserve(num_nops * 4u + 4u);
+ for (size_t i = 0; i != num_nops; ++i) {
+ PushBackInsn(&result, kNopInsn);
+ }
+ return result;
+ }
+
std::vector<uint8_t> GenNopsAndBl(size_t num_nops, uint32_t bl) {
std::vector<uint8_t> result;
result.reserve(num_nops * 4u + 4u);
for (size_t i = 0; i != num_nops; ++i) {
- result.insert(result.end(), kNopCode.begin(), kNopCode.end());
+ PushBackInsn(&result, kNopInsn);
}
- result.push_back(static_cast<uint8_t>(bl));
- result.push_back(static_cast<uint8_t>(bl >> 8));
- result.push_back(static_cast<uint8_t>(bl >> 16));
- result.push_back(static_cast<uint8_t>(bl >> 24));
+ PushBackInsn(&result, bl);
return result;
}
@@ -167,7 +212,7 @@
std::vector<uint8_t> result;
result.reserve(num_nops * 4u + 8u);
for (size_t i = 0; i != num_nops; ++i) {
- result.insert(result.end(), kNopCode.begin(), kNopCode.end());
+ PushBackInsn(&result, kNopInsn);
}
CHECK_ALIGNED(method_offset, 4u);
CHECK_ALIGNED(target_offset, 4u);
@@ -188,14 +233,8 @@
((disp & 0xffffc000) >> (14 - 5)) | // immhi = (disp >> 14) is at bit 5,
// We take the sign bit from the disp, limiting disp to +- 2GiB.
((disp & 0x80000000) >> (31 - 23)); // sign bit in immhi is at bit 23.
- result.push_back(static_cast<uint8_t>(adrp));
- result.push_back(static_cast<uint8_t>(adrp >> 8));
- result.push_back(static_cast<uint8_t>(adrp >> 16));
- result.push_back(static_cast<uint8_t>(adrp >> 24));
- result.push_back(static_cast<uint8_t>(use_insn));
- result.push_back(static_cast<uint8_t>(use_insn >> 8));
- result.push_back(static_cast<uint8_t>(use_insn >> 16));
- result.push_back(static_cast<uint8_t>(use_insn >> 24));
+ PushBackInsn(&result, adrp);
+ PushBackInsn(&result, use_insn);
return result;
}
@@ -208,7 +247,7 @@
void TestNopsAdrpLdr(size_t num_nops, uint32_t dex_cache_arrays_begin, uint32_t element_offset) {
dex_cache_arrays_begin_ = dex_cache_arrays_begin;
auto code = GenNopsAndAdrpLdr(num_nops, 0u, 0u); // Unpatched.
- LinkerPatch patches[] = {
+ const LinkerPatch patches[] = {
LinkerPatch::DexCacheArrayPatch(num_nops * 4u , nullptr, num_nops * 4u, element_offset),
LinkerPatch::DexCacheArrayPatch(num_nops * 4u + 4u, nullptr, num_nops * 4u, element_offset),
};
@@ -233,7 +272,7 @@
constexpr uint32_t kStringIndex = 1u;
string_index_to_offset_map_.Put(kStringIndex, string_offset);
auto code = GenNopsAndAdrpAdd(num_nops, 0u, 0u); // Unpatched.
- LinkerPatch patches[] = {
+ const LinkerPatch patches[] = {
LinkerPatch::RelativeStringPatch(num_nops * 4u , nullptr, num_nops * 4u, kStringIndex),
LinkerPatch::RelativeStringPatch(num_nops * 4u + 4u, nullptr, num_nops * 4u, kStringIndex),
};
@@ -247,16 +286,6 @@
EXPECT_TRUE(CheckLinkedMethod(MethodRef(1u), ArrayRef<const uint8_t>(expected_code)));
}
- void InsertInsn(std::vector<uint8_t>* code, size_t pos, uint32_t insn) {
- CHECK_LE(pos, code->size());
- const uint8_t insn_code[] = {
- static_cast<uint8_t>(insn), static_cast<uint8_t>(insn >> 8),
- static_cast<uint8_t>(insn >> 16), static_cast<uint8_t>(insn >> 24),
- };
- static_assert(sizeof(insn_code) == 4u, "Invalid sizeof(insn_code).");
- code->insert(code->begin() + pos, insn_code, insn_code + sizeof(insn_code));
- }
-
void PrepareNopsAdrpInsn2Ldr(size_t num_nops,
uint32_t insn2,
uint32_t dex_cache_arrays_begin,
@@ -264,7 +293,7 @@
dex_cache_arrays_begin_ = dex_cache_arrays_begin;
auto code = GenNopsAndAdrpLdr(num_nops, 0u, 0u); // Unpatched.
InsertInsn(&code, num_nops * 4u + 4u, insn2);
- LinkerPatch patches[] = {
+ const LinkerPatch patches[] = {
LinkerPatch::DexCacheArrayPatch(num_nops * 4u , nullptr, num_nops * 4u, element_offset),
LinkerPatch::DexCacheArrayPatch(num_nops * 4u + 8u, nullptr, num_nops * 4u, element_offset),
};
@@ -279,7 +308,7 @@
string_index_to_offset_map_.Put(kStringIndex, string_offset);
auto code = GenNopsAndAdrpAdd(num_nops, 0u, 0u); // Unpatched.
InsertInsn(&code, num_nops * 4u + 4u, insn2);
- LinkerPatch patches[] = {
+ const LinkerPatch patches[] = {
LinkerPatch::RelativeStringPatch(num_nops * 4u , nullptr, num_nops * 4u, kStringIndex),
LinkerPatch::RelativeStringPatch(num_nops * 4u + 8u, nullptr, num_nops * 4u, kStringIndex),
};
@@ -329,7 +358,7 @@
InsertInsn(&expected_thunk_code, 4u, b_in);
ASSERT_EQ(expected_thunk_code.size(), 8u);
- uint32_t thunk_size = ThunkSize();
+ uint32_t thunk_size = MethodCallThunkSize();
ASSERT_EQ(thunk_offset + thunk_size, output_.size());
ASSERT_EQ(thunk_size, expected_thunk_code.size());
ArrayRef<const uint8_t> thunk_code(&output_[thunk_offset], thunk_size);
@@ -433,6 +462,33 @@
uint32_t insn2 = sprel_ldr_insn | ((sprel_disp_in_load_units & 0xfffu) << 10);
TestAdrpInsn2Add(insn2, adrp_offset, has_thunk, string_offset);
}
+
+ std::vector<uint8_t> CompileBakerOffsetThunk(uint32_t base_reg, uint32_t holder_reg) {
+ const LinkerPatch patch = LinkerPatch::BakerReadBarrierBranchPatch(
+ 0u, Arm64RelativePatcher::EncodeBakerReadBarrierFieldData(base_reg, holder_reg));
+ auto* patcher = down_cast<Arm64RelativePatcher*>(patcher_.get());
+ ArmBaseRelativePatcher::ThunkKey key = patcher->GetBakerReadBarrierKey(patch);
+ return patcher->CompileThunk(key);
+ }
+
+ std::vector<uint8_t> CompileBakerGcRootThunk(uint32_t root_reg) {
+ LinkerPatch patch = LinkerPatch::BakerReadBarrierBranchPatch(
+ 0u, Arm64RelativePatcher::EncodeBakerReadBarrierGcRootData(root_reg));
+ auto* patcher = down_cast<Arm64RelativePatcher*>(patcher_.get());
+ ArmBaseRelativePatcher::ThunkKey key = patcher->GetBakerReadBarrierKey(patch);
+ return patcher->CompileThunk(key);
+ }
+
+ uint32_t GetOutputInsn(uint32_t offset) {
+ CHECK_LE(offset, output_.size());
+ CHECK_GE(output_.size() - offset, 4u);
+ return (static_cast<uint32_t>(output_[offset]) << 0) |
+ (static_cast<uint32_t>(output_[offset + 1]) << 8) |
+ (static_cast<uint32_t>(output_[offset + 2]) << 16) |
+ (static_cast<uint32_t>(output_[offset + 3]) << 24);
+ }
+
+ void TestBakerField(uint32_t offset, uint32_t root_reg);
};
const uint8_t Arm64RelativePatcherTest::kCallRawCode[] = {
@@ -458,24 +514,22 @@
};
TEST_F(Arm64RelativePatcherTestDefault, CallSelf) {
- LinkerPatch patches[] = {
+ const LinkerPatch patches[] = {
LinkerPatch::RelativeCodePatch(0u, nullptr, 1u),
};
AddCompiledMethod(MethodRef(1u), kCallCode, ArrayRef<const LinkerPatch>(patches));
Link();
- static const uint8_t expected_code[] = {
- 0x00, 0x00, 0x00, 0x94
- };
+ const std::vector<uint8_t> expected_code = RawCode({kBlPlus0});
EXPECT_TRUE(CheckLinkedMethod(MethodRef(1u), ArrayRef<const uint8_t>(expected_code)));
}
TEST_F(Arm64RelativePatcherTestDefault, CallOther) {
- LinkerPatch method1_patches[] = {
+ const LinkerPatch method1_patches[] = {
LinkerPatch::RelativeCodePatch(0u, nullptr, 2u),
};
AddCompiledMethod(MethodRef(1u), kCallCode, ArrayRef<const LinkerPatch>(method1_patches));
- LinkerPatch method2_patches[] = {
+ const LinkerPatch method2_patches[] = {
LinkerPatch::RelativeCodePatch(0u, nullptr, 1u),
};
AddCompiledMethod(MethodRef(2u), kCallCode, ArrayRef<const LinkerPatch>(method2_patches));
@@ -486,9 +540,7 @@
uint32_t diff_after = method2_offset - method1_offset;
CHECK_ALIGNED(diff_after, 4u);
ASSERT_LT(diff_after >> 2, 1u << 8); // Simple encoding, (diff_after >> 2) fits into 8 bits.
- static const uint8_t method1_expected_code[] = {
- static_cast<uint8_t>(diff_after >> 2), 0x00, 0x00, 0x94
- };
+ const std::vector<uint8_t> method1_expected_code = RawCode({kBlPlus0 + (diff_after >> 2)});
EXPECT_TRUE(CheckLinkedMethod(MethodRef(1u), ArrayRef<const uint8_t>(method1_expected_code)));
uint32_t diff_before = method1_offset - method2_offset;
CHECK_ALIGNED(diff_before, 4u);
@@ -498,7 +550,7 @@
}
TEST_F(Arm64RelativePatcherTestDefault, CallTrampoline) {
- LinkerPatch patches[] = {
+ const LinkerPatch patches[] = {
LinkerPatch::RelativeCodePatch(0u, nullptr, 2u),
};
AddCompiledMethod(MethodRef(1u), kCallCode, ArrayRef<const LinkerPatch>(patches));
@@ -518,7 +570,7 @@
constexpr uint32_t bl_offset_in_last_method = 1u * 4u; // After NOPs.
ArrayRef<const uint8_t> last_method_code(last_method_raw_code);
ASSERT_EQ(bl_offset_in_last_method + 4u, last_method_code.size());
- LinkerPatch last_method_patches[] = {
+ const LinkerPatch last_method_patches[] = {
LinkerPatch::RelativeCodePatch(bl_offset_in_last_method, nullptr, missing_method_index),
};
@@ -551,7 +603,7 @@
ArrayRef<const uint8_t> method1_code(method1_raw_code);
ASSERT_EQ(bl_offset_in_method1 + 4u, method1_code.size());
uint32_t expected_last_method_idx = 65; // Based on 2MiB chunks in Create2MethodsWithGap().
- LinkerPatch method1_patches[] = {
+ const LinkerPatch method1_patches[] = {
LinkerPatch::RelativeCodePatch(bl_offset_in_method1, nullptr, expected_last_method_idx),
};
@@ -577,7 +629,7 @@
constexpr uint32_t bl_offset_in_last_method = 0u * 4u; // After NOPs.
ArrayRef<const uint8_t> last_method_code(last_method_raw_code);
ASSERT_EQ(bl_offset_in_last_method + 4u, last_method_code.size());
- LinkerPatch last_method_patches[] = {
+ const LinkerPatch last_method_patches[] = {
LinkerPatch::RelativeCodePatch(bl_offset_in_last_method, nullptr, 1u),
};
@@ -603,7 +655,7 @@
ArrayRef<const uint8_t> method1_code(method1_raw_code);
ASSERT_EQ(bl_offset_in_method1 + 4u, method1_code.size());
uint32_t expected_last_method_idx = 65; // Based on 2MiB chunks in Create2MethodsWithGap().
- LinkerPatch method1_patches[] = {
+ const LinkerPatch method1_patches[] = {
LinkerPatch::RelativeCodePatch(bl_offset_in_method1, nullptr, expected_last_method_idx),
};
@@ -620,9 +672,10 @@
uint32_t last_method_offset = GetMethodOffset(last_method_idx);
ASSERT_TRUE(IsAligned<kArm64Alignment>(last_method_offset));
uint32_t last_method_header_offset = last_method_offset - sizeof(OatQuickMethodHeader);
+ uint32_t thunk_size = MethodCallThunkSize();
uint32_t thunk_offset =
- RoundDown(last_method_header_offset - ThunkSize(), GetInstructionSetAlignment(kArm64));
- DCHECK_EQ(thunk_offset + ThunkSize() + CodeAlignmentSize(thunk_offset + ThunkSize()),
+ RoundDown(last_method_header_offset - thunk_size, GetInstructionSetAlignment(kArm64));
+ DCHECK_EQ(thunk_offset + thunk_size + CodeAlignmentSize(thunk_offset + thunk_size),
last_method_header_offset);
uint32_t diff = thunk_offset - (method1_offset + bl_offset_in_method1);
CHECK_ALIGNED(diff, 4u);
@@ -637,7 +690,7 @@
constexpr uint32_t bl_offset_in_last_method = 1u * 4u; // After NOPs.
ArrayRef<const uint8_t> last_method_code(last_method_raw_code);
ASSERT_EQ(bl_offset_in_last_method + 4u, last_method_code.size());
- LinkerPatch last_method_patches[] = {
+ const LinkerPatch last_method_patches[] = {
LinkerPatch::RelativeCodePatch(bl_offset_in_last_method, nullptr, 1u),
};
@@ -832,5 +885,383 @@
TEST_FOR_OFFSETS(LDRX_SPREL_ADD_TEST, 0, 8)
+void Arm64RelativePatcherTest::TestBakerField(uint32_t offset, uint32_t root_reg) {
+ uint32_t valid_regs[] = {
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14, 15, 18, 19, // IP0 and IP1 are reserved.
+ 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
+ // LR and SP/ZR are reserved.
+ };
+ DCHECK_ALIGNED(offset, 4u);
+ DCHECK_LT(offset, 16 * KB);
+ constexpr size_t kMethodCodeSize = 8u;
+ constexpr size_t kLiteralOffset = 0u;
+ uint32_t method_idx = 0u;
+ for (uint32_t base_reg : valid_regs) {
+ for (uint32_t holder_reg : valid_regs) {
+ uint32_t ldr = kLdrWInsn | (offset << (10 - 2)) | (base_reg << 5) | root_reg;
+ const std::vector<uint8_t> raw_code = RawCode({kCbnzIP1Plus0Insn, ldr});
+ ASSERT_EQ(kMethodCodeSize, raw_code.size());
+ ArrayRef<const uint8_t> code(raw_code);
+ uint32_t encoded_data =
+ Arm64RelativePatcher::EncodeBakerReadBarrierFieldData(base_reg, holder_reg);
+ const LinkerPatch patches[] = {
+ LinkerPatch::BakerReadBarrierBranchPatch(kLiteralOffset, encoded_data),
+ };
+ ++method_idx;
+ AddCompiledMethod(MethodRef(method_idx), code, ArrayRef<const LinkerPatch>(patches));
+ }
+ }
+ Link();
+
+ // All thunks are at the end.
+ uint32_t thunk_offset = GetMethodOffset(method_idx) + RoundUp(kMethodCodeSize, kArm64Alignment);
+ method_idx = 0u;
+ for (uint32_t base_reg : valid_regs) {
+ for (uint32_t holder_reg : valid_regs) {
+ ++method_idx;
+ uint32_t cbnz_offset = thunk_offset - (GetMethodOffset(method_idx) + kLiteralOffset);
+ uint32_t cbnz = kCbnzIP1Plus0Insn | (cbnz_offset << (5 - 2));
+ uint32_t ldr = kLdrWInsn | (offset << (10 - 2)) | (base_reg << 5) | root_reg;
+ const std::vector<uint8_t> expected_code = RawCode({cbnz, ldr});
+ ASSERT_EQ(kMethodCodeSize, expected_code.size());
+ ASSERT_TRUE(
+ CheckLinkedMethod(MethodRef(method_idx), ArrayRef<const uint8_t>(expected_code)));
+
+ std::vector<uint8_t> expected_thunk = CompileBakerOffsetThunk(base_reg, holder_reg);
+ ASSERT_GT(output_.size(), thunk_offset);
+ ASSERT_GE(output_.size() - thunk_offset, expected_thunk.size());
+ ArrayRef<const uint8_t> compiled_thunk(output_.data() + thunk_offset,
+ expected_thunk.size());
+ if (ArrayRef<const uint8_t>(expected_thunk) != compiled_thunk) {
+ DumpDiff(ArrayRef<const uint8_t>(expected_thunk), compiled_thunk);
+ ASSERT_TRUE(false);
+ }
+
+ size_t gray_check_offset = thunk_offset;
+ if (holder_reg == base_reg) {
+ // Verify that the null-check CBZ uses the correct register, i.e. holder_reg.
+ ASSERT_GE(output_.size() - gray_check_offset, 4u);
+ ASSERT_EQ(0x34000000 | holder_reg, GetOutputInsn(thunk_offset) & 0xff00001f);
+ gray_check_offset +=4u;
+ }
+ // Verify that the lock word for gray bit check is loaded from the holder address.
+ static constexpr size_t kGrayCheckInsns = 5;
+ ASSERT_GE(output_.size() - gray_check_offset, 4u * kGrayCheckInsns);
+ const uint32_t load_lock_word =
+ kLdrWInsn |
+ (mirror::Object::MonitorOffset().Uint32Value() << (10 - 2)) |
+ (holder_reg << 5) |
+ /* ip0 */ 16;
+ EXPECT_EQ(load_lock_word, GetOutputInsn(gray_check_offset));
+ // Verify the gray bit check.
+ const uint32_t check_gray_bit_witout_offset =
+ 0x37000000 | (LockWord::kReadBarrierStateShift << 19) | /* ip0 */ 16;
+ EXPECT_EQ(check_gray_bit_witout_offset, GetOutputInsn(gray_check_offset + 4u) & 0xfff8001f);
+ // Verify the fake dependency.
+ const uint32_t fake_dependency =
+ 0x8b408000 | // ADD Xd, Xn, Xm, LSR 32
+ (/* ip0 */ 16 << 16) | // Xm = ip0
+ (base_reg << 5) | // Xn = base_reg
+ base_reg; // Xd = base_reg
+ EXPECT_EQ(fake_dependency, GetOutputInsn(gray_check_offset + 12u));
+ // Do not check the rest of the implementation.
+
+ // The next thunk follows on the next aligned offset.
+ thunk_offset += RoundUp(expected_thunk.size(), kArm64Alignment);
+ }
+ }
+}
+
+#define TEST_BAKER_FIELD(offset, root_reg) \
+ TEST_F(Arm64RelativePatcherTestDefault, \
+ BakerOffset##offset##_##root_reg) { \
+ TestBakerField(offset, root_reg); \
+ }
+
+TEST_BAKER_FIELD(/* offset */ 0, /* root_reg */ 0)
+TEST_BAKER_FIELD(/* offset */ 8, /* root_reg */ 15)
+TEST_BAKER_FIELD(/* offset */ 0x3ffc, /* root_reg */ 29)
+
+TEST_F(Arm64RelativePatcherTestDefault, BakerOffsetThunkInTheMiddle) {
+ // One thunk in the middle with maximum distance branches to it from both sides.
+ // Use offset = 0, base_reg = 0, root_reg = 0, the LDR is simply `kLdrWInsn`.
+ constexpr uint32_t kLiteralOffset1 = 4;
+ const std::vector<uint8_t> raw_code1 = RawCode({kNopInsn, kCbnzIP1Plus0Insn, kLdrWInsn});
+ ArrayRef<const uint8_t> code1(raw_code1);
+ uint32_t encoded_data =
+ Arm64RelativePatcher::EncodeBakerReadBarrierFieldData(/* base_reg */ 0, /* holder_reg */ 0);
+ const LinkerPatch patches1[] = {
+ LinkerPatch::BakerReadBarrierBranchPatch(kLiteralOffset1, encoded_data),
+ };
+ AddCompiledMethod(MethodRef(1u), code1, ArrayRef<const LinkerPatch>(patches1));
+
+ // Allow thunk at 1MiB offset from the start of the method above. Literal offset being 4
+ // allows the branch to reach that thunk.
+ size_t filler1_size =
+ 1 * MB - RoundUp(raw_code1.size() + sizeof(OatQuickMethodHeader), kArm64Alignment);
+ std::vector<uint8_t> raw_filler1_code = GenNops(filler1_size / 4u);
+ ArrayRef<const uint8_t> filler1_code(raw_filler1_code);
+ AddCompiledMethod(MethodRef(2u), filler1_code);
+
+ // Enforce thunk reservation with a tiny method.
+ AddCompiledMethod(MethodRef(3u), kNopCode);
+
+ // Allow reaching the thunk from the very beginning of a method 1MiB away. Backward branch
+ // reaches the full 1MiB. Things to subtract:
+ // - thunk size and method 3 pre-header, rounded up (padding in between if needed)
+ // - method 3 code and method 4 pre-header, rounded up (padding in between if needed)
+ // - method 4 header (let there be no padding between method 4 code and method 5 pre-header).
+ size_t thunk_size = CompileBakerOffsetThunk(/* base_reg */ 0, /* holder_reg */ 0).size();
+ size_t filler2_size =
+ 1 * MB - RoundUp(thunk_size + sizeof(OatQuickMethodHeader), kArm64Alignment)
+ - RoundUp(kNopCode.size() + sizeof(OatQuickMethodHeader), kArm64Alignment)
+ - sizeof(OatQuickMethodHeader);
+ std::vector<uint8_t> raw_filler2_code = GenNops(filler2_size / 4u);
+ ArrayRef<const uint8_t> filler2_code(raw_filler2_code);
+ AddCompiledMethod(MethodRef(4u), filler2_code);
+
+ constexpr uint32_t kLiteralOffset2 = 0;
+ const std::vector<uint8_t> raw_code2 = RawCode({kCbnzIP1Plus0Insn, kLdrWInsn});
+ ArrayRef<const uint8_t> code2(raw_code2);
+ const LinkerPatch patches2[] = {
+ LinkerPatch::BakerReadBarrierBranchPatch(kLiteralOffset2, encoded_data),
+ };
+ AddCompiledMethod(MethodRef(5u), code2, ArrayRef<const LinkerPatch>(patches2));
+
+ Link();
+
+ uint32_t first_method_offset = GetMethodOffset(1u);
+ uint32_t last_method_offset = GetMethodOffset(5u);
+ EXPECT_EQ(2 * MB, last_method_offset - first_method_offset);
+
+ const uint32_t cbnz_max_forward = kCbnzIP1Plus0Insn | 0x007fffe0;
+ const uint32_t cbnz_max_backward = kCbnzIP1Plus0Insn | 0x00800000;
+ const std::vector<uint8_t> expected_code1 = RawCode({kNopInsn, cbnz_max_forward, kLdrWInsn});
+ const std::vector<uint8_t> expected_code2 = RawCode({cbnz_max_backward, kLdrWInsn});
+ ASSERT_TRUE(CheckLinkedMethod(MethodRef(1), ArrayRef<const uint8_t>(expected_code1)));
+ ASSERT_TRUE(CheckLinkedMethod(MethodRef(5), ArrayRef<const uint8_t>(expected_code2)));
+}
+
+TEST_F(Arm64RelativePatcherTestDefault, BakerOffsetThunkBeforeFiller) {
+ // Based on the first part of BakerOffsetThunkInTheMiddle but the CBNZ is one instruction
+ // earlier, so the thunk is emitted before the filler.
+ // Use offset = 0, base_reg = 0, root_reg = 0, the LDR is simply `kLdrWInsn`.
+ constexpr uint32_t kLiteralOffset1 = 0;
+ const std::vector<uint8_t> raw_code1 = RawCode({kCbnzIP1Plus0Insn, kLdrWInsn, kNopInsn});
+ ArrayRef<const uint8_t> code1(raw_code1);
+ uint32_t encoded_data =
+ Arm64RelativePatcher::EncodeBakerReadBarrierFieldData(/* base_reg */ 0, /* holder_reg */ 0);
+ const LinkerPatch patches1[] = {
+ LinkerPatch::BakerReadBarrierBranchPatch(kLiteralOffset1, encoded_data),
+ };
+ AddCompiledMethod(MethodRef(1u), code1, ArrayRef<const LinkerPatch>(patches1));
+
+ // Allow thunk at 1MiB offset from the start of the method above. Literal offset being 4
+ // allows the branch to reach that thunk.
+ size_t filler1_size =
+ 1 * MB - RoundUp(raw_code1.size() + sizeof(OatQuickMethodHeader), kArm64Alignment);
+ std::vector<uint8_t> raw_filler1_code = GenNops(filler1_size / 4u);
+ ArrayRef<const uint8_t> filler1_code(raw_filler1_code);
+ AddCompiledMethod(MethodRef(2u), filler1_code);
+
+ Link();
+
+ const uint32_t cbnz_offset = RoundUp(raw_code1.size(), kArm64Alignment) - kLiteralOffset1;
+ const uint32_t cbnz = kCbnzIP1Plus0Insn | (cbnz_offset << (5 - 2));
+ const std::vector<uint8_t> expected_code1 = RawCode({cbnz, kLdrWInsn, kNopInsn});
+ ASSERT_TRUE(CheckLinkedMethod(MethodRef(1), ArrayRef<const uint8_t>(expected_code1)));
+}
+
+TEST_F(Arm64RelativePatcherTestDefault, BakerOffsetThunkInTheMiddleUnreachableFromLast) {
+ // Based on the BakerOffsetThunkInTheMiddle but the CBNZ in the last method is preceded
+ // by NOP and cannot reach the thunk in the middle, so we emit an extra thunk at the end.
+ // Use offset = 0, base_reg = 0, root_reg = 0, the LDR is simply `kLdrWInsn`.
+ constexpr uint32_t kLiteralOffset1 = 4;
+ const std::vector<uint8_t> raw_code1 = RawCode({kNopInsn, kCbnzIP1Plus0Insn, kLdrWInsn});
+ ArrayRef<const uint8_t> code1(raw_code1);
+ uint32_t encoded_data =
+ Arm64RelativePatcher::EncodeBakerReadBarrierFieldData(/* base_reg */ 0, /* holder_reg */ 0);
+ const LinkerPatch patches1[] = {
+ LinkerPatch::BakerReadBarrierBranchPatch(kLiteralOffset1, encoded_data),
+ };
+ AddCompiledMethod(MethodRef(1u), code1, ArrayRef<const LinkerPatch>(patches1));
+
+ // Allow thunk at 1MiB offset from the start of the method above. Literal offset being 4
+ // allows the branch to reach that thunk.
+ size_t filler1_size =
+ 1 * MB - RoundUp(raw_code1.size() + sizeof(OatQuickMethodHeader), kArm64Alignment);
+ std::vector<uint8_t> raw_filler1_code = GenNops(filler1_size / 4u);
+ ArrayRef<const uint8_t> filler1_code(raw_filler1_code);
+ AddCompiledMethod(MethodRef(2u), filler1_code);
+
+ // Enforce thunk reservation with a tiny method.
+ AddCompiledMethod(MethodRef(3u), kNopCode);
+
+ // If not for the extra NOP, this would allow reaching the thunk from the very beginning
+ // of a method 1MiB away. Backward branch reaches the full 1MiB. Things to subtract:
+ // - thunk size and method 3 pre-header, rounded up (padding in between if needed)
+ // - method 3 code and method 4 pre-header, rounded up (padding in between if needed)
+ // - method 4 header (let there be no padding between method 4 code and method 5 pre-header).
+ size_t thunk_size = CompileBakerOffsetThunk(/* base_reg */ 0, /* holder_reg */ 0).size();
+ size_t filler2_size =
+ 1 * MB - RoundUp(thunk_size + sizeof(OatQuickMethodHeader), kArm64Alignment)
+ - RoundUp(kNopCode.size() + sizeof(OatQuickMethodHeader), kArm64Alignment)
+ - sizeof(OatQuickMethodHeader);
+ std::vector<uint8_t> raw_filler2_code = GenNops(filler2_size / 4u);
+ ArrayRef<const uint8_t> filler2_code(raw_filler2_code);
+ AddCompiledMethod(MethodRef(4u), filler2_code);
+
+ // Extra NOP compared to BakerOffsetThunkInTheMiddle.
+ constexpr uint32_t kLiteralOffset2 = 4;
+ const std::vector<uint8_t> raw_code2 = RawCode({kNopInsn, kCbnzIP1Plus0Insn, kLdrWInsn});
+ ArrayRef<const uint8_t> code2(raw_code2);
+ const LinkerPatch patches2[] = {
+ LinkerPatch::BakerReadBarrierBranchPatch(kLiteralOffset2, encoded_data),
+ };
+ AddCompiledMethod(MethodRef(5u), code2, ArrayRef<const LinkerPatch>(patches2));
+
+ Link();
+
+ const uint32_t cbnz_max_forward = kCbnzIP1Plus0Insn | 0x007fffe0;
+ const uint32_t cbnz_last_offset = RoundUp(raw_code2.size(), kArm64Alignment) - kLiteralOffset2;
+ const uint32_t cbnz_last = kCbnzIP1Plus0Insn | (cbnz_last_offset << (5 - 2));
+ const std::vector<uint8_t> expected_code1 = RawCode({kNopInsn, cbnz_max_forward, kLdrWInsn});
+ const std::vector<uint8_t> expected_code2 = RawCode({kNopInsn, cbnz_last, kLdrWInsn});
+ ASSERT_TRUE(CheckLinkedMethod(MethodRef(1), ArrayRef<const uint8_t>(expected_code1)));
+ ASSERT_TRUE(CheckLinkedMethod(MethodRef(5), ArrayRef<const uint8_t>(expected_code2)));
+}
+
+TEST_F(Arm64RelativePatcherTestDefault, BakerRootGcRoot) {
+ uint32_t valid_regs[] = {
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14, 15, 18, 19, // IP0 and IP1 are reserved.
+ 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
+ // LR and SP/ZR are reserved.
+ };
+ constexpr size_t kMethodCodeSize = 8u;
+ constexpr size_t kLiteralOffset = 4u;
+ uint32_t method_idx = 0u;
+ for (uint32_t root_reg : valid_regs) {
+ ++method_idx;
+ uint32_t ldr = kLdrWInsn | (/* offset */ 8 << (10 - 2)) | (/* base_reg */ 0 << 5) | root_reg;
+ const std::vector<uint8_t> raw_code = RawCode({ldr, kCbnzIP1Plus0Insn});
+ ASSERT_EQ(kMethodCodeSize, raw_code.size());
+ ArrayRef<const uint8_t> code(raw_code);
+ const LinkerPatch patches[] = {
+ LinkerPatch::BakerReadBarrierBranchPatch(
+ kLiteralOffset, Arm64RelativePatcher::EncodeBakerReadBarrierGcRootData(root_reg)),
+ };
+ AddCompiledMethod(MethodRef(method_idx), code, ArrayRef<const LinkerPatch>(patches));
+ }
+ Link();
+
+ // All thunks are at the end.
+ uint32_t thunk_offset = GetMethodOffset(method_idx) + RoundUp(kMethodCodeSize, kArm64Alignment);
+ method_idx = 0u;
+ for (uint32_t root_reg : valid_regs) {
+ ++method_idx;
+ uint32_t cbnz_offset = thunk_offset - (GetMethodOffset(method_idx) + kLiteralOffset);
+ uint32_t cbnz = kCbnzIP1Plus0Insn | (cbnz_offset << (5 - 2));
+ uint32_t ldr = kLdrWInsn | (/* offset */ 8 << (10 - 2)) | (/* base_reg */ 0 << 5) | root_reg;
+ const std::vector<uint8_t> expected_code = RawCode({ldr, cbnz});
+ ASSERT_EQ(kMethodCodeSize, expected_code.size());
+ EXPECT_TRUE(CheckLinkedMethod(MethodRef(method_idx), ArrayRef<const uint8_t>(expected_code)));
+
+ std::vector<uint8_t> expected_thunk = CompileBakerGcRootThunk(root_reg);
+ ASSERT_GT(output_.size(), thunk_offset);
+ ASSERT_GE(output_.size() - thunk_offset, expected_thunk.size());
+ ArrayRef<const uint8_t> compiled_thunk(output_.data() + thunk_offset,
+ expected_thunk.size());
+ if (ArrayRef<const uint8_t>(expected_thunk) != compiled_thunk) {
+ DumpDiff(ArrayRef<const uint8_t>(expected_thunk), compiled_thunk);
+ ASSERT_TRUE(false);
+ }
+
+ // Verify that the fast-path null-check CBZ uses the correct register, i.e. root_reg.
+ ASSERT_GE(output_.size() - thunk_offset, 4u);
+ ASSERT_EQ(0x34000000 | root_reg, GetOutputInsn(thunk_offset) & 0xff00001f);
+ // Do not check the rest of the implementation.
+
+ // The next thunk follows on the next aligned offset.
+ thunk_offset += RoundUp(expected_thunk.size(), kArm64Alignment);
+ }
+}
+
+TEST_F(Arm64RelativePatcherTestDefault, BakerAndMethodCallInteraction) {
+ // During development, there was a `DCHECK_LE(MaxNextOffset(), next_thunk.MaxNextOffset());`
+ // in `ArmBaseRelativePatcher::ThunkData::MakeSpaceBefore()` which does not necessarily
+ // hold when we're reserving thunks of different sizes. This test exposes the situation
+ // by using Baker thunks and a method call thunk.
+
+ // Add a method call patch that can reach to method 1 offset + 128MiB.
+ uint32_t method_idx = 0u;
+ constexpr size_t kMethodCallLiteralOffset = 4u;
+ constexpr uint32_t kMissingMethodIdx = 2u;
+ const std::vector<uint8_t> raw_code1 = RawCode({kNopInsn, kBlPlus0});
+ const LinkerPatch method1_patches[] = {
+ LinkerPatch::RelativeCodePatch(kMethodCallLiteralOffset, nullptr, 2u),
+ };
+ ArrayRef<const uint8_t> code1(raw_code1);
+ ++method_idx;
+ AddCompiledMethod(MethodRef(1u), code1, ArrayRef<const LinkerPatch>(method1_patches));
+
+ // Skip kMissingMethodIdx.
+ ++method_idx;
+ ASSERT_EQ(kMissingMethodIdx, method_idx);
+ // Add a method with the right size that the method code for the next one starts 1MiB
+ // after code for method 1.
+ size_t filler_size =
+ 1 * MB - RoundUp(raw_code1.size() + sizeof(OatQuickMethodHeader), kArm64Alignment)
+ - sizeof(OatQuickMethodHeader);
+ std::vector<uint8_t> filler_code = GenNops(filler_size / 4u);
+ ++method_idx;
+ AddCompiledMethod(MethodRef(method_idx), ArrayRef<const uint8_t>(filler_code));
+ // Add 126 methods with 1MiB code+header, making the code for the next method start 1MiB
+ // before the currently scheduled MaxNextOffset() for the method call thunk.
+ for (uint32_t i = 0; i != 126; ++i) {
+ filler_size = 1 * MB - sizeof(OatQuickMethodHeader);
+ filler_code = GenNops(filler_size / 4u);
+ ++method_idx;
+ AddCompiledMethod(MethodRef(method_idx), ArrayRef<const uint8_t>(filler_code));
+ }
+
+ // Add 2 Baker GC root patches to the last method, one that would allow the thunk at
+ // 1MiB + kArm64Alignment, i.e. kArm64Alignment after the method call thunk, and the
+ // second that needs it kArm64Alignment after that. Given the size of the GC root thunk
+ // is more than the space required by the method call thunk plus kArm64Alignment,
+ // this pushes the first GC root thunk's pending MaxNextOffset() before the method call
+ // thunk's pending MaxNextOffset() which needs to be adjusted.
+ ASSERT_LT(RoundUp(CompileMethodCallThunk().size(), kArm64Alignment) + kArm64Alignment,
+ CompileBakerGcRootThunk(/* root_reg */ 0).size());
+ static_assert(kArm64Alignment == 16, "Code below assumes kArm64Alignment == 16");
+ constexpr size_t kBakerLiteralOffset1 = 4u + kArm64Alignment;
+ constexpr size_t kBakerLiteralOffset2 = 4u + 2 * kArm64Alignment;
+ // Use offset = 0, base_reg = 0, the LDR is simply `kLdrWInsn | root_reg`.
+ const uint32_t ldr1 = kLdrWInsn | /* root_reg */ 1;
+ const uint32_t ldr2 = kLdrWInsn | /* root_reg */ 2;
+ const std::vector<uint8_t> last_method_raw_code = RawCode({
+ kNopInsn, kNopInsn, kNopInsn, kNopInsn, // Padding before first GC root read barrier.
+ ldr1, kCbnzIP1Plus0Insn, // First GC root LDR with read barrier.
+ kNopInsn, kNopInsn, // Padding before second GC root read barrier.
+ ldr2, kCbnzIP1Plus0Insn, // Second GC root LDR with read barrier.
+ });
+ uint32_t encoded_data1 = Arm64RelativePatcher::EncodeBakerReadBarrierGcRootData(/* root_reg */ 1);
+ uint32_t encoded_data2 = Arm64RelativePatcher::EncodeBakerReadBarrierGcRootData(/* root_reg */ 2);
+ const LinkerPatch last_method_patches[] = {
+ LinkerPatch::BakerReadBarrierBranchPatch(kBakerLiteralOffset1, encoded_data1),
+ LinkerPatch::BakerReadBarrierBranchPatch(kBakerLiteralOffset2, encoded_data2),
+ };
+ ++method_idx;
+ AddCompiledMethod(MethodRef(method_idx),
+ ArrayRef<const uint8_t>(last_method_raw_code),
+ ArrayRef<const LinkerPatch>(last_method_patches));
+
+ // The main purpose of the test is to check that Link() does not cause a crash.
+ Link();
+
+ ASSERT_EQ(127 * MB, GetMethodOffset(method_idx) - GetMethodOffset(1u));
+}
+
} // namespace linker
} // namespace art
diff --git a/compiler/linker/mips/relative_patcher_mips.cc b/compiler/linker/mips/relative_patcher_mips.cc
index fe5f9a9..8da530f 100644
--- a/compiler/linker/mips/relative_patcher_mips.cc
+++ b/compiler/linker/mips/relative_patcher_mips.cc
@@ -117,5 +117,11 @@
(*code)[literal_low_offset + 1] = static_cast<uint8_t>(diff >> 8);
}
+void MipsRelativePatcher::PatchBakerReadBarrierBranch(std::vector<uint8_t>* code ATTRIBUTE_UNUSED,
+ const LinkerPatch& patch ATTRIBUTE_UNUSED,
+ uint32_t patch_offset ATTRIBUTE_UNUSED) {
+ LOG(FATAL) << "UNIMPLEMENTED";
+}
+
} // namespace linker
} // namespace art
diff --git a/compiler/linker/mips/relative_patcher_mips.h b/compiler/linker/mips/relative_patcher_mips.h
index 4ff2f2f..852a345 100644
--- a/compiler/linker/mips/relative_patcher_mips.h
+++ b/compiler/linker/mips/relative_patcher_mips.h
@@ -41,6 +41,9 @@
const LinkerPatch& patch,
uint32_t patch_offset,
uint32_t target_offset) OVERRIDE;
+ void PatchBakerReadBarrierBranch(std::vector<uint8_t>* code,
+ const LinkerPatch& patch,
+ uint32_t patch_offset) OVERRIDE;
private:
// We'll maximize the range of a single load instruction for dex cache array accesses
diff --git a/compiler/linker/mips64/relative_patcher_mips64.cc b/compiler/linker/mips64/relative_patcher_mips64.cc
index c479716..3488d6d 100644
--- a/compiler/linker/mips64/relative_patcher_mips64.cc
+++ b/compiler/linker/mips64/relative_patcher_mips64.cc
@@ -107,5 +107,11 @@
(*code)[literal_offset + 5] = static_cast<uint8_t>(diff >> 8);
}
+void Mips64RelativePatcher::PatchBakerReadBarrierBranch(std::vector<uint8_t>* code ATTRIBUTE_UNUSED,
+ const LinkerPatch& patch ATTRIBUTE_UNUSED,
+ uint32_t patch_offset ATTRIBUTE_UNUSED) {
+ LOG(FATAL) << "UNIMPLEMENTED";
+}
+
} // namespace linker
} // namespace art
diff --git a/compiler/linker/mips64/relative_patcher_mips64.h b/compiler/linker/mips64/relative_patcher_mips64.h
index 8ef8ceb..f478d7f 100644
--- a/compiler/linker/mips64/relative_patcher_mips64.h
+++ b/compiler/linker/mips64/relative_patcher_mips64.h
@@ -39,6 +39,9 @@
const LinkerPatch& patch,
uint32_t patch_offset,
uint32_t target_offset) OVERRIDE;
+ void PatchBakerReadBarrierBranch(std::vector<uint8_t>* code,
+ const LinkerPatch& patch,
+ uint32_t patch_offset) OVERRIDE;
private:
DISALLOW_COPY_AND_ASSIGN(Mips64RelativePatcher);
diff --git a/compiler/linker/multi_oat_relative_patcher.h b/compiler/linker/multi_oat_relative_patcher.h
index dbda03f..247b290 100644
--- a/compiler/linker/multi_oat_relative_patcher.h
+++ b/compiler/linker/multi_oat_relative_patcher.h
@@ -112,6 +112,13 @@
relative_patcher_->PatchPcRelativeReference(code, patch, patch_offset, target_offset);
}
+ void PatchBakerReadBarrierBranch(std::vector<uint8_t>* code,
+ const LinkerPatch& patch,
+ uint32_t patch_offset) {
+ patch_offset += adjustment_;
+ relative_patcher_->PatchBakerReadBarrierBranch(code, patch, patch_offset);
+ }
+
// Wrappers around RelativePatcher for statistics retrieval.
uint32_t CodeAlignmentSize() const;
uint32_t RelativeCallThunksSize() const;
diff --git a/compiler/linker/multi_oat_relative_patcher_test.cc b/compiler/linker/multi_oat_relative_patcher_test.cc
index 92a96a0..951588a 100644
--- a/compiler/linker/multi_oat_relative_patcher_test.cc
+++ b/compiler/linker/multi_oat_relative_patcher_test.cc
@@ -63,7 +63,7 @@
if (next_write_call_thunk_ != 0u) {
offset += next_write_call_thunk_;
std::vector<uint8_t> thunk(next_write_call_thunk_, 'c');
- bool success = WriteRelCallThunk(out, ArrayRef<const uint8_t>(thunk));
+ bool success = WriteThunk(out, ArrayRef<const uint8_t>(thunk));
CHECK(success);
next_write_call_thunk_ = 0u;
}
@@ -95,6 +95,12 @@
last_target_offset_ = target_offset;
}
+ void PatchBakerReadBarrierBranch(std::vector<uint8_t>* code ATTRIBUTE_UNUSED,
+ const LinkerPatch& patch ATTRIBUTE_UNUSED,
+ uint32_t patch_offset ATTRIBUTE_UNUSED) {
+ LOG(FATAL) << "UNIMPLEMENTED";
+ }
+
uint32_t last_reserve_offset_ = 0u;
MethodReference last_reserve_method_ = kNullMethodRef;
uint32_t next_reserve_adjustment_ = 0u;
diff --git a/compiler/linker/relative_patcher.cc b/compiler/linker/relative_patcher.cc
index f1538b1..ee49453 100644
--- a/compiler/linker/relative_patcher.cc
+++ b/compiler/linker/relative_patcher.cc
@@ -75,6 +75,12 @@
LOG(FATAL) << "Unexpected relative dex cache array patch.";
}
+ void PatchBakerReadBarrierBranch(std::vector<uint8_t>* code ATTRIBUTE_UNUSED,
+ const LinkerPatch& patch ATTRIBUTE_UNUSED,
+ uint32_t patch_offset ATTRIBUTE_UNUSED) {
+ LOG(FATAL) << "Unexpected baker read barrier branch patch.";
+ }
+
private:
DISALLOW_COPY_AND_ASSIGN(RelativePatcherNone);
};
@@ -127,7 +133,7 @@
return true;
}
-bool RelativePatcher::WriteRelCallThunk(OutputStream* out, const ArrayRef<const uint8_t>& thunk) {
+bool RelativePatcher::WriteThunk(OutputStream* out, const ArrayRef<const uint8_t>& thunk) {
if (UNLIKELY(!out->WriteFully(thunk.data(), thunk.size()))) {
return false;
}
diff --git a/compiler/linker/relative_patcher.h b/compiler/linker/relative_patcher.h
index 15e955b..38c8228 100644
--- a/compiler/linker/relative_patcher.h
+++ b/compiler/linker/relative_patcher.h
@@ -109,6 +109,11 @@
uint32_t patch_offset,
uint32_t target_offset) = 0;
+ // Patch a branch to a Baker read barrier thunk.
+ virtual void PatchBakerReadBarrierBranch(std::vector<uint8_t>* code,
+ const LinkerPatch& patch,
+ uint32_t patch_offset) = 0;
+
protected:
RelativePatcher()
: size_code_alignment_(0u),
@@ -117,7 +122,7 @@
}
bool WriteCodeAlignment(OutputStream* out, uint32_t aligned_code_delta);
- bool WriteRelCallThunk(OutputStream* out, const ArrayRef<const uint8_t>& thunk);
+ bool WriteThunk(OutputStream* out, const ArrayRef<const uint8_t>& thunk);
bool WriteMiscThunk(OutputStream* out, const ArrayRef<const uint8_t>& thunk);
private:
diff --git a/compiler/linker/relative_patcher_test.h b/compiler/linker/relative_patcher_test.h
index 908cb41..d9a87a0 100644
--- a/compiler/linker/relative_patcher_test.h
+++ b/compiler/linker/relative_patcher_test.h
@@ -76,9 +76,10 @@
return MethodReference(nullptr, method_idx);
}
- void AddCompiledMethod(MethodReference method_ref,
- const ArrayRef<const uint8_t>& code,
- const ArrayRef<const LinkerPatch>& patches) {
+ void AddCompiledMethod(
+ MethodReference method_ref,
+ const ArrayRef<const uint8_t>& code,
+ const ArrayRef<const LinkerPatch>& patches = ArrayRef<const LinkerPatch>()) {
compiled_method_refs_.push_back(method_ref);
compiled_methods_.emplace_back(new CompiledMethod(
&driver_,
@@ -169,6 +170,10 @@
patch,
offset + patch.LiteralOffset(),
target_offset);
+ } else if (patch.GetType() == LinkerPatch::Type::kBakerReadBarrierBranch) {
+ patcher_->PatchBakerReadBarrierBranch(&patched_code_,
+ patch,
+ offset + patch.LiteralOffset());
} else {
LOG(FATAL) << "Bad patch type. " << patch.GetType();
UNREACHABLE();
diff --git a/compiler/linker/x86/relative_patcher_x86.cc b/compiler/linker/x86/relative_patcher_x86.cc
index 768d31a..6967b0b 100644
--- a/compiler/linker/x86/relative_patcher_x86.cc
+++ b/compiler/linker/x86/relative_patcher_x86.cc
@@ -56,5 +56,11 @@
(*code)[literal_offset + 3u] = static_cast<uint8_t>(diff >> 24);
}
+void X86RelativePatcher::PatchBakerReadBarrierBranch(std::vector<uint8_t>* code ATTRIBUTE_UNUSED,
+ const LinkerPatch& patch ATTRIBUTE_UNUSED,
+ uint32_t patch_offset ATTRIBUTE_UNUSED) {
+ LOG(FATAL) << "UNIMPLEMENTED";
+}
+
} // namespace linker
} // namespace art
diff --git a/compiler/linker/x86/relative_patcher_x86.h b/compiler/linker/x86/relative_patcher_x86.h
index fbf9ad4..63a8338 100644
--- a/compiler/linker/x86/relative_patcher_x86.h
+++ b/compiler/linker/x86/relative_patcher_x86.h
@@ -30,6 +30,9 @@
const LinkerPatch& patch,
uint32_t patch_offset,
uint32_t target_offset) OVERRIDE;
+ void PatchBakerReadBarrierBranch(std::vector<uint8_t>* code,
+ const LinkerPatch& patch,
+ uint32_t patch_offset) OVERRIDE;
};
} // namespace linker
diff --git a/compiler/linker/x86_64/relative_patcher_x86_64.cc b/compiler/linker/x86_64/relative_patcher_x86_64.cc
index 2ff6930..156ece9 100644
--- a/compiler/linker/x86_64/relative_patcher_x86_64.cc
+++ b/compiler/linker/x86_64/relative_patcher_x86_64.cc
@@ -34,5 +34,11 @@
reinterpret_cast<unaligned_int32_t*>(&(*code)[patch.LiteralOffset()])[0] = displacement;
}
+void X86_64RelativePatcher::PatchBakerReadBarrierBranch(std::vector<uint8_t>* code ATTRIBUTE_UNUSED,
+ const LinkerPatch& patch ATTRIBUTE_UNUSED,
+ uint32_t patch_offset ATTRIBUTE_UNUSED) {
+ LOG(FATAL) << "UNIMPLEMENTED";
+}
+
} // namespace linker
} // namespace art
diff --git a/compiler/linker/x86_64/relative_patcher_x86_64.h b/compiler/linker/x86_64/relative_patcher_x86_64.h
index 11bb6d5..4f3ec49 100644
--- a/compiler/linker/x86_64/relative_patcher_x86_64.h
+++ b/compiler/linker/x86_64/relative_patcher_x86_64.h
@@ -30,6 +30,9 @@
const LinkerPatch& patch,
uint32_t patch_offset,
uint32_t target_offset) OVERRIDE;
+ void PatchBakerReadBarrierBranch(std::vector<uint8_t>* code,
+ const LinkerPatch& patch,
+ uint32_t patch_offset) OVERRIDE;
};
} // namespace linker
diff --git a/compiler/oat_writer.cc b/compiler/oat_writer.cc
index 105db1d..1781643 100644
--- a/compiler/oat_writer.cc
+++ b/compiler/oat_writer.cc
@@ -1348,6 +1348,12 @@
PatchObjectAddress(&patched_code_, literal_offset, type);
break;
}
+ case LinkerPatch::Type::kBakerReadBarrierBranch: {
+ writer_->relative_patcher_->PatchBakerReadBarrierBranch(&patched_code_,
+ patch,
+ offset_ + literal_offset);
+ break;
+ }
default: {
DCHECK(false) << "Unexpected linker patch type: " << patch.GetType();
break;
diff --git a/compiler/optimizing/code_generator_arm64.cc b/compiler/optimizing/code_generator_arm64.cc
index 794e05c..4955562 100644
--- a/compiler/optimizing/code_generator_arm64.cc
+++ b/compiler/optimizing/code_generator_arm64.cc
@@ -16,6 +16,7 @@
#include "code_generator_arm64.h"
+#include "arch/arm64/asm_support_arm64.h"
#include "arch/arm64/instruction_set_features_arm64.h"
#include "art_method.h"
#include "code_generator_utils.h"
@@ -25,6 +26,7 @@
#include "gc/accounting/card_table.h"
#include "intrinsics.h"
#include "intrinsics_arm64.h"
+#include "linker/arm64/relative_patcher_arm64.h"
#include "mirror/array-inl.h"
#include "mirror/class-inl.h"
#include "offsets.h"
@@ -68,6 +70,7 @@
using helpers::OutputCPURegister;
using helpers::OutputFPRegister;
using helpers::OutputRegister;
+using helpers::QRegisterFrom;
using helpers::RegisterFrom;
using helpers::StackOperandFrom;
using helpers::VIXLRegCodeFromART;
@@ -80,6 +83,27 @@
// generates less code/data with a small num_entries.
static constexpr uint32_t kPackedSwitchCompareJumpThreshold = 7;
+// Reference load (except object array loads) is using LDR Wt, [Xn, #offset] which can handle
+// offset < 16KiB. For offsets >= 16KiB, the load shall be emitted as two or more instructions.
+// For the Baker read barrier implementation using link-generated thunks we need to split
+// the offset explicitly.
+constexpr uint32_t kReferenceLoadMinFarOffset = 16 * KB;
+
+// Flags controlling the use of link-time generated thunks for Baker read barriers.
+// Not yet implemented for heap poisoning.
+constexpr bool kBakerReadBarrierLinkTimeThunksEnableForFields = !kPoisonHeapReferences;
+constexpr bool kBakerReadBarrierLinkTimeThunksEnableForGcRoots = !kPoisonHeapReferences;
+
+// Some instructions have special requirements for a temporary, for example
+// LoadClass/kBssEntry and LoadString/kBssEntry for Baker read barrier require
+// temp that's not an R0 (to avoid an extra move) and Baker read barrier field
+// loads with large offsets need a fixed register to limit the number of link-time
+// thunks we generate. For these and similar cases, we want to reserve a specific
+// register that's neither callee-save nor an argument register. We choose x15.
+inline Location FixedTempLocation() {
+ return Location::RegisterLocation(x15.GetCode());
+}
+
inline Condition ARM64Condition(IfCondition cond) {
switch (cond) {
case kCondEQ: return eq;
@@ -297,23 +321,22 @@
constexpr bool call_saves_everything_except_r0_ip0 = (!kUseReadBarrier || kUseBakerReadBarrier);
CodeGeneratorARM64* arm64_codegen = down_cast<CodeGeneratorARM64*>(codegen);
- // For HLoadClass/kBssEntry/kSaveEverything, make sure we preserve the page address of
- // the entry which is in a scratch register. Make sure it's not used for saving/restoring
- // registers. Exclude the scratch register also for non-Baker read barrier for simplicity.
+ InvokeRuntimeCallingConvention calling_convention;
+ // For HLoadClass/kBssEntry/kSaveEverything, the page address of the entry is in a temp
+ // register, make sure it's not clobbered by the call or by saving/restoring registers.
DCHECK_EQ(instruction_->IsLoadClass(), cls_ == instruction_);
bool is_load_class_bss_entry =
(cls_ == instruction_) && (cls_->GetLoadKind() == HLoadClass::LoadKind::kBssEntry);
- UseScratchRegisterScope temps(arm64_codegen->GetVIXLAssembler());
if (is_load_class_bss_entry) {
- // This temp is a scratch register.
DCHECK(bss_entry_temp_.IsValid());
- temps.Exclude(bss_entry_temp_);
+ DCHECK(!bss_entry_temp_.Is(calling_convention.GetRegisterAt(0)));
+ DCHECK(
+ !UseScratchRegisterScope(arm64_codegen->GetVIXLAssembler()).IsAvailable(bss_entry_temp_));
}
__ Bind(GetEntryLabel());
SaveLiveRegisters(codegen, locations);
- InvokeRuntimeCallingConvention calling_convention;
dex::TypeIndex type_index = cls_->GetTypeIndex();
__ Mov(calling_convention.GetRegisterAt(0).W(), type_index.index_);
QuickEntrypointEnum entrypoint = do_clinit_ ? kQuickInitializeStaticStorage
@@ -386,14 +409,15 @@
DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg()));
CodeGeneratorARM64* arm64_codegen = down_cast<CodeGeneratorARM64*>(codegen);
- // temp_ is a scratch register. Make sure it's not used for saving/restoring registers.
- UseScratchRegisterScope temps(arm64_codegen->GetVIXLAssembler());
- temps.Exclude(temp_);
+ InvokeRuntimeCallingConvention calling_convention;
+ // Make sure `temp_` is not clobbered by the call or by saving/restoring registers.
+ DCHECK(temp_.IsValid());
+ DCHECK(!temp_.Is(calling_convention.GetRegisterAt(0)));
+ DCHECK(!UseScratchRegisterScope(arm64_codegen->GetVIXLAssembler()).IsAvailable(temp_));
__ Bind(GetEntryLabel());
SaveLiveRegisters(codegen, locations);
- InvokeRuntimeCallingConvention calling_convention;
const dex::StringIndex string_index = instruction_->AsLoadString()->GetStringIndex();
__ Mov(calling_convention.GetRegisterAt(0).W(), string_index.index_);
arm64_codegen->InvokeRuntime(kQuickResolveString, instruction_, instruction_->GetDexPc(), this);
@@ -1415,6 +1439,7 @@
graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
pc_relative_type_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
type_bss_entry_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
+ baker_read_barrier_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
jit_string_patches_(StringReferenceValueComparator(),
graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
jit_class_patches_(TypeReferenceValueComparator(),
@@ -1459,9 +1484,12 @@
}
Location ParallelMoveResolverARM64::AllocateScratchLocationFor(Location::Kind kind) {
- DCHECK(kind == Location::kRegister || kind == Location::kFpuRegister ||
- kind == Location::kStackSlot || kind == Location::kDoubleStackSlot);
- kind = (kind == Location::kFpuRegister) ? Location::kFpuRegister : Location::kRegister;
+ DCHECK(kind == Location::kRegister || kind == Location::kFpuRegister
+ || kind == Location::kStackSlot || kind == Location::kDoubleStackSlot
+ || kind == Location::kSIMDStackSlot);
+ kind = (kind == Location::kFpuRegister || kind == Location::kSIMDStackSlot)
+ ? Location::kFpuRegister
+ : Location::kRegister;
Location scratch = GetScratchLocation(kind);
if (!scratch.Equals(Location::NoLocation())) {
return scratch;
@@ -1471,7 +1499,9 @@
scratch = LocationFrom(vixl_temps_.AcquireX());
} else {
DCHECK(kind == Location::kFpuRegister);
- scratch = LocationFrom(vixl_temps_.AcquireD());
+ scratch = LocationFrom(codegen_->GetGraph()->HasSIMD()
+ ? vixl_temps_.AcquireVRegisterOfSize(kQRegSize)
+ : vixl_temps_.AcquireD());
}
AddScratchLocation(scratch);
return scratch;
@@ -1482,7 +1512,7 @@
vixl_temps_.Release(XRegisterFrom(loc));
} else {
DCHECK(loc.IsFpuRegister());
- vixl_temps_.Release(DRegisterFrom(loc));
+ vixl_temps_.Release(codegen_->GetGraph()->HasSIMD() ? QRegisterFrom(loc) : DRegisterFrom(loc));
}
RemoveScratchLocation(loc);
}
@@ -1745,6 +1775,8 @@
if (source.IsStackSlot() || source.IsDoubleStackSlot()) {
DCHECK(dst.Is64Bits() == source.IsDoubleStackSlot());
__ Ldr(dst, StackOperandFrom(source));
+ } else if (source.IsSIMDStackSlot()) {
+ __ Ldr(QRegisterFrom(destination), StackOperandFrom(source));
} else if (source.IsConstant()) {
DCHECK(CoherentConstantAndType(source, dst_type));
MoveConstant(dst, source.GetConstant());
@@ -1767,7 +1799,29 @@
__ Fmov(RegisterFrom(destination, dst_type), FPRegisterFrom(source, source_type));
} else {
DCHECK(destination.IsFpuRegister());
- __ Fmov(FPRegister(dst), FPRegisterFrom(source, dst_type));
+ if (GetGraph()->HasSIMD()) {
+ __ Mov(QRegisterFrom(destination), QRegisterFrom(source));
+ } else {
+ __ Fmov(FPRegister(dst), FPRegisterFrom(source, dst_type));
+ }
+ }
+ }
+ } else if (destination.IsSIMDStackSlot()) {
+ if (source.IsFpuRegister()) {
+ __ Str(QRegisterFrom(source), StackOperandFrom(destination));
+ } else {
+ DCHECK(source.IsSIMDStackSlot());
+ UseScratchRegisterScope temps(GetVIXLAssembler());
+ if (GetVIXLAssembler()->GetScratchFPRegisterList()->IsEmpty()) {
+ Register temp = temps.AcquireX();
+ __ Ldr(temp, MemOperand(sp, source.GetStackIndex()));
+ __ Str(temp, MemOperand(sp, destination.GetStackIndex()));
+ __ Ldr(temp, MemOperand(sp, source.GetStackIndex() + kArm64WordSize));
+ __ Str(temp, MemOperand(sp, destination.GetStackIndex() + kArm64WordSize));
+ } else {
+ FPRegister temp = temps.AcquireVRegisterOfSize(kQRegSize);
+ __ Ldr(temp, StackOperandFrom(source));
+ __ Str(temp, StackOperandFrom(destination));
}
}
} else { // The destination is not a register. It must be a stack slot.
@@ -2206,7 +2260,8 @@
}
}
-void LocationsBuilderARM64::HandleFieldGet(HInstruction* instruction) {
+void LocationsBuilderARM64::HandleFieldGet(HInstruction* instruction,
+ const FieldInfo& field_info) {
DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
bool object_field_get_with_read_barrier =
@@ -2220,7 +2275,17 @@
locations->SetCustomSlowPathCallerSaves(RegisterSet::Empty()); // No caller-save registers.
// We need a temporary register for the read barrier marking slow
// path in CodeGeneratorARM64::GenerateFieldLoadWithBakerReadBarrier.
- locations->AddTemp(Location::RequiresRegister());
+ if (kBakerReadBarrierLinkTimeThunksEnableForFields &&
+ !Runtime::Current()->UseJitCompilation() &&
+ !field_info.IsVolatile()) {
+ // If link-time thunks for the Baker read barrier are enabled, for AOT
+ // non-volatile loads we need a temporary only if the offset is too big.
+ if (field_info.GetFieldOffset().Uint32Value() >= kReferenceLoadMinFarOffset) {
+ locations->AddTemp(FixedTempLocation());
+ }
+ } else {
+ locations->AddTemp(Location::RequiresRegister());
+ }
}
locations->SetInAt(0, Location::RequiresRegister());
if (Primitive::IsFloatingPointType(instruction->GetType())) {
@@ -2249,7 +2314,8 @@
// Object FieldGet with Baker's read barrier case.
// /* HeapReference<Object> */ out = *(base + offset)
Register base = RegisterFrom(base_loc, Primitive::kPrimNot);
- Register temp = WRegisterFrom(locations->GetTemp(0));
+ Location maybe_temp =
+ (locations->GetTempCount() != 0) ? locations->GetTemp(0) : Location::NoLocation();
// Note that potential implicit null checks are handled in this
// CodeGeneratorARM64::GenerateFieldLoadWithBakerReadBarrier call.
codegen_->GenerateFieldLoadWithBakerReadBarrier(
@@ -2257,7 +2323,7 @@
out,
base,
offset,
- temp,
+ maybe_temp,
/* needs_null_check */ true,
field_info.IsVolatile());
} else {
@@ -2642,7 +2708,21 @@
locations->SetCustomSlowPathCallerSaves(RegisterSet::Empty()); // No caller-save registers.
// We need a temporary register for the read barrier marking slow
// path in CodeGeneratorARM64::GenerateArrayLoadWithBakerReadBarrier.
- locations->AddTemp(Location::RequiresRegister());
+ if (kBakerReadBarrierLinkTimeThunksEnableForFields &&
+ !Runtime::Current()->UseJitCompilation() &&
+ instruction->GetIndex()->IsConstant()) {
+ // Array loads with constant index are treated as field loads.
+ // If link-time thunks for the Baker read barrier are enabled, for AOT
+ // constant index loads we need a temporary only if the offset is too big.
+ uint32_t offset = CodeGenerator::GetArrayDataOffset(instruction);
+ uint32_t index = instruction->GetIndex()->AsIntConstant()->GetValue();
+ offset += index << Primitive::ComponentSizeShift(Primitive::kPrimNot);
+ if (offset >= kReferenceLoadMinFarOffset) {
+ locations->AddTemp(FixedTempLocation());
+ }
+ } else {
+ locations->AddTemp(Location::RequiresRegister());
+ }
}
locations->SetInAt(0, Location::RequiresRegister());
locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
@@ -2678,11 +2758,25 @@
if (type == Primitive::kPrimNot && kEmitCompilerReadBarrier && kUseBakerReadBarrier) {
// Object ArrayGet with Baker's read barrier case.
- Register temp = WRegisterFrom(locations->GetTemp(0));
// Note that a potential implicit null check is handled in the
// CodeGeneratorARM64::GenerateArrayLoadWithBakerReadBarrier call.
- codegen_->GenerateArrayLoadWithBakerReadBarrier(
- instruction, out, obj.W(), offset, index, temp, /* needs_null_check */ true);
+ if (index.IsConstant()) {
+ // Array load with a constant index can be treated as a field load.
+ offset += Int64ConstantFrom(index) << Primitive::ComponentSizeShift(type);
+ Location maybe_temp =
+ (locations->GetTempCount() != 0) ? locations->GetTemp(0) : Location::NoLocation();
+ codegen_->GenerateFieldLoadWithBakerReadBarrier(instruction,
+ out,
+ obj.W(),
+ offset,
+ maybe_temp,
+ /* needs_null_check */ true,
+ /* use_load_acquire */ false);
+ } else {
+ Register temp = WRegisterFrom(locations->GetTemp(0));
+ codegen_->GenerateArrayLoadWithBakerReadBarrier(
+ instruction, out, obj.W(), offset, index, temp, /* needs_null_check */ true);
+ }
} else {
// General case.
MemOperand source = HeapOperand(obj);
@@ -3712,7 +3806,7 @@
}
void LocationsBuilderARM64::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
- HandleFieldGet(instruction);
+ HandleFieldGet(instruction, instruction->GetFieldInfo());
}
void InstructionCodeGeneratorARM64::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
@@ -4514,6 +4608,11 @@
return NewPcRelativePatch(dex_file, element_offset, adrp_label, &pc_relative_dex_cache_patches_);
}
+vixl::aarch64::Label* CodeGeneratorARM64::NewBakerReadBarrierPatch(uint32_t custom_data) {
+ baker_read_barrier_patches_.emplace_back(custom_data);
+ return &baker_read_barrier_patches_.back().label;
+}
+
vixl::aarch64::Label* CodeGeneratorARM64::NewPcRelativePatch(
const DexFile& dex_file,
uint32_t offset_or_index,
@@ -4612,7 +4711,8 @@
pc_relative_string_patches_.size() +
boot_image_type_patches_.size() +
pc_relative_type_patches_.size() +
- type_bss_entry_patches_.size();
+ type_bss_entry_patches_.size() +
+ baker_read_barrier_patches_.size();
linker_patches->reserve(size);
for (const PcRelativePatchInfo& info : pc_relative_dex_cache_patches_) {
linker_patches->push_back(LinkerPatch::DexCacheArrayPatch(info.label.GetLocation(),
@@ -4646,6 +4746,10 @@
target_type.dex_file,
target_type.type_index.index_));
}
+ for (const BakerReadBarrierPatchInfo& info : baker_read_barrier_patches_) {
+ linker_patches->push_back(LinkerPatch::BakerReadBarrierBranchPatch(info.label.GetLocation(),
+ info.custom_data));
+ }
DCHECK_EQ(size, linker_patches->size());
}
@@ -4758,8 +4862,7 @@
if (cls->GetLoadKind() == HLoadClass::LoadKind::kBssEntry) {
if (!kUseReadBarrier || kUseBakerReadBarrier) {
// Rely on the type resolution or initialization and marking to save everything we need.
- // Note that IP0 may be clobbered by saving/restoring the live register (only one thanks
- // to the custom calling convention) or by marking, so we shall use IP1.
+ locations->AddTemp(FixedTempLocation());
RegisterSet caller_saves = RegisterSet::Empty();
InvokeRuntimeCallingConvention calling_convention;
caller_saves.Add(Location::RegisterLocation(calling_convention.GetRegisterAt(0).GetCode()));
@@ -4836,11 +4939,7 @@
// Add ADRP with its PC-relative Class .bss entry patch.
const DexFile& dex_file = cls->GetDexFile();
dex::TypeIndex type_index = cls->GetTypeIndex();
- // We can go to slow path even with non-zero reference and in that case marking
- // can clobber IP0, so we need to use IP1 which shall be preserved.
- bss_entry_temp = ip1;
- UseScratchRegisterScope temps(codegen_->GetVIXLAssembler());
- temps.Exclude(bss_entry_temp);
+ bss_entry_temp = XRegisterFrom(cls->GetLocations()->GetTemp(0));
bss_entry_adrp_label = codegen_->NewBssEntryTypePatch(dex_file, type_index);
codegen_->EmitAdrpPlaceholder(bss_entry_adrp_label, bss_entry_temp);
// Add LDR with its PC-relative Class patch.
@@ -4947,8 +5046,7 @@
if (load->GetLoadKind() == HLoadString::LoadKind::kBssEntry) {
if (!kUseReadBarrier || kUseBakerReadBarrier) {
// Rely on the pResolveString and marking to save everything we need.
- // Note that IP0 may be clobbered by saving/restoring the live register (only one thanks
- // to the custom calling convention) or by marking, so we shall use IP1.
+ locations->AddTemp(FixedTempLocation());
RegisterSet caller_saves = RegisterSet::Empty();
InvokeRuntimeCallingConvention calling_convention;
caller_saves.Add(Location::RegisterLocation(calling_convention.GetRegisterAt(0).GetCode()));
@@ -4999,11 +5097,7 @@
const DexFile& dex_file = load->GetDexFile();
const dex::StringIndex string_index = load->GetStringIndex();
DCHECK(!codegen_->GetCompilerOptions().IsBootImage());
- // We could use IP0 as the marking shall not clobber IP0 if the reference is null and
- // that's when we need the slow path. But let's not rely on such details and use IP1.
- Register temp = ip1;
- UseScratchRegisterScope temps(codegen_->GetVIXLAssembler());
- temps.Exclude(temp);
+ Register temp = XRegisterFrom(load->GetLocations()->GetTemp(0));
vixl::aarch64::Label* adrp_label = codegen_->NewPcRelativeStringPatch(dex_file, string_index);
codegen_->EmitAdrpPlaceholder(adrp_label, temp);
// Add LDR with its PC-relative String patch.
@@ -5438,7 +5532,7 @@
}
void LocationsBuilderARM64::VisitStaticFieldGet(HStaticFieldGet* instruction) {
- HandleFieldGet(instruction);
+ HandleFieldGet(instruction, instruction->GetFieldInfo());
}
void InstructionCodeGeneratorARM64::VisitStaticFieldGet(HStaticFieldGet* instruction) {
@@ -5747,7 +5841,6 @@
Register out_reg = RegisterFrom(out, type);
if (read_barrier_option == kWithReadBarrier) {
CHECK(kEmitCompilerReadBarrier);
- Register temp_reg = RegisterFrom(maybe_temp, type);
if (kUseBakerReadBarrier) {
// Load with fast path based Baker's read barrier.
// /* HeapReference<Object> */ out = *(out + offset)
@@ -5755,7 +5848,7 @@
out,
out_reg,
offset,
- temp_reg,
+ maybe_temp,
/* needs_null_check */ false,
/* use_load_acquire */ false);
} else {
@@ -5763,6 +5856,7 @@
// Save the value of `out` into `maybe_temp` before overwriting it
// in the following move operation, as we will need it for the
// read barrier below.
+ Register temp_reg = RegisterFrom(maybe_temp, type);
__ Mov(temp_reg, out_reg);
// /* HeapReference<Object> */ out = *(out + offset)
__ Ldr(out_reg, HeapOperand(out_reg, offset));
@@ -5790,13 +5884,12 @@
CHECK(kEmitCompilerReadBarrier);
if (kUseBakerReadBarrier) {
// Load with fast path based Baker's read barrier.
- Register temp_reg = RegisterFrom(maybe_temp, type);
// /* HeapReference<Object> */ out = *(obj + offset)
codegen_->GenerateFieldLoadWithBakerReadBarrier(instruction,
out,
obj_reg,
offset,
- temp_reg,
+ maybe_temp,
/* needs_null_check */ false,
/* use_load_acquire */ false);
} else {
@@ -5827,52 +5920,97 @@
if (kUseBakerReadBarrier) {
// Fast path implementation of art::ReadBarrier::BarrierForRoot when
// Baker's read barrier are used.
- //
- // Note that we do not actually check the value of
- // `GetIsGcMarking()` to decide whether to mark the loaded GC
- // root or not. Instead, we load into `temp` the read barrier
- // mark entry point corresponding to register `root`. If `temp`
- // is null, it means that `GetIsGcMarking()` is false, and vice
- // versa.
- //
- // temp = Thread::Current()->pReadBarrierMarkReg ## root.reg()
- // GcRoot<mirror::Object> root = *(obj+offset); // Original reference load.
- // if (temp != nullptr) { // <=> Thread::Current()->GetIsGcMarking()
- // // Slow path.
- // root = temp(root); // root = ReadBarrier::Mark(root); // Runtime entry point call.
- // }
+ if (kBakerReadBarrierLinkTimeThunksEnableForGcRoots &&
+ !Runtime::Current()->UseJitCompilation()) {
+ // Note that we do not actually check the value of `GetIsGcMarking()`
+ // to decide whether to mark the loaded GC root or not. Instead, we
+ // load into `temp` the read barrier mark introspection entrypoint.
+ // If `temp` is null, it means that `GetIsGcMarking()` is false, and
+ // vice versa.
+ //
+ // We use link-time generated thunks for the slow path. That thunk
+ // checks the reference and jumps to the entrypoint if needed.
+ //
+ // temp = Thread::Current()->pReadBarrierMarkIntrospection
+ // lr = &return_address;
+ // GcRoot<mirror::Object> root = *(obj+offset); // Original reference load.
+ // if (temp != nullptr) {
+ // goto gc_root_thunk<root_reg>(lr)
+ // }
+ // return_address:
- // Slow path marking the GC root `root`. The entrypoint will already be loaded in `temp`.
- Register temp = lr;
- SlowPathCodeARM64* slow_path = new (GetGraph()->GetArena()) ReadBarrierMarkSlowPathARM64(
- instruction, root, /* entrypoint */ LocationFrom(temp));
- codegen_->AddSlowPath(slow_path);
+ UseScratchRegisterScope temps(GetVIXLAssembler());
+ DCHECK(temps.IsAvailable(ip0));
+ DCHECK(temps.IsAvailable(ip1));
+ temps.Exclude(ip0, ip1);
+ uint32_t custom_data =
+ linker::Arm64RelativePatcher::EncodeBakerReadBarrierGcRootData(root_reg.GetCode());
+ vixl::aarch64::Label* cbnz_label = codegen_->NewBakerReadBarrierPatch(custom_data);
- // temp = Thread::Current()->pReadBarrierMarkReg ## root.reg()
- const int32_t entry_point_offset =
- CodeGenerator::GetReadBarrierMarkEntryPointsOffset<kArm64PointerSize>(root.reg());
- // Loading the entrypoint does not require a load acquire since it is only changed when
- // threads are suspended or running a checkpoint.
- __ Ldr(temp, MemOperand(tr, entry_point_offset));
-
- // /* GcRoot<mirror::Object> */ root = *(obj + offset)
- if (fixup_label == nullptr) {
- __ Ldr(root_reg, MemOperand(obj, offset));
+ // ip1 = Thread::Current()->pReadBarrierMarkReg16, i.e. pReadBarrierMarkIntrospection.
+ DCHECK_EQ(ip0.GetCode(), 16u);
+ const int32_t entry_point_offset =
+ CodeGenerator::GetReadBarrierMarkEntryPointsOffset<kArm64PointerSize>(ip0.GetCode());
+ __ Ldr(ip1, MemOperand(tr, entry_point_offset));
+ EmissionCheckScope guard(GetVIXLAssembler(), 3 * vixl::aarch64::kInstructionSize);
+ vixl::aarch64::Label return_address;
+ __ adr(lr, &return_address);
+ if (fixup_label != nullptr) {
+ __ Bind(fixup_label);
+ }
+ static_assert(BAKER_MARK_INTROSPECTION_GC_ROOT_LDR_OFFSET == -8,
+ "GC root LDR must be 2 instruction (8B) before the return address label.");
+ __ ldr(root_reg, MemOperand(obj.X(), offset));
+ __ Bind(cbnz_label);
+ __ cbnz(ip1, static_cast<int64_t>(0)); // Placeholder, patched at link-time.
+ __ Bind(&return_address);
} else {
- codegen_->EmitLdrOffsetPlaceholder(fixup_label, root_reg, obj);
- }
- static_assert(
- sizeof(mirror::CompressedReference<mirror::Object>) == sizeof(GcRoot<mirror::Object>),
- "art::mirror::CompressedReference<mirror::Object> and art::GcRoot<mirror::Object> "
- "have different sizes.");
- static_assert(sizeof(mirror::CompressedReference<mirror::Object>) == sizeof(int32_t),
- "art::mirror::CompressedReference<mirror::Object> and int32_t "
- "have different sizes.");
+ // Note that we do not actually check the value of
+ // `GetIsGcMarking()` to decide whether to mark the loaded GC
+ // root or not. Instead, we load into `temp` the read barrier
+ // mark entry point corresponding to register `root`. If `temp`
+ // is null, it means that `GetIsGcMarking()` is false, and vice
+ // versa.
+ //
+ // temp = Thread::Current()->pReadBarrierMarkReg ## root.reg()
+ // GcRoot<mirror::Object> root = *(obj+offset); // Original reference load.
+ // if (temp != nullptr) { // <=> Thread::Current()->GetIsGcMarking()
+ // // Slow path.
+ // root = temp(root); // root = ReadBarrier::Mark(root); // Runtime entry point call.
+ // }
- // The entrypoint is null when the GC is not marking, this prevents one load compared to
- // checking GetIsGcMarking.
- __ Cbnz(temp, slow_path->GetEntryLabel());
- __ Bind(slow_path->GetExitLabel());
+ // Slow path marking the GC root `root`. The entrypoint will already be loaded in `temp`.
+ Register temp = lr;
+ SlowPathCodeARM64* slow_path = new (GetGraph()->GetArena()) ReadBarrierMarkSlowPathARM64(
+ instruction, root, /* entrypoint */ LocationFrom(temp));
+ codegen_->AddSlowPath(slow_path);
+
+ // temp = Thread::Current()->pReadBarrierMarkReg ## root.reg()
+ const int32_t entry_point_offset =
+ CodeGenerator::GetReadBarrierMarkEntryPointsOffset<kArm64PointerSize>(root.reg());
+ // Loading the entrypoint does not require a load acquire since it is only changed when
+ // threads are suspended or running a checkpoint.
+ __ Ldr(temp, MemOperand(tr, entry_point_offset));
+
+ // /* GcRoot<mirror::Object> */ root = *(obj + offset)
+ if (fixup_label == nullptr) {
+ __ Ldr(root_reg, MemOperand(obj, offset));
+ } else {
+ codegen_->EmitLdrOffsetPlaceholder(fixup_label, root_reg, obj);
+ }
+ static_assert(
+ sizeof(mirror::CompressedReference<mirror::Object>) == sizeof(GcRoot<mirror::Object>),
+ "art::mirror::CompressedReference<mirror::Object> and art::GcRoot<mirror::Object> "
+ "have different sizes.");
+ static_assert(sizeof(mirror::CompressedReference<mirror::Object>) == sizeof(int32_t),
+ "art::mirror::CompressedReference<mirror::Object> and int32_t "
+ "have different sizes.");
+
+ // The entrypoint is null when the GC is not marking, this prevents one load compared to
+ // checking GetIsGcMarking.
+ __ Cbnz(temp, slow_path->GetEntryLabel());
+ __ Bind(slow_path->GetExitLabel());
+ }
} else {
// GC root loaded through a slow path for read barriers other
// than Baker's.
@@ -5902,13 +6040,76 @@
Location ref,
Register obj,
uint32_t offset,
- Register temp,
+ Location maybe_temp,
bool needs_null_check,
bool use_load_acquire) {
DCHECK(kEmitCompilerReadBarrier);
DCHECK(kUseBakerReadBarrier);
+ if (kBakerReadBarrierLinkTimeThunksEnableForFields &&
+ !use_load_acquire &&
+ !Runtime::Current()->UseJitCompilation()) {
+ // Note that we do not actually check the value of `GetIsGcMarking()`
+ // to decide whether to mark the loaded GC root or not. Instead, we
+ // load into `temp` the read barrier mark introspection entrypoint.
+ // If `temp` is null, it means that `GetIsGcMarking()` is false, and
+ // vice versa.
+ //
+ // We use link-time generated thunks for the slow path. That thunk checks
+ // the holder and jumps to the entrypoint if needed. If the holder is not
+ // gray, it creates a fake dependency and returns to the LDR instruction.
+ //
+ // temp = Thread::Current()->pReadBarrierMarkIntrospection
+ // lr = &return_address;
+ // if (temp != nullptr) {
+ // goto field_thunk<holder_reg, base_reg>(lr)
+ // }
+ // not_gray_return_address:
+ // // Original reference load. If the offset is too large to fit
+ // // into LDR, we use an adjusted base register here.
+ // GcRoot<mirror::Object> root = *(obj+offset);
+ // gray_return_address:
+
+ DCHECK_ALIGNED(offset, sizeof(mirror::HeapReference<mirror::Object>));
+ Register base = obj;
+ if (offset >= kReferenceLoadMinFarOffset) {
+ DCHECK(maybe_temp.IsRegister());
+ base = WRegisterFrom(maybe_temp);
+ static_assert(IsPowerOfTwo(kReferenceLoadMinFarOffset), "Expecting a power of 2.");
+ __ Add(base, obj, Operand(offset & ~(kReferenceLoadMinFarOffset - 1u)));
+ offset &= (kReferenceLoadMinFarOffset - 1u);
+ }
+ UseScratchRegisterScope temps(GetVIXLAssembler());
+ DCHECK(temps.IsAvailable(ip0));
+ DCHECK(temps.IsAvailable(ip1));
+ temps.Exclude(ip0, ip1);
+ uint32_t custom_data = linker::Arm64RelativePatcher::EncodeBakerReadBarrierFieldData(
+ base.GetCode(),
+ obj.GetCode());
+ vixl::aarch64::Label* cbnz_label = NewBakerReadBarrierPatch(custom_data);
+
+ // ip1 = Thread::Current()->pReadBarrierMarkReg16, i.e. pReadBarrierMarkIntrospection.
+ DCHECK_EQ(ip0.GetCode(), 16u);
+ const int32_t entry_point_offset =
+ CodeGenerator::GetReadBarrierMarkEntryPointsOffset<kArm64PointerSize>(ip0.GetCode());
+ __ Ldr(ip1, MemOperand(tr, entry_point_offset));
+ EmissionCheckScope guard(GetVIXLAssembler(), 3 * vixl::aarch64::kInstructionSize);
+ vixl::aarch64::Label return_address;
+ __ adr(lr, &return_address);
+ __ Bind(cbnz_label);
+ __ cbnz(ip1, static_cast<int64_t>(0)); // Placeholder, patched at link-time.
+ static_assert(BAKER_MARK_INTROSPECTION_FIELD_LDR_OFFSET == -4,
+ "Field LDR must be 1 instruction (4B) before the return address label.");
+ __ ldr(RegisterFrom(ref, Primitive::kPrimNot), MemOperand(base.X(), offset));
+ if (needs_null_check) {
+ MaybeRecordImplicitNullCheck(instruction);
+ }
+ __ Bind(&return_address);
+ return;
+ }
+
// /* HeapReference<Object> */ ref = *(obj + offset)
+ Register temp = WRegisterFrom(maybe_temp);
Location no_index = Location::NoLocation();
size_t no_scale_factor = 0u;
GenerateReferenceLoadWithBakerReadBarrier(instruction,
diff --git a/compiler/optimizing/code_generator_arm64.h b/compiler/optimizing/code_generator_arm64.h
index 10d8b84..58feea2 100644
--- a/compiler/optimizing/code_generator_arm64.h
+++ b/compiler/optimizing/code_generator_arm64.h
@@ -351,7 +351,7 @@
private:
void HandleBinaryOp(HBinaryOperation* instr);
void HandleFieldSet(HInstruction* instruction);
- void HandleFieldGet(HInstruction* instruction);
+ void HandleFieldGet(HInstruction* instruction, const FieldInfo& field_info);
void HandleInvoke(HInvoke* instr);
void HandleCondition(HCondition* instruction);
void HandleShift(HBinaryOperation* instr);
@@ -412,8 +412,9 @@
}
size_t GetFloatingPointSpillSlotSize() const OVERRIDE {
- // Allocated in D registers, which are word sized.
- return kArm64WordSize;
+ return GetGraph()->HasSIMD()
+ ? 2 * kArm64WordSize // 16 bytes == 2 arm64 words for each spill
+ : 1 * kArm64WordSize; // 8 bytes == 1 arm64 words for each spill
}
uintptr_t GetAddressOf(HBasicBlock* block) OVERRIDE {
@@ -578,6 +579,10 @@
uint32_t element_offset,
vixl::aarch64::Label* adrp_label = nullptr);
+ // Add a new baker read barrier patch and return the label to be bound
+ // before the CBNZ instruction.
+ vixl::aarch64::Label* NewBakerReadBarrierPatch(uint32_t custom_data);
+
vixl::aarch64::Literal<uint32_t>* DeduplicateBootImageStringLiteral(
const DexFile& dex_file,
dex::StringIndex string_index);
@@ -609,7 +614,7 @@
Location ref,
vixl::aarch64::Register obj,
uint32_t offset,
- vixl::aarch64::Register temp,
+ Location maybe_temp,
bool needs_null_check,
bool use_load_acquire);
// Fast path implementation of ReadBarrier::Barrier for a heap
@@ -737,6 +742,13 @@
vixl::aarch64::Label* pc_insn_label;
};
+ struct BakerReadBarrierPatchInfo {
+ explicit BakerReadBarrierPatchInfo(uint32_t data) : label(), custom_data(data) { }
+
+ vixl::aarch64::Label label;
+ uint32_t custom_data;
+ };
+
vixl::aarch64::Label* NewPcRelativePatch(const DexFile& dex_file,
uint32_t offset_or_index,
vixl::aarch64::Label* adrp_label,
@@ -776,6 +788,8 @@
ArenaDeque<PcRelativePatchInfo> pc_relative_type_patches_;
// PC-relative type patch info for kBssEntry.
ArenaDeque<PcRelativePatchInfo> type_bss_entry_patches_;
+ // Baker read barrier patch info.
+ ArenaDeque<BakerReadBarrierPatchInfo> baker_read_barrier_patches_;
// Patches for string literals in JIT compiled code.
StringToLiteralMap jit_string_patches_;
diff --git a/compiler/optimizing/code_generator_arm_vixl.cc b/compiler/optimizing/code_generator_arm_vixl.cc
index cce412b..b6678b0 100644
--- a/compiler/optimizing/code_generator_arm_vixl.cc
+++ b/compiler/optimizing/code_generator_arm_vixl.cc
@@ -3634,8 +3634,8 @@
} else {
DCHECK(in.IsConstant());
DCHECK(in.GetConstant()->IsLongConstant());
- int32_t value = Int32ConstantFrom(in);
- __ Mov(OutputRegister(conversion), value);
+ int64_t value = in.GetConstant()->AsLongConstant()->GetValue();
+ __ Mov(OutputRegister(conversion), static_cast<int32_t>(value));
}
break;
diff --git a/compiler/optimizing/code_generator_mips.cc b/compiler/optimizing/code_generator_mips.cc
index 287891f..aa030b2 100644
--- a/compiler/optimizing/code_generator_mips.cc
+++ b/compiler/optimizing/code_generator_mips.cc
@@ -2509,8 +2509,7 @@
(index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
__ LoadFromOffset(kLoadSignedHalfword, out, obj, offset, null_checker);
} else {
- __ Sll(TMP, index.AsRegister<Register>(), TIMES_2);
- __ Addu(TMP, obj, TMP);
+ __ ShiftAndAdd(TMP, index.AsRegister<Register>(), obj, TIMES_2, TMP);
__ LoadFromOffset(kLoadSignedHalfword, out, TMP, data_offset, null_checker);
}
break;
@@ -2557,13 +2556,11 @@
__ LoadFromOffset(kLoadUnsignedByte, out, TMP, data_offset);
__ B(&done);
__ Bind(&uncompressed_load);
- __ Sll(TMP, index_reg, TIMES_2);
- __ Addu(TMP, obj, TMP);
+ __ ShiftAndAdd(TMP, index_reg, obj, TIMES_2, TMP);
__ LoadFromOffset(kLoadUnsignedHalfword, out, TMP, data_offset);
__ Bind(&done);
} else {
- __ Sll(TMP, index_reg, TIMES_2);
- __ Addu(TMP, obj, TMP);
+ __ ShiftAndAdd(TMP, index_reg, obj, TIMES_2, TMP);
__ LoadFromOffset(kLoadUnsignedHalfword, out, TMP, data_offset, null_checker);
}
}
@@ -2578,8 +2575,7 @@
(index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
__ LoadFromOffset(kLoadWord, out, obj, offset, null_checker);
} else {
- __ Sll(TMP, index.AsRegister<Register>(), TIMES_4);
- __ Addu(TMP, obj, TMP);
+ __ ShiftAndAdd(TMP, index.AsRegister<Register>(), obj, TIMES_4, TMP);
__ LoadFromOffset(kLoadWord, out, TMP, data_offset, null_checker);
}
break;
@@ -2613,8 +2609,7 @@
// reference, if heap poisoning is enabled).
codegen_->MaybeGenerateReadBarrierSlow(instruction, out_loc, out_loc, obj_loc, offset);
} else {
- __ Sll(TMP, index.AsRegister<Register>(), TIMES_4);
- __ Addu(TMP, obj, TMP);
+ __ ShiftAndAdd(TMP, index.AsRegister<Register>(), obj, TIMES_4, TMP);
__ LoadFromOffset(kLoadWord, out, TMP, data_offset, null_checker);
// If read barriers are enabled, emit read barriers other than
// Baker's using a slow path (and also unpoison the loaded
@@ -2637,8 +2632,7 @@
(index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
__ LoadFromOffset(kLoadDoubleword, out, obj, offset, null_checker);
} else {
- __ Sll(TMP, index.AsRegister<Register>(), TIMES_8);
- __ Addu(TMP, obj, TMP);
+ __ ShiftAndAdd(TMP, index.AsRegister<Register>(), obj, TIMES_8, TMP);
__ LoadFromOffset(kLoadDoubleword, out, TMP, data_offset, null_checker);
}
break;
@@ -2651,8 +2645,7 @@
(index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
__ LoadSFromOffset(out, obj, offset, null_checker);
} else {
- __ Sll(TMP, index.AsRegister<Register>(), TIMES_4);
- __ Addu(TMP, obj, TMP);
+ __ ShiftAndAdd(TMP, index.AsRegister<Register>(), obj, TIMES_4, TMP);
__ LoadSFromOffset(out, TMP, data_offset, null_checker);
}
break;
@@ -2665,8 +2658,7 @@
(index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
__ LoadDFromOffset(out, obj, offset, null_checker);
} else {
- __ Sll(TMP, index.AsRegister<Register>(), TIMES_8);
- __ Addu(TMP, obj, TMP);
+ __ ShiftAndAdd(TMP, index.AsRegister<Register>(), obj, TIMES_8, TMP);
__ LoadDFromOffset(out, TMP, data_offset, null_checker);
}
break;
@@ -2779,8 +2771,7 @@
if (index.IsConstant()) {
data_offset += index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2;
} else {
- __ Sll(base_reg, index.AsRegister<Register>(), TIMES_2);
- __ Addu(base_reg, obj, base_reg);
+ __ ShiftAndAdd(base_reg, index.AsRegister<Register>(), obj, TIMES_2, base_reg);
}
if (value_location.IsConstant()) {
int32_t value = CodeGenerator::GetInt32ValueOf(value_location.GetConstant());
@@ -2797,8 +2788,7 @@
if (index.IsConstant()) {
data_offset += index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4;
} else {
- __ Sll(base_reg, index.AsRegister<Register>(), TIMES_4);
- __ Addu(base_reg, obj, base_reg);
+ __ ShiftAndAdd(base_reg, index.AsRegister<Register>(), obj, TIMES_4, base_reg);
}
if (value_location.IsConstant()) {
int32_t value = CodeGenerator::GetInt32ValueOf(value_location.GetConstant());
@@ -2817,8 +2807,7 @@
if (index.IsConstant()) {
data_offset += index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4;
} else {
- __ Sll(base_reg, index.AsRegister<Register>(), TIMES_4);
- __ Addu(base_reg, obj, base_reg);
+ __ ShiftAndAdd(base_reg, index.AsRegister<Register>(), obj, TIMES_4, base_reg);
}
int32_t value = CodeGenerator::GetInt32ValueOf(value_location.GetConstant());
DCHECK_EQ(value, 0);
@@ -2848,8 +2837,7 @@
if (index.IsConstant()) {
data_offset += index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4;
} else {
- __ Sll(base_reg, index.AsRegister<Register>(), TIMES_4);
- __ Addu(base_reg, obj, base_reg);
+ __ ShiftAndAdd(base_reg, index.AsRegister<Register>(), obj, TIMES_4, base_reg);
}
__ StoreToOffset(kStoreWord, value, base_reg, data_offset, null_checker);
__ B(&done);
@@ -2907,8 +2895,7 @@
if (index.IsConstant()) {
data_offset += index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4;
} else {
- __ Sll(base_reg, index.AsRegister<Register>(), TIMES_4);
- __ Addu(base_reg, obj, base_reg);
+ __ ShiftAndAdd(base_reg, index.AsRegister<Register>(), obj, TIMES_4, base_reg);
}
__ StoreToOffset(kStoreWord, source, base_reg, data_offset);
@@ -2933,8 +2920,7 @@
if (index.IsConstant()) {
data_offset += index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8;
} else {
- __ Sll(base_reg, index.AsRegister<Register>(), TIMES_8);
- __ Addu(base_reg, obj, base_reg);
+ __ ShiftAndAdd(base_reg, index.AsRegister<Register>(), obj, TIMES_8, base_reg);
}
if (value_location.IsConstant()) {
int64_t value = CodeGenerator::GetInt64ValueOf(value_location.GetConstant());
@@ -2951,8 +2937,7 @@
if (index.IsConstant()) {
data_offset += index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4;
} else {
- __ Sll(base_reg, index.AsRegister<Register>(), TIMES_4);
- __ Addu(base_reg, obj, base_reg);
+ __ ShiftAndAdd(base_reg, index.AsRegister<Register>(), obj, TIMES_4, base_reg);
}
if (value_location.IsConstant()) {
int32_t value = CodeGenerator::GetInt32ValueOf(value_location.GetConstant());
@@ -2969,8 +2954,7 @@
if (index.IsConstant()) {
data_offset += index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8;
} else {
- __ Sll(base_reg, index.AsRegister<Register>(), TIMES_8);
- __ Addu(base_reg, obj, base_reg);
+ __ ShiftAndAdd(base_reg, index.AsRegister<Register>(), obj, TIMES_8, base_reg);
}
if (value_location.IsConstant()) {
int64_t value = CodeGenerator::GetInt64ValueOf(value_location.GetConstant());
@@ -6351,8 +6335,7 @@
Register index_reg = index.IsRegisterPair()
? index.AsRegisterPairLow<Register>()
: index.AsRegister<Register>();
- __ Sll(TMP, index_reg, scale_factor);
- __ Addu(TMP, obj, TMP);
+ __ ShiftAndAdd(TMP, index_reg, obj, scale_factor, TMP);
__ LoadFromOffset(kLoadWord, ref_reg, TMP, offset);
}
} else {
@@ -8446,8 +8429,7 @@
// We are in the range of the table.
// Load the target address from the jump table, indexing by the value.
__ LoadLabelAddress(AT, constant_area, table->GetLabel());
- __ Sll(TMP, TMP, 2);
- __ Addu(TMP, TMP, AT);
+ __ ShiftAndAdd(TMP, TMP, AT, 2, TMP);
__ Lw(TMP, TMP, 0);
// Compute the absolute target address by adding the table start address
// (the table contains offsets to targets relative to its start).
diff --git a/compiler/optimizing/code_generator_mips64.cc b/compiler/optimizing/code_generator_mips64.cc
index 78b31e9..19250c6 100644
--- a/compiler/optimizing/code_generator_mips64.cc
+++ b/compiler/optimizing/code_generator_mips64.cc
@@ -2059,8 +2059,7 @@
(index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
__ LoadFromOffset(kLoadSignedHalfword, out, obj, offset, null_checker);
} else {
- __ Dsll(TMP, index.AsRegister<GpuRegister>(), TIMES_2);
- __ Daddu(TMP, obj, TMP);
+ __ Dlsa(TMP, index.AsRegister<GpuRegister>(), obj, TIMES_2);
__ LoadFromOffset(kLoadSignedHalfword, out, TMP, data_offset, null_checker);
}
break;
@@ -2107,13 +2106,11 @@
__ LoadFromOffset(kLoadUnsignedByte, out, TMP, data_offset);
__ Bc(&done);
__ Bind(&uncompressed_load);
- __ Dsll(TMP, index_reg, TIMES_2);
- __ Daddu(TMP, obj, TMP);
+ __ Dlsa(TMP, index_reg, obj, TIMES_2);
__ LoadFromOffset(kLoadUnsignedHalfword, out, TMP, data_offset);
__ Bind(&done);
} else {
- __ Dsll(TMP, index_reg, TIMES_2);
- __ Daddu(TMP, obj, TMP);
+ __ Dlsa(TMP, index_reg, obj, TIMES_2);
__ LoadFromOffset(kLoadUnsignedHalfword, out, TMP, data_offset, null_checker);
}
}
@@ -2129,8 +2126,7 @@
(index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
__ LoadFromOffset(load_type, out, obj, offset, null_checker);
} else {
- __ Dsll(TMP, index.AsRegister<GpuRegister>(), TIMES_4);
- __ Daddu(TMP, obj, TMP);
+ __ Dlsa(TMP, index.AsRegister<GpuRegister>(), obj, TIMES_4);
__ LoadFromOffset(load_type, out, TMP, data_offset, null_checker);
}
break;
@@ -2164,8 +2160,7 @@
// reference, if heap poisoning is enabled).
codegen_->MaybeGenerateReadBarrierSlow(instruction, out_loc, out_loc, obj_loc, offset);
} else {
- __ Sll(TMP, index.AsRegister<GpuRegister>(), TIMES_4);
- __ Addu(TMP, obj, TMP);
+ __ Dlsa(TMP, index.AsRegister<GpuRegister>(), obj, TIMES_4);
__ LoadFromOffset(kLoadUnsignedWord, out, TMP, data_offset, null_checker);
// If read barriers are enabled, emit read barriers other than
// Baker's using a slow path (and also unpoison the loaded
@@ -2188,8 +2183,7 @@
(index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
__ LoadFromOffset(kLoadDoubleword, out, obj, offset, null_checker);
} else {
- __ Dsll(TMP, index.AsRegister<GpuRegister>(), TIMES_8);
- __ Daddu(TMP, obj, TMP);
+ __ Dlsa(TMP, index.AsRegister<GpuRegister>(), obj, TIMES_8);
__ LoadFromOffset(kLoadDoubleword, out, TMP, data_offset, null_checker);
}
break;
@@ -2202,8 +2196,7 @@
(index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
__ LoadFpuFromOffset(kLoadWord, out, obj, offset, null_checker);
} else {
- __ Dsll(TMP, index.AsRegister<GpuRegister>(), TIMES_4);
- __ Daddu(TMP, obj, TMP);
+ __ Dlsa(TMP, index.AsRegister<GpuRegister>(), obj, TIMES_4);
__ LoadFpuFromOffset(kLoadWord, out, TMP, data_offset, null_checker);
}
break;
@@ -2216,8 +2209,7 @@
(index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
__ LoadFpuFromOffset(kLoadDoubleword, out, obj, offset, null_checker);
} else {
- __ Dsll(TMP, index.AsRegister<GpuRegister>(), TIMES_8);
- __ Daddu(TMP, obj, TMP);
+ __ Dlsa(TMP, index.AsRegister<GpuRegister>(), obj, TIMES_8);
__ LoadFpuFromOffset(kLoadDoubleword, out, TMP, data_offset, null_checker);
}
break;
@@ -2330,8 +2322,7 @@
if (index.IsConstant()) {
data_offset += index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2;
} else {
- __ Dsll(base_reg, index.AsRegister<GpuRegister>(), TIMES_2);
- __ Daddu(base_reg, obj, base_reg);
+ __ Dlsa(base_reg, index.AsRegister<GpuRegister>(), obj, TIMES_2);
}
if (value_location.IsConstant()) {
int32_t value = CodeGenerator::GetInt32ValueOf(value_location.GetConstant());
@@ -2348,8 +2339,7 @@
if (index.IsConstant()) {
data_offset += index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4;
} else {
- __ Dsll(base_reg, index.AsRegister<GpuRegister>(), TIMES_4);
- __ Daddu(base_reg, obj, base_reg);
+ __ Dlsa(base_reg, index.AsRegister<GpuRegister>(), obj, TIMES_4);
}
if (value_location.IsConstant()) {
int32_t value = CodeGenerator::GetInt32ValueOf(value_location.GetConstant());
@@ -2368,8 +2358,7 @@
if (index.IsConstant()) {
data_offset += index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4;
} else {
- __ Dsll(base_reg, index.AsRegister<GpuRegister>(), TIMES_4);
- __ Daddu(base_reg, obj, base_reg);
+ __ Dlsa(base_reg, index.AsRegister<GpuRegister>(), obj, TIMES_4);
}
int32_t value = CodeGenerator::GetInt32ValueOf(value_location.GetConstant());
DCHECK_EQ(value, 0);
@@ -2399,8 +2388,7 @@
if (index.IsConstant()) {
data_offset += index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4;
} else {
- __ Dsll(base_reg, index.AsRegister<GpuRegister>(), TIMES_4);
- __ Daddu(base_reg, obj, base_reg);
+ __ Dlsa(base_reg, index.AsRegister<GpuRegister>(), obj, TIMES_4);
}
__ StoreToOffset(kStoreWord, value, base_reg, data_offset, null_checker);
__ Bc(&done);
@@ -2458,8 +2446,7 @@
if (index.IsConstant()) {
data_offset += index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4;
} else {
- __ Dsll(base_reg, index.AsRegister<GpuRegister>(), TIMES_4);
- __ Daddu(base_reg, obj, base_reg);
+ __ Dlsa(base_reg, index.AsRegister<GpuRegister>(), obj, TIMES_4);
}
__ StoreToOffset(kStoreWord, source, base_reg, data_offset);
@@ -2484,8 +2471,7 @@
if (index.IsConstant()) {
data_offset += index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8;
} else {
- __ Dsll(base_reg, index.AsRegister<GpuRegister>(), TIMES_8);
- __ Daddu(base_reg, obj, base_reg);
+ __ Dlsa(base_reg, index.AsRegister<GpuRegister>(), obj, TIMES_8);
}
if (value_location.IsConstant()) {
int64_t value = CodeGenerator::GetInt64ValueOf(value_location.GetConstant());
@@ -2502,8 +2488,7 @@
if (index.IsConstant()) {
data_offset += index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4;
} else {
- __ Dsll(base_reg, index.AsRegister<GpuRegister>(), TIMES_4);
- __ Daddu(base_reg, obj, base_reg);
+ __ Dlsa(base_reg, index.AsRegister<GpuRegister>(), obj, TIMES_4);
}
if (value_location.IsConstant()) {
int32_t value = CodeGenerator::GetInt32ValueOf(value_location.GetConstant());
@@ -2520,8 +2505,7 @@
if (index.IsConstant()) {
data_offset += index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8;
} else {
- __ Dsll(base_reg, index.AsRegister<GpuRegister>(), TIMES_8);
- __ Daddu(base_reg, obj, base_reg);
+ __ Dlsa(base_reg, index.AsRegister<GpuRegister>(), obj, TIMES_8);
}
if (value_location.IsConstant()) {
int64_t value = CodeGenerator::GetInt64ValueOf(value_location.GetConstant());
@@ -4447,8 +4431,11 @@
__ LoadFromOffset(kLoadUnsignedWord, ref_reg, obj, computed_offset);
} else {
GpuRegister index_reg = index.AsRegister<GpuRegister>();
- __ Dsll(TMP, index_reg, scale_factor);
- __ Daddu(TMP, obj, TMP);
+ if (scale_factor == TIMES_1) {
+ __ Daddu(TMP, index_reg, obj);
+ } else {
+ __ Dlsa(TMP, index_reg, obj, scale_factor);
+ }
__ LoadFromOffset(kLoadUnsignedWord, ref_reg, TMP, offset);
}
} else {
@@ -6203,8 +6190,7 @@
// We are in the range of the table.
// Load the target address from the jump table, indexing by the value.
__ LoadLabelAddress(AT, table->GetLabel());
- __ Sll(TMP, TMP, 2);
- __ Daddu(TMP, TMP, AT);
+ __ Dlsa(TMP, TMP, AT, 2);
__ Lw(TMP, TMP, 0);
// Compute the absolute target address by adding the table start address
// (the table contains offsets to targets relative to its start).
diff --git a/compiler/optimizing/code_generator_vector_arm64.cc b/compiler/optimizing/code_generator_vector_arm64.cc
index f4874fe..0923920 100644
--- a/compiler/optimizing/code_generator_vector_arm64.cc
+++ b/compiler/optimizing/code_generator_vector_arm64.cc
@@ -22,7 +22,7 @@
namespace art {
namespace arm64 {
-using helpers::DRegisterFrom;
+using helpers::VRegisterFrom;
using helpers::HeapOperand;
using helpers::InputRegisterAt;
using helpers::Int64ConstantFrom;
@@ -38,10 +38,12 @@
case Primitive::kPrimChar:
case Primitive::kPrimShort:
case Primitive::kPrimInt:
+ case Primitive::kPrimLong:
locations->SetInAt(0, Location::RequiresRegister());
locations->SetOut(Location::RequiresFpuRegister());
break;
case Primitive::kPrimFloat:
+ case Primitive::kPrimDouble:
locations->SetInAt(0, Location::RequiresFpuRegister());
locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
break;
@@ -53,25 +55,33 @@
void InstructionCodeGeneratorARM64::VisitVecReplicateScalar(HVecReplicateScalar* instruction) {
LocationSummary* locations = instruction->GetLocations();
- FPRegister dst = DRegisterFrom(locations->Out());
+ VRegister dst = VRegisterFrom(locations->Out());
switch (instruction->GetPackedType()) {
case Primitive::kPrimBoolean:
case Primitive::kPrimByte:
- DCHECK_EQ(8u, instruction->GetVectorLength());
- __ Dup(dst.V8B(), InputRegisterAt(instruction, 0));
+ DCHECK_EQ(16u, instruction->GetVectorLength());
+ __ Dup(dst.V16B(), InputRegisterAt(instruction, 0));
break;
case Primitive::kPrimChar:
case Primitive::kPrimShort:
- DCHECK_EQ(4u, instruction->GetVectorLength());
- __ Dup(dst.V4H(), InputRegisterAt(instruction, 0));
+ DCHECK_EQ(8u, instruction->GetVectorLength());
+ __ Dup(dst.V8H(), InputRegisterAt(instruction, 0));
break;
case Primitive::kPrimInt:
+ DCHECK_EQ(4u, instruction->GetVectorLength());
+ __ Dup(dst.V4S(), InputRegisterAt(instruction, 0));
+ break;
+ case Primitive::kPrimLong:
DCHECK_EQ(2u, instruction->GetVectorLength());
- __ Dup(dst.V2S(), InputRegisterAt(instruction, 0));
+ __ Dup(dst.V2D(), XRegisterFrom(locations->InAt(0)));
break;
case Primitive::kPrimFloat:
+ DCHECK_EQ(4u, instruction->GetVectorLength());
+ __ Dup(dst.V4S(), VRegisterFrom(locations->InAt(0)).V4S(), 0);
+ break;
+ case Primitive::kPrimDouble:
DCHECK_EQ(2u, instruction->GetVectorLength());
- __ Dup(dst.V2S(), DRegisterFrom(locations->InAt(0)).V2S(), 0);
+ __ Dup(dst.V2D(), VRegisterFrom(locations->InAt(0)).V2D(), 0);
break;
default:
LOG(FATAL) << "Unsupported SIMD type";
@@ -109,7 +119,9 @@
case Primitive::kPrimChar:
case Primitive::kPrimShort:
case Primitive::kPrimInt:
+ case Primitive::kPrimLong:
case Primitive::kPrimFloat:
+ case Primitive::kPrimDouble:
locations->SetInAt(0, Location::RequiresFpuRegister());
locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
break;
@@ -125,13 +137,13 @@
void InstructionCodeGeneratorARM64::VisitVecCnv(HVecCnv* instruction) {
LocationSummary* locations = instruction->GetLocations();
- FPRegister src = DRegisterFrom(locations->InAt(0));
- FPRegister dst = DRegisterFrom(locations->Out());
+ VRegister src = VRegisterFrom(locations->InAt(0));
+ VRegister dst = VRegisterFrom(locations->Out());
Primitive::Type from = instruction->GetInputType();
Primitive::Type to = instruction->GetResultType();
if (from == Primitive::kPrimInt && to == Primitive::kPrimFloat) {
- DCHECK_EQ(2u, instruction->GetVectorLength());
- __ Scvtf(dst.V2S(), src.V2S());
+ DCHECK_EQ(4u, instruction->GetVectorLength());
+ __ Scvtf(dst.V4S(), src.V4S());
} else {
LOG(FATAL) << "Unsupported SIMD type";
}
@@ -143,25 +155,33 @@
void InstructionCodeGeneratorARM64::VisitVecNeg(HVecNeg* instruction) {
LocationSummary* locations = instruction->GetLocations();
- FPRegister src = DRegisterFrom(locations->InAt(0));
- FPRegister dst = DRegisterFrom(locations->Out());
+ VRegister src = VRegisterFrom(locations->InAt(0));
+ VRegister dst = VRegisterFrom(locations->Out());
switch (instruction->GetPackedType()) {
case Primitive::kPrimByte:
- DCHECK_EQ(8u, instruction->GetVectorLength());
- __ Neg(dst.V8B(), src.V8B());
+ DCHECK_EQ(16u, instruction->GetVectorLength());
+ __ Neg(dst.V16B(), src.V16B());
break;
case Primitive::kPrimChar:
case Primitive::kPrimShort:
- DCHECK_EQ(4u, instruction->GetVectorLength());
- __ Neg(dst.V4H(), src.V4H());
+ DCHECK_EQ(8u, instruction->GetVectorLength());
+ __ Neg(dst.V8H(), src.V8H());
break;
case Primitive::kPrimInt:
+ DCHECK_EQ(4u, instruction->GetVectorLength());
+ __ Neg(dst.V4S(), src.V4S());
+ break;
+ case Primitive::kPrimLong:
DCHECK_EQ(2u, instruction->GetVectorLength());
- __ Neg(dst.V2S(), src.V2S());
+ __ Neg(dst.V2D(), src.V2D());
break;
case Primitive::kPrimFloat:
+ DCHECK_EQ(4u, instruction->GetVectorLength());
+ __ Fneg(dst.V4S(), src.V4S());
+ break;
+ case Primitive::kPrimDouble:
DCHECK_EQ(2u, instruction->GetVectorLength());
- __ Fneg(dst.V2S(), src.V2S());
+ __ Fneg(dst.V2D(), src.V2D());
break;
default:
LOG(FATAL) << "Unsupported SIMD type";
@@ -175,25 +195,33 @@
void InstructionCodeGeneratorARM64::VisitVecAbs(HVecAbs* instruction) {
LocationSummary* locations = instruction->GetLocations();
- FPRegister src = DRegisterFrom(locations->InAt(0));
- FPRegister dst = DRegisterFrom(locations->Out());
+ VRegister src = VRegisterFrom(locations->InAt(0));
+ VRegister dst = VRegisterFrom(locations->Out());
switch (instruction->GetPackedType()) {
case Primitive::kPrimByte:
- DCHECK_EQ(8u, instruction->GetVectorLength());
- __ Abs(dst.V8B(), src.V8B());
+ DCHECK_EQ(16u, instruction->GetVectorLength());
+ __ Abs(dst.V16B(), src.V16B());
break;
case Primitive::kPrimChar:
case Primitive::kPrimShort:
- DCHECK_EQ(4u, instruction->GetVectorLength());
- __ Abs(dst.V4H(), src.V4H());
+ DCHECK_EQ(8u, instruction->GetVectorLength());
+ __ Abs(dst.V8H(), src.V8H());
break;
case Primitive::kPrimInt:
+ DCHECK_EQ(4u, instruction->GetVectorLength());
+ __ Abs(dst.V4S(), src.V4S());
+ break;
+ case Primitive::kPrimLong:
DCHECK_EQ(2u, instruction->GetVectorLength());
- __ Abs(dst.V2S(), src.V2S());
+ __ Abs(dst.V2D(), src.V2D());
break;
case Primitive::kPrimFloat:
+ DCHECK_EQ(4u, instruction->GetVectorLength());
+ __ Fabs(dst.V4S(), src.V4S());
+ break;
+ case Primitive::kPrimDouble:
DCHECK_EQ(2u, instruction->GetVectorLength());
- __ Fabs(dst.V2S(), src.V2S());
+ __ Fabs(dst.V2D(), src.V2D());
break;
default:
LOG(FATAL) << "Unsupported SIMD type";
@@ -206,19 +234,20 @@
void InstructionCodeGeneratorARM64::VisitVecNot(HVecNot* instruction) {
LocationSummary* locations = instruction->GetLocations();
- FPRegister src = DRegisterFrom(locations->InAt(0));
- FPRegister dst = DRegisterFrom(locations->Out());
+ VRegister src = VRegisterFrom(locations->InAt(0));
+ VRegister dst = VRegisterFrom(locations->Out());
switch (instruction->GetPackedType()) {
case Primitive::kPrimBoolean: // special case boolean-not
- DCHECK_EQ(8u, instruction->GetVectorLength());
- __ Movi(dst.V8B(), 1);
- __ Eor(dst.V8B(), dst.V8B(), src.V8B());
+ DCHECK_EQ(16u, instruction->GetVectorLength());
+ __ Movi(dst.V16B(), 1);
+ __ Eor(dst.V16B(), dst.V16B(), src.V16B());
break;
case Primitive::kPrimByte:
case Primitive::kPrimChar:
case Primitive::kPrimShort:
case Primitive::kPrimInt:
- __ Not(dst.V8B(), src.V8B()); // lanes do not matter
+ case Primitive::kPrimLong:
+ __ Not(dst.V16B(), src.V16B()); // lanes do not matter
break;
default:
LOG(FATAL) << "Unsupported SIMD type";
@@ -235,7 +264,9 @@
case Primitive::kPrimChar:
case Primitive::kPrimShort:
case Primitive::kPrimInt:
+ case Primitive::kPrimLong:
case Primitive::kPrimFloat:
+ case Primitive::kPrimDouble:
locations->SetInAt(0, Location::RequiresFpuRegister());
locations->SetInAt(1, Location::RequiresFpuRegister());
locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
@@ -252,26 +283,34 @@
void InstructionCodeGeneratorARM64::VisitVecAdd(HVecAdd* instruction) {
LocationSummary* locations = instruction->GetLocations();
- FPRegister lhs = DRegisterFrom(locations->InAt(0));
- FPRegister rhs = DRegisterFrom(locations->InAt(1));
- FPRegister dst = DRegisterFrom(locations->Out());
+ VRegister lhs = VRegisterFrom(locations->InAt(0));
+ VRegister rhs = VRegisterFrom(locations->InAt(1));
+ VRegister dst = VRegisterFrom(locations->Out());
switch (instruction->GetPackedType()) {
case Primitive::kPrimByte:
- DCHECK_EQ(8u, instruction->GetVectorLength());
- __ Add(dst.V8B(), lhs.V8B(), rhs.V8B());
+ DCHECK_EQ(16u, instruction->GetVectorLength());
+ __ Add(dst.V16B(), lhs.V16B(), rhs.V16B());
break;
case Primitive::kPrimChar:
case Primitive::kPrimShort:
- DCHECK_EQ(4u, instruction->GetVectorLength());
- __ Add(dst.V4H(), lhs.V4H(), rhs.V4H());
+ DCHECK_EQ(8u, instruction->GetVectorLength());
+ __ Add(dst.V8H(), lhs.V8H(), rhs.V8H());
break;
case Primitive::kPrimInt:
+ DCHECK_EQ(4u, instruction->GetVectorLength());
+ __ Add(dst.V4S(), lhs.V4S(), rhs.V4S());
+ break;
+ case Primitive::kPrimLong:
DCHECK_EQ(2u, instruction->GetVectorLength());
- __ Add(dst.V2S(), lhs.V2S(), rhs.V2S());
+ __ Add(dst.V2D(), lhs.V2D(), rhs.V2D());
break;
case Primitive::kPrimFloat:
+ DCHECK_EQ(4u, instruction->GetVectorLength());
+ __ Fadd(dst.V4S(), lhs.V4S(), rhs.V4S());
+ break;
+ case Primitive::kPrimDouble:
DCHECK_EQ(2u, instruction->GetVectorLength());
- __ Fadd(dst.V2S(), lhs.V2S(), rhs.V2S());
+ __ Fadd(dst.V2D(), lhs.V2D(), rhs.V2D());
break;
default:
LOG(FATAL) << "Unsupported SIMD type";
@@ -285,26 +324,34 @@
void InstructionCodeGeneratorARM64::VisitVecSub(HVecSub* instruction) {
LocationSummary* locations = instruction->GetLocations();
- FPRegister lhs = DRegisterFrom(locations->InAt(0));
- FPRegister rhs = DRegisterFrom(locations->InAt(1));
- FPRegister dst = DRegisterFrom(locations->Out());
+ VRegister lhs = VRegisterFrom(locations->InAt(0));
+ VRegister rhs = VRegisterFrom(locations->InAt(1));
+ VRegister dst = VRegisterFrom(locations->Out());
switch (instruction->GetPackedType()) {
case Primitive::kPrimByte:
- DCHECK_EQ(8u, instruction->GetVectorLength());
- __ Sub(dst.V8B(), lhs.V8B(), rhs.V8B());
+ DCHECK_EQ(16u, instruction->GetVectorLength());
+ __ Sub(dst.V16B(), lhs.V16B(), rhs.V16B());
break;
case Primitive::kPrimChar:
case Primitive::kPrimShort:
- DCHECK_EQ(4u, instruction->GetVectorLength());
- __ Sub(dst.V4H(), lhs.V4H(), rhs.V4H());
+ DCHECK_EQ(8u, instruction->GetVectorLength());
+ __ Sub(dst.V8H(), lhs.V8H(), rhs.V8H());
break;
case Primitive::kPrimInt:
+ DCHECK_EQ(4u, instruction->GetVectorLength());
+ __ Sub(dst.V4S(), lhs.V4S(), rhs.V4S());
+ break;
+ case Primitive::kPrimLong:
DCHECK_EQ(2u, instruction->GetVectorLength());
- __ Sub(dst.V2S(), lhs.V2S(), rhs.V2S());
+ __ Sub(dst.V2D(), lhs.V2D(), rhs.V2D());
break;
case Primitive::kPrimFloat:
+ DCHECK_EQ(4u, instruction->GetVectorLength());
+ __ Fsub(dst.V4S(), lhs.V4S(), rhs.V4S());
+ break;
+ case Primitive::kPrimDouble:
DCHECK_EQ(2u, instruction->GetVectorLength());
- __ Fsub(dst.V2S(), lhs.V2S(), rhs.V2S());
+ __ Fsub(dst.V2D(), lhs.V2D(), rhs.V2D());
break;
default:
LOG(FATAL) << "Unsupported SIMD type";
@@ -318,26 +365,30 @@
void InstructionCodeGeneratorARM64::VisitVecMul(HVecMul* instruction) {
LocationSummary* locations = instruction->GetLocations();
- FPRegister lhs = DRegisterFrom(locations->InAt(0));
- FPRegister rhs = DRegisterFrom(locations->InAt(1));
- FPRegister dst = DRegisterFrom(locations->Out());
+ VRegister lhs = VRegisterFrom(locations->InAt(0));
+ VRegister rhs = VRegisterFrom(locations->InAt(1));
+ VRegister dst = VRegisterFrom(locations->Out());
switch (instruction->GetPackedType()) {
case Primitive::kPrimByte:
- DCHECK_EQ(8u, instruction->GetVectorLength());
- __ Mul(dst.V8B(), lhs.V8B(), rhs.V8B());
+ DCHECK_EQ(16u, instruction->GetVectorLength());
+ __ Mul(dst.V16B(), lhs.V16B(), rhs.V16B());
break;
case Primitive::kPrimChar:
case Primitive::kPrimShort:
- DCHECK_EQ(4u, instruction->GetVectorLength());
- __ Mul(dst.V4H(), lhs.V4H(), rhs.V4H());
+ DCHECK_EQ(8u, instruction->GetVectorLength());
+ __ Mul(dst.V8H(), lhs.V8H(), rhs.V8H());
break;
case Primitive::kPrimInt:
- DCHECK_EQ(2u, instruction->GetVectorLength());
- __ Mul(dst.V2S(), lhs.V2S(), rhs.V2S());
+ DCHECK_EQ(4u, instruction->GetVectorLength());
+ __ Mul(dst.V4S(), lhs.V4S(), rhs.V4S());
break;
case Primitive::kPrimFloat:
+ DCHECK_EQ(4u, instruction->GetVectorLength());
+ __ Fmul(dst.V4S(), lhs.V4S(), rhs.V4S());
+ break;
+ case Primitive::kPrimDouble:
DCHECK_EQ(2u, instruction->GetVectorLength());
- __ Fmul(dst.V2S(), lhs.V2S(), rhs.V2S());
+ __ Fmul(dst.V2D(), lhs.V2D(), rhs.V2D());
break;
default:
LOG(FATAL) << "Unsupported SIMD type";
@@ -351,13 +402,17 @@
void InstructionCodeGeneratorARM64::VisitVecDiv(HVecDiv* instruction) {
LocationSummary* locations = instruction->GetLocations();
- FPRegister lhs = DRegisterFrom(locations->InAt(0));
- FPRegister rhs = DRegisterFrom(locations->InAt(1));
- FPRegister dst = DRegisterFrom(locations->Out());
+ VRegister lhs = VRegisterFrom(locations->InAt(0));
+ VRegister rhs = VRegisterFrom(locations->InAt(1));
+ VRegister dst = VRegisterFrom(locations->Out());
switch (instruction->GetPackedType()) {
case Primitive::kPrimFloat:
+ DCHECK_EQ(4u, instruction->GetVectorLength());
+ __ Fdiv(dst.V4S(), lhs.V4S(), rhs.V4S());
+ break;
+ case Primitive::kPrimDouble:
DCHECK_EQ(2u, instruction->GetVectorLength());
- __ Fdiv(dst.V2S(), lhs.V2S(), rhs.V2S());
+ __ Fdiv(dst.V2D(), lhs.V2D(), rhs.V2D());
break;
default:
LOG(FATAL) << "Unsupported SIMD type";
@@ -371,17 +426,19 @@
void InstructionCodeGeneratorARM64::VisitVecAnd(HVecAnd* instruction) {
LocationSummary* locations = instruction->GetLocations();
- FPRegister lhs = DRegisterFrom(locations->InAt(0));
- FPRegister rhs = DRegisterFrom(locations->InAt(1));
- FPRegister dst = DRegisterFrom(locations->Out());
+ VRegister lhs = VRegisterFrom(locations->InAt(0));
+ VRegister rhs = VRegisterFrom(locations->InAt(1));
+ VRegister dst = VRegisterFrom(locations->Out());
switch (instruction->GetPackedType()) {
case Primitive::kPrimBoolean:
case Primitive::kPrimByte:
case Primitive::kPrimChar:
case Primitive::kPrimShort:
case Primitive::kPrimInt:
+ case Primitive::kPrimLong:
case Primitive::kPrimFloat:
- __ And(dst.V8B(), lhs.V8B(), rhs.V8B()); // lanes do not matter
+ case Primitive::kPrimDouble:
+ __ And(dst.V16B(), lhs.V16B(), rhs.V16B()); // lanes do not matter
break;
default:
LOG(FATAL) << "Unsupported SIMD type";
@@ -403,17 +460,19 @@
void InstructionCodeGeneratorARM64::VisitVecOr(HVecOr* instruction) {
LocationSummary* locations = instruction->GetLocations();
- FPRegister lhs = DRegisterFrom(locations->InAt(0));
- FPRegister rhs = DRegisterFrom(locations->InAt(1));
- FPRegister dst = DRegisterFrom(locations->Out());
+ VRegister lhs = VRegisterFrom(locations->InAt(0));
+ VRegister rhs = VRegisterFrom(locations->InAt(1));
+ VRegister dst = VRegisterFrom(locations->Out());
switch (instruction->GetPackedType()) {
case Primitive::kPrimBoolean:
case Primitive::kPrimByte:
case Primitive::kPrimChar:
case Primitive::kPrimShort:
case Primitive::kPrimInt:
+ case Primitive::kPrimLong:
case Primitive::kPrimFloat:
- __ Orr(dst.V8B(), lhs.V8B(), rhs.V8B()); // lanes do not matter
+ case Primitive::kPrimDouble:
+ __ Orr(dst.V16B(), lhs.V16B(), rhs.V16B()); // lanes do not matter
break;
default:
LOG(FATAL) << "Unsupported SIMD type";
@@ -427,17 +486,19 @@
void InstructionCodeGeneratorARM64::VisitVecXor(HVecXor* instruction) {
LocationSummary* locations = instruction->GetLocations();
- FPRegister lhs = DRegisterFrom(locations->InAt(0));
- FPRegister rhs = DRegisterFrom(locations->InAt(1));
- FPRegister dst = DRegisterFrom(locations->Out());
+ VRegister lhs = VRegisterFrom(locations->InAt(0));
+ VRegister rhs = VRegisterFrom(locations->InAt(1));
+ VRegister dst = VRegisterFrom(locations->Out());
switch (instruction->GetPackedType()) {
case Primitive::kPrimBoolean:
case Primitive::kPrimByte:
case Primitive::kPrimChar:
case Primitive::kPrimShort:
case Primitive::kPrimInt:
+ case Primitive::kPrimLong:
case Primitive::kPrimFloat:
- __ Eor(dst.V8B(), lhs.V8B(), rhs.V8B()); // lanes do not matter
+ case Primitive::kPrimDouble:
+ __ Eor(dst.V16B(), lhs.V16B(), rhs.V16B()); // lanes do not matter
break;
default:
LOG(FATAL) << "Unsupported SIMD type";
@@ -453,6 +514,7 @@
case Primitive::kPrimChar:
case Primitive::kPrimShort:
case Primitive::kPrimInt:
+ case Primitive::kPrimLong:
locations->SetInAt(0, Location::RequiresFpuRegister());
locations->SetInAt(1, Location::ConstantLocation(instruction->InputAt(1)->AsConstant()));
locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
@@ -469,22 +531,26 @@
void InstructionCodeGeneratorARM64::VisitVecShl(HVecShl* instruction) {
LocationSummary* locations = instruction->GetLocations();
- FPRegister lhs = DRegisterFrom(locations->InAt(0));
- FPRegister dst = DRegisterFrom(locations->Out());
+ VRegister lhs = VRegisterFrom(locations->InAt(0));
+ VRegister dst = VRegisterFrom(locations->Out());
int32_t value = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue();
switch (instruction->GetPackedType()) {
case Primitive::kPrimByte:
- DCHECK_EQ(8u, instruction->GetVectorLength());
- __ Shl(dst.V8B(), lhs.V8B(), value);
+ DCHECK_EQ(16u, instruction->GetVectorLength());
+ __ Shl(dst.V16B(), lhs.V16B(), value);
break;
case Primitive::kPrimChar:
case Primitive::kPrimShort:
- DCHECK_EQ(4u, instruction->GetVectorLength());
- __ Shl(dst.V4H(), lhs.V4H(), value);
+ DCHECK_EQ(8u, instruction->GetVectorLength());
+ __ Shl(dst.V8H(), lhs.V8H(), value);
break;
case Primitive::kPrimInt:
+ DCHECK_EQ(4u, instruction->GetVectorLength());
+ __ Shl(dst.V4S(), lhs.V4S(), value);
+ break;
+ case Primitive::kPrimLong:
DCHECK_EQ(2u, instruction->GetVectorLength());
- __ Shl(dst.V2S(), lhs.V2S(), value);
+ __ Shl(dst.V2D(), lhs.V2D(), value);
break;
default:
LOG(FATAL) << "Unsupported SIMD type";
@@ -498,22 +564,26 @@
void InstructionCodeGeneratorARM64::VisitVecShr(HVecShr* instruction) {
LocationSummary* locations = instruction->GetLocations();
- FPRegister lhs = DRegisterFrom(locations->InAt(0));
- FPRegister dst = DRegisterFrom(locations->Out());
+ VRegister lhs = VRegisterFrom(locations->InAt(0));
+ VRegister dst = VRegisterFrom(locations->Out());
int32_t value = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue();
switch (instruction->GetPackedType()) {
case Primitive::kPrimByte:
- DCHECK_EQ(8u, instruction->GetVectorLength());
- __ Sshr(dst.V8B(), lhs.V8B(), value);
+ DCHECK_EQ(16u, instruction->GetVectorLength());
+ __ Sshr(dst.V16B(), lhs.V16B(), value);
break;
case Primitive::kPrimChar:
case Primitive::kPrimShort:
- DCHECK_EQ(4u, instruction->GetVectorLength());
- __ Sshr(dst.V4H(), lhs.V4H(), value);
+ DCHECK_EQ(8u, instruction->GetVectorLength());
+ __ Sshr(dst.V8H(), lhs.V8H(), value);
break;
case Primitive::kPrimInt:
+ DCHECK_EQ(4u, instruction->GetVectorLength());
+ __ Sshr(dst.V4S(), lhs.V4S(), value);
+ break;
+ case Primitive::kPrimLong:
DCHECK_EQ(2u, instruction->GetVectorLength());
- __ Sshr(dst.V2S(), lhs.V2S(), value);
+ __ Sshr(dst.V2D(), lhs.V2D(), value);
break;
default:
LOG(FATAL) << "Unsupported SIMD type";
@@ -527,22 +597,26 @@
void InstructionCodeGeneratorARM64::VisitVecUShr(HVecUShr* instruction) {
LocationSummary* locations = instruction->GetLocations();
- FPRegister lhs = DRegisterFrom(locations->InAt(0));
- FPRegister dst = DRegisterFrom(locations->Out());
+ VRegister lhs = VRegisterFrom(locations->InAt(0));
+ VRegister dst = VRegisterFrom(locations->Out());
int32_t value = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue();
switch (instruction->GetPackedType()) {
case Primitive::kPrimByte:
- DCHECK_EQ(8u, instruction->GetVectorLength());
- __ Ushr(dst.V8B(), lhs.V8B(), value);
+ DCHECK_EQ(16u, instruction->GetVectorLength());
+ __ Ushr(dst.V16B(), lhs.V16B(), value);
break;
case Primitive::kPrimChar:
case Primitive::kPrimShort:
- DCHECK_EQ(4u, instruction->GetVectorLength());
- __ Ushr(dst.V4H(), lhs.V4H(), value);
+ DCHECK_EQ(8u, instruction->GetVectorLength());
+ __ Ushr(dst.V8H(), lhs.V8H(), value);
break;
case Primitive::kPrimInt:
+ DCHECK_EQ(4u, instruction->GetVectorLength());
+ __ Ushr(dst.V4S(), lhs.V4S(), value);
+ break;
+ case Primitive::kPrimLong:
DCHECK_EQ(2u, instruction->GetVectorLength());
- __ Ushr(dst.V2S(), lhs.V2S(), value);
+ __ Ushr(dst.V2D(), lhs.V2D(), value);
break;
default:
LOG(FATAL) << "Unsupported SIMD type";
@@ -561,7 +635,9 @@
case Primitive::kPrimChar:
case Primitive::kPrimShort:
case Primitive::kPrimInt:
+ case Primitive::kPrimLong:
case Primitive::kPrimFloat:
+ case Primitive::kPrimDouble:
locations->SetInAt(0, Location::RequiresRegister());
locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
if (is_load) {
@@ -613,22 +689,27 @@
void InstructionCodeGeneratorARM64::VisitVecLoad(HVecLoad* instruction) {
Location reg_loc = Location::NoLocation();
MemOperand mem = CreateVecMemRegisters(instruction, ®_loc, /*is_load*/ true);
- FPRegister reg = DRegisterFrom(reg_loc);
+ VRegister reg = VRegisterFrom(reg_loc);
switch (instruction->GetPackedType()) {
case Primitive::kPrimBoolean:
case Primitive::kPrimByte:
- DCHECK_EQ(8u, instruction->GetVectorLength());
- __ Ld1(reg.V8B(), mem);
+ DCHECK_EQ(16u, instruction->GetVectorLength());
+ __ Ld1(reg.V16B(), mem);
break;
case Primitive::kPrimChar:
case Primitive::kPrimShort:
- DCHECK_EQ(4u, instruction->GetVectorLength());
- __ Ld1(reg.V4H(), mem);
+ DCHECK_EQ(8u, instruction->GetVectorLength());
+ __ Ld1(reg.V8H(), mem);
break;
case Primitive::kPrimInt:
case Primitive::kPrimFloat:
+ DCHECK_EQ(4u, instruction->GetVectorLength());
+ __ Ld1(reg.V4S(), mem);
+ break;
+ case Primitive::kPrimLong:
+ case Primitive::kPrimDouble:
DCHECK_EQ(2u, instruction->GetVectorLength());
- __ Ld1(reg.V2S(), mem);
+ __ Ld1(reg.V2D(), mem);
break;
default:
LOG(FATAL) << "Unsupported SIMD type";
@@ -643,22 +724,27 @@
void InstructionCodeGeneratorARM64::VisitVecStore(HVecStore* instruction) {
Location reg_loc = Location::NoLocation();
MemOperand mem = CreateVecMemRegisters(instruction, ®_loc, /*is_load*/ false);
- FPRegister reg = DRegisterFrom(reg_loc);
+ VRegister reg = VRegisterFrom(reg_loc);
switch (instruction->GetPackedType()) {
case Primitive::kPrimBoolean:
case Primitive::kPrimByte:
- DCHECK_EQ(8u, instruction->GetVectorLength());
- __ St1(reg.V8B(), mem);
+ DCHECK_EQ(16u, instruction->GetVectorLength());
+ __ St1(reg.V16B(), mem);
break;
case Primitive::kPrimChar:
case Primitive::kPrimShort:
- DCHECK_EQ(4u, instruction->GetVectorLength());
- __ St1(reg.V4H(), mem);
+ DCHECK_EQ(8u, instruction->GetVectorLength());
+ __ St1(reg.V8H(), mem);
break;
case Primitive::kPrimInt:
case Primitive::kPrimFloat:
+ DCHECK_EQ(4u, instruction->GetVectorLength());
+ __ St1(reg.V4S(), mem);
+ break;
+ case Primitive::kPrimLong:
+ case Primitive::kPrimDouble:
DCHECK_EQ(2u, instruction->GetVectorLength());
- __ St1(reg.V2S(), mem);
+ __ St1(reg.V2D(), mem);
break;
default:
LOG(FATAL) << "Unsupported SIMD type";
diff --git a/compiler/optimizing/codegen_test.cc b/compiler/optimizing/codegen_test.cc
index f8bbf68..4ba5c55 100644
--- a/compiler/optimizing/codegen_test.cc
+++ b/compiler/optimizing/codegen_test.cc
@@ -769,6 +769,45 @@
InternalCodeAllocator code_allocator;
codegen.Finalize(&code_allocator);
}
+
+// Check that ParallelMoveResolver works fine for ARM64 for both cases when SIMD is on and off.
+TEST_F(CodegenTest, ARM64ParallelMoveResolverSIMD) {
+ std::unique_ptr<const Arm64InstructionSetFeatures> features(
+ Arm64InstructionSetFeatures::FromCppDefines());
+ ArenaPool pool;
+ ArenaAllocator allocator(&pool);
+ HGraph* graph = CreateGraph(&allocator);
+ arm64::CodeGeneratorARM64 codegen(graph, *features.get(), CompilerOptions());
+
+ codegen.Initialize();
+
+ graph->SetHasSIMD(true);
+ for (int i = 0; i < 2; i++) {
+ HParallelMove* move = new (graph->GetArena()) HParallelMove(graph->GetArena());
+ move->AddMove(Location::SIMDStackSlot(0),
+ Location::SIMDStackSlot(257),
+ Primitive::kPrimDouble,
+ nullptr);
+ move->AddMove(Location::SIMDStackSlot(257),
+ Location::SIMDStackSlot(0),
+ Primitive::kPrimDouble,
+ nullptr);
+ move->AddMove(Location::FpuRegisterLocation(0),
+ Location::FpuRegisterLocation(1),
+ Primitive::kPrimDouble,
+ nullptr);
+ move->AddMove(Location::FpuRegisterLocation(1),
+ Location::FpuRegisterLocation(0),
+ Primitive::kPrimDouble,
+ nullptr);
+ codegen.GetMoveResolver()->EmitNativeCode(move);
+ graph->SetHasSIMD(false);
+ }
+
+ InternalCodeAllocator code_allocator;
+ codegen.Finalize(&code_allocator);
+}
+
#endif
#ifdef ART_ENABLE_CODEGEN_mips
diff --git a/compiler/optimizing/common_arm64.h b/compiler/optimizing/common_arm64.h
index d3f431e..721f74e 100644
--- a/compiler/optimizing/common_arm64.h
+++ b/compiler/optimizing/common_arm64.h
@@ -92,6 +92,16 @@
return vixl::aarch64::FPRegister::GetDRegFromCode(location.reg());
}
+inline vixl::aarch64::FPRegister QRegisterFrom(Location location) {
+ DCHECK(location.IsFpuRegister()) << location;
+ return vixl::aarch64::FPRegister::GetQRegFromCode(location.reg());
+}
+
+inline vixl::aarch64::FPRegister VRegisterFrom(Location location) {
+ DCHECK(location.IsFpuRegister()) << location;
+ return vixl::aarch64::FPRegister::GetVRegFromCode(location.reg());
+}
+
inline vixl::aarch64::FPRegister SRegisterFrom(Location location) {
DCHECK(location.IsFpuRegister()) << location;
return vixl::aarch64::FPRegister::GetSRegFromCode(location.reg());
diff --git a/compiler/optimizing/intrinsics_arm64.cc b/compiler/optimizing/intrinsics_arm64.cc
index 423fd3c..47bcb5d 100644
--- a/compiler/optimizing/intrinsics_arm64.cc
+++ b/compiler/optimizing/intrinsics_arm64.cc
@@ -2507,9 +2507,11 @@
// We use a block to end the scratch scope before the write barrier, thus
// freeing the temporary registers so they can be used in `MarkGCCard`.
UseScratchRegisterScope temps(masm);
+ Location temp3_loc; // Used only for Baker read barrier.
Register temp3;
if (kEmitCompilerReadBarrier && kUseBakerReadBarrier) {
- temp3 = WRegisterFrom(locations->GetTemp(2));
+ temp3_loc = locations->GetTemp(2);
+ temp3 = WRegisterFrom(temp3_loc);
} else {
temp3 = temps.AcquireW();
}
@@ -2527,7 +2529,7 @@
temp1_loc,
src.W(),
class_offset,
- temp2,
+ temp3_loc,
/* needs_null_check */ false,
/* use_load_acquire */ false);
// Bail out if the source is not a non primitive array.
@@ -2536,7 +2538,7 @@
temp1_loc,
temp1,
component_offset,
- temp2,
+ temp3_loc,
/* needs_null_check */ false,
/* use_load_acquire */ false);
__ Cbz(temp1, intrinsic_slow_path->GetEntryLabel());
@@ -2553,7 +2555,7 @@
temp1_loc,
dest.W(),
class_offset,
- temp2,
+ temp3_loc,
/* needs_null_check */ false,
/* use_load_acquire */ false);
@@ -2570,7 +2572,7 @@
temp2_loc,
temp1,
component_offset,
- temp3,
+ temp3_loc,
/* needs_null_check */ false,
/* use_load_acquire */ false);
__ Cbz(temp2, intrinsic_slow_path->GetEntryLabel());
@@ -2589,7 +2591,7 @@
temp2_loc,
src.W(),
class_offset,
- temp3,
+ temp3_loc,
/* needs_null_check */ false,
/* use_load_acquire */ false);
// Note: if heap poisoning is on, we are comparing two unpoisoned references here.
@@ -2603,7 +2605,7 @@
temp1_loc,
temp1,
component_offset,
- temp2,
+ temp3_loc,
/* needs_null_check */ false,
/* use_load_acquire */ false);
// /* HeapReference<Class> */ temp1 = temp1->super_class_
@@ -2687,7 +2689,7 @@
temp1_loc,
src.W(),
class_offset,
- temp2,
+ temp3_loc,
/* needs_null_check */ false,
/* use_load_acquire */ false);
// /* HeapReference<Class> */ temp2 = temp1->component_type_
@@ -2695,7 +2697,7 @@
temp2_loc,
temp1,
component_offset,
- temp3,
+ temp3_loc,
/* needs_null_check */ false,
/* use_load_acquire */ false);
__ Cbz(temp2, intrinsic_slow_path->GetEntryLabel());
@@ -2755,9 +2757,17 @@
// Make sure `tmp` is not IP0, as it is clobbered by
// ReadBarrierMarkRegX entry points in
// ReadBarrierSystemArrayCopySlowPathARM64.
+ DCHECK(temps.IsAvailable(ip0));
temps.Exclude(ip0);
Register tmp = temps.AcquireW();
DCHECK_NE(LocationFrom(tmp).reg(), IP0);
+ // Put IP0 back in the pool so that VIXL has at least one
+ // scratch register available to emit macro-instructions (note
+ // that IP1 is already used for `tmp`). Indeed some
+ // macro-instructions used in GenSystemArrayCopyAddresses
+ // (invoked hereunder) may require a scratch register (for
+ // instance to emit a load with a large constant offset).
+ temps.Include(ip0);
// /* int32_t */ monitor = src->monitor_
__ Ldr(tmp, HeapOperand(src.W(), monitor_offset));
diff --git a/compiler/optimizing/intrinsics_mips.cc b/compiler/optimizing/intrinsics_mips.cc
index b67793c..41df56b 100644
--- a/compiler/optimizing/intrinsics_mips.cc
+++ b/compiler/optimizing/intrinsics_mips.cc
@@ -2701,12 +2701,7 @@
// Calculate destination address.
__ Addiu(dstPtr, dstObj, data_offset);
- if (IsR6()) {
- __ Lsa(dstPtr, dstBegin, dstPtr, char_shift);
- } else {
- __ Sll(AT, dstBegin, char_shift);
- __ Addu(dstPtr, dstPtr, AT);
- }
+ __ ShiftAndAdd(dstPtr, dstBegin, dstPtr, char_shift);
if (mirror::kUseStringCompression) {
MipsLabel uncompressed_copy, compressed_loop;
@@ -2734,12 +2729,7 @@
// Calculate source address.
__ Addiu(srcPtr, srcObj, value_offset);
- if (IsR6()) {
- __ Lsa(srcPtr, srcBegin, srcPtr, char_shift);
- } else {
- __ Sll(AT, srcBegin, char_shift);
- __ Addu(srcPtr, srcPtr, AT);
- }
+ __ ShiftAndAdd(srcPtr, srcBegin, srcPtr, char_shift);
__ Bind(&loop);
__ Lh(AT, srcPtr, 0);
@@ -2752,6 +2742,397 @@
__ Bind(&done);
}
+static void CreateFPToFPCallLocations(ArenaAllocator* arena, HInvoke* invoke) {
+ LocationSummary* locations = new (arena) LocationSummary(invoke,
+ LocationSummary::kCallOnMainOnly,
+ kIntrinsified);
+ InvokeRuntimeCallingConvention calling_convention;
+
+ locations->SetInAt(0, Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(0)));
+ locations->SetOut(calling_convention.GetReturnLocation(Primitive::kPrimDouble));
+}
+
+static void CreateFPFPToFPCallLocations(ArenaAllocator* arena, HInvoke* invoke) {
+ LocationSummary* locations = new (arena) LocationSummary(invoke,
+ LocationSummary::kCallOnMainOnly,
+ kIntrinsified);
+ InvokeRuntimeCallingConvention calling_convention;
+
+ locations->SetInAt(0, Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(0)));
+ locations->SetInAt(1, Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(1)));
+ locations->SetOut(calling_convention.GetReturnLocation(Primitive::kPrimDouble));
+}
+
+static void GenFPToFPCall(HInvoke* invoke, CodeGeneratorMIPS* codegen, QuickEntrypointEnum entry) {
+ LocationSummary* locations = invoke->GetLocations();
+ FRegister in = locations->InAt(0).AsFpuRegister<FRegister>();
+ DCHECK_EQ(in, F12);
+ FRegister out = locations->Out().AsFpuRegister<FRegister>();
+ DCHECK_EQ(out, F0);
+
+ codegen->InvokeRuntime(entry, invoke, invoke->GetDexPc());
+}
+
+static void GenFPFPToFPCall(HInvoke* invoke,
+ CodeGeneratorMIPS* codegen,
+ QuickEntrypointEnum entry) {
+ LocationSummary* locations = invoke->GetLocations();
+ FRegister in0 = locations->InAt(0).AsFpuRegister<FRegister>();
+ DCHECK_EQ(in0, F12);
+ FRegister in1 = locations->InAt(1).AsFpuRegister<FRegister>();
+ DCHECK_EQ(in1, F14);
+ FRegister out = locations->Out().AsFpuRegister<FRegister>();
+ DCHECK_EQ(out, F0);
+
+ codegen->InvokeRuntime(entry, invoke, invoke->GetDexPc());
+}
+
+// static double java.lang.Math.cos(double a)
+void IntrinsicLocationsBuilderMIPS::VisitMathCos(HInvoke* invoke) {
+ CreateFPToFPCallLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorMIPS::VisitMathCos(HInvoke* invoke) {
+ GenFPToFPCall(invoke, codegen_, kQuickCos);
+}
+
+// static double java.lang.Math.sin(double a)
+void IntrinsicLocationsBuilderMIPS::VisitMathSin(HInvoke* invoke) {
+ CreateFPToFPCallLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorMIPS::VisitMathSin(HInvoke* invoke) {
+ GenFPToFPCall(invoke, codegen_, kQuickSin);
+}
+
+// static double java.lang.Math.acos(double a)
+void IntrinsicLocationsBuilderMIPS::VisitMathAcos(HInvoke* invoke) {
+ CreateFPToFPCallLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorMIPS::VisitMathAcos(HInvoke* invoke) {
+ GenFPToFPCall(invoke, codegen_, kQuickAcos);
+}
+
+// static double java.lang.Math.asin(double a)
+void IntrinsicLocationsBuilderMIPS::VisitMathAsin(HInvoke* invoke) {
+ CreateFPToFPCallLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorMIPS::VisitMathAsin(HInvoke* invoke) {
+ GenFPToFPCall(invoke, codegen_, kQuickAsin);
+}
+
+// static double java.lang.Math.atan(double a)
+void IntrinsicLocationsBuilderMIPS::VisitMathAtan(HInvoke* invoke) {
+ CreateFPToFPCallLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorMIPS::VisitMathAtan(HInvoke* invoke) {
+ GenFPToFPCall(invoke, codegen_, kQuickAtan);
+}
+
+// static double java.lang.Math.atan2(double y, double x)
+void IntrinsicLocationsBuilderMIPS::VisitMathAtan2(HInvoke* invoke) {
+ CreateFPFPToFPCallLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorMIPS::VisitMathAtan2(HInvoke* invoke) {
+ GenFPFPToFPCall(invoke, codegen_, kQuickAtan2);
+}
+
+// static double java.lang.Math.cbrt(double a)
+void IntrinsicLocationsBuilderMIPS::VisitMathCbrt(HInvoke* invoke) {
+ CreateFPToFPCallLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorMIPS::VisitMathCbrt(HInvoke* invoke) {
+ GenFPToFPCall(invoke, codegen_, kQuickCbrt);
+}
+
+// static double java.lang.Math.cosh(double x)
+void IntrinsicLocationsBuilderMIPS::VisitMathCosh(HInvoke* invoke) {
+ CreateFPToFPCallLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorMIPS::VisitMathCosh(HInvoke* invoke) {
+ GenFPToFPCall(invoke, codegen_, kQuickCosh);
+}
+
+// static double java.lang.Math.exp(double a)
+void IntrinsicLocationsBuilderMIPS::VisitMathExp(HInvoke* invoke) {
+ CreateFPToFPCallLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorMIPS::VisitMathExp(HInvoke* invoke) {
+ GenFPToFPCall(invoke, codegen_, kQuickExp);
+}
+
+// static double java.lang.Math.expm1(double x)
+void IntrinsicLocationsBuilderMIPS::VisitMathExpm1(HInvoke* invoke) {
+ CreateFPToFPCallLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorMIPS::VisitMathExpm1(HInvoke* invoke) {
+ GenFPToFPCall(invoke, codegen_, kQuickExpm1);
+}
+
+// static double java.lang.Math.hypot(double x, double y)
+void IntrinsicLocationsBuilderMIPS::VisitMathHypot(HInvoke* invoke) {
+ CreateFPFPToFPCallLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorMIPS::VisitMathHypot(HInvoke* invoke) {
+ GenFPFPToFPCall(invoke, codegen_, kQuickHypot);
+}
+
+// static double java.lang.Math.log(double a)
+void IntrinsicLocationsBuilderMIPS::VisitMathLog(HInvoke* invoke) {
+ CreateFPToFPCallLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorMIPS::VisitMathLog(HInvoke* invoke) {
+ GenFPToFPCall(invoke, codegen_, kQuickLog);
+}
+
+// static double java.lang.Math.log10(double x)
+void IntrinsicLocationsBuilderMIPS::VisitMathLog10(HInvoke* invoke) {
+ CreateFPToFPCallLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorMIPS::VisitMathLog10(HInvoke* invoke) {
+ GenFPToFPCall(invoke, codegen_, kQuickLog10);
+}
+
+// static double java.lang.Math.nextAfter(double start, double direction)
+void IntrinsicLocationsBuilderMIPS::VisitMathNextAfter(HInvoke* invoke) {
+ CreateFPFPToFPCallLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorMIPS::VisitMathNextAfter(HInvoke* invoke) {
+ GenFPFPToFPCall(invoke, codegen_, kQuickNextAfter);
+}
+
+// static double java.lang.Math.sinh(double x)
+void IntrinsicLocationsBuilderMIPS::VisitMathSinh(HInvoke* invoke) {
+ CreateFPToFPCallLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorMIPS::VisitMathSinh(HInvoke* invoke) {
+ GenFPToFPCall(invoke, codegen_, kQuickSinh);
+}
+
+// static double java.lang.Math.tan(double a)
+void IntrinsicLocationsBuilderMIPS::VisitMathTan(HInvoke* invoke) {
+ CreateFPToFPCallLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorMIPS::VisitMathTan(HInvoke* invoke) {
+ GenFPToFPCall(invoke, codegen_, kQuickTan);
+}
+
+// static double java.lang.Math.tanh(double x)
+void IntrinsicLocationsBuilderMIPS::VisitMathTanh(HInvoke* invoke) {
+ CreateFPToFPCallLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorMIPS::VisitMathTanh(HInvoke* invoke) {
+ GenFPToFPCall(invoke, codegen_, kQuickTanh);
+}
+
+// static void java.lang.System.arraycopy(Object src, int srcPos,
+// Object dest, int destPos,
+// int length)
+void IntrinsicLocationsBuilderMIPS::VisitSystemArrayCopyChar(HInvoke* invoke) {
+ HIntConstant* src_pos = invoke->InputAt(1)->AsIntConstant();
+ HIntConstant* dest_pos = invoke->InputAt(3)->AsIntConstant();
+ HIntConstant* length = invoke->InputAt(4)->AsIntConstant();
+
+ // As long as we are checking, we might as well check to see if the src and dest
+ // positions are >= 0.
+ if ((src_pos != nullptr && src_pos->GetValue() < 0) ||
+ (dest_pos != nullptr && dest_pos->GetValue() < 0)) {
+ // We will have to fail anyways.
+ return;
+ }
+
+ // And since we are already checking, check the length too.
+ if (length != nullptr) {
+ int32_t len = length->GetValue();
+ if (len < 0) {
+ // Just call as normal.
+ return;
+ }
+ }
+
+ // Okay, it is safe to generate inline code.
+ LocationSummary* locations =
+ new (arena_) LocationSummary(invoke, LocationSummary::kCallOnSlowPath, kIntrinsified);
+ // arraycopy(Object src, int srcPos, Object dest, int destPos, int length).
+ locations->SetInAt(0, Location::RequiresRegister());
+ locations->SetInAt(1, Location::RegisterOrConstant(invoke->InputAt(1)));
+ locations->SetInAt(2, Location::RequiresRegister());
+ locations->SetInAt(3, Location::RegisterOrConstant(invoke->InputAt(3)));
+ locations->SetInAt(4, Location::RegisterOrConstant(invoke->InputAt(4)));
+
+ locations->AddTemp(Location::RequiresRegister());
+ locations->AddTemp(Location::RequiresRegister());
+ locations->AddTemp(Location::RequiresRegister());
+}
+
+// Utility routine to verify that "length(input) - pos >= length"
+static void EnoughItems(MipsAssembler* assembler,
+ Register length_input_minus_pos,
+ Location length,
+ SlowPathCodeMIPS* slow_path) {
+ if (length.IsConstant()) {
+ int32_t length_constant = length.GetConstant()->AsIntConstant()->GetValue();
+
+ if (IsInt<16>(length_constant)) {
+ __ Slti(TMP, length_input_minus_pos, length_constant);
+ __ Bnez(TMP, slow_path->GetEntryLabel());
+ } else {
+ __ LoadConst32(TMP, length_constant);
+ __ Blt(length_input_minus_pos, TMP, slow_path->GetEntryLabel());
+ }
+ } else {
+ __ Blt(length_input_minus_pos, length.AsRegister<Register>(), slow_path->GetEntryLabel());
+ }
+}
+
+static void CheckPosition(MipsAssembler* assembler,
+ Location pos,
+ Register input,
+ Location length,
+ SlowPathCodeMIPS* slow_path,
+ bool length_is_input_length = false) {
+ // Where is the length in the Array?
+ const uint32_t length_offset = mirror::Array::LengthOffset().Uint32Value();
+
+ // Calculate length(input) - pos.
+ if (pos.IsConstant()) {
+ int32_t pos_const = pos.GetConstant()->AsIntConstant()->GetValue();
+ if (pos_const == 0) {
+ if (!length_is_input_length) {
+ // Check that length(input) >= length.
+ __ LoadFromOffset(kLoadWord, AT, input, length_offset);
+ EnoughItems(assembler, AT, length, slow_path);
+ }
+ } else {
+ // Check that (length(input) - pos) >= zero.
+ __ LoadFromOffset(kLoadWord, AT, input, length_offset);
+ DCHECK_GT(pos_const, 0);
+ __ Addiu32(AT, AT, -pos_const, TMP);
+ __ Bltz(AT, slow_path->GetEntryLabel());
+
+ // Verify that (length(input) - pos) >= length.
+ EnoughItems(assembler, AT, length, slow_path);
+ }
+ } else if (length_is_input_length) {
+ // The only way the copy can succeed is if pos is zero.
+ Register pos_reg = pos.AsRegister<Register>();
+ __ Bnez(pos_reg, slow_path->GetEntryLabel());
+ } else {
+ // Verify that pos >= 0.
+ Register pos_reg = pos.AsRegister<Register>();
+ __ Bltz(pos_reg, slow_path->GetEntryLabel());
+
+ // Check that (length(input) - pos) >= zero.
+ __ LoadFromOffset(kLoadWord, AT, input, length_offset);
+ __ Subu(AT, AT, pos_reg);
+ __ Bltz(AT, slow_path->GetEntryLabel());
+
+ // Verify that (length(input) - pos) >= length.
+ EnoughItems(assembler, AT, length, slow_path);
+ }
+}
+
+void IntrinsicCodeGeneratorMIPS::VisitSystemArrayCopyChar(HInvoke* invoke) {
+ MipsAssembler* assembler = GetAssembler();
+ LocationSummary* locations = invoke->GetLocations();
+
+ Register src = locations->InAt(0).AsRegister<Register>();
+ Location src_pos = locations->InAt(1);
+ Register dest = locations->InAt(2).AsRegister<Register>();
+ Location dest_pos = locations->InAt(3);
+ Location length = locations->InAt(4);
+
+ MipsLabel loop;
+
+ Register dest_base = locations->GetTemp(0).AsRegister<Register>();
+ Register src_base = locations->GetTemp(1).AsRegister<Register>();
+ Register count = locations->GetTemp(2).AsRegister<Register>();
+
+ SlowPathCodeMIPS* slow_path = new (GetAllocator()) IntrinsicSlowPathMIPS(invoke);
+ codegen_->AddSlowPath(slow_path);
+
+ // Bail out if the source and destination are the same (to handle overlap).
+ __ Beq(src, dest, slow_path->GetEntryLabel());
+
+ // Bail out if the source is null.
+ __ Beqz(src, slow_path->GetEntryLabel());
+
+ // Bail out if the destination is null.
+ __ Beqz(dest, slow_path->GetEntryLabel());
+
+ // Load length into register for count.
+ if (length.IsConstant()) {
+ __ LoadConst32(count, length.GetConstant()->AsIntConstant()->GetValue());
+ } else {
+ // If the length is negative, bail out.
+ // We have already checked in the LocationsBuilder for the constant case.
+ __ Bltz(length.AsRegister<Register>(), slow_path->GetEntryLabel());
+
+ __ Move(count, length.AsRegister<Register>());
+ }
+
+ // Validity checks: source.
+ CheckPosition(assembler, src_pos, src, Location::RegisterLocation(count), slow_path);
+
+ // Validity checks: dest.
+ CheckPosition(assembler, dest_pos, dest, Location::RegisterLocation(count), slow_path);
+
+ // If count is zero, we're done.
+ __ Beqz(count, slow_path->GetExitLabel());
+
+ // Okay, everything checks out. Finally time to do the copy.
+ // Check assumption that sizeof(Char) is 2 (used in scaling below).
+ const size_t char_size = Primitive::ComponentSize(Primitive::kPrimChar);
+ DCHECK_EQ(char_size, 2u);
+
+ const size_t char_shift = Primitive::ComponentSizeShift(Primitive::kPrimChar);
+
+ const uint32_t data_offset = mirror::Array::DataOffset(char_size).Uint32Value();
+
+ // Calculate source and destination addresses.
+ if (src_pos.IsConstant()) {
+ int32_t src_pos_const = src_pos.GetConstant()->AsIntConstant()->GetValue();
+
+ __ Addiu32(src_base, src, data_offset + char_size * src_pos_const, TMP);
+ } else {
+ __ Addiu32(src_base, src, data_offset, TMP);
+ __ ShiftAndAdd(src_base, src_pos.AsRegister<Register>(), src_base, char_shift);
+ }
+ if (dest_pos.IsConstant()) {
+ int32_t dest_pos_const = dest_pos.GetConstant()->AsIntConstant()->GetValue();
+
+ __ Addiu32(dest_base, dest, data_offset + char_size * dest_pos_const, TMP);
+ } else {
+ __ Addiu32(dest_base, dest, data_offset, TMP);
+ __ ShiftAndAdd(dest_base, dest_pos.AsRegister<Register>(), dest_base, char_shift);
+ }
+
+ __ Bind(&loop);
+ __ Lh(TMP, src_base, 0);
+ __ Addiu(src_base, src_base, char_size);
+ __ Addiu(count, count, -1);
+ __ Sh(TMP, dest_base, 0);
+ __ Addiu(dest_base, dest_base, char_size);
+ __ Bnez(count, &loop);
+
+ __ Bind(slow_path->GetExitLabel());
+}
+
// Unimplemented intrinsics.
UNIMPLEMENTED_INTRINSIC(MIPS, MathCeil)
@@ -2763,27 +3144,8 @@
UNIMPLEMENTED_INTRINSIC(MIPS, UnsafeCASLong)
UNIMPLEMENTED_INTRINSIC(MIPS, ReferenceGetReferent)
-UNIMPLEMENTED_INTRINSIC(MIPS, SystemArrayCopyChar)
UNIMPLEMENTED_INTRINSIC(MIPS, SystemArrayCopy)
-UNIMPLEMENTED_INTRINSIC(MIPS, MathCos)
-UNIMPLEMENTED_INTRINSIC(MIPS, MathSin)
-UNIMPLEMENTED_INTRINSIC(MIPS, MathAcos)
-UNIMPLEMENTED_INTRINSIC(MIPS, MathAsin)
-UNIMPLEMENTED_INTRINSIC(MIPS, MathAtan)
-UNIMPLEMENTED_INTRINSIC(MIPS, MathAtan2)
-UNIMPLEMENTED_INTRINSIC(MIPS, MathCbrt)
-UNIMPLEMENTED_INTRINSIC(MIPS, MathCosh)
-UNIMPLEMENTED_INTRINSIC(MIPS, MathExp)
-UNIMPLEMENTED_INTRINSIC(MIPS, MathExpm1)
-UNIMPLEMENTED_INTRINSIC(MIPS, MathHypot)
-UNIMPLEMENTED_INTRINSIC(MIPS, MathLog)
-UNIMPLEMENTED_INTRINSIC(MIPS, MathLog10)
-UNIMPLEMENTED_INTRINSIC(MIPS, MathNextAfter)
-UNIMPLEMENTED_INTRINSIC(MIPS, MathSinh)
-UNIMPLEMENTED_INTRINSIC(MIPS, MathTan)
-UNIMPLEMENTED_INTRINSIC(MIPS, MathTanh)
-
UNIMPLEMENTED_INTRINSIC(MIPS, StringStringIndexOf);
UNIMPLEMENTED_INTRINSIC(MIPS, StringStringIndexOfAfter);
UNIMPLEMENTED_INTRINSIC(MIPS, StringBufferAppend);
diff --git a/compiler/optimizing/intrinsics_mips64.cc b/compiler/optimizing/intrinsics_mips64.cc
index c2518a7..82d0567 100644
--- a/compiler/optimizing/intrinsics_mips64.cc
+++ b/compiler/optimizing/intrinsics_mips64.cc
@@ -2171,28 +2171,210 @@
GenLowestOneBit(invoke->GetLocations(), Primitive::kPrimLong, GetAssembler());
}
+static void CreateFPToFPCallLocations(ArenaAllocator* arena, HInvoke* invoke) {
+ LocationSummary* locations = new (arena) LocationSummary(invoke,
+ LocationSummary::kCallOnMainOnly,
+ kIntrinsified);
+ InvokeRuntimeCallingConvention calling_convention;
+
+ locations->SetInAt(0, Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(0)));
+ locations->SetOut(calling_convention.GetReturnLocation(Primitive::kPrimDouble));
+}
+
+static void CreateFPFPToFPCallLocations(ArenaAllocator* arena, HInvoke* invoke) {
+ LocationSummary* locations = new (arena) LocationSummary(invoke,
+ LocationSummary::kCallOnMainOnly,
+ kIntrinsified);
+ InvokeRuntimeCallingConvention calling_convention;
+
+ locations->SetInAt(0, Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(0)));
+ locations->SetInAt(1, Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(1)));
+ locations->SetOut(calling_convention.GetReturnLocation(Primitive::kPrimDouble));
+}
+
+static void GenFPToFPCall(HInvoke* invoke,
+ CodeGeneratorMIPS64* codegen,
+ QuickEntrypointEnum entry) {
+ LocationSummary* locations = invoke->GetLocations();
+ FpuRegister in = locations->InAt(0).AsFpuRegister<FpuRegister>();
+ DCHECK_EQ(in, F12);
+ FpuRegister out = locations->Out().AsFpuRegister<FpuRegister>();
+ DCHECK_EQ(out, F0);
+
+ codegen->InvokeRuntime(entry, invoke, invoke->GetDexPc());
+}
+
+static void GenFPFPToFPCall(HInvoke* invoke,
+ CodeGeneratorMIPS64* codegen,
+ QuickEntrypointEnum entry) {
+ LocationSummary* locations = invoke->GetLocations();
+ FpuRegister in0 = locations->InAt(0).AsFpuRegister<FpuRegister>();
+ DCHECK_EQ(in0, F12);
+ FpuRegister in1 = locations->InAt(1).AsFpuRegister<FpuRegister>();
+ DCHECK_EQ(in1, F13);
+ FpuRegister out = locations->Out().AsFpuRegister<FpuRegister>();
+ DCHECK_EQ(out, F0);
+
+ codegen->InvokeRuntime(entry, invoke, invoke->GetDexPc());
+}
+
+// static double java.lang.Math.cos(double a)
+void IntrinsicLocationsBuilderMIPS64::VisitMathCos(HInvoke* invoke) {
+ CreateFPToFPCallLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorMIPS64::VisitMathCos(HInvoke* invoke) {
+ GenFPToFPCall(invoke, codegen_, kQuickCos);
+}
+
+// static double java.lang.Math.sin(double a)
+void IntrinsicLocationsBuilderMIPS64::VisitMathSin(HInvoke* invoke) {
+ CreateFPToFPCallLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorMIPS64::VisitMathSin(HInvoke* invoke) {
+ GenFPToFPCall(invoke, codegen_, kQuickSin);
+}
+
+// static double java.lang.Math.acos(double a)
+void IntrinsicLocationsBuilderMIPS64::VisitMathAcos(HInvoke* invoke) {
+ CreateFPToFPCallLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorMIPS64::VisitMathAcos(HInvoke* invoke) {
+ GenFPToFPCall(invoke, codegen_, kQuickAcos);
+}
+
+// static double java.lang.Math.asin(double a)
+void IntrinsicLocationsBuilderMIPS64::VisitMathAsin(HInvoke* invoke) {
+ CreateFPToFPCallLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorMIPS64::VisitMathAsin(HInvoke* invoke) {
+ GenFPToFPCall(invoke, codegen_, kQuickAsin);
+}
+
+// static double java.lang.Math.atan(double a)
+void IntrinsicLocationsBuilderMIPS64::VisitMathAtan(HInvoke* invoke) {
+ CreateFPToFPCallLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorMIPS64::VisitMathAtan(HInvoke* invoke) {
+ GenFPToFPCall(invoke, codegen_, kQuickAtan);
+}
+
+// static double java.lang.Math.atan2(double y, double x)
+void IntrinsicLocationsBuilderMIPS64::VisitMathAtan2(HInvoke* invoke) {
+ CreateFPFPToFPCallLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorMIPS64::VisitMathAtan2(HInvoke* invoke) {
+ GenFPFPToFPCall(invoke, codegen_, kQuickAtan2);
+}
+
+// static double java.lang.Math.cbrt(double a)
+void IntrinsicLocationsBuilderMIPS64::VisitMathCbrt(HInvoke* invoke) {
+ CreateFPToFPCallLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorMIPS64::VisitMathCbrt(HInvoke* invoke) {
+ GenFPToFPCall(invoke, codegen_, kQuickCbrt);
+}
+
+// static double java.lang.Math.cosh(double x)
+void IntrinsicLocationsBuilderMIPS64::VisitMathCosh(HInvoke* invoke) {
+ CreateFPToFPCallLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorMIPS64::VisitMathCosh(HInvoke* invoke) {
+ GenFPToFPCall(invoke, codegen_, kQuickCosh);
+}
+
+// static double java.lang.Math.exp(double a)
+void IntrinsicLocationsBuilderMIPS64::VisitMathExp(HInvoke* invoke) {
+ CreateFPToFPCallLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorMIPS64::VisitMathExp(HInvoke* invoke) {
+ GenFPToFPCall(invoke, codegen_, kQuickExp);
+}
+
+// static double java.lang.Math.expm1(double x)
+void IntrinsicLocationsBuilderMIPS64::VisitMathExpm1(HInvoke* invoke) {
+ CreateFPToFPCallLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorMIPS64::VisitMathExpm1(HInvoke* invoke) {
+ GenFPToFPCall(invoke, codegen_, kQuickExpm1);
+}
+
+// static double java.lang.Math.hypot(double x, double y)
+void IntrinsicLocationsBuilderMIPS64::VisitMathHypot(HInvoke* invoke) {
+ CreateFPFPToFPCallLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorMIPS64::VisitMathHypot(HInvoke* invoke) {
+ GenFPFPToFPCall(invoke, codegen_, kQuickHypot);
+}
+
+// static double java.lang.Math.log(double a)
+void IntrinsicLocationsBuilderMIPS64::VisitMathLog(HInvoke* invoke) {
+ CreateFPToFPCallLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorMIPS64::VisitMathLog(HInvoke* invoke) {
+ GenFPToFPCall(invoke, codegen_, kQuickLog);
+}
+
+// static double java.lang.Math.log10(double x)
+void IntrinsicLocationsBuilderMIPS64::VisitMathLog10(HInvoke* invoke) {
+ CreateFPToFPCallLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorMIPS64::VisitMathLog10(HInvoke* invoke) {
+ GenFPToFPCall(invoke, codegen_, kQuickLog10);
+}
+
+// static double java.lang.Math.nextAfter(double start, double direction)
+void IntrinsicLocationsBuilderMIPS64::VisitMathNextAfter(HInvoke* invoke) {
+ CreateFPFPToFPCallLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorMIPS64::VisitMathNextAfter(HInvoke* invoke) {
+ GenFPFPToFPCall(invoke, codegen_, kQuickNextAfter);
+}
+
+// static double java.lang.Math.sinh(double x)
+void IntrinsicLocationsBuilderMIPS64::VisitMathSinh(HInvoke* invoke) {
+ CreateFPToFPCallLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorMIPS64::VisitMathSinh(HInvoke* invoke) {
+ GenFPToFPCall(invoke, codegen_, kQuickSinh);
+}
+
+// static double java.lang.Math.tan(double a)
+void IntrinsicLocationsBuilderMIPS64::VisitMathTan(HInvoke* invoke) {
+ CreateFPToFPCallLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorMIPS64::VisitMathTan(HInvoke* invoke) {
+ GenFPToFPCall(invoke, codegen_, kQuickTan);
+}
+
+// static double java.lang.Math.tanh(double x)
+void IntrinsicLocationsBuilderMIPS64::VisitMathTanh(HInvoke* invoke) {
+ CreateFPToFPCallLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorMIPS64::VisitMathTanh(HInvoke* invoke) {
+ GenFPToFPCall(invoke, codegen_, kQuickTanh);
+}
+
UNIMPLEMENTED_INTRINSIC(MIPS64, ReferenceGetReferent)
UNIMPLEMENTED_INTRINSIC(MIPS64, SystemArrayCopyChar)
UNIMPLEMENTED_INTRINSIC(MIPS64, SystemArrayCopy)
-UNIMPLEMENTED_INTRINSIC(MIPS64, MathCos)
-UNIMPLEMENTED_INTRINSIC(MIPS64, MathSin)
-UNIMPLEMENTED_INTRINSIC(MIPS64, MathAcos)
-UNIMPLEMENTED_INTRINSIC(MIPS64, MathAsin)
-UNIMPLEMENTED_INTRINSIC(MIPS64, MathAtan)
-UNIMPLEMENTED_INTRINSIC(MIPS64, MathAtan2)
-UNIMPLEMENTED_INTRINSIC(MIPS64, MathCbrt)
-UNIMPLEMENTED_INTRINSIC(MIPS64, MathCosh)
-UNIMPLEMENTED_INTRINSIC(MIPS64, MathExp)
-UNIMPLEMENTED_INTRINSIC(MIPS64, MathExpm1)
-UNIMPLEMENTED_INTRINSIC(MIPS64, MathHypot)
-UNIMPLEMENTED_INTRINSIC(MIPS64, MathLog)
-UNIMPLEMENTED_INTRINSIC(MIPS64, MathLog10)
-UNIMPLEMENTED_INTRINSIC(MIPS64, MathNextAfter)
-UNIMPLEMENTED_INTRINSIC(MIPS64, MathSinh)
-UNIMPLEMENTED_INTRINSIC(MIPS64, MathTan)
-UNIMPLEMENTED_INTRINSIC(MIPS64, MathTanh)
-
UNIMPLEMENTED_INTRINSIC(MIPS64, StringStringIndexOf);
UNIMPLEMENTED_INTRINSIC(MIPS64, StringStringIndexOfAfter);
UNIMPLEMENTED_INTRINSIC(MIPS64, StringBufferAppend);
diff --git a/compiler/optimizing/loop_optimization.cc b/compiler/optimizing/loop_optimization.cc
index 8eeff1f..8e88c1e 100644
--- a/compiler/optimizing/loop_optimization.cc
+++ b/compiler/optimizing/loop_optimization.cc
@@ -623,6 +623,12 @@
}
return true;
} else if (instruction->IsArrayGet()) {
+ // Strings are different, with a different offset to the actual data
+ // and some compressed to save memory. For now, all cases are rejected
+ // to avoid the complexity.
+ if (instruction->AsArrayGet()->IsStringCharAt()) {
+ return false;
+ }
// Accept a right-hand-side array base[index] for
// (1) exact matching vector type,
// (2) loop-invariant base,
@@ -770,21 +776,25 @@
return false;
case kArm64:
// Allow vectorization for all ARM devices, because Android assumes that
- // ARMv8 AArch64 always supports advanced SIMD. For now, only D registers
- // (64-bit vectors) not Q registers (128-bit vectors).
+ // ARMv8 AArch64 always supports advanced SIMD.
switch (type) {
case Primitive::kPrimBoolean:
case Primitive::kPrimByte:
*restrictions |= kNoDiv | kNoAbs;
- return TrySetVectorLength(8);
+ return TrySetVectorLength(16);
case Primitive::kPrimChar:
case Primitive::kPrimShort:
*restrictions |= kNoDiv | kNoAbs;
- return TrySetVectorLength(4);
+ return TrySetVectorLength(8);
case Primitive::kPrimInt:
*restrictions |= kNoDiv;
+ return TrySetVectorLength(4);
+ case Primitive::kPrimLong:
+ *restrictions |= kNoDiv | kNoMul;
return TrySetVectorLength(2);
case Primitive::kPrimFloat:
+ return TrySetVectorLength(4);
+ case Primitive::kPrimDouble:
return TrySetVectorLength(2);
default:
return false;
@@ -1072,7 +1082,10 @@
HInstruction* s = block->GetFirstInstruction();
if (s != nullptr && s->IsSuspendCheck()) {
HInstruction* c = s->GetNext();
- if (c != nullptr && c->IsCondition() && c->GetUses().HasExactlyOneElement()) {
+ if (c != nullptr &&
+ c->IsCondition() &&
+ c->GetUses().HasExactlyOneElement() && // only used for termination
+ !c->HasEnvironmentUses()) { // unlikely, but not impossible
HInstruction* i = c->GetNext();
if (i != nullptr && i->IsIf() && i->InputAt(0) == c) {
iset_->insert(c);
diff --git a/compiler/utils/mips/assembler_mips.cc b/compiler/utils/mips/assembler_mips.cc
index 2e2231b..a99d02d 100644
--- a/compiler/utils/mips/assembler_mips.cc
+++ b/compiler/utils/mips/assembler_mips.cc
@@ -635,6 +635,7 @@
DsFsmInstrRrr(EmitR(0x1f, rt, rd, static_cast<Register>(pos + size - 1), pos, 0x04), rd, rd, rt);
}
+// TODO: This instruction is available in both R6 and MSA and it should be used when available.
void MipsAssembler::Lsa(Register rd, Register rs, Register rt, int saPlusOne) {
CHECK(IsR6());
CHECK(1 <= saPlusOne && saPlusOne <= 4) << saPlusOne;
@@ -642,6 +643,24 @@
DsFsmInstrRrr(EmitR(0x0, rs, rt, rd, sa, 0x05), rd, rs, rt);
}
+void MipsAssembler::ShiftAndAdd(Register dst,
+ Register src_idx,
+ Register src_base,
+ int shamt,
+ Register tmp) {
+ CHECK(0 <= shamt && shamt <= 4) << shamt;
+ CHECK_NE(src_base, tmp);
+ if (shamt == TIMES_1) {
+ // Catch the special case where the shift amount is zero (0).
+ Addu(dst, src_base, src_idx);
+ } else if (IsR6()) {
+ Lsa(dst, src_idx, src_base, shamt);
+ } else {
+ Sll(tmp, src_idx, shamt);
+ Addu(dst, src_base, tmp);
+ }
+}
+
void MipsAssembler::Lb(Register rt, Register rs, uint16_t imm16) {
DsFsmInstrRrr(EmitI(0x20, rs, rt, imm16), rt, rs, rs);
}
diff --git a/compiler/utils/mips/assembler_mips.h b/compiler/utils/mips/assembler_mips.h
index 1a5a23d..463daeb 100644
--- a/compiler/utils/mips/assembler_mips.h
+++ b/compiler/utils/mips/assembler_mips.h
@@ -263,6 +263,7 @@
void Ext(Register rd, Register rt, int pos, int size); // R2+
void Ins(Register rd, Register rt, int pos, int size); // R2+
void Lsa(Register rd, Register rs, Register rt, int saPlusOne); // R6
+ void ShiftAndAdd(Register dst, Register src_idx, Register src_base, int shamt, Register tmp = AT);
void Lb(Register rt, Register rs, uint16_t imm16);
void Lh(Register rt, Register rs, uint16_t imm16);
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index b4ea20b..81566c4 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -2931,7 +2931,7 @@
// time (bug 10645725) unless we're a debug build or running on valgrind. Note: The Dex2Oat class
// should not destruct the runtime in this case.
if (!art::kIsDebugBuild && (RUNNING_ON_MEMORY_TOOL == 0)) {
- exit(result);
+ _exit(result);
}
return result;
}
diff --git a/dexlayout/Android.bp b/dexlayout/Android.bp
index e26d051..4b65c52 100644
--- a/dexlayout/Android.bp
+++ b/dexlayout/Android.bp
@@ -14,6 +14,7 @@
art_cc_defaults {
name: "libart-dexlayout-defaults",
+ defaults: ["art_defaults"],
host_supported: true,
srcs: [
"dexlayout.cc",
diff --git a/dexlayout/dex_ir.cc b/dexlayout/dex_ir.cc
index 4905b5c..6bd9da8 100644
--- a/dexlayout/dex_ir.cc
+++ b/dexlayout/dex_ir.cc
@@ -496,8 +496,8 @@
dex_file.GetClassAnnotationSet(disk_annotations_item);
AnnotationSetItem* class_annotation = nullptr;
if (class_set_item != nullptr) {
- uint32_t offset = disk_annotations_item->class_annotations_off_;
- class_annotation = CreateAnnotationSetItem(dex_file, class_set_item, offset);
+ uint32_t item_offset = disk_annotations_item->class_annotations_off_;
+ class_annotation = CreateAnnotationSetItem(dex_file, class_set_item, item_offset);
}
const DexFile::FieldAnnotationsItem* fields =
dex_file.GetFieldAnnotations(disk_annotations_item);
@@ -784,7 +784,7 @@
std::function<uint32_t(const dex_ir::Collections&)> offset_fn;
};
-static const std::vector<FileSectionDescriptor> kFileSectionDescriptors = {
+static const FileSectionDescriptor kFileSectionDescriptors[] = {
{
"Header",
DexFile::kDexTypeHeaderItem,
diff --git a/dexlayout/dexdiag.cc b/dexlayout/dexdiag.cc
index 3edf051..688201b 100644
--- a/dexlayout/dexdiag.cc
+++ b/dexlayout/dexdiag.cc
@@ -21,9 +21,12 @@
#include <iostream>
#include <memory>
+#include <vector>
#include "android-base/stringprintf.h"
+#include "base/stringpiece.h"
+
#include "dex_file.h"
#include "dex_ir.h"
#include "dex_ir_builder.h"
@@ -37,9 +40,13 @@
static constexpr size_t kLineLength = 32;
-static bool g_show_key = false;
static bool g_verbose = false;
-static bool g_show_statistics = false;
+
+// The width needed to print a file page offset (32-bit).
+static constexpr int kPageCountWidth =
+ static_cast<int>(std::numeric_limits<uint32_t>::digits10);
+// Display the sections.
+static constexpr char kSectionHeader[] = "Section name";
struct DexSectionInfo {
public:
@@ -88,12 +95,73 @@
DISALLOW_COPY_AND_ASSIGN(PageCount);
};
-static void PrintLetterKey() {
- std::cout << "letter section_type" << std::endl;
- for (const auto& p : kDexSectionInfoMap) {
- const DexSectionInfo& section_info = p.second;
- std::cout << section_info.letter << " " << section_info.name.c_str() << std::endl;
+class Printer {
+ public:
+ Printer() : section_header_width_(ComputeHeaderWidth()) {
}
+
+ void PrintHeader() const {
+ std::cout << StringPrintf("%-*s %*s %*s %% of %% of",
+ section_header_width_,
+ kSectionHeader,
+ kPageCountWidth,
+ "resident",
+ kPageCountWidth,
+ "total"
+ )
+ << std::endl;
+ std::cout << StringPrintf("%-*s %*s %*s sect. total",
+ section_header_width_,
+ "",
+ kPageCountWidth,
+ "pages",
+ kPageCountWidth,
+ "pages")
+ << std::endl;
+ }
+
+ void PrintOne(const char* name,
+ size_t resident,
+ size_t mapped,
+ double percent_of_section,
+ double percent_of_total) const {
+ // 6.2 is sufficient to print 0-100% with two decimal places of accuracy.
+ std::cout << StringPrintf("%-*s %*zd %*zd %6.2f %6.2f",
+ section_header_width_,
+ name,
+ kPageCountWidth,
+ resident,
+ kPageCountWidth,
+ mapped,
+ percent_of_section,
+ percent_of_total)
+ << std::endl;
+ }
+
+ void PrintSkipLine() const { std::cout << std::endl; }
+
+ // Computes the width of the section header column in the table (for fixed formatting).
+ static int ComputeHeaderWidth() {
+ int header_width = 0;
+ for (const auto& pair : kDexSectionInfoMap) {
+ const DexSectionInfo& section_info = pair.second;
+ header_width = std::max(header_width, static_cast<int>(section_info.name.length()));
+ }
+ return header_width;
+ }
+
+ private:
+ const int section_header_width_;
+};
+
+static void PrintLetterKey() {
+ std::cout << "L pagetype" << std::endl;
+ for (const auto& pair : kDexSectionInfoMap) {
+ const DexSectionInfo& section_info = pair.second;
+ std::cout << section_info.letter << " " << section_info.name.c_str() << std::endl;
+ }
+ std::cout << "* (Executable page resident)" << std::endl;
+ std::cout << ". (Mapped page not resident)" << std::endl;
}
static char PageTypeChar(uint16_t type) {
@@ -150,7 +218,8 @@
static void DisplayDexStatistics(size_t start,
size_t end,
const PageCount& resident_pages,
- const std::vector<dex_ir::DexFileSection>& sections) {
+ const std::vector<dex_ir::DexFileSection>& sections,
+ Printer* printer) {
// Compute the total possible sizes for sections.
PageCount mapped_pages;
DCHECK_GE(end, start);
@@ -162,34 +231,7 @@
mapped_pages.Increment(FindSectionTypeForPage(page, sections));
}
size_t total_resident_pages = 0;
- // Compute the width of the section header column in the table (for fixed formatting).
- int section_header_width = 0;
- for (const auto& section_info : kDexSectionInfoMap) {
- section_header_width = std::max(section_header_width,
- static_cast<int>(section_info.second.name.length()));
- }
- // The width needed to print a file page offset (32-bit).
- static constexpr int kPageCountWidth =
- static_cast<int>(std::numeric_limits<uint32_t>::digits10);
- // Display the sections.
- static constexpr char kSectionHeader[] = "Section name";
- std::cout << StringPrintf("%-*s %*s %*s %% of %% of",
- section_header_width,
- kSectionHeader,
- kPageCountWidth,
- "resident",
- kPageCountWidth,
- "total"
- )
- << std::endl;
- std::cout << StringPrintf("%-*s %*s %*s sect. total",
- section_header_width,
- "",
- kPageCountWidth,
- "pages",
- kPageCountWidth,
- "pages")
- << std::endl;
+ printer->PrintHeader();
for (size_t i = sections.size(); i > 0; --i) {
const dex_ir::DexFileSection& section = sections[i - 1];
const uint16_t type = section.type;
@@ -199,35 +241,27 @@
if (mapped_pages.Get(type) > 0) {
percent_resident = 100.0 * pages_resident / mapped_pages.Get(type);
}
- // 6.2 is sufficient to print 0-100% with two decimal places of accuracy.
- std::cout << StringPrintf("%-*s %*zd %*zd %6.2f %6.2f",
- section_header_width,
- section_info.name.c_str(),
- kPageCountWidth,
- pages_resident,
- kPageCountWidth,
- mapped_pages.Get(type),
- percent_resident,
- 100.0 * pages_resident / total_mapped_pages)
- << std::endl;
+ printer->PrintOne(section_info.name.c_str(),
+ pages_resident,
+ mapped_pages.Get(type),
+ percent_resident,
+ 100.0 * pages_resident / total_mapped_pages);
total_resident_pages += pages_resident;
}
- std::cout << StringPrintf("%-*s %*zd %*zd %6.2f",
- section_header_width,
- "GRAND TOTAL",
- kPageCountWidth,
- total_resident_pages,
- kPageCountWidth,
- total_mapped_pages,
- 100.0 * total_resident_pages / total_mapped_pages)
- << std::endl
- << std::endl;
+ double percent_of_total = 100.0 * total_resident_pages / total_mapped_pages;
+ printer->PrintOne("GRAND TOTAL",
+ total_resident_pages,
+ total_mapped_pages,
+ percent_of_total,
+ percent_of_total);
+ printer->PrintSkipLine();
}
static void ProcessOneDexMapping(uint64_t* pagemap,
uint64_t map_start,
const DexFile* dex_file,
- uint64_t vdex_start) {
+ uint64_t vdex_start,
+ Printer* printer) {
uint64_t dex_file_start = reinterpret_cast<uint64_t>(dex_file->Begin());
size_t dex_file_size = dex_file->Size();
if (dex_file_start < vdex_start) {
@@ -256,12 +290,10 @@
}
PageCount section_resident_pages;
ProcessPageMap(pagemap, start_page, end_page, sections, §ion_resident_pages);
- if (g_show_statistics) {
- DisplayDexStatistics(start_page, end_page, section_resident_pages, sections);
- }
+ DisplayDexStatistics(start_page, end_page, section_resident_pages, sections, printer);
}
-static bool DisplayMappingIfFromVdexFile(pm_map_t* map) {
+static bool DisplayMappingIfFromVdexFile(pm_map_t* map, Printer* printer) {
// Confirm that the map is from a vdex file.
static const char* suffixes[] = { ".vdex" };
std::string vdex_name;
@@ -284,9 +316,9 @@
&error_msg /*out*/));
if (vdex == nullptr) {
std::cerr << "Could not open vdex file "
- << vdex_name.c_str()
+ << vdex_name
<< ": error "
- << error_msg.c_str()
+ << error_msg
<< std::endl;
return false;
}
@@ -294,9 +326,9 @@
std::vector<std::unique_ptr<const DexFile>> dex_files;
if (!vdex->OpenAllDexFiles(&dex_files, &error_msg)) {
std::cerr << "Dex files could not be opened for "
- << vdex_name.c_str()
+ << vdex_name
<< ": error "
- << error_msg.c_str()
+ << error_msg
<< std::endl;
}
// Open the page mapping (one uint64_t per page) for the entire vdex mapping.
@@ -315,18 +347,91 @@
ProcessOneDexMapping(pagemap,
pm_map_start(map),
dex_file.get(),
- reinterpret_cast<uint64_t>(vdex->Begin()));
+ reinterpret_cast<uint64_t>(vdex->Begin()),
+ printer);
}
free(pagemap);
return true;
}
+static void ProcessOneOatMapping(uint64_t* pagemap, size_t size, Printer* printer) {
+ size_t resident_page_count = 0;
+ for (size_t page = 0; page < size; ++page) {
+ char type_char = '.';
+ if (PM_PAGEMAP_PRESENT(pagemap[page])) {
+ ++resident_page_count;
+ type_char = '*';
+ }
+ if (g_verbose) {
+ std::cout << type_char;
+ if (page % kLineLength == kLineLength - 1) {
+ std::cout << std::endl;
+ }
+ }
+ }
+ if (g_verbose) {
+ if (size % kLineLength != 0) {
+ std::cout << std::endl;
+ }
+ }
+ double percent_of_total = 100.0 * resident_page_count / size;
+ printer->PrintHeader();
+ printer->PrintOne("EXECUTABLE", resident_page_count, size, percent_of_total, percent_of_total);
+ printer->PrintSkipLine();
+}
+
+static bool DisplayMappingIfFromOatFile(pm_map_t* map, Printer* printer) {
+ // Confirm that the map is from a vdex file.
+ static const char* suffixes[] = { ".odex", ".oat" };
+ std::string vdex_name;
+ bool found = false;
+ for (size_t j = 0; j < sizeof(suffixes) / sizeof(suffixes[0]); ++j) {
+ if (strstr(pm_map_name(map), suffixes[j]) != nullptr) {
+ vdex_name = pm_map_name(map);
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ return true;
+ }
+ // Open the page mapping (one uint64_t per page) for the entire vdex mapping.
+ uint64_t* pagemap;
+ size_t len;
+ if (pm_map_pagemap(map, &pagemap, &len) != 0) {
+ std::cerr << "Error creating pagemap." << std::endl;
+ return false;
+ }
+ // Process the dex files.
+ std::cout << "MAPPING "
+ << pm_map_name(map)
+ << StringPrintf(": %zx-%zx", pm_map_start(map), pm_map_end(map))
+ << std::endl;
+ ProcessOneOatMapping(pagemap, len, printer);
+ free(pagemap);
+ return true;
+}
+
+static bool FilterByNameContains(const std::string& mapped_file_name,
+ const std::vector<std::string>& name_filters) {
+ // If no filters were set, everything matches.
+ if (name_filters.empty()) {
+ return true;
+ }
+ for (const auto& name_contains : name_filters) {
+ if (mapped_file_name.find(name_contains) != std::string::npos) {
+ return true;
+ }
+ }
+ return false;
+}
static void Usage(const char* cmd) {
- std::cerr << "Usage: " << cmd << " [-k] [-s] [-v] pid" << std::endl
- << " -k Shows a key to verbose display characters." << std::endl
- << " -s Shows section statistics for individual dex files." << std::endl
- << " -v Verbosely displays resident pages for dex files." << std::endl;
+ std::cerr << "Usage: " << cmd << " [options] pid" << std::endl
+ << " --contains=<string>: Display sections containing string." << std::endl
+ << " --help: Shows this message." << std::endl
+ << " --verbose: Makes displays verbose." << std::endl;
+ PrintLetterKey();
}
static int DexDiagMain(int argc, char* argv[]) {
@@ -335,14 +440,18 @@
return EXIT_FAILURE;
}
+ std::vector<std::string> name_filters;
// TODO: add option to track usage by class name, etc.
for (int i = 1; i < argc - 1; ++i) {
- if (strcmp(argv[i], "-k") == 0) {
- g_show_key = true;
- } else if (strcmp(argv[i], "-s") == 0) {
- g_show_statistics = true;
- } else if (strcmp(argv[i], "-v") == 0) {
+ const StringPiece option(argv[i]);
+ if (option == "--help") {
+ Usage(argv[0]);
+ return EXIT_SUCCESS;
+ } else if (option == "--verbose") {
g_verbose = true;
+ } else if (option.starts_with("--contains=")) {
+ std::string contains(option.substr(strlen("--contains=")).data());
+ name_filters.push_back(contains);
} else {
Usage(argv[0]);
return EXIT_FAILURE;
@@ -387,16 +496,21 @@
}
// Process the mappings that are due to DEX files.
+ Printer printer;
for (size_t i = 0; i < num_maps; ++i) {
- if (!DisplayMappingIfFromVdexFile(maps[i])) {
+ std::string mapped_file_name = pm_map_name(maps[i]);
+ // Filter by name contains options (if any).
+ if (!FilterByNameContains(mapped_file_name, name_filters)) {
+ continue;
+ }
+ if (!DisplayMappingIfFromVdexFile(maps[i], &printer)) {
+ return EXIT_FAILURE;
+ } else if (!DisplayMappingIfFromOatFile(maps[i], &printer)) {
return EXIT_FAILURE;
}
}
- if (g_show_key) {
- PrintLetterKey();
- }
- return 0;
+ return EXIT_SUCCESS;
}
} // namespace art
diff --git a/dexlayout/dexlayout.cc b/dexlayout/dexlayout.cc
index 0536f322..344d735 100644
--- a/dexlayout/dexlayout.cc
+++ b/dexlayout/dexlayout.cc
@@ -393,6 +393,7 @@
index = dec_insn->VRegB();
secondary_index = dec_insn->VRegH();
width = 4;
+ break;
default:
break;
} // switch
@@ -1816,7 +1817,15 @@
output_location += "/" + dex_file_location + ".new";
}
new_file.reset(OS::CreateEmptyFile(output_location.c_str()));
- ftruncate(new_file->Fd(), header_->FileSize());
+ if (new_file == nullptr) {
+ LOG(ERROR) << "Could not create dex writer output file: " << output_location;
+ return;
+ }
+ if (ftruncate(new_file->Fd(), header_->FileSize()) != 0) {
+ LOG(ERROR) << "Could not grow dex writer output file: " << output_location;;
+ new_file->Erase();
+ return;
+ }
mem_map_.reset(MemMap::MapFile(header_->FileSize(), PROT_READ | PROT_WRITE, MAP_SHARED,
new_file->Fd(), 0, /*low_4gb*/ false, output_location.c_str(), &error_msg));
} else {
@@ -1825,7 +1834,7 @@
}
if (mem_map_ == nullptr) {
LOG(ERROR) << "Could not create mem map for dex writer output: " << error_msg;
- if (new_file.get() != nullptr) {
+ if (new_file != nullptr) {
new_file->Erase();
}
return;
diff --git a/runtime/arch/arm64/asm_support_arm64.h b/runtime/arch/arm64/asm_support_arm64.h
index 5e7b51d..cfcd6a7 100644
--- a/runtime/arch/arm64/asm_support_arm64.h
+++ b/runtime/arch/arm64/asm_support_arm64.h
@@ -24,4 +24,18 @@
#define FRAME_SIZE_SAVE_REFS_AND_ARGS 224
#define FRAME_SIZE_SAVE_EVERYTHING 512
+// The offset from art_quick_read_barrier_mark_introspection to the array switch cases,
+// i.e. art_quick_read_barrier_mark_introspection_arrays.
+#define BAKER_MARK_INTROSPECTION_ARRAY_SWITCH_OFFSET 0x100
+// The offset from art_quick_read_barrier_mark_introspection to the GC root entrypoint,
+// i.e. art_quick_read_barrier_mark_introspection_gc_roots.
+#define BAKER_MARK_INTROSPECTION_GC_ROOT_ENTRYPOINT_OFFSET 0x300
+
+// The offset of the reference load LDR from the return address in LR for field loads.
+#define BAKER_MARK_INTROSPECTION_FIELD_LDR_OFFSET -4
+// The offset of the reference load LDR from the return address in LR for array loads.
+#define BAKER_MARK_INTROSPECTION_ARRAY_LDR_OFFSET -4
+// The offset of the reference load LDR from the return address in LR for GC root loads.
+#define BAKER_MARK_INTROSPECTION_GC_ROOT_LDR_OFFSET -8
+
#endif // ART_RUNTIME_ARCH_ARM64_ASM_SUPPORT_ARM64_H_
diff --git a/runtime/arch/arm64/entrypoints_init_arm64.cc b/runtime/arch/arm64/entrypoints_init_arm64.cc
index 6add107..bc7bcb1 100644
--- a/runtime/arch/arm64/entrypoints_init_arm64.cc
+++ b/runtime/arch/arm64/entrypoints_init_arm64.cc
@@ -17,6 +17,7 @@
#include <math.h>
#include <string.h>
+#include "arch/arm64/asm_support_arm64.h"
#include "entrypoints/jni/jni_entrypoints.h"
#include "entrypoints/quick/quick_alloc_entrypoints.h"
#include "entrypoints/quick/quick_default_externs.h"
@@ -70,6 +71,10 @@
extern "C" mirror::Object* art_quick_read_barrier_mark_reg28(mirror::Object*);
extern "C" mirror::Object* art_quick_read_barrier_mark_reg29(mirror::Object*);
+extern "C" mirror::Object* art_quick_read_barrier_mark_introspection(mirror::Object*);
+extern "C" mirror::Object* art_quick_read_barrier_mark_introspection_arrays(mirror::Object*);
+extern "C" mirror::Object* art_quick_read_barrier_mark_introspection_gc_roots(mirror::Object*);
+
void UpdateReadBarrierEntrypoints(QuickEntryPoints* qpoints, bool is_marking) {
// ARM64 is the architecture with the largest number of core
// registers (32) that supports the read barrier configuration.
@@ -109,6 +114,21 @@
qpoints->pReadBarrierMarkReg27 = is_marking ? art_quick_read_barrier_mark_reg27 : nullptr;
qpoints->pReadBarrierMarkReg28 = is_marking ? art_quick_read_barrier_mark_reg28 : nullptr;
qpoints->pReadBarrierMarkReg29 = is_marking ? art_quick_read_barrier_mark_reg29 : nullptr;
+
+ // Check that array switch cases are at appropriate offsets from the introspection entrypoint.
+ DCHECK_ALIGNED(art_quick_read_barrier_mark_introspection, 512u);
+ intptr_t array_diff =
+ reinterpret_cast<intptr_t>(art_quick_read_barrier_mark_introspection_arrays) -
+ reinterpret_cast<intptr_t>(art_quick_read_barrier_mark_introspection);
+ DCHECK_EQ(BAKER_MARK_INTROSPECTION_ARRAY_SWITCH_OFFSET, array_diff);
+ // Check that the GC root entrypoint is at appropriate offset from the introspection entrypoint.
+ intptr_t gc_roots_diff =
+ reinterpret_cast<intptr_t>(art_quick_read_barrier_mark_introspection_gc_roots) -
+ reinterpret_cast<intptr_t>(art_quick_read_barrier_mark_introspection);
+ DCHECK_EQ(BAKER_MARK_INTROSPECTION_GC_ROOT_ENTRYPOINT_OFFSET, gc_roots_diff);
+ // The register 16, i.e. IP0, is reserved, so there is no art_quick_read_barrier_mark_reg16.
+ // We're using the entry to hold a pointer to the introspection entrypoint instead.
+ qpoints->pReadBarrierMarkReg16 = is_marking ? art_quick_read_barrier_mark_introspection : nullptr;
}
void InitEntryPoints(JniEntryPoints* jpoints, QuickEntryPoints* qpoints) {
diff --git a/runtime/arch/arm64/quick_entrypoints_arm64.S b/runtime/arch/arm64/quick_entrypoints_arm64.S
index b2bbd0d..c7fa7f5 100644
--- a/runtime/arch/arm64/quick_entrypoints_arm64.S
+++ b/runtime/arch/arm64/quick_entrypoints_arm64.S
@@ -2494,6 +2494,240 @@
READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg28, w28, x28
READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg29, w29, x29
+
+.macro SELECT_X_OR_W_FOR_MACRO macro_to_use, x, w, xreg
+ .if \xreg
+ \macro_to_use \x
+ .else
+ \macro_to_use \w
+ .endif
+.endm
+
+.macro FOR_REGISTERS macro_for_register, macro_for_reserved_register, xreg
+ SELECT_X_OR_W_FOR_MACRO \macro_for_register, x0, w0, \xreg
+ SELECT_X_OR_W_FOR_MACRO \macro_for_register, x1, w1, \xreg
+ SELECT_X_OR_W_FOR_MACRO \macro_for_register, x2, w2, \xreg
+ SELECT_X_OR_W_FOR_MACRO \macro_for_register, x3, w3, \xreg
+ SELECT_X_OR_W_FOR_MACRO \macro_for_register, x4, w4, \xreg
+ SELECT_X_OR_W_FOR_MACRO \macro_for_register, x5, w5, \xreg
+ SELECT_X_OR_W_FOR_MACRO \macro_for_register, x6, w6, \xreg
+ SELECT_X_OR_W_FOR_MACRO \macro_for_register, x7, w7, \xreg
+ SELECT_X_OR_W_FOR_MACRO \macro_for_register, x8, w8, \xreg
+ SELECT_X_OR_W_FOR_MACRO \macro_for_register, x9, w9, \xreg
+ SELECT_X_OR_W_FOR_MACRO \macro_for_register, x10, w10, \xreg
+ SELECT_X_OR_W_FOR_MACRO \macro_for_register, x11, w11, \xreg
+ SELECT_X_OR_W_FOR_MACRO \macro_for_register, x12, w12, \xreg
+ SELECT_X_OR_W_FOR_MACRO \macro_for_register, x13, w13, \xreg
+ SELECT_X_OR_W_FOR_MACRO \macro_for_register, x14, w14, \xreg
+ SELECT_X_OR_W_FOR_MACRO \macro_for_register, x15, w15, \xreg
+ \macro_for_reserved_register // IP0 is reserved
+ \macro_for_reserved_register // IP1 is reserved
+ SELECT_X_OR_W_FOR_MACRO \macro_for_register, x18, w18, \xreg
+ SELECT_X_OR_W_FOR_MACRO \macro_for_register, x19, w19, \xreg
+ SELECT_X_OR_W_FOR_MACRO \macro_for_register, x20, w20, \xreg
+ SELECT_X_OR_W_FOR_MACRO \macro_for_register, x21, w21, \xreg
+ SELECT_X_OR_W_FOR_MACRO \macro_for_register, x22, w22, \xreg
+ SELECT_X_OR_W_FOR_MACRO \macro_for_register, x23, w23, \xreg
+ SELECT_X_OR_W_FOR_MACRO \macro_for_register, x24, w24, \xreg
+ SELECT_X_OR_W_FOR_MACRO \macro_for_register, x25, w25, \xreg
+ SELECT_X_OR_W_FOR_MACRO \macro_for_register, x26, w26, \xreg
+ SELECT_X_OR_W_FOR_MACRO \macro_for_register, x27, w27, \xreg
+ SELECT_X_OR_W_FOR_MACRO \macro_for_register, x28, w28, \xreg
+ SELECT_X_OR_W_FOR_MACRO \macro_for_register, x29, w29, \xreg
+ \macro_for_reserved_register // lr is reserved
+ \macro_for_reserved_register // sp is reserved
+.endm
+
+.macro FOR_XREGISTERS macro_for_register, macro_for_reserved_register
+ FOR_REGISTERS \macro_for_register, \macro_for_reserved_register, /* xreg */ 1
+.endm
+
+.macro FOR_WREGISTERS macro_for_register, macro_for_reserved_register
+ FOR_REGISTERS \macro_for_register, \macro_for_reserved_register, /* xreg */ 0
+.endm
+
+.macro BRK0_BRK0
+ brk 0
+ brk 0
+.endm
+
+#if BAKER_MARK_INTROSPECTION_FIELD_LDR_OFFSET != BAKER_MARK_INTROSPECTION_ARRAY_LDR_OFFSET
+#error "Array and field introspection code sharing requires same LDR offset."
+#endif
+.macro INTROSPECTION_ARRAY_LOAD index_reg
+ ldr wIP0, [xIP0, \index_reg, lsl #2]
+ b art_quick_read_barrier_mark_introspection
+.endm
+
+.macro MOV_WIP0_TO_WREG_AND_BL_LR reg
+ mov \reg, wIP0
+ br lr // Do not use RET as we do not enter the entrypoint with "BL".
+.endm
+
+.macro READ_BARRIER_MARK_INTROSPECTION_SLOW_PATH ldr_offset
+ /*
+ * Allocate 44 stack slots * 8 = 352 bytes:
+ * - 19 slots for core registers X0-15, X18-X19, LR
+ * - 1 slot padding
+ * - 24 slots for floating-point registers D0-D7 and D16-D31
+ */
+ // Save all potentially live caller-save core registers.
+ SAVE_TWO_REGS_INCREASE_FRAME x0, x1, 352
+ SAVE_TWO_REGS x2, x3, 16
+ SAVE_TWO_REGS x4, x5, 32
+ SAVE_TWO_REGS x6, x7, 48
+ SAVE_TWO_REGS x8, x9, 64
+ SAVE_TWO_REGS x10, x11, 80
+ SAVE_TWO_REGS x12, x13, 96
+ SAVE_TWO_REGS x14, x15, 112
+ SAVE_TWO_REGS x18, x19, 128 // Skip x16, x17, i.e. IP0, IP1.
+ SAVE_REG xLR, 144 // Save return address, skip padding at 152.
+ // Save all potentially live caller-save floating-point registers.
+ stp d0, d1, [sp, #160]
+ stp d2, d3, [sp, #176]
+ stp d4, d5, [sp, #192]
+ stp d6, d7, [sp, #208]
+ stp d16, d17, [sp, #224]
+ stp d18, d19, [sp, #240]
+ stp d20, d21, [sp, #256]
+ stp d22, d23, [sp, #272]
+ stp d24, d25, [sp, #288]
+ stp d26, d27, [sp, #304]
+ stp d28, d29, [sp, #320]
+ stp d30, d31, [sp, #336]
+
+ mov x0, xIP0
+ bl artReadBarrierMark // artReadBarrierMark(obj)
+ mov xIP0, x0
+
+ // Restore core regs, except x0 and x1 as the return register switch case
+ // address calculation is smoother with an extra register.
+ RESTORE_TWO_REGS x2, x3, 16
+ RESTORE_TWO_REGS x4, x5, 32
+ RESTORE_TWO_REGS x6, x7, 48
+ RESTORE_TWO_REGS x8, x9, 64
+ RESTORE_TWO_REGS x10, x11, 80
+ RESTORE_TWO_REGS x12, x13, 96
+ RESTORE_TWO_REGS x14, x15, 112
+ RESTORE_TWO_REGS x18, x19, 128 // Skip x16, x17, i.e. IP0, IP1.
+ RESTORE_REG xLR, 144 // Restore return address.
+ // Save all potentially live caller-save floating-point registers.
+ stp d0, d1, [sp, #160]
+ stp d2, d3, [sp, #176]
+ stp d4, d5, [sp, #192]
+ stp d6, d7, [sp, #208]
+ stp d16, d17, [sp, #224]
+ stp d18, d19, [sp, #240]
+ stp d20, d21, [sp, #256]
+ stp d22, d23, [sp, #272]
+ stp d24, d25, [sp, #288]
+ stp d26, d27, [sp, #304]
+ stp d28, d29, [sp, #320]
+ stp d30, d31, [sp, #336]
+
+ ldr x0, [lr, #\ldr_offset] // Load the instruction.
+ adr xIP1, .Lmark_introspection_return_switch
+ bfi xIP1, x0, #3, #5 // Calculate switch case address.
+ RESTORE_TWO_REGS_DECREASE_FRAME x0, x1, 352
+ br xIP1
+.endm
+
+ /*
+ * Use introspection to load a reference from the same address as the LDR
+ * instruction in generated code would load (unless loaded by the thunk,
+ * see below), call ReadBarrier::Mark() with that reference if needed
+ * and return it in the same register as the LDR instruction would load.
+ *
+ * The entrypoint is called through a thunk that differs across load kinds.
+ * For field and array loads the LDR instruction in generated code follows
+ * the branch to the thunk, i.e. the LDR is at [LR, #-4], and the thunk
+ * knows the holder and performs the gray bit check, returning to the LDR
+ * instruction if the object is not gray, so this entrypoint no longer
+ * needs to know anything about the holder. For GC root loads, the LDR
+ * instruction in generated code precedes the branch to the thunk (i.e.
+ * the LDR is at [LR, #-8]) and the thunk does not do the gray bit check.
+ *
+ * For field accesses and array loads with a constant index the thunk loads
+ * the reference into IP0 using introspection and calls the main entrypoint,
+ * art_quick_read_barrier_mark_introspection.
+ *
+ * For array accesses with non-constant index, the thunk inserts the bits
+ * 16-21 of the LDR instruction to the entrypoint address, effectively
+ * calculating a switch case label based on the index register (bits 16-20)
+ * and adding an extra offset (bit 21 is set) to differentiate from the
+ * main entrypoint, then moves the base register to IP0 and jumps to the
+ * switch case. Therefore we need to align the main entrypoint to 512 bytes,
+ * accounting for a 256-byte offset followed by 32 array entrypoints
+ * starting at art_quick_read_barrier_mark_introspection_arrays, each
+ * containing an LDR (register) and a branch to the main entrypoint.
+ *
+ * For GC root accesses we cannot use the main entrypoint because of the
+ * different offset where the LDR instruction in generated code is located.
+ * To re-use the same entrypoint pointer in generated code, we make sure
+ * that the gc root entrypoint (a copy of the entrypoint with a different
+ * offset for introspection loads) is located at a known offset (768 bytes,
+ * or BAKER_MARK_INTROSPECTION_GC_ROOT_ENTRYPOINT_OFFSET) from the main
+ * entrypoint and the GC root thunk adjusts the entrypoint pointer, moves
+ * the root register to IP0 and jumps to the customized entrypoint,
+ * art_quick_read_barrier_mark_introspection_gc_roots. The thunk also
+ * performs all the fast-path checks, so we need just the slow path.
+ *
+ * The code structure is
+ * art_quick_read_barrier_mark_introspection:
+ * Up to 256 bytes for the main entrypoint code.
+ * Padding to 256 bytes if needed.
+ * art_quick_read_barrier_mark_introspection_arrays:
+ * Exactly 256 bytes for array load switch cases (32x2 instructions).
+ * .Lmark_introspection_return_switch:
+ * Exactly 256 bytes for return switch cases (32x2 instructions).
+ * art_quick_read_barrier_mark_introspection_gc_roots:
+ * GC root entrypoint code.
+ */
+ .balign 512
+ENTRY art_quick_read_barrier_mark_introspection
+ // At this point, IP0 contains the reference, IP1 can be freely used.
+ // If reference is null, just return it in the right register.
+ cbz wIP0, .Lmark_introspection_return
+ // Use wIP1 as temp and check the mark bit of the reference.
+ ldr wIP1, [xIP0, #MIRROR_OBJECT_LOCK_WORD_OFFSET]
+ tbz wIP1, #LOCK_WORD_MARK_BIT_SHIFT, .Lmark_introspection_unmarked
+.Lmark_introspection_return:
+ // Without an extra register for the return switch case address calculation,
+ // we exploit the high word of the xIP0 to temporarily store the ref_reg*8,
+ // so the return switch below must move wIP0 instead of xIP0 to the register.
+ ldr wIP1, [lr, #BAKER_MARK_INTROSPECTION_FIELD_LDR_OFFSET] // Load the instruction.
+ bfi xIP0, xIP1, #(32 + 3), #5 // Extract ref_reg*8 to high word in xIP0.
+ adr xIP1, .Lmark_introspection_return_switch
+ bfxil xIP1, xIP0, #32, #8 // Calculate return switch case address.
+ br xIP1
+.Lmark_introspection_unmarked:
+ // Check if the top two bits are one, if this is the case it is a forwarding address.
+ tst wIP1, wIP1, lsl #1
+ bmi .Lmark_introspection_forwarding_address
+ READ_BARRIER_MARK_INTROSPECTION_SLOW_PATH BAKER_MARK_INTROSPECTION_FIELD_LDR_OFFSET
+
+.Lmark_introspection_forwarding_address:
+ // Shift left by the forwarding address shift. This clears out the state bits since they are
+ // in the top 2 bits of the lock word.
+ lsl wIP0, wIP1, #LOCK_WORD_STATE_FORWARDING_ADDRESS_SHIFT
+ b .Lmark_introspection_return
+
+ // We're very close to the alloted 256B for the entrypoint code before the
+ // array switch cases. Should we go a little bit over the limit, we can
+ // move some code after the array switch cases and return switch cases.
+ .balign 256
+ .hidden art_quick_read_barrier_mark_introspection_arrays
+ .global art_quick_read_barrier_mark_introspection_arrays
+art_quick_read_barrier_mark_introspection_arrays:
+ FOR_XREGISTERS INTROSPECTION_ARRAY_LOAD, BRK0_BRK0
+.Lmark_introspection_return_switch:
+ FOR_WREGISTERS MOV_WIP0_TO_WREG_AND_BL_LR, BRK0_BRK0
+ .hidden art_quick_read_barrier_mark_introspection_gc_roots
+ .global art_quick_read_barrier_mark_introspection_gc_roots
+art_quick_read_barrier_mark_introspection_gc_roots:
+ READ_BARRIER_MARK_INTROSPECTION_SLOW_PATH BAKER_MARK_INTROSPECTION_GC_ROOT_LDR_OFFSET
+END art_quick_read_barrier_mark_introspection
+
.extern artInvokePolymorphic
ENTRY art_quick_invoke_polymorphic
SETUP_SAVE_REFS_AND_ARGS_FRAME // Save callee saves in case allocation triggers GC.
diff --git a/runtime/arch/mips/entrypoints_direct_mips.h b/runtime/arch/mips/entrypoints_direct_mips.h
index 937cd1e..1020781 100644
--- a/runtime/arch/mips/entrypoints_direct_mips.h
+++ b/runtime/arch/mips/entrypoints_direct_mips.h
@@ -47,7 +47,24 @@
entrypoint == kQuickCmplFloat ||
entrypoint == kQuickReadBarrierJni ||
entrypoint == kQuickReadBarrierSlow ||
- entrypoint == kQuickReadBarrierForRootSlow;
+ entrypoint == kQuickReadBarrierForRootSlow ||
+ entrypoint == kQuickCos ||
+ entrypoint == kQuickSin ||
+ entrypoint == kQuickAcos ||
+ entrypoint == kQuickAsin ||
+ entrypoint == kQuickAtan ||
+ entrypoint == kQuickAtan2 ||
+ entrypoint == kQuickCbrt ||
+ entrypoint == kQuickCosh ||
+ entrypoint == kQuickExp ||
+ entrypoint == kQuickExpm1 ||
+ entrypoint == kQuickHypot ||
+ entrypoint == kQuickLog ||
+ entrypoint == kQuickLog10 ||
+ entrypoint == kQuickNextAfter ||
+ entrypoint == kQuickSinh ||
+ entrypoint == kQuickTan ||
+ entrypoint == kQuickTanh;
}
} // namespace art
diff --git a/runtime/arch/mips/entrypoints_init_mips.cc b/runtime/arch/mips/entrypoints_init_mips.cc
index 2349620..434e33c 100644
--- a/runtime/arch/mips/entrypoints_init_mips.cc
+++ b/runtime/arch/mips/entrypoints_init_mips.cc
@@ -312,6 +312,42 @@
qpoints->pUshrLong = art_quick_ushr_long;
static_assert(!IsDirectEntrypoint(kQuickUshrLong), "Non-direct C stub marked direct.");
+ // More math.
+ qpoints->pCos = cos;
+ static_assert(IsDirectEntrypoint(kQuickCos), "Direct C stub marked non-direct.");
+ qpoints->pSin = sin;
+ static_assert(IsDirectEntrypoint(kQuickSin), "Direct C stub marked non-direct.");
+ qpoints->pAcos = acos;
+ static_assert(IsDirectEntrypoint(kQuickAcos), "Direct C stub marked non-direct.");
+ qpoints->pAsin = asin;
+ static_assert(IsDirectEntrypoint(kQuickAsin), "Direct C stub marked non-direct.");
+ qpoints->pAtan = atan;
+ static_assert(IsDirectEntrypoint(kQuickAtan), "Direct C stub marked non-direct.");
+ qpoints->pAtan2 = atan2;
+ static_assert(IsDirectEntrypoint(kQuickAtan2), "Direct C stub marked non-direct.");
+ qpoints->pCbrt = cbrt;
+ static_assert(IsDirectEntrypoint(kQuickCbrt), "Direct C stub marked non-direct.");
+ qpoints->pCosh = cosh;
+ static_assert(IsDirectEntrypoint(kQuickCosh), "Direct C stub marked non-direct.");
+ qpoints->pExp = exp;
+ static_assert(IsDirectEntrypoint(kQuickExp), "Direct C stub marked non-direct.");
+ qpoints->pExpm1 = expm1;
+ static_assert(IsDirectEntrypoint(kQuickExpm1), "Direct C stub marked non-direct.");
+ qpoints->pHypot = hypot;
+ static_assert(IsDirectEntrypoint(kQuickHypot), "Direct C stub marked non-direct.");
+ qpoints->pLog = log;
+ static_assert(IsDirectEntrypoint(kQuickLog), "Direct C stub marked non-direct.");
+ qpoints->pLog10 = log10;
+ static_assert(IsDirectEntrypoint(kQuickLog10), "Direct C stub marked non-direct.");
+ qpoints->pNextAfter = nextafter;
+ static_assert(IsDirectEntrypoint(kQuickNextAfter), "Direct C stub marked non-direct.");
+ qpoints->pSinh = sinh;
+ static_assert(IsDirectEntrypoint(kQuickSinh), "Direct C stub marked non-direct.");
+ qpoints->pTan = tan;
+ static_assert(IsDirectEntrypoint(kQuickTan), "Direct C stub marked non-direct.");
+ qpoints->pTanh = tanh;
+ static_assert(IsDirectEntrypoint(kQuickTanh), "Direct C stub marked non-direct.");
+
// Intrinsics
qpoints->pIndexOf = art_quick_indexof;
static_assert(!IsDirectEntrypoint(kQuickIndexOf), "Non-direct C stub marked direct.");
diff --git a/runtime/arch/mips64/entrypoints_init_mips64.cc b/runtime/arch/mips64/entrypoints_init_mips64.cc
index 66405cb..f8242ae 100644
--- a/runtime/arch/mips64/entrypoints_init_mips64.cc
+++ b/runtime/arch/mips64/entrypoints_init_mips64.cc
@@ -137,6 +137,25 @@
qpoints->pShrLong = nullptr;
qpoints->pUshrLong = nullptr;
+ // More math.
+ qpoints->pCos = cos;
+ qpoints->pSin = sin;
+ qpoints->pAcos = acos;
+ qpoints->pAsin = asin;
+ qpoints->pAtan = atan;
+ qpoints->pAtan2 = atan2;
+ qpoints->pCbrt = cbrt;
+ qpoints->pCosh = cosh;
+ qpoints->pExp = exp;
+ qpoints->pExpm1 = expm1;
+ qpoints->pHypot = hypot;
+ qpoints->pLog = log;
+ qpoints->pLog10 = log10;
+ qpoints->pNextAfter = nextafter;
+ qpoints->pSinh = sinh;
+ qpoints->pTan = tan;
+ qpoints->pTanh = tanh;
+
// Intrinsics
qpoints->pIndexOf = art_quick_indexof;
qpoints->pStringCompareTo = art_quick_string_compareto;
diff --git a/runtime/base/arena_allocator.cc b/runtime/base/arena_allocator.cc
index e763e43..935fd81 100644
--- a/runtime/base/arena_allocator.cc
+++ b/runtime/base/arena_allocator.cc
@@ -78,6 +78,7 @@
"RegAllocator ",
"RegAllocVldt ",
"StackMapStm ",
+ "VectorNode ",
"CodeGen ",
"Assembler ",
"ParallelMove ",
@@ -150,8 +151,15 @@
#if __clang_major__ >= 4
#pragma GCC diagnostic ignored "-Winstantiation-after-specialization"
#endif
-// Explicitly instantiate the used implementation.
-template class ArenaAllocatorStatsImpl<kArenaAllocatorCountAllocations>;
+// We're going to use ArenaAllocatorStatsImpl<kArenaAllocatorCountAllocations> which needs
+// to be explicitly instantiated if kArenaAllocatorCountAllocations is true. Explicit
+// instantiation of the specialization ArenaAllocatorStatsImpl<false> does not do anything
+// but requires the warning "-Winstantiation-after-specialization" to be turned off.
+//
+// To avoid bit-rot of the ArenaAllocatorStatsImpl<true>, instantiate it also in debug builds
+// (but keep the unnecessary code out of release builds) as we do not usually compile with
+// kArenaAllocatorCountAllocations set to true.
+template class ArenaAllocatorStatsImpl<kArenaAllocatorCountAllocations || kIsDebugBuild>;
#pragma GCC diagnostic pop
void ArenaAllocatorMemoryTool::DoMakeDefined(void* ptr, size_t size) {
diff --git a/runtime/base/logging.h b/runtime/base/logging.h
index a173ac2..7a9184e 100644
--- a/runtime/base/logging.h
+++ b/runtime/base/logging.h
@@ -56,6 +56,7 @@
bool image;
bool systrace_lock_logging; // Enabled with "-verbose:sys-locks".
bool agents;
+ bool dex; // Some dex access output etc.
};
// Global log verbosity setting, initialized by InitLogging.
diff --git a/runtime/base/mutex-inl.h b/runtime/base/mutex-inl.h
index 44a84c8..08b370e 100644
--- a/runtime/base/mutex-inl.h
+++ b/runtime/base/mutex-inl.h
@@ -89,13 +89,14 @@
// Check if a bad Mutex of this level or lower is held.
bool bad_mutexes_held = false;
for (int i = level_; i >= 0; --i) {
- BaseMutex* held_mutex = self->GetHeldMutex(static_cast<LockLevel>(i));
- if (UNLIKELY(held_mutex != nullptr)) {
+ LockLevel lock_level_i = static_cast<LockLevel>(i);
+ BaseMutex* held_mutex = self->GetHeldMutex(lock_level_i);
+ if (UNLIKELY(held_mutex != nullptr) && lock_level_i != kAbortLock) {
LOG(ERROR) << "Lock level violation: holding \"" << held_mutex->name_ << "\" "
- << "(level " << LockLevel(i) << " - " << i
+ << "(level " << lock_level_i << " - " << i
<< ") while locking \"" << name_ << "\" "
<< "(level " << level_ << " - " << static_cast<int>(level_) << ")";
- if (i > kAbortLock) {
+ if (lock_level_i > kAbortLock) {
// Only abort in the check below if this is more than abort level lock.
bad_mutexes_held = true;
}
diff --git a/runtime/debugger.cc b/runtime/debugger.cc
index 868d8df..039b60a 100644
--- a/runtime/debugger.cc
+++ b/runtime/debugger.cc
@@ -2453,7 +2453,7 @@
bool needs_resume;
{
MutexLock mu2(soa.Self(), *Locks::thread_suspend_count_lock_);
- needs_resume = thread->GetSuspendCount() > 0;
+ needs_resume = thread->GetDebugSuspendCount() > 0;
}
if (needs_resume) {
Runtime::Current()->GetThreadList()->Resume(thread, true);
diff --git a/runtime/dex_file-inl.h b/runtime/dex_file-inl.h
index e884e39..41db4d8 100644
--- a/runtime/dex_file-inl.h
+++ b/runtime/dex_file-inl.h
@@ -59,11 +59,17 @@
}
inline const char* DexFile::StringByTypeIdx(dex::TypeIndex idx, uint32_t* unicode_length) const {
+ if (!idx.IsValid()) {
+ return nullptr;
+ }
const TypeId& type_id = GetTypeId(idx);
return StringDataAndUtf16LengthByIdx(type_id.descriptor_idx_, unicode_length);
}
inline const char* DexFile::StringByTypeIdx(dex::TypeIndex idx) const {
+ if (!idx.IsValid()) {
+ return nullptr;
+ }
const TypeId& type_id = GetTypeId(idx);
return StringDataByIdx(type_id.descriptor_idx_);
}
diff --git a/runtime/dex_file.cc b/runtime/dex_file.cc
index 85100ae..688f95b 100644
--- a/runtime/dex_file.cc
+++ b/runtime/dex_file.cc
@@ -590,6 +590,10 @@
void DexFile::InitializeSectionsFromMapList() {
const MapList* map_list = reinterpret_cast<const MapList*>(begin_ + header_->map_off_);
+ if (header_->map_off_ == 0 || header_->map_off_ > size_) {
+ // Bad offset. The dex file verifier runs after this method and will reject the file.
+ return;
+ }
const size_t count = map_list->size_;
size_t map_limit = header_->map_off_ + count * sizeof(MapItem);
diff --git a/runtime/dex_file_test.cc b/runtime/dex_file_test.cc
index 9131715..f811287 100644
--- a/runtime/dex_file_test.cc
+++ b/runtime/dex_file_test.cc
@@ -161,6 +161,16 @@
"ACACAAALABgAAAAAAAAAAACgge4CAABjbGFzc2VzLmRleFVUBQADAWPlV3V4CwABBOQDAQAEiBMA"
"AFBLBQYAAAAAAwADAPUAAABkBAAAAAA=";
+static const char kRawDexBadMapOffset[] =
+ "ZGV4CjAzNQAZKGSz85r+tXJ1I24FYi+FpQtWbXtelAmoAQAAcAAAAHhWNBIAAAAAAAAAAEAwIBAF"
+ "AAAAcAAAAAMAAACEAAAAAQAAAJAAAAAAAAAAAAAAAAIAAACcAAAAAQAAAKwAAADcAAAAzAAAAOQA"
+ "AADsAAAA9AAAAPkAAAANAQAAAgAAAAMAAAAEAAAABAAAAAIAAAAAAAAAAAAAAAAAAAABAAAAAAAA"
+ "AAAAAAABAAAAAQAAAAAAAAABAAAAAAAAABUBAAAAAAAAAQABAAEAAAAQAQAABAAAAHAQAQAAAA4A"
+ "Bjxpbml0PgAGQS5qYXZhAANMQTsAEkxqYXZhL2xhbmcvT2JqZWN0OwABVgABAAcOAAAAAQAAgYAE"
+ "zAEACwAAAAAAAAABAAAAAAAAAAEAAAAFAAAAcAAAAAIAAAADAAAAhAAAAAMAAAABAAAAkAAAAAUA"
+ "AAACAAAAnAAAAAYAAAABAAAArAAAAAEgAAABAAAAzAAAAAIgAAAFAAAA5AAAAAMgAAABAAAAEAEA"
+ "AAAgAAABAAAAFQEAAAAQAAABAAAAIAEAAA==";
+
static void DecodeAndWriteDexFile(const char* base64, const char* location) {
// decode base64
CHECK(base64 != nullptr);
@@ -212,7 +222,8 @@
static std::unique_ptr<const DexFile> OpenDexFileInMemoryBase64(const char* base64,
const char* location,
- uint32_t location_checksum) {
+ uint32_t location_checksum,
+ bool expect_success) {
CHECK(base64 != nullptr);
std::vector<uint8_t> dex_bytes = DecodeBase64Vec(base64);
CHECK_NE(dex_bytes.size(), 0u);
@@ -232,7 +243,11 @@
/* verify */ true,
/* verify_checksum */ true,
&error_message));
- CHECK(dex_file != nullptr) << error_message;
+ if (expect_success) {
+ CHECK(dex_file != nullptr) << error_message;
+ } else {
+ CHECK(dex_file == nullptr) << "Expected dex file open to fail.";
+ }
return dex_file;
}
@@ -282,7 +297,7 @@
TEST_F(DexFileTest, HeaderInMemory) {
ScratchFile tmp;
std::unique_ptr<const DexFile> raw =
- OpenDexFileInMemoryBase64(kRawDex, tmp.GetFilename().c_str(), 0x00d87910U);
+ OpenDexFileInMemoryBase64(kRawDex, tmp.GetFilename().c_str(), 0x00d87910U, true);
ValidateDexFileHeader(std::move(raw));
}
@@ -569,4 +584,18 @@
EXPECT_EQ(dex_files.size(), 3u);
}
+TEST_F(DexFileTest, OpenDexBadMapOffset) {
+ ScratchFile tmp;
+ std::unique_ptr<const DexFile> raw =
+ OpenDexFileInMemoryBase64(kRawDexBadMapOffset, tmp.GetFilename().c_str(), 0xb3642819U, false);
+ EXPECT_EQ(raw, nullptr);
+}
+
+TEST_F(DexFileTest, GetStringWithNoIndex) {
+ ScratchFile tmp;
+ std::unique_ptr<const DexFile> raw(OpenDexFileBase64(kRawDex, tmp.GetFilename().c_str()));
+ dex::TypeIndex idx;
+ EXPECT_EQ(raw->StringByTypeIdx(idx), nullptr);
+}
+
} // namespace art
diff --git a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
index 25073a8..354ae20 100644
--- a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
@@ -1075,7 +1075,7 @@
<< called_method.dex_file->PrettyMethod(called_method.dex_method_index);
}
} else {
- VLOG(oat) << "Accessed dex file for invoke " << invoke_type << " "
+ VLOG(dex) << "Accessed dex file for invoke " << invoke_type << " "
<< called_method.dex_method_index;
}
} else {
diff --git a/runtime/gc/collector/concurrent_copying.cc b/runtime/gc/collector/concurrent_copying.cc
index 24ba52f..bcf5008 100644
--- a/runtime/gc/collector/concurrent_copying.cc
+++ b/runtime/gc/collector/concurrent_copying.cc
@@ -1108,7 +1108,9 @@
space::RegionSpace* region_space = collector->RegionSpace();
CHECK(!region_space->IsInFromSpace(obj)) << "Scanning object " << obj << " in from space";
VerifyNoFromSpaceRefsFieldVisitor visitor(collector);
- obj->VisitReferences(visitor, visitor);
+ obj->VisitReferences</*kVisitNativeRoots*/true, kDefaultVerifyFlags, kWithoutReadBarrier>(
+ visitor,
+ visitor);
if (kUseBakerReadBarrier) {
CHECK_EQ(obj->GetReadBarrierState(), ReadBarrier::WhiteState())
<< "obj=" << obj << " non-white rb_state " << obj->GetReadBarrierState();
@@ -1232,7 +1234,9 @@
CHECK(!region_space->IsInFromSpace(obj)) << "Scanning object " << obj << " in from space";
collector->AssertToSpaceInvariant(nullptr, MemberOffset(0), obj);
AssertToSpaceInvariantFieldVisitor visitor(collector);
- obj->VisitReferences(visitor, visitor);
+ obj->VisitReferences</*kVisitNativeRoots*/true, kDefaultVerifyFlags, kWithoutReadBarrier>(
+ visitor,
+ visitor);
}
private:
@@ -1471,8 +1475,7 @@
// Add to the live bytes per unevacuated from space. Note this code is always run by the
// GC-running thread (no synchronization required).
DCHECK(region_space_bitmap_->Test(to_ref));
- // Disable the read barrier in SizeOf for performance, which is safe.
- size_t obj_size = to_ref->SizeOf<kDefaultVerifyFlags, kWithoutReadBarrier>();
+ size_t obj_size = to_ref->SizeOf<kDefaultVerifyFlags>();
size_t alloc_size = RoundUp(obj_size, space::RegionSpace::kAlignment);
region_space_->AddLiveBytes(to_ref, alloc_size);
}
@@ -1714,16 +1717,19 @@
}
// Assert the to-space invariant.
-void ConcurrentCopying::AssertToSpaceInvariant(mirror::Object* obj, MemberOffset offset,
+void ConcurrentCopying::AssertToSpaceInvariant(mirror::Object* obj,
+ MemberOffset offset,
mirror::Object* ref) {
- CHECK(heap_->collector_type_ == kCollectorTypeCC) << static_cast<size_t>(heap_->collector_type_);
+ CHECK_EQ(heap_->collector_type_, kCollectorTypeCC);
if (is_asserting_to_space_invariant_) {
- if (region_space_->IsInToSpace(ref)) {
+ using RegionType = space::RegionSpace::RegionType;
+ space::RegionSpace::RegionType type = region_space_->GetRegionType(ref);
+ if (type == RegionType::kRegionTypeToSpace) {
// OK.
return;
- } else if (region_space_->IsInUnevacFromSpace(ref)) {
+ } else if (type == RegionType::kRegionTypeUnevacFromSpace) {
CHECK(IsMarkedInUnevacFromSpace(ref)) << ref;
- } else if (region_space_->IsInFromSpace(ref)) {
+ } else if (UNLIKELY(type == RegionType::kRegionTypeFromSpace)) {
// Not OK. Do extra logging.
if (obj != nullptr) {
LogFromSpaceRefHolder(obj, offset);
@@ -1888,10 +1894,10 @@
explicit RefFieldsVisitor(ConcurrentCopying* collector)
: collector_(collector) {}
- void operator()(ObjPtr<mirror::Object> obj, MemberOffset offset, bool /* is_static */)
+ void operator()(mirror::Object* obj, MemberOffset offset, bool /* is_static */)
const ALWAYS_INLINE REQUIRES_SHARED(Locks::mutator_lock_)
REQUIRES_SHARED(Locks::heap_bitmap_lock_) {
- collector_->Process(obj.Ptr(), offset);
+ collector_->Process(obj, offset);
}
void operator()(ObjPtr<mirror::Class> klass, ObjPtr<mirror::Reference> ref) const
@@ -2064,7 +2070,7 @@
AssertToSpaceInvariant(nullptr, MemberOffset(0), java_lang_Object.Ptr());
CHECK_EQ(byte_size, (java_lang_Object->GetObjectSize<kVerifyNone, kWithoutReadBarrier>()));
dummy_obj->SetClass(java_lang_Object.Ptr());
- CHECK_EQ(byte_size, (dummy_obj->SizeOf<kVerifyNone, kWithoutReadBarrier>()));
+ CHECK_EQ(byte_size, (dummy_obj->SizeOf<kVerifyNone>()));
} else {
// Use an int array.
dummy_obj->SetClass(int_array_class);
@@ -2075,7 +2081,7 @@
CHECK_EQ(dummy_arr->GetLength(), length)
<< "byte_size=" << byte_size << " length=" << length
<< " component_size=" << component_size << " data_offset=" << data_offset;
- CHECK_EQ(byte_size, (dummy_obj->SizeOf<kVerifyNone, kWithoutReadBarrier>()))
+ CHECK_EQ(byte_size, (dummy_obj->SizeOf<kVerifyNone>()))
<< "byte_size=" << byte_size << " length=" << length
<< " component_size=" << component_size << " data_offset=" << data_offset;
}
@@ -2142,10 +2148,10 @@
mirror::Object* ConcurrentCopying::Copy(mirror::Object* from_ref) {
DCHECK(region_space_->IsInFromSpace(from_ref));
- // No read barrier to avoid nested RB that might violate the to-space
- // invariant. Note that from_ref is a from space ref so the SizeOf()
- // call will access the from-space meta objects, but it's ok and necessary.
- size_t obj_size = from_ref->SizeOf<kDefaultVerifyFlags, kWithoutReadBarrier>();
+ // There must not be a read barrier to avoid nested RB that might violate the to-space invariant.
+ // Note that from_ref is a from space ref so the SizeOf() call will access the from-space meta
+ // objects, but it's ok and necessary.
+ size_t obj_size = from_ref->SizeOf<kDefaultVerifyFlags>();
size_t region_space_alloc_size = RoundUp(obj_size, space::RegionSpace::kAlignment);
size_t region_space_bytes_allocated = 0U;
size_t non_moving_space_bytes_allocated = 0U;
diff --git a/runtime/gc/gc_cause.cc b/runtime/gc/gc_cause.cc
index c1c1cad..c35ec7c 100644
--- a/runtime/gc/gc_cause.cc
+++ b/runtime/gc/gc_cause.cc
@@ -29,6 +29,7 @@
case kGcCauseBackground: return "Background";
case kGcCauseExplicit: return "Explicit";
case kGcCauseForNativeAlloc: return "NativeAlloc";
+ case kGcCauseForNativeAllocBackground: return "NativeAllocBackground";
case kGcCauseCollectorTransition: return "CollectorTransition";
case kGcCauseDisableMovingGc: return "DisableMovingGc";
case kGcCauseHomogeneousSpaceCompact: return "HomogeneousSpaceCompact";
diff --git a/runtime/gc/gc_cause.h b/runtime/gc/gc_cause.h
index eb27547..41c8943 100644
--- a/runtime/gc/gc_cause.h
+++ b/runtime/gc/gc_cause.h
@@ -33,6 +33,8 @@
kGcCauseExplicit,
// GC triggered for a native allocation.
kGcCauseForNativeAlloc,
+ // Background GC triggered for a native allocation.
+ kGcCauseForNativeAllocBackground,
// GC triggered for a collector transition.
kGcCauseCollectorTransition,
// Not a real GC cause, used when we disable moving GC (currently for GetPrimitiveArrayCritical).
diff --git a/runtime/gc/heap.cc b/runtime/gc/heap.cc
index f04bc89..4a25610 100644
--- a/runtime/gc/heap.cc
+++ b/runtime/gc/heap.cc
@@ -2337,9 +2337,7 @@
size_t bin_size = object_addr - context->prev_;
// Add the bin consisting of the end of the previous object to the start of the current object.
collector->AddBin(bin_size, context->prev_);
- // Turn off read barrier. ZygoteCompactingCollector doesn't use it (even in the CC build.)
- context->prev_ = object_addr + RoundUp(obj->SizeOf<kDefaultVerifyFlags, kWithoutReadBarrier>(),
- kObjectAlignment);
+ context->prev_ = object_addr + RoundUp(obj->SizeOf<kDefaultVerifyFlags>(), kObjectAlignment);
}
void AddBin(size_t size, uintptr_t position) {
@@ -2359,8 +2357,7 @@
virtual mirror::Object* MarkNonForwardedObject(mirror::Object* obj)
REQUIRES(Locks::heap_bitmap_lock_, Locks::mutator_lock_) {
- // Turn off read barrier. ZygoteCompactingCollector doesn't use it (even in the CC build.)
- size_t obj_size = obj->SizeOf<kDefaultVerifyFlags, kWithoutReadBarrier>();
+ size_t obj_size = obj->SizeOf<kDefaultVerifyFlags>();
size_t alloc_size = RoundUp(obj_size, kObjectAlignment);
mirror::Object* forward_address;
// Find the smallest bin which we can move obj in.
@@ -2542,6 +2539,13 @@
// to large objects.
mod_union_table->SetCards();
} else {
+ // Make sure to clear the zygote space cards so that we don't dirty pages in the next GC. There
+ // may be dirty cards from the zygote compaction or reference processing. These cards are not
+ // necessary to have marked since the zygote space may not refer to any objects not in the
+ // zygote or image spaces at this point.
+ mod_union_table->ProcessCards();
+ mod_union_table->ClearTable();
+
// For CC we never collect zygote large objects. This means we do not need to set the cards for
// the zygote mod-union table and we can also clear all of the existing image mod-union tables.
// The existing mod-union tables are only for image spaces and may only reference zygote and
@@ -3682,20 +3686,21 @@
ObjPtr<mirror::Object>* obj) {
StackHandleScope<1> hs(self);
HandleWrapperObjPtr<mirror::Object> wrapper(hs.NewHandleWrapper(obj));
- RequestConcurrentGC(self, force_full);
+ RequestConcurrentGC(self, kGcCauseBackground, force_full);
}
class Heap::ConcurrentGCTask : public HeapTask {
public:
- ConcurrentGCTask(uint64_t target_time, bool force_full)
- : HeapTask(target_time), force_full_(force_full) { }
+ ConcurrentGCTask(uint64_t target_time, GcCause cause, bool force_full)
+ : HeapTask(target_time), cause_(cause), force_full_(force_full) {}
virtual void Run(Thread* self) OVERRIDE {
gc::Heap* heap = Runtime::Current()->GetHeap();
- heap->ConcurrentGC(self, force_full_);
+ heap->ConcurrentGC(self, cause_, force_full_);
heap->ClearConcurrentGCRequest();
}
private:
+ const GcCause cause_;
const bool force_full_; // If true, force full (or partial) collection.
};
@@ -3709,18 +3714,19 @@
concurrent_gc_pending_.StoreRelaxed(false);
}
-void Heap::RequestConcurrentGC(Thread* self, bool force_full) {
+void Heap::RequestConcurrentGC(Thread* self, GcCause cause, bool force_full) {
if (CanAddHeapTask(self) &&
concurrent_gc_pending_.CompareExchangeStrongSequentiallyConsistent(false, true)) {
task_processor_->AddTask(self, new ConcurrentGCTask(NanoTime(), // Start straight away.
+ cause,
force_full));
}
}
-void Heap::ConcurrentGC(Thread* self, bool force_full) {
+void Heap::ConcurrentGC(Thread* self, GcCause cause, bool force_full) {
if (!Runtime::Current()->IsShuttingDown(self)) {
// Wait for any GCs currently running to finish.
- if (WaitForGcToComplete(kGcCauseBackground, self) == collector::kGcTypeNone) {
+ if (WaitForGcToComplete(cause, self) == collector::kGcTypeNone) {
// If the we can't run the GC type we wanted to run, find the next appropriate one and try that
// instead. E.g. can't do partial, so do full instead.
collector::GcType next_gc_type = next_gc_type_;
@@ -3728,13 +3734,11 @@
if (force_full && next_gc_type == collector::kGcTypeSticky) {
next_gc_type = NonStickyGcType();
}
- if (CollectGarbageInternal(next_gc_type, kGcCauseBackground, false) ==
- collector::kGcTypeNone) {
+ if (CollectGarbageInternal(next_gc_type, cause, false) == collector::kGcTypeNone) {
for (collector::GcType gc_type : gc_plan_) {
// Attempt to run the collector, if we succeed, we are done.
if (gc_type > next_gc_type &&
- CollectGarbageInternal(gc_type, kGcCauseBackground, false) !=
- collector::kGcTypeNone) {
+ CollectGarbageInternal(gc_type, cause, false) != collector::kGcTypeNone) {
break;
}
}
@@ -3936,7 +3940,7 @@
// Trigger another GC because there have been enough native bytes
// allocated since the last GC.
if (IsGcConcurrent()) {
- RequestConcurrentGC(ThreadForEnv(env), /*force_full*/true);
+ RequestConcurrentGC(ThreadForEnv(env), kGcCauseForNativeAllocBackground, /*force_full*/true);
} else {
CollectGarbageInternal(NonStickyGcType(), kGcCauseForNativeAlloc, false);
}
diff --git a/runtime/gc/heap.h b/runtime/gc/heap.h
index 1a782b4..241d84c 100644
--- a/runtime/gc/heap.h
+++ b/runtime/gc/heap.h
@@ -330,7 +330,7 @@
// Does a concurrent GC, should only be called by the GC daemon thread
// through runtime.
- void ConcurrentGC(Thread* self, bool force_full)
+ void ConcurrentGC(Thread* self, GcCause cause, bool force_full)
REQUIRES(!Locks::runtime_shutdown_lock_, !*gc_complete_lock_, !*pending_task_lock_);
// Implements VMDebug.countInstancesOfClass and JDWP VM_InstanceCount.
@@ -743,7 +743,8 @@
void RequestTrim(Thread* self) REQUIRES(!*pending_task_lock_);
// Request asynchronous GC.
- void RequestConcurrentGC(Thread* self, bool force_full) REQUIRES(!*pending_task_lock_);
+ void RequestConcurrentGC(Thread* self, GcCause cause, bool force_full)
+ REQUIRES(!*pending_task_lock_);
// Whether or not we may use a garbage collector, used so that we only create collectors we need.
bool MayUseCollector(CollectorType type) const;
diff --git a/runtime/gc/heap_test.cc b/runtime/gc/heap_test.cc
index 515a6fd..6d426c2 100644
--- a/runtime/gc/heap_test.cc
+++ b/runtime/gc/heap_test.cc
@@ -72,6 +72,11 @@
bitmap->Set(fake_end_of_heap_object);
}
+TEST_F(HeapTest, DumpGCPerformanceOnShutdown) {
+ Runtime::Current()->GetHeap()->CollectGarbage(/* clear_soft_references */ false);
+ Runtime::Current()->SetDumpGCPerformanceOnShutdown(true);
+}
+
class ZygoteHeapTest : public CommonRuntimeTest {
void SetUpRuntimeOptions(RuntimeOptions* options) {
CommonRuntimeTest::SetUpRuntimeOptions(options);
diff --git a/runtime/method_handles.cc b/runtime/method_handles.cc
index bd7c4ad..b6f8a17 100644
--- a/runtime/method_handles.cc
+++ b/runtime/method_handles.cc
@@ -925,8 +925,17 @@
case mirror::MethodHandle::kInstancePut: {
size_t obj_reg = is_range ? first_arg : args[0];
size_t value_reg = is_range ? (first_arg + 1) : args[1];
- JValue value = GetValueFromShadowFrame(shadow_frame, field_type, value_reg);
- if (do_conversions && !ConvertArgumentValue(callsite_type, handle_type, 1, &value)) {
+ const size_t kPTypeIndex = 1;
+ // Use ptypes instead of field type since we may be unboxing a reference for a primitive
+ // field. The field type is incorrect for this case.
+ JValue value = GetValueFromShadowFrame(
+ shadow_frame,
+ callsite_type->GetPTypes()->Get(kPTypeIndex)->GetPrimitiveType(),
+ value_reg);
+ if (do_conversions && !ConvertArgumentValue(callsite_type,
+ handle_type,
+ kPTypeIndex,
+ &value)) {
DCHECK(self->IsExceptionPending());
return false;
}
@@ -940,8 +949,17 @@
return false;
}
size_t value_reg = is_range ? first_arg : args[0];
- JValue value = GetValueFromShadowFrame(shadow_frame, field_type, value_reg);
- if (do_conversions && !ConvertArgumentValue(callsite_type, handle_type, 0, &value)) {
+ const size_t kPTypeIndex = 0;
+ // Use ptypes instead of field type since we may be unboxing a reference for a primitive
+ // field. The field type is incorrect for this case.
+ JValue value = GetValueFromShadowFrame(
+ shadow_frame,
+ callsite_type->GetPTypes()->Get(kPTypeIndex)->GetPrimitiveType(),
+ value_reg);
+ if (do_conversions && !ConvertArgumentValue(callsite_type,
+ handle_type,
+ kPTypeIndex,
+ &value)) {
DCHECK(self->IsExceptionPending());
return false;
}
diff --git a/runtime/mirror/object-inl.h b/runtime/mirror/object-inl.h
index 811f1ea..f83645e 100644
--- a/runtime/mirror/object-inl.h
+++ b/runtime/mirror/object-inl.h
@@ -513,8 +513,11 @@
return GetClass<kVerifyFlags>()->IsPhantomReferenceClass();
}
-template<VerifyObjectFlags kVerifyFlags, ReadBarrierOption kReadBarrierOption>
+template<VerifyObjectFlags kVerifyFlags>
inline size_t Object::SizeOf() {
+ // Read barrier is never required for SizeOf since objects sizes are constant. Reading from-space
+ // values is OK because of that.
+ static constexpr ReadBarrierOption kReadBarrierOption = kWithoutReadBarrier;
size_t result;
constexpr auto kNewFlags = static_cast<VerifyObjectFlags>(kVerifyFlags & ~kVerifyThis);
if (IsArrayInstance<kVerifyFlags, kReadBarrierOption>()) {
diff --git a/runtime/mirror/object.h b/runtime/mirror/object.h
index f7ab26d..417a22d 100644
--- a/runtime/mirror/object.h
+++ b/runtime/mirror/object.h
@@ -128,8 +128,7 @@
template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
ALWAYS_INLINE bool InstanceOf(ObjPtr<Class> klass) REQUIRES_SHARED(Locks::mutator_lock_);
- template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags,
- ReadBarrierOption kReadBarrierOption = kWithReadBarrier>
+ template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
size_t SizeOf() REQUIRES_SHARED(Locks::mutator_lock_);
Object* Clone(Thread* self) REQUIRES_SHARED(Locks::mutator_lock_)
diff --git a/runtime/native/dalvik_system_VMRuntime.cc b/runtime/native/dalvik_system_VMRuntime.cc
index 11f8505..34bbf32 100644
--- a/runtime/native/dalvik_system_VMRuntime.cc
+++ b/runtime/native/dalvik_system_VMRuntime.cc
@@ -252,7 +252,7 @@
}
static void VMRuntime_concurrentGC(JNIEnv* env, jobject) {
- Runtime::Current()->GetHeap()->ConcurrentGC(ThreadForEnv(env), true);
+ Runtime::Current()->GetHeap()->ConcurrentGC(ThreadForEnv(env), gc::kGcCauseBackground, true);
}
static void VMRuntime_requestHeapTrim(JNIEnv* env, jobject) {
@@ -260,7 +260,9 @@
}
static void VMRuntime_requestConcurrentGC(JNIEnv* env, jobject) {
- Runtime::Current()->GetHeap()->RequestConcurrentGC(ThreadForEnv(env), true);
+ Runtime::Current()->GetHeap()->RequestConcurrentGC(ThreadForEnv(env),
+ gc::kGcCauseBackground,
+ true);
}
static void VMRuntime_startHeapTaskProcessor(JNIEnv* env, jobject) {
diff --git a/runtime/oat.h b/runtime/oat.h
index faa0129..58ea91b 100644
--- a/runtime/oat.h
+++ b/runtime/oat.h
@@ -32,7 +32,7 @@
class PACKED(4) OatHeader {
public:
static constexpr uint8_t kOatMagic[] = { 'o', 'a', 't', '\n' };
- static constexpr uint8_t kOatVersion[] = { '1', '1', '7', '\0' }; // Read barriers on MIPS.
+ static constexpr uint8_t kOatVersion[] = { '1', '1', '8', '\0' }; // ARM64 Read barriers thunks.
static constexpr const char* kImageLocationKey = "image-location";
static constexpr const char* kDex2OatCmdLineKey = "dex2oat-cmdline";
diff --git a/runtime/oat_file_manager.cc b/runtime/oat_file_manager.cc
index d04dbbe..a950980 100644
--- a/runtime/oat_file_manager.cc
+++ b/runtime/oat_file_manager.cc
@@ -482,6 +482,8 @@
}
// Now drain the queue.
+ bool has_duplicates = false;
+ error_msg->clear();
while (!queue.empty()) {
// Modifying the top element is only safe if we pop right after.
DexFileAndClassPair compare_pop(queue.top());
@@ -493,12 +495,15 @@
if (strcmp(compare_pop.GetCachedDescriptor(), top.GetCachedDescriptor()) == 0) {
// Same descriptor. Check whether it's crossing old-oat-files to new-oat-files.
if (compare_pop.FromLoadedOat() != top.FromLoadedOat()) {
- *error_msg =
- StringPrintf("Found duplicated class when checking oat files: '%s' in %s and %s",
+ error_msg->append(
+ StringPrintf("Found duplicated class when checking oat files: '%s' in %s and %s\n",
compare_pop.GetCachedDescriptor(),
compare_pop.GetDexFile()->GetLocation().c_str(),
- top.GetDexFile()->GetLocation().c_str());
- return true;
+ top.GetDexFile()->GetLocation().c_str()));
+ if (!VLOG_IS_ON(oat)) {
+ return true;
+ }
+ has_duplicates = true;
}
queue.pop();
AddNext(top, queue);
@@ -510,7 +515,7 @@
AddNext(compare_pop, queue);
}
- return false;
+ return has_duplicates;
}
// Check for class-def collisions in dex files.
diff --git a/runtime/openjdkjvmti/events-inl.h b/runtime/openjdkjvmti/events-inl.h
index 1ddbb86..233b45c 100644
--- a/runtime/openjdkjvmti/events-inl.h
+++ b/runtime/openjdkjvmti/events-inl.h
@@ -131,6 +131,9 @@
unsigned char* current_class_data = const_cast<unsigned char*>(class_data);
ArtJvmTiEnv* last_env = nullptr;
for (ArtJvmTiEnv* env : envs) {
+ if (env == nullptr) {
+ continue;
+ }
if (ShouldDispatch<kEvent>(env, thread)) {
jint new_len = 0;
unsigned char* new_data = nullptr;
@@ -171,7 +174,9 @@
template <ArtJvmtiEvent kEvent, typename ...Args>
inline void EventHandler::DispatchEvent(art::Thread* thread, Args... args) const {
for (ArtJvmTiEnv* env : envs) {
- DispatchEvent<kEvent, Args...>(env, thread, args...);
+ if (env != nullptr) {
+ DispatchEvent<kEvent, Args...>(env, thread, args...);
+ }
}
}
@@ -253,6 +258,9 @@
inline void EventHandler::RecalculateGlobalEventMask(ArtJvmtiEvent event) {
bool union_value = false;
for (const ArtJvmTiEnv* stored_env : envs) {
+ if (stored_env == nullptr) {
+ continue;
+ }
union_value |= stored_env->event_masks.global_event_mask.Test(event);
union_value |= stored_env->event_masks.unioned_thread_event_mask.Test(event);
if (union_value) {
diff --git a/runtime/openjdkjvmti/events.cc b/runtime/openjdkjvmti/events.cc
index 34492a9..521494a 100644
--- a/runtime/openjdkjvmti/events.cc
+++ b/runtime/openjdkjvmti/events.cc
@@ -141,13 +141,21 @@
}
void EventHandler::RegisterArtJvmTiEnv(ArtJvmTiEnv* env) {
- envs.push_back(env);
+ // Since we never shrink this array we might as well try to fill gaps.
+ auto it = std::find(envs.begin(), envs.end(), nullptr);
+ if (it != envs.end()) {
+ *it = env;
+ } else {
+ envs.push_back(env);
+ }
}
void EventHandler::RemoveArtJvmTiEnv(ArtJvmTiEnv* env) {
+ // Since we might be currently iterating over the envs list we cannot actually erase elements.
+ // Instead we will simply replace them with 'nullptr' and skip them manually.
auto it = std::find(envs.begin(), envs.end(), env);
if (it != envs.end()) {
- envs.erase(it);
+ *it = nullptr;
for (size_t i = static_cast<size_t>(ArtJvmtiEvent::kMinEventTypeVal);
i <= static_cast<size_t>(ArtJvmtiEvent::kMaxEventTypeVal);
++i) {
diff --git a/runtime/openjdkjvmti/events.h b/runtime/openjdkjvmti/events.h
index ae8bf0f..b9e3cf0 100644
--- a/runtime/openjdkjvmti/events.h
+++ b/runtime/openjdkjvmti/events.h
@@ -202,6 +202,8 @@
void HandleEventType(ArtJvmtiEvent event, bool enable);
// List of all JvmTiEnv objects that have been created, in their creation order.
+ // NB Some elements might be null representing envs that have been deleted. They should be skipped
+ // anytime this list is used.
std::vector<ArtJvmTiEnv*> envs;
// A union of all enabled events, anywhere.
diff --git a/runtime/openjdkjvmti/ti_class_definition.cc b/runtime/openjdkjvmti/ti_class_definition.cc
index 153692b..0671105 100644
--- a/runtime/openjdkjvmti/ti_class_definition.cc
+++ b/runtime/openjdkjvmti/ti_class_definition.cc
@@ -102,7 +102,9 @@
} else if (orig_dex->IsDexCache()) {
dex_file = orig_dex->AsDexCache()->GetDexFile();
} else {
- DCHECK_EQ(orig_dex->GetClass()->GetPrimitiveType(), art::Primitive::kPrimLong);
+ DCHECK(orig_dex->GetClass()->DescriptorEquals("Ljava/lang/Long;"))
+ << "Expected java/lang/Long but found object of type "
+ << orig_dex->GetClass()->PrettyClass();
art::ObjPtr<art::mirror::Class> prim_long_class(
art::Runtime::Current()->GetClassLinker()->GetClassRoot(
art::ClassLinker::kPrimitiveLong));
diff --git a/runtime/openjdkjvmti/ti_heap.cc b/runtime/openjdkjvmti/ti_heap.cc
index 49d9aca..7fc5104 100644
--- a/runtime/openjdkjvmti/ti_heap.cc
+++ b/runtime/openjdkjvmti/ti_heap.cc
@@ -888,8 +888,8 @@
bool add_to_worklist = ReportRoot(root_obj, info);
// We use visited_ to mark roots already so we do not need another set.
if (visited_->find(root_obj) == visited_->end()) {
- visited_->insert(root_obj);
if (add_to_worklist) {
+ visited_->insert(root_obj);
worklist_->push_back(root_obj);
}
}
diff --git a/runtime/openjdkjvmti/ti_method.cc b/runtime/openjdkjvmti/ti_method.cc
index bc73029..01bf21d 100644
--- a/runtime/openjdkjvmti/ti_method.cc
+++ b/runtime/openjdkjvmti/ti_method.cc
@@ -61,8 +61,13 @@
art::ScopedObjectAccess soa(art::Thread::Current());
if (art_method->IsProxyMethod() || art_method->IsAbstract()) {
- // This isn't specified as an error case, so return 0.
- *size_ptr = 0;
+ // Use the shorty.
+ art::ArtMethod* base_method = art_method->GetInterfaceMethodIfProxy(art::kRuntimePointerSize);
+ size_t arg_count = art::ArtMethod::NumArgRegisters(base_method->GetShorty());
+ if (!base_method->IsStatic()) {
+ arg_count++;
+ }
+ *size_ptr = static_cast<jint>(arg_count);
return ERR(NONE);
}
@@ -203,9 +208,9 @@
art::ScopedObjectAccess soa(art::Thread::Current());
if (art_method->IsProxyMethod() || art_method->IsAbstract()) {
- // This isn't specified as an error case, so return 0/0.
- *start_location_ptr = 0;
- *end_location_ptr = 0;
+ // This isn't specified as an error case, so return -1/-1 as the RI does.
+ *start_location_ptr = -1;
+ *end_location_ptr = -1;
return ERR(NONE);
}
diff --git a/runtime/openjdkjvmti/ti_properties.cc b/runtime/openjdkjvmti/ti_properties.cc
index 4f4f013..8ee5366 100644
--- a/runtime/openjdkjvmti/ti_properties.cc
+++ b/runtime/openjdkjvmti/ti_properties.cc
@@ -34,8 +34,15 @@
#include <string.h>
#include <vector>
+#include "jni.h"
+#include "ScopedLocalRef.h"
+#include "ScopedUtfChars.h"
+
#include "art_jvmti.h"
#include "runtime.h"
+#include "thread-inl.h"
+#include "ti_phase.h"
+#include "well_known_classes.h"
namespace openjdkjvmti {
@@ -145,6 +152,56 @@
return result;
}
+// See dalvik_system_VMRuntime.cpp.
+static const char* DefaultToDot(const std::string& class_path) {
+ return class_path.empty() ? "." : class_path.c_str();
+}
+
+// Handle kPropertyLibraryPath.
+static jvmtiError GetLibraryPath(jvmtiEnv* env, char** value_ptr) {
+ const std::vector<std::string>& runtime_props = art::Runtime::Current()->GetProperties();
+ for (const std::string& prop_assignment : runtime_props) {
+ size_t assign_pos = prop_assignment.find('=');
+ if (assign_pos != std::string::npos && assign_pos > 0) {
+ if (prop_assignment.substr(0, assign_pos) == kPropertyLibraryPath) {
+ return Copy(env, prop_assignment.substr(assign_pos + 1).c_str(), value_ptr);
+ }
+ }
+ }
+ if (!PhaseUtil::IsLivePhase()) {
+ return ERR(NOT_AVAILABLE);
+ }
+ // We expect this call to be rare. So don't optimize.
+ DCHECK(art::Thread::Current() != nullptr);
+ JNIEnv* jni_env = art::Thread::Current()->GetJniEnv();
+ jmethodID get_prop = jni_env->GetStaticMethodID(art::WellKnownClasses::java_lang_System,
+ "getProperty",
+ "(Ljava/lang/String;)Ljava/lang/String;");
+ CHECK(get_prop != nullptr);
+
+ ScopedLocalRef<jobject> input_str(jni_env, jni_env->NewStringUTF(kPropertyLibraryPath));
+ if (input_str.get() == nullptr) {
+ jni_env->ExceptionClear();
+ return ERR(OUT_OF_MEMORY);
+ }
+
+ ScopedLocalRef<jobject> prop_res(
+ jni_env, jni_env->CallStaticObjectMethod(art::WellKnownClasses::java_lang_System,
+ get_prop,
+ input_str.get()));
+ if (jni_env->ExceptionCheck() == JNI_TRUE) {
+ jni_env->ExceptionClear();
+ return ERR(INTERNAL);
+ }
+ if (prop_res.get() == nullptr) {
+ *value_ptr = nullptr;
+ return ERR(NONE);
+ }
+
+ ScopedUtfChars chars(jni_env, reinterpret_cast<jstring>(prop_res.get()));
+ return Copy(env, chars.c_str(), value_ptr);
+}
+
jvmtiError PropertiesUtil::GetSystemProperty(jvmtiEnv* env,
const char* property,
char** value_ptr) {
@@ -153,22 +210,11 @@
}
if (strcmp(property, kPropertyLibraryPath) == 0) {
- // TODO: In the live phase, we should probably compare to System.getProperty. java.library.path
- // may not be set initially, and is then freely modifiable.
- const std::vector<std::string>& runtime_props = art::Runtime::Current()->GetProperties();
- for (const std::string& prop_assignment : runtime_props) {
- size_t assign_pos = prop_assignment.find('=');
- if (assign_pos != std::string::npos && assign_pos > 0) {
- if (prop_assignment.substr(0, assign_pos) == kPropertyLibraryPath) {
- return Copy(env, prop_assignment.substr(assign_pos + 1).c_str(), value_ptr);
- }
- }
- }
- return ERR(NOT_AVAILABLE);
+ return GetLibraryPath(env, value_ptr);
}
if (strcmp(property, kPropertyClassPath) == 0) {
- return Copy(env, art::Runtime::Current()->GetClassPathString().c_str(), value_ptr);
+ return Copy(env, DefaultToDot(art::Runtime::Current()->GetClassPathString()), value_ptr);
}
for (size_t i = 0; i != kPropertiesSize; ++i) {
diff --git a/runtime/openjdkjvmti/ti_redefine.cc b/runtime/openjdkjvmti/ti_redefine.cc
index 0655079..358bb0f 100644
--- a/runtime/openjdkjvmti/ti_redefine.cc
+++ b/runtime/openjdkjvmti/ti_redefine.cc
@@ -1418,14 +1418,18 @@
art::mirror::Class* klass = GetMirrorClass();
art::mirror::ClassExt* ext = klass->GetExtData();
art::mirror::PointerArray* methods = ext->GetObsoleteMethods();
- int32_t old_length =
- cur_data->GetOldDexCaches() == nullptr ? 0 : cur_data->GetOldDexCaches()->GetLength();
+ art::mirror::PointerArray* old_methods = cur_data->GetOldObsoleteMethods();
+ int32_t old_length = old_methods == nullptr ? 0 : old_methods->GetLength();
int32_t expected_length =
old_length + klass->NumDirectMethods() + klass->NumDeclaredVirtualMethods();
// Check to make sure we are only undoing this one.
if (expected_length == methods->GetLength()) {
- for (int32_t i = old_length; i < expected_length; i++) {
- if (methods->GetElementPtrSize<art::ArtMethod*>(i, art::kRuntimePointerSize) != nullptr) {
+ for (int32_t i = 0; i < expected_length; i++) {
+ art::ArtMethod* expected = nullptr;
+ if (i < old_length) {
+ expected = old_methods->GetElementPtrSize<art::ArtMethod*>(i, art::kRuntimePointerSize);
+ }
+ if (methods->GetElementPtrSize<art::ArtMethod*>(i, art::kRuntimePointerSize) != expected) {
// We actually have some new obsolete methods. Just abort since we cannot safely shrink the
// obsolete methods array.
return;
diff --git a/runtime/read_barrier-inl.h b/runtime/read_barrier-inl.h
index 2b38b2e..c102fb0 100644
--- a/runtime/read_barrier-inl.h
+++ b/runtime/read_barrier-inl.h
@@ -28,12 +28,15 @@
namespace art {
+// Disabled for performance reasons.
+static constexpr bool kCheckDebugDisallowReadBarrierCount = false;
+
template <typename MirrorType, ReadBarrierOption kReadBarrierOption, bool kAlwaysUpdateField>
inline MirrorType* ReadBarrier::Barrier(
mirror::Object* obj, MemberOffset offset, mirror::HeapReference<MirrorType>* ref_addr) {
constexpr bool with_read_barrier = kReadBarrierOption == kWithReadBarrier;
if (kUseReadBarrier && with_read_barrier) {
- if (kIsDebugBuild) {
+ if (kCheckDebugDisallowReadBarrierCount) {
Thread* const self = Thread::Current();
if (self != nullptr) {
CHECK_EQ(self->GetDebugDisallowReadBarrierCount(), 0u);
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index 48efbe5..a48a58d 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -269,13 +269,6 @@
UnloadNativeBridge();
}
- if (dump_gc_performance_on_shutdown_) {
- // This can't be called from the Heap destructor below because it
- // could call RosAlloc::InspectAll() which needs the thread_list
- // to be still alive.
- heap_->DumpGcPerformanceInfo(LOG_STREAM(INFO));
- }
-
Thread* self = Thread::Current();
const bool attach_shutdown_thread = self == nullptr;
if (attach_shutdown_thread) {
@@ -285,6 +278,13 @@
LOG(WARNING) << "Current thread not detached in Runtime shutdown";
}
+ if (dump_gc_performance_on_shutdown_) {
+ // This can't be called from the Heap destructor below because it
+ // could call RosAlloc::InspectAll() which needs the thread_list
+ // to be still alive.
+ heap_->DumpGcPerformanceInfo(LOG_STREAM(INFO));
+ }
+
if (jit_ != nullptr) {
// Stop the profile saver thread before marking the runtime as shutting down.
// The saver will try to dump the profiles before being sopped and that
@@ -1722,6 +1722,7 @@
mirror::MethodHandlesLookup::VisitRoots(visitor);
mirror::EmulatedStackFrame::VisitRoots(visitor);
mirror::ClassExt::VisitRoots(visitor);
+ mirror::CallSite::VisitRoots(visitor);
// Visit all the primitive array types classes.
mirror::PrimitiveArray<uint8_t>::VisitRoots(visitor); // BooleanArray
mirror::PrimitiveArray<int8_t>::VisitRoots(visitor); // ByteArray
diff --git a/runtime/runtime.h b/runtime/runtime.h
index 92feabb..20db628 100644
--- a/runtime/runtime.h
+++ b/runtime/runtime.h
@@ -661,6 +661,10 @@
void InitThreadGroups(Thread* self);
+ void SetDumpGCPerformanceOnShutdown(bool value) {
+ dump_gc_performance_on_shutdown_ = value;
+ }
+
private:
static void InitPlatformSignalHandlers();
diff --git a/runtime/stack.cc b/runtime/stack.cc
index 333128b..5c6eead 100644
--- a/runtime/stack.cc
+++ b/runtime/stack.cc
@@ -913,7 +913,9 @@
<< " next=" << *cur_quick_frame_;
}
- cur_depth_++;
+ if (kCount == CountTransitions::kYes || !method->IsRuntimeMethod()) {
+ cur_depth_++;
+ }
method = *cur_quick_frame_;
}
} else if (cur_shadow_frame_ != nullptr) {
diff --git a/runtime/thread.cc b/runtime/thread.cc
index 008c388..a8a03c7 100644
--- a/runtime/thread.cc
+++ b/runtime/thread.cc
@@ -1451,7 +1451,8 @@
MutexLock mu2(self, *Locks::thread_suspend_count_lock_);
DCHECK_NE(GetState(), ThreadState::kRunnable);
- CHECK(ModifySuspendCount(self, -1, nullptr, false));
+ bool updated = ModifySuspendCount(self, -1, nullptr, false);
+ DCHECK(updated);
}
return; // We're done, break out of the loop.
@@ -1928,6 +1929,23 @@
Thread::Current()->AssertNoPendingException();
Runtime::Current()->GetClassLinker()->RunRootClinits();
+
+ // The thread counts as started from now on. We need to add it to the ThreadGroup. For regular
+ // threads, this is done in Thread.start() on the Java side.
+ {
+ // This is only ever done once. There's no benefit in caching the method.
+ jmethodID thread_group_add = soa.Env()->GetMethodID(WellKnownClasses::java_lang_ThreadGroup,
+ "add",
+ "(Ljava/lang/Thread;)V");
+ CHECK(thread_group_add != nullptr);
+ ScopedLocalRef<jobject> thread_jobject(
+ soa.Env(), soa.Env()->AddLocalReference<jobject>(Thread::Current()->GetPeer()));
+ soa.Env()->CallNonvirtualVoidMethod(runtime->GetMainThreadGroup(),
+ WellKnownClasses::java_lang_ThreadGroup,
+ thread_group_add,
+ thread_jobject.get());
+ Thread::Current()->AssertNoPendingException();
+ }
}
void Thread::Shutdown() {
diff --git a/runtime/thread.h b/runtime/thread.h
index de0b892..4d5d644 100644
--- a/runtime/thread.h
+++ b/runtime/thread.h
@@ -244,6 +244,7 @@
int delta,
AtomicInteger* suspend_barrier,
bool for_debugger)
+ WARN_UNUSED
REQUIRES(Locks::thread_suspend_count_lock_);
bool RequestCheckpoint(Closure* function)
@@ -1276,6 +1277,7 @@
int delta,
AtomicInteger* suspend_barrier,
bool for_debugger)
+ WARN_UNUSED
REQUIRES(Locks::thread_suspend_count_lock_);
void RunCheckpointFunction();
diff --git a/runtime/thread_list.cc b/runtime/thread_list.cc
index 8d72fe8..2e0d866 100644
--- a/runtime/thread_list.cc
+++ b/runtime/thread_list.cc
@@ -323,7 +323,8 @@
// Spurious fail, try again.
continue;
}
- thread->ModifySuspendCount(self, +1, nullptr, false);
+ bool updated = thread->ModifySuspendCount(self, +1, nullptr, false);
+ DCHECK(updated);
suspended_count_modified_threads.push_back(thread);
break;
}
@@ -365,7 +366,8 @@
checkpoint_function->Run(thread);
{
MutexLock mu2(self, *Locks::thread_suspend_count_lock_);
- thread->ModifySuspendCount(self, -1, nullptr, false);
+ bool updated = thread->ModifySuspendCount(self, -1, nullptr, false);
+ DCHECK(updated);
}
}
@@ -565,7 +567,8 @@
if ((state == kWaitingForGcThreadFlip || thread->IsTransitioningToRunnable()) &&
thread->GetSuspendCount() == 1) {
// The thread will resume right after the broadcast.
- thread->ModifySuspendCount(self, -1, nullptr, false);
+ bool updated = thread->ModifySuspendCount(self, -1, nullptr, false);
+ DCHECK(updated);
++runnable_thread_count;
} else {
other_threads.push_back(thread);
@@ -598,7 +601,8 @@
TimingLogger::ScopedTiming split4("ResumeOtherThreads", collector->GetTimings());
MutexLock mu2(self, *Locks::thread_suspend_count_lock_);
for (const auto& thread : other_threads) {
- thread->ModifySuspendCount(self, -1, nullptr, false);
+ bool updated = thread->ModifySuspendCount(self, -1, nullptr, false);
+ DCHECK(updated);
}
Thread::resume_cond_->Broadcast(self);
}
@@ -708,7 +712,8 @@
continue;
}
VLOG(threads) << "requesting thread suspend: " << *thread;
- thread->ModifySuspendCount(self, +1, &pending_threads, debug_suspend);
+ bool updated = thread->ModifySuspendCount(self, +1, &pending_threads, debug_suspend);
+ DCHECK(updated);
// Must install the pending_threads counter first, then check thread->IsSuspend() and clear
// the counter. Otherwise there's a race with Thread::TransitionFromRunnableToSuspended()
@@ -786,7 +791,8 @@
if (thread == self) {
continue;
}
- thread->ModifySuspendCount(self, -1, nullptr, false);
+ bool updated = thread->ModifySuspendCount(self, -1, nullptr, false);
+ DCHECK(updated);
}
// Broadcast a notification to all suspended threads, some or all of
@@ -828,7 +834,8 @@
<< ") thread not within thread list";
return;
}
- thread->ModifySuspendCount(self, -1, nullptr, for_debugger);
+ bool updated = thread->ModifySuspendCount(self, -1, nullptr, for_debugger);
+ DCHECK(updated);
}
{
@@ -884,7 +891,11 @@
// If we incremented the suspend count but the thread reset its peer, we need to
// re-decrement it since it is shutting down and may deadlock the runtime in
// ThreadList::WaitForOtherNonDaemonThreadsToExit.
- suspended_thread->ModifySuspendCount(soa.Self(), -1, nullptr, debug_suspension);
+ bool updated = suspended_thread->ModifySuspendCount(soa.Self(),
+ -1,
+ nullptr,
+ debug_suspension);
+ DCHECK(updated);
}
ThreadSuspendByPeerWarning(self,
::android::base::WARNING,
@@ -910,7 +921,8 @@
}
CHECK(suspended_thread == nullptr);
suspended_thread = thread;
- suspended_thread->ModifySuspendCount(self, +1, nullptr, debug_suspension);
+ bool updated = suspended_thread->ModifySuspendCount(self, +1, nullptr, debug_suspension);
+ DCHECK(updated);
request_suspension = false;
} else {
// If the caller isn't requesting suspension, a suspension should have already occurred.
@@ -942,7 +954,11 @@
peer);
if (suspended_thread != nullptr) {
CHECK_EQ(suspended_thread, thread);
- suspended_thread->ModifySuspendCount(soa.Self(), -1, nullptr, debug_suspension);
+ bool updated = suspended_thread->ModifySuspendCount(soa.Self(),
+ -1,
+ nullptr,
+ debug_suspension);
+ DCHECK(updated);
}
*timed_out = true;
return nullptr;
@@ -1015,7 +1031,8 @@
// which will allow this thread to be suspended.
continue;
}
- thread->ModifySuspendCount(self, +1, nullptr, debug_suspension);
+ bool updated = thread->ModifySuspendCount(self, +1, nullptr, debug_suspension);
+ DCHECK(updated);
suspended_thread = thread;
} else {
CHECK_EQ(suspended_thread, thread);
@@ -1046,7 +1063,8 @@
"Thread suspension timed out",
thread_id);
if (suspended_thread != nullptr) {
- thread->ModifySuspendCount(soa.Self(), -1, nullptr, debug_suspension);
+ bool updated = thread->ModifySuspendCount(soa.Self(), -1, nullptr, debug_suspension);
+ DCHECK(updated);
}
*timed_out = true;
return nullptr;
@@ -1123,7 +1141,8 @@
// to ensure that we're the only one fiddling with the suspend count
// though.
MutexLock mu(self, *Locks::thread_suspend_count_lock_);
- self->ModifySuspendCount(self, +1, nullptr, true);
+ bool updated = self->ModifySuspendCount(self, +1, nullptr, true);
+ DCHECK(updated);
CHECK_GT(self->GetSuspendCount(), 0);
VLOG(threads) << *self << " self-suspending (debugger)";
@@ -1207,7 +1226,8 @@
continue;
}
VLOG(threads) << "requesting thread resume: " << *thread;
- thread->ModifySuspendCount(self, -1, nullptr, true);
+ bool updated = thread->ModifySuspendCount(self, -1, nullptr, true);
+ DCHECK(updated);
}
}
}
@@ -1236,7 +1256,11 @@
if (thread == self || thread->GetDebugSuspendCount() == 0) {
continue;
}
- thread->ModifySuspendCount(self, -thread->GetDebugSuspendCount(), nullptr, true);
+ bool suspended = thread->ModifySuspendCount(self,
+ -thread->GetDebugSuspendCount(),
+ nullptr,
+ true);
+ DCHECK(suspended);
}
}
@@ -1293,7 +1317,8 @@
// daemons.
CHECK(thread->IsDaemon()) << *thread;
if (thread != self) {
- thread->ModifySuspendCount(self, +1, nullptr, false);
+ bool updated = thread->ModifySuspendCount(self, +1, nullptr, false);
+ DCHECK(updated);
++daemons_left;
}
// We are shutting down the runtime, set the JNI functions of all the JNIEnvs to be
@@ -1352,10 +1377,12 @@
// Modify suspend count in increments of 1 to maintain invariants in ModifySuspendCount. While
// this isn't particularly efficient the suspend counts are most commonly 0 or 1.
for (int delta = debug_suspend_all_count_; delta > 0; delta--) {
- self->ModifySuspendCount(self, +1, nullptr, true);
+ bool updated = self->ModifySuspendCount(self, +1, nullptr, true);
+ DCHECK(updated);
}
for (int delta = suspend_all_count_ - debug_suspend_all_count_; delta > 0; delta--) {
- self->ModifySuspendCount(self, +1, nullptr, false);
+ bool updated = self->ModifySuspendCount(self, +1, nullptr, false);
+ DCHECK(updated);
}
CHECK(!Contains(self));
list_.push_back(self);
@@ -1450,11 +1477,13 @@
MutexLock mu(self, *Locks::thread_list_lock_);
MutexLock mu2(self, *Locks::thread_suspend_count_lock_);
for (Thread* thread : list_) {
- thread->ModifySuspendCount(self, +1, nullptr, false);
+ bool suspended = thread->ModifySuspendCount(self, +1, nullptr, false);
+ DCHECK(suspended);
if (thread == self || thread->IsSuspended()) {
threads_to_visit.push_back(thread);
} else {
- thread->ModifySuspendCount(self, -1, nullptr, false);
+ bool resumed = thread->ModifySuspendCount(self, -1, nullptr, false);
+ DCHECK(resumed);
}
}
}
@@ -1469,7 +1498,8 @@
{
MutexLock mu2(self, *Locks::thread_suspend_count_lock_);
for (Thread* thread : threads_to_visit) {
- thread->ModifySuspendCount(self, -1, nullptr, false);
+ bool updated = thread->ModifySuspendCount(self, -1, nullptr, false);
+ DCHECK(updated);
}
}
}
diff --git a/sigchainlib/sigchain.cc b/sigchainlib/sigchain.cc
index cc1b78d..f4799d2 100644
--- a/sigchainlib/sigchain.cc
+++ b/sigchainlib/sigchain.cc
@@ -23,12 +23,14 @@
#include <dlfcn.h>
#include <errno.h>
+#include <pthread.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <initializer_list>
+#include <mutex>
#include <utility>
#include "sigchain.h"
@@ -61,7 +63,6 @@
// doesn't have SA_RESTART, and raise the signal to avoid restarting syscalls that are
// expected to be interrupted?
-
static void log(const char* format, ...) {
char buf[256];
va_list ap;
@@ -91,7 +92,41 @@
static decltype(&sigaction) linked_sigaction;
static decltype(&sigprocmask) linked_sigprocmask;
-__thread bool handling_signal;
+
+static pthread_key_t GetHandlingSignalKey() {
+ static pthread_key_t key;
+ static std::once_flag once;
+ std::call_once(once, []() {
+ int rc = pthread_key_create(&key, nullptr);
+ if (rc != 0) {
+ fatal("failed to create sigchain pthread key: %s", strerror(rc));
+ }
+ });
+ return key;
+}
+
+static bool GetHandlingSignal() {
+ void* result = pthread_getspecific(GetHandlingSignalKey());
+ return reinterpret_cast<uintptr_t>(result);
+}
+
+static void SetHandlingSignal(bool value) {
+ pthread_setspecific(GetHandlingSignalKey(),
+ reinterpret_cast<void*>(static_cast<uintptr_t>(value)));
+}
+
+class ScopedHandlingSignal {
+ public:
+ ScopedHandlingSignal() : original_value_(GetHandlingSignal()) {
+ }
+
+ ~ScopedHandlingSignal() {
+ SetHandlingSignal(original_value_);
+ }
+
+ private:
+ bool original_value_;
+};
class SignalChain {
public:
@@ -164,20 +199,6 @@
static SignalChain chains[_NSIG];
-class ScopedFlagRestorer {
- public:
- explicit ScopedFlagRestorer(bool* flag) : flag_(flag), original_value_(*flag) {
- }
-
- ~ScopedFlagRestorer() {
- *flag_ = original_value_;
- }
-
- private:
- bool* flag_;
- bool original_value_;
-};
-
class ScopedSignalUnblocker {
public:
explicit ScopedSignalUnblocker(const std::initializer_list<int>& signals) {
@@ -202,13 +223,13 @@
};
void SignalChain::Handler(int signo, siginfo_t* siginfo, void* ucontext_raw) {
- ScopedFlagRestorer flag(&handling_signal);
+ ScopedHandlingSignal handling_signal;
// Try the special handlers first.
// If one of them crashes, we'll reenter this handler and pass that crash onto the user handler.
- if (!handling_signal) {
+ if (!GetHandlingSignal()) {
ScopedSignalUnblocker unblocked { SIGABRT, SIGBUS, SIGFPE, SIGILL, SIGSEGV }; // NOLINT
- handling_signal = true;
+ SetHandlingSignal(true);
for (const auto& handler : chains[signo].special_handlers_) {
if (handler != nullptr && handler(signo, siginfo, ucontext_raw)) {
@@ -306,7 +327,7 @@
extern "C" int sigprocmask(int how, const sigset_t* bionic_new_set, sigset_t* bionic_old_set) {
// When inside a signal handler, forward directly to the actual sigprocmask.
- if (handling_signal) {
+ if (GetHandlingSignal()) {
return linked_sigprocmask(how, bionic_new_set, bionic_old_set);
}
diff --git a/test/051-thread/expected.txt b/test/051-thread/expected.txt
index 3fc3492..c8af963 100644
--- a/test/051-thread/expected.txt
+++ b/test/051-thread/expected.txt
@@ -12,4 +12,6 @@
testSetName finished
testThreadPriorities starting
testThreadPriorities finished
+Found current Thread in ThreadGroup
+Found expected stack in getAllStackTraces()
thread test done
diff --git a/test/051-thread/src/Main.java b/test/051-thread/src/Main.java
index 82fc0d4..08cb5de 100644
--- a/test/051-thread/src/Main.java
+++ b/test/051-thread/src/Main.java
@@ -15,6 +15,9 @@
*/
import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.List;
/**
* Test some basic thread stuff.
@@ -28,6 +31,8 @@
testSleepZero();
testSetName();
testThreadPriorities();
+ testMainThreadGroup();
+ testMainThreadAllStackTraces();
System.out.println("thread test done");
}
@@ -159,6 +164,49 @@
System.out.print("testThreadPriorities finished\n");
}
+ private static void testMainThreadGroup() {
+ Thread threads[] = new Thread[10];
+ Thread current = Thread.currentThread();
+ current.getThreadGroup().enumerate(threads);
+
+ for (Thread t : threads) {
+ if (t == current) {
+ System.out.println("Found current Thread in ThreadGroup");
+ return;
+ }
+ }
+ throw new RuntimeException("Did not find main thread: " + Arrays.toString(threads));
+ }
+
+ private static void testMainThreadAllStackTraces() {
+ StackTraceElement[] trace = Thread.getAllStackTraces().get(Thread.currentThread());
+ if (trace == null) {
+ throw new RuntimeException("Did not find main thread: " + Thread.getAllStackTraces());
+ }
+ List<StackTraceElement> list = Arrays.asList(trace);
+ Iterator<StackTraceElement> it = list.iterator();
+ while (it.hasNext()) {
+ StackTraceElement ste = it.next();
+ if (ste.getClassName().equals("Main")) {
+ if (!ste.getMethodName().equals("testMainThreadAllStackTraces")) {
+ throw new RuntimeException(list.toString());
+ }
+
+ StackTraceElement ste2 = it.next();
+ if (!ste2.getClassName().equals("Main")) {
+ throw new RuntimeException(list.toString());
+ }
+ if (!ste2.getMethodName().equals("main")) {
+ throw new RuntimeException(list.toString());
+ }
+
+ System.out.println("Found expected stack in getAllStackTraces()");
+ return;
+ }
+ }
+ throw new RuntimeException(list.toString());
+ }
+
private static native int getNativePriority();
private static native boolean supportsThreadPriorities();
diff --git a/test/160-read-barrier-stress/expected.txt b/test/160-read-barrier-stress/expected.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/160-read-barrier-stress/expected.txt
diff --git a/test/160-read-barrier-stress/info.txt b/test/160-read-barrier-stress/info.txt
new file mode 100644
index 0000000..505fe33
--- /dev/null
+++ b/test/160-read-barrier-stress/info.txt
@@ -0,0 +1 @@
+Test stressing read barriers for CC GC.
diff --git a/test/160-read-barrier-stress/run b/test/160-read-barrier-stress/run
new file mode 100644
index 0000000..ab82229
--- /dev/null
+++ b/test/160-read-barrier-stress/run
@@ -0,0 +1,18 @@
+#!/bin/bash
+#
+# Copyright (C) 2017 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Limit the Java heap to 16MiB to force more GCs.
+exec ${RUN} $@ --runtime-option -Xmx16m
diff --git a/test/160-read-barrier-stress/src/Main.java b/test/160-read-barrier-stress/src/Main.java
new file mode 100644
index 0000000..7e130ce
--- /dev/null
+++ b/test/160-read-barrier-stress/src/Main.java
@@ -0,0 +1,1111 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+public class Main {
+ public static void main(String[] args) {
+ // Initialize local variables for comparison.
+ Object f0000 = manyFields.testField0000;
+ Object f1024 = manyFields.testField1024;
+ Object f4444 = manyFields.testField4444;
+ Object f4999 = manyFields.testField4999;
+ // Initialize largeArray for comparison.
+ largeArray[0] = f0000;
+ largeArray[1024] = f1024;
+ largeArray[4444] = f4444;
+ largeArray[4999] = f4999;
+ // Read indexes, they cannot be considered constant because the variables are volatile.
+ int i0 = index0;
+ int i1024 = index1024;
+ int i4444 = index4444;
+ int i4999 = index4999;
+ // Initialize strings, hide this under a condition based on a volatile field.
+ String testString0 = null;
+ String testString1 = null;
+ String testString2 = null;
+ String testString3 = null;
+ if (index0 != 12345678) {
+ // By having this in the const-string instructions in an if-block, we avoid
+ // GVN eliminating identical const-string instructions in the loop below.
+ testString0 = "testString0";
+ testString1 = "testString1";
+ testString2 = "testString2";
+ testString3 = "testString3";
+ }
+
+ // Continually check reads from `manyFields` and `largeArray` while allocating
+ // over 64MiB memory (with heap size limited to 16MiB), ensuring we run GC and
+ // stress the read barrier implementation if concurrent collector is enabled.
+ for (int i = 0; i != 64 * 1024; ++i) {
+ allocateAtLeast1KiB();
+ ManyFields mf = manyFields; // Load the volatile `manyFields` once on each iteration.
+ Object[] la = largeArray; // Load the volatile `largeArray` once on each iteration.
+ // Test reference field access.
+ assertSameObject(f0000, mf.testField0000);
+ assertSameObject(f1024, mf.testField1024);
+ assertSameObject(f4444, mf.testField4444);
+ assertSameObject(f4999, mf.testField4999);
+ // Test array access with constant index.
+ assertSameObject(f0000, la[0]);
+ assertSameObject(f1024, la[1024]);
+ assertSameObject(f4444, la[4444]);
+ assertSameObject(f4999, la[4999]);
+ // Test array access with non-constant index.
+ assertSameObject(f0000, la[i0]);
+ assertSameObject(f1024, la[i1024]);
+ assertSameObject(f4444, la[i4444]);
+ assertSameObject(f4999, la[i4999]);
+ // Test GC roots.
+ if (index0 != 12345678) {
+ assertSameObject(testString0, "testString0");
+ assertSameObject(testString1, "testString1");
+ assertSameObject(testString2, "testString2");
+ assertSameObject(testString3, "testString3");
+ }
+ // TODO: Stress GC roots (const-string/const-class, kBssEntry/kReferrersClass).
+ }
+ }
+
+ public static void assertSameObject(Object lhs, Object rhs) {
+ if (lhs != rhs) {
+ throw new Error("Different objects: " + lhs + " and " + rhs);
+ }
+ }
+
+ public static void allocateAtLeast1KiB() {
+ // Give GC more work by allocating Object arrays.
+ memory[allocationIndex] = new Object[1024 / 4];
+ ++allocationIndex;
+ if (allocationIndex == memory.length) {
+ allocationIndex = 0;
+ }
+ }
+
+ // Make these volatile to avoid load elimination.
+ public static volatile ManyFields manyFields = new ManyFields();
+ public static volatile Object[] largeArray = new Object[5000];
+ public static volatile int index0 = 0;
+ public static volatile int index1024 = 1024;
+ public static volatile int index4444 = 4444;
+ public static volatile int index4999 = 4999;
+
+ // We shall retain some allocated memory and release old allocations
+ // so that the GC has something to do.
+ public static Object[] memory = new Object[1024];
+ public static int allocationIndex = 0;
+}
+
+class ManyFields extends ManyFieldsBase3 {
+ public Object testField4000 = new Integer(4000);
+ public Object testField4001 = new Integer(4001);
+ public Object testField4002 = new Integer(4002);
+ public Object testField4003 = new Integer(4003);
+ public Object testField4004 = new Integer(4004);
+ public Object testField4005 = new Integer(4005);
+ public Object testField4006 = new Integer(4006);
+ public Object testField4007 = new Integer(4007);
+ public Object testField4008 = new Integer(4008);
+ public Object testField4009 = new Integer(4009);
+ public Object testField4010 = new Integer(4010);
+ public Object testField4011 = new Integer(4011);
+ public Object testField4012 = new Integer(4012);
+ public Object testField4013 = new Integer(4013);
+ public Object testField4014 = new Integer(4014);
+ public Object testField4015 = new Integer(4015);
+ public Object testField4016 = new Integer(4016);
+ public Object testField4017 = new Integer(4017);
+ public Object testField4018 = new Integer(4018);
+ public Object testField4019 = new Integer(4019);
+ public Object testField4020 = new Integer(4020);
+ public Object testField4021 = new Integer(4021);
+ public Object testField4022 = new Integer(4022);
+ public Object testField4023 = new Integer(4023);
+ public Object testField4024 = new Integer(4024);
+ public Object testField4025 = new Integer(4025);
+ public Object testField4026 = new Integer(4026);
+ public Object testField4027 = new Integer(4027);
+ public Object testField4028 = new Integer(4028);
+ public Object testField4029 = new Integer(4029);
+ public Object testField4030 = new Integer(4030);
+ public Object testField4031 = new Integer(4031);
+ public Object testField4032 = new Integer(4032);
+ public Object testField4033 = new Integer(4033);
+ public Object testField4034 = new Integer(4034);
+ public Object testField4035 = new Integer(4035);
+ public Object testField4036 = new Integer(4036);
+ public Object testField4037 = new Integer(4037);
+ public Object testField4038 = new Integer(4038);
+ public Object testField4039 = new Integer(4039);
+ public Object testField4040 = new Integer(4040);
+ public Object testField4041 = new Integer(4041);
+ public Object testField4042 = new Integer(4042);
+ public Object testField4043 = new Integer(4043);
+ public Object testField4044 = new Integer(4044);
+ public Object testField4045 = new Integer(4045);
+ public Object testField4046 = new Integer(4046);
+ public Object testField4047 = new Integer(4047);
+ public Object testField4048 = new Integer(4048);
+ public Object testField4049 = new Integer(4049);
+ public Object testField4050 = new Integer(4050);
+ public Object testField4051 = new Integer(4051);
+ public Object testField4052 = new Integer(4052);
+ public Object testField4053 = new Integer(4053);
+ public Object testField4054 = new Integer(4054);
+ public Object testField4055 = new Integer(4055);
+ public Object testField4056 = new Integer(4056);
+ public Object testField4057 = new Integer(4057);
+ public Object testField4058 = new Integer(4058);
+ public Object testField4059 = new Integer(4059);
+ public Object testField4060 = new Integer(4060);
+ public Object testField4061 = new Integer(4061);
+ public Object testField4062 = new Integer(4062);
+ public Object testField4063 = new Integer(4063);
+ public Object testField4064 = new Integer(4064);
+ public Object testField4065 = new Integer(4065);
+ public Object testField4066 = new Integer(4066);
+ public Object testField4067 = new Integer(4067);
+ public Object testField4068 = new Integer(4068);
+ public Object testField4069 = new Integer(4069);
+ public Object testField4070 = new Integer(4070);
+ public Object testField4071 = new Integer(4071);
+ public Object testField4072 = new Integer(4072);
+ public Object testField4073 = new Integer(4073);
+ public Object testField4074 = new Integer(4074);
+ public Object testField4075 = new Integer(4075);
+ public Object testField4076 = new Integer(4076);
+ public Object testField4077 = new Integer(4077);
+ public Object testField4078 = new Integer(4078);
+ public Object testField4079 = new Integer(4079);
+ public Object testField4080 = new Integer(4080);
+ public Object testField4081 = new Integer(4081);
+ public Object testField4082 = new Integer(4082);
+ public Object testField4083 = new Integer(4083);
+ public Object testField4084 = new Integer(4084);
+ public Object testField4085 = new Integer(4085);
+ public Object testField4086 = new Integer(4086);
+ public Object testField4087 = new Integer(4087);
+ public Object testField4088 = new Integer(4088);
+ public Object testField4089 = new Integer(4089);
+ public Object testField4090 = new Integer(4090);
+ public Object testField4091 = new Integer(4091);
+ public Object testField4092 = new Integer(4092);
+ public Object testField4093 = new Integer(4093);
+ public Object testField4094 = new Integer(4094);
+ public Object testField4095 = new Integer(4095);
+ public Object testField4096 = new Integer(4096);
+ public Object testField4097 = new Integer(4097);
+ public Object testField4098 = new Integer(4098);
+ public Object testField4099 = new Integer(4099);
+ public Object testField4100 = new Integer(4100);
+ public Object testField4101 = new Integer(4101);
+ public Object testField4102 = new Integer(4102);
+ public Object testField4103 = new Integer(4103);
+ public Object testField4104 = new Integer(4104);
+ public Object testField4105 = new Integer(4105);
+ public Object testField4106 = new Integer(4106);
+ public Object testField4107 = new Integer(4107);
+ public Object testField4108 = new Integer(4108);
+ public Object testField4109 = new Integer(4109);
+ public Object testField4110 = new Integer(4110);
+ public Object testField4111 = new Integer(4111);
+ public Object testField4112 = new Integer(4112);
+ public Object testField4113 = new Integer(4113);
+ public Object testField4114 = new Integer(4114);
+ public Object testField4115 = new Integer(4115);
+ public Object testField4116 = new Integer(4116);
+ public Object testField4117 = new Integer(4117);
+ public Object testField4118 = new Integer(4118);
+ public Object testField4119 = new Integer(4119);
+ public Object testField4120 = new Integer(4120);
+ public Object testField4121 = new Integer(4121);
+ public Object testField4122 = new Integer(4122);
+ public Object testField4123 = new Integer(4123);
+ public Object testField4124 = new Integer(4124);
+ public Object testField4125 = new Integer(4125);
+ public Object testField4126 = new Integer(4126);
+ public Object testField4127 = new Integer(4127);
+ public Object testField4128 = new Integer(4128);
+ public Object testField4129 = new Integer(4129);
+ public Object testField4130 = new Integer(4130);
+ public Object testField4131 = new Integer(4131);
+ public Object testField4132 = new Integer(4132);
+ public Object testField4133 = new Integer(4133);
+ public Object testField4134 = new Integer(4134);
+ public Object testField4135 = new Integer(4135);
+ public Object testField4136 = new Integer(4136);
+ public Object testField4137 = new Integer(4137);
+ public Object testField4138 = new Integer(4138);
+ public Object testField4139 = new Integer(4139);
+ public Object testField4140 = new Integer(4140);
+ public Object testField4141 = new Integer(4141);
+ public Object testField4142 = new Integer(4142);
+ public Object testField4143 = new Integer(4143);
+ public Object testField4144 = new Integer(4144);
+ public Object testField4145 = new Integer(4145);
+ public Object testField4146 = new Integer(4146);
+ public Object testField4147 = new Integer(4147);
+ public Object testField4148 = new Integer(4148);
+ public Object testField4149 = new Integer(4149);
+ public Object testField4150 = new Integer(4150);
+ public Object testField4151 = new Integer(4151);
+ public Object testField4152 = new Integer(4152);
+ public Object testField4153 = new Integer(4153);
+ public Object testField4154 = new Integer(4154);
+ public Object testField4155 = new Integer(4155);
+ public Object testField4156 = new Integer(4156);
+ public Object testField4157 = new Integer(4157);
+ public Object testField4158 = new Integer(4158);
+ public Object testField4159 = new Integer(4159);
+ public Object testField4160 = new Integer(4160);
+ public Object testField4161 = new Integer(4161);
+ public Object testField4162 = new Integer(4162);
+ public Object testField4163 = new Integer(4163);
+ public Object testField4164 = new Integer(4164);
+ public Object testField4165 = new Integer(4165);
+ public Object testField4166 = new Integer(4166);
+ public Object testField4167 = new Integer(4167);
+ public Object testField4168 = new Integer(4168);
+ public Object testField4169 = new Integer(4169);
+ public Object testField4170 = new Integer(4170);
+ public Object testField4171 = new Integer(4171);
+ public Object testField4172 = new Integer(4172);
+ public Object testField4173 = new Integer(4173);
+ public Object testField4174 = new Integer(4174);
+ public Object testField4175 = new Integer(4175);
+ public Object testField4176 = new Integer(4176);
+ public Object testField4177 = new Integer(4177);
+ public Object testField4178 = new Integer(4178);
+ public Object testField4179 = new Integer(4179);
+ public Object testField4180 = new Integer(4180);
+ public Object testField4181 = new Integer(4181);
+ public Object testField4182 = new Integer(4182);
+ public Object testField4183 = new Integer(4183);
+ public Object testField4184 = new Integer(4184);
+ public Object testField4185 = new Integer(4185);
+ public Object testField4186 = new Integer(4186);
+ public Object testField4187 = new Integer(4187);
+ public Object testField4188 = new Integer(4188);
+ public Object testField4189 = new Integer(4189);
+ public Object testField4190 = new Integer(4190);
+ public Object testField4191 = new Integer(4191);
+ public Object testField4192 = new Integer(4192);
+ public Object testField4193 = new Integer(4193);
+ public Object testField4194 = new Integer(4194);
+ public Object testField4195 = new Integer(4195);
+ public Object testField4196 = new Integer(4196);
+ public Object testField4197 = new Integer(4197);
+ public Object testField4198 = new Integer(4198);
+ public Object testField4199 = new Integer(4199);
+ public Object testField4200 = new Integer(4200);
+ public Object testField4201 = new Integer(4201);
+ public Object testField4202 = new Integer(4202);
+ public Object testField4203 = new Integer(4203);
+ public Object testField4204 = new Integer(4204);
+ public Object testField4205 = new Integer(4205);
+ public Object testField4206 = new Integer(4206);
+ public Object testField4207 = new Integer(4207);
+ public Object testField4208 = new Integer(4208);
+ public Object testField4209 = new Integer(4209);
+ public Object testField4210 = new Integer(4210);
+ public Object testField4211 = new Integer(4211);
+ public Object testField4212 = new Integer(4212);
+ public Object testField4213 = new Integer(4213);
+ public Object testField4214 = new Integer(4214);
+ public Object testField4215 = new Integer(4215);
+ public Object testField4216 = new Integer(4216);
+ public Object testField4217 = new Integer(4217);
+ public Object testField4218 = new Integer(4218);
+ public Object testField4219 = new Integer(4219);
+ public Object testField4220 = new Integer(4220);
+ public Object testField4221 = new Integer(4221);
+ public Object testField4222 = new Integer(4222);
+ public Object testField4223 = new Integer(4223);
+ public Object testField4224 = new Integer(4224);
+ public Object testField4225 = new Integer(4225);
+ public Object testField4226 = new Integer(4226);
+ public Object testField4227 = new Integer(4227);
+ public Object testField4228 = new Integer(4228);
+ public Object testField4229 = new Integer(4229);
+ public Object testField4230 = new Integer(4230);
+ public Object testField4231 = new Integer(4231);
+ public Object testField4232 = new Integer(4232);
+ public Object testField4233 = new Integer(4233);
+ public Object testField4234 = new Integer(4234);
+ public Object testField4235 = new Integer(4235);
+ public Object testField4236 = new Integer(4236);
+ public Object testField4237 = new Integer(4237);
+ public Object testField4238 = new Integer(4238);
+ public Object testField4239 = new Integer(4239);
+ public Object testField4240 = new Integer(4240);
+ public Object testField4241 = new Integer(4241);
+ public Object testField4242 = new Integer(4242);
+ public Object testField4243 = new Integer(4243);
+ public Object testField4244 = new Integer(4244);
+ public Object testField4245 = new Integer(4245);
+ public Object testField4246 = new Integer(4246);
+ public Object testField4247 = new Integer(4247);
+ public Object testField4248 = new Integer(4248);
+ public Object testField4249 = new Integer(4249);
+ public Object testField4250 = new Integer(4250);
+ public Object testField4251 = new Integer(4251);
+ public Object testField4252 = new Integer(4252);
+ public Object testField4253 = new Integer(4253);
+ public Object testField4254 = new Integer(4254);
+ public Object testField4255 = new Integer(4255);
+ public Object testField4256 = new Integer(4256);
+ public Object testField4257 = new Integer(4257);
+ public Object testField4258 = new Integer(4258);
+ public Object testField4259 = new Integer(4259);
+ public Object testField4260 = new Integer(4260);
+ public Object testField4261 = new Integer(4261);
+ public Object testField4262 = new Integer(4262);
+ public Object testField4263 = new Integer(4263);
+ public Object testField4264 = new Integer(4264);
+ public Object testField4265 = new Integer(4265);
+ public Object testField4266 = new Integer(4266);
+ public Object testField4267 = new Integer(4267);
+ public Object testField4268 = new Integer(4268);
+ public Object testField4269 = new Integer(4269);
+ public Object testField4270 = new Integer(4270);
+ public Object testField4271 = new Integer(4271);
+ public Object testField4272 = new Integer(4272);
+ public Object testField4273 = new Integer(4273);
+ public Object testField4274 = new Integer(4274);
+ public Object testField4275 = new Integer(4275);
+ public Object testField4276 = new Integer(4276);
+ public Object testField4277 = new Integer(4277);
+ public Object testField4278 = new Integer(4278);
+ public Object testField4279 = new Integer(4279);
+ public Object testField4280 = new Integer(4280);
+ public Object testField4281 = new Integer(4281);
+ public Object testField4282 = new Integer(4282);
+ public Object testField4283 = new Integer(4283);
+ public Object testField4284 = new Integer(4284);
+ public Object testField4285 = new Integer(4285);
+ public Object testField4286 = new Integer(4286);
+ public Object testField4287 = new Integer(4287);
+ public Object testField4288 = new Integer(4288);
+ public Object testField4289 = new Integer(4289);
+ public Object testField4290 = new Integer(4290);
+ public Object testField4291 = new Integer(4291);
+ public Object testField4292 = new Integer(4292);
+ public Object testField4293 = new Integer(4293);
+ public Object testField4294 = new Integer(4294);
+ public Object testField4295 = new Integer(4295);
+ public Object testField4296 = new Integer(4296);
+ public Object testField4297 = new Integer(4297);
+ public Object testField4298 = new Integer(4298);
+ public Object testField4299 = new Integer(4299);
+ public Object testField4300 = new Integer(4300);
+ public Object testField4301 = new Integer(4301);
+ public Object testField4302 = new Integer(4302);
+ public Object testField4303 = new Integer(4303);
+ public Object testField4304 = new Integer(4304);
+ public Object testField4305 = new Integer(4305);
+ public Object testField4306 = new Integer(4306);
+ public Object testField4307 = new Integer(4307);
+ public Object testField4308 = new Integer(4308);
+ public Object testField4309 = new Integer(4309);
+ public Object testField4310 = new Integer(4310);
+ public Object testField4311 = new Integer(4311);
+ public Object testField4312 = new Integer(4312);
+ public Object testField4313 = new Integer(4313);
+ public Object testField4314 = new Integer(4314);
+ public Object testField4315 = new Integer(4315);
+ public Object testField4316 = new Integer(4316);
+ public Object testField4317 = new Integer(4317);
+ public Object testField4318 = new Integer(4318);
+ public Object testField4319 = new Integer(4319);
+ public Object testField4320 = new Integer(4320);
+ public Object testField4321 = new Integer(4321);
+ public Object testField4322 = new Integer(4322);
+ public Object testField4323 = new Integer(4323);
+ public Object testField4324 = new Integer(4324);
+ public Object testField4325 = new Integer(4325);
+ public Object testField4326 = new Integer(4326);
+ public Object testField4327 = new Integer(4327);
+ public Object testField4328 = new Integer(4328);
+ public Object testField4329 = new Integer(4329);
+ public Object testField4330 = new Integer(4330);
+ public Object testField4331 = new Integer(4331);
+ public Object testField4332 = new Integer(4332);
+ public Object testField4333 = new Integer(4333);
+ public Object testField4334 = new Integer(4334);
+ public Object testField4335 = new Integer(4335);
+ public Object testField4336 = new Integer(4336);
+ public Object testField4337 = new Integer(4337);
+ public Object testField4338 = new Integer(4338);
+ public Object testField4339 = new Integer(4339);
+ public Object testField4340 = new Integer(4340);
+ public Object testField4341 = new Integer(4341);
+ public Object testField4342 = new Integer(4342);
+ public Object testField4343 = new Integer(4343);
+ public Object testField4344 = new Integer(4344);
+ public Object testField4345 = new Integer(4345);
+ public Object testField4346 = new Integer(4346);
+ public Object testField4347 = new Integer(4347);
+ public Object testField4348 = new Integer(4348);
+ public Object testField4349 = new Integer(4349);
+ public Object testField4350 = new Integer(4350);
+ public Object testField4351 = new Integer(4351);
+ public Object testField4352 = new Integer(4352);
+ public Object testField4353 = new Integer(4353);
+ public Object testField4354 = new Integer(4354);
+ public Object testField4355 = new Integer(4355);
+ public Object testField4356 = new Integer(4356);
+ public Object testField4357 = new Integer(4357);
+ public Object testField4358 = new Integer(4358);
+ public Object testField4359 = new Integer(4359);
+ public Object testField4360 = new Integer(4360);
+ public Object testField4361 = new Integer(4361);
+ public Object testField4362 = new Integer(4362);
+ public Object testField4363 = new Integer(4363);
+ public Object testField4364 = new Integer(4364);
+ public Object testField4365 = new Integer(4365);
+ public Object testField4366 = new Integer(4366);
+ public Object testField4367 = new Integer(4367);
+ public Object testField4368 = new Integer(4368);
+ public Object testField4369 = new Integer(4369);
+ public Object testField4370 = new Integer(4370);
+ public Object testField4371 = new Integer(4371);
+ public Object testField4372 = new Integer(4372);
+ public Object testField4373 = new Integer(4373);
+ public Object testField4374 = new Integer(4374);
+ public Object testField4375 = new Integer(4375);
+ public Object testField4376 = new Integer(4376);
+ public Object testField4377 = new Integer(4377);
+ public Object testField4378 = new Integer(4378);
+ public Object testField4379 = new Integer(4379);
+ public Object testField4380 = new Integer(4380);
+ public Object testField4381 = new Integer(4381);
+ public Object testField4382 = new Integer(4382);
+ public Object testField4383 = new Integer(4383);
+ public Object testField4384 = new Integer(4384);
+ public Object testField4385 = new Integer(4385);
+ public Object testField4386 = new Integer(4386);
+ public Object testField4387 = new Integer(4387);
+ public Object testField4388 = new Integer(4388);
+ public Object testField4389 = new Integer(4389);
+ public Object testField4390 = new Integer(4390);
+ public Object testField4391 = new Integer(4391);
+ public Object testField4392 = new Integer(4392);
+ public Object testField4393 = new Integer(4393);
+ public Object testField4394 = new Integer(4394);
+ public Object testField4395 = new Integer(4395);
+ public Object testField4396 = new Integer(4396);
+ public Object testField4397 = new Integer(4397);
+ public Object testField4398 = new Integer(4398);
+ public Object testField4399 = new Integer(4399);
+ public Object testField4400 = new Integer(4400);
+ public Object testField4401 = new Integer(4401);
+ public Object testField4402 = new Integer(4402);
+ public Object testField4403 = new Integer(4403);
+ public Object testField4404 = new Integer(4404);
+ public Object testField4405 = new Integer(4405);
+ public Object testField4406 = new Integer(4406);
+ public Object testField4407 = new Integer(4407);
+ public Object testField4408 = new Integer(4408);
+ public Object testField4409 = new Integer(4409);
+ public Object testField4410 = new Integer(4410);
+ public Object testField4411 = new Integer(4411);
+ public Object testField4412 = new Integer(4412);
+ public Object testField4413 = new Integer(4413);
+ public Object testField4414 = new Integer(4414);
+ public Object testField4415 = new Integer(4415);
+ public Object testField4416 = new Integer(4416);
+ public Object testField4417 = new Integer(4417);
+ public Object testField4418 = new Integer(4418);
+ public Object testField4419 = new Integer(4419);
+ public Object testField4420 = new Integer(4420);
+ public Object testField4421 = new Integer(4421);
+ public Object testField4422 = new Integer(4422);
+ public Object testField4423 = new Integer(4423);
+ public Object testField4424 = new Integer(4424);
+ public Object testField4425 = new Integer(4425);
+ public Object testField4426 = new Integer(4426);
+ public Object testField4427 = new Integer(4427);
+ public Object testField4428 = new Integer(4428);
+ public Object testField4429 = new Integer(4429);
+ public Object testField4430 = new Integer(4430);
+ public Object testField4431 = new Integer(4431);
+ public Object testField4432 = new Integer(4432);
+ public Object testField4433 = new Integer(4433);
+ public Object testField4434 = new Integer(4434);
+ public Object testField4435 = new Integer(4435);
+ public Object testField4436 = new Integer(4436);
+ public Object testField4437 = new Integer(4437);
+ public Object testField4438 = new Integer(4438);
+ public Object testField4439 = new Integer(4439);
+ public Object testField4440 = new Integer(4440);
+ public Object testField4441 = new Integer(4441);
+ public Object testField4442 = new Integer(4442);
+ public Object testField4443 = new Integer(4443);
+ public Object testField4444 = new Integer(4444);
+ public Object testField4445 = new Integer(4445);
+ public Object testField4446 = new Integer(4446);
+ public Object testField4447 = new Integer(4447);
+ public Object testField4448 = new Integer(4448);
+ public Object testField4449 = new Integer(4449);
+ public Object testField4450 = new Integer(4450);
+ public Object testField4451 = new Integer(4451);
+ public Object testField4452 = new Integer(4452);
+ public Object testField4453 = new Integer(4453);
+ public Object testField4454 = new Integer(4454);
+ public Object testField4455 = new Integer(4455);
+ public Object testField4456 = new Integer(4456);
+ public Object testField4457 = new Integer(4457);
+ public Object testField4458 = new Integer(4458);
+ public Object testField4459 = new Integer(4459);
+ public Object testField4460 = new Integer(4460);
+ public Object testField4461 = new Integer(4461);
+ public Object testField4462 = new Integer(4462);
+ public Object testField4463 = new Integer(4463);
+ public Object testField4464 = new Integer(4464);
+ public Object testField4465 = new Integer(4465);
+ public Object testField4466 = new Integer(4466);
+ public Object testField4467 = new Integer(4467);
+ public Object testField4468 = new Integer(4468);
+ public Object testField4469 = new Integer(4469);
+ public Object testField4470 = new Integer(4470);
+ public Object testField4471 = new Integer(4471);
+ public Object testField4472 = new Integer(4472);
+ public Object testField4473 = new Integer(4473);
+ public Object testField4474 = new Integer(4474);
+ public Object testField4475 = new Integer(4475);
+ public Object testField4476 = new Integer(4476);
+ public Object testField4477 = new Integer(4477);
+ public Object testField4478 = new Integer(4478);
+ public Object testField4479 = new Integer(4479);
+ public Object testField4480 = new Integer(4480);
+ public Object testField4481 = new Integer(4481);
+ public Object testField4482 = new Integer(4482);
+ public Object testField4483 = new Integer(4483);
+ public Object testField4484 = new Integer(4484);
+ public Object testField4485 = new Integer(4485);
+ public Object testField4486 = new Integer(4486);
+ public Object testField4487 = new Integer(4487);
+ public Object testField4488 = new Integer(4488);
+ public Object testField4489 = new Integer(4489);
+ public Object testField4490 = new Integer(4490);
+ public Object testField4491 = new Integer(4491);
+ public Object testField4492 = new Integer(4492);
+ public Object testField4493 = new Integer(4493);
+ public Object testField4494 = new Integer(4494);
+ public Object testField4495 = new Integer(4495);
+ public Object testField4496 = new Integer(4496);
+ public Object testField4497 = new Integer(4497);
+ public Object testField4498 = new Integer(4498);
+ public Object testField4499 = new Integer(4499);
+ public Object testField4500 = new Integer(4500);
+ public Object testField4501 = new Integer(4501);
+ public Object testField4502 = new Integer(4502);
+ public Object testField4503 = new Integer(4503);
+ public Object testField4504 = new Integer(4504);
+ public Object testField4505 = new Integer(4505);
+ public Object testField4506 = new Integer(4506);
+ public Object testField4507 = new Integer(4507);
+ public Object testField4508 = new Integer(4508);
+ public Object testField4509 = new Integer(4509);
+ public Object testField4510 = new Integer(4510);
+ public Object testField4511 = new Integer(4511);
+ public Object testField4512 = new Integer(4512);
+ public Object testField4513 = new Integer(4513);
+ public Object testField4514 = new Integer(4514);
+ public Object testField4515 = new Integer(4515);
+ public Object testField4516 = new Integer(4516);
+ public Object testField4517 = new Integer(4517);
+ public Object testField4518 = new Integer(4518);
+ public Object testField4519 = new Integer(4519);
+ public Object testField4520 = new Integer(4520);
+ public Object testField4521 = new Integer(4521);
+ public Object testField4522 = new Integer(4522);
+ public Object testField4523 = new Integer(4523);
+ public Object testField4524 = new Integer(4524);
+ public Object testField4525 = new Integer(4525);
+ public Object testField4526 = new Integer(4526);
+ public Object testField4527 = new Integer(4527);
+ public Object testField4528 = new Integer(4528);
+ public Object testField4529 = new Integer(4529);
+ public Object testField4530 = new Integer(4530);
+ public Object testField4531 = new Integer(4531);
+ public Object testField4532 = new Integer(4532);
+ public Object testField4533 = new Integer(4533);
+ public Object testField4534 = new Integer(4534);
+ public Object testField4535 = new Integer(4535);
+ public Object testField4536 = new Integer(4536);
+ public Object testField4537 = new Integer(4537);
+ public Object testField4538 = new Integer(4538);
+ public Object testField4539 = new Integer(4539);
+ public Object testField4540 = new Integer(4540);
+ public Object testField4541 = new Integer(4541);
+ public Object testField4542 = new Integer(4542);
+ public Object testField4543 = new Integer(4543);
+ public Object testField4544 = new Integer(4544);
+ public Object testField4545 = new Integer(4545);
+ public Object testField4546 = new Integer(4546);
+ public Object testField4547 = new Integer(4547);
+ public Object testField4548 = new Integer(4548);
+ public Object testField4549 = new Integer(4549);
+ public Object testField4550 = new Integer(4550);
+ public Object testField4551 = new Integer(4551);
+ public Object testField4552 = new Integer(4552);
+ public Object testField4553 = new Integer(4553);
+ public Object testField4554 = new Integer(4554);
+ public Object testField4555 = new Integer(4555);
+ public Object testField4556 = new Integer(4556);
+ public Object testField4557 = new Integer(4557);
+ public Object testField4558 = new Integer(4558);
+ public Object testField4559 = new Integer(4559);
+ public Object testField4560 = new Integer(4560);
+ public Object testField4561 = new Integer(4561);
+ public Object testField4562 = new Integer(4562);
+ public Object testField4563 = new Integer(4563);
+ public Object testField4564 = new Integer(4564);
+ public Object testField4565 = new Integer(4565);
+ public Object testField4566 = new Integer(4566);
+ public Object testField4567 = new Integer(4567);
+ public Object testField4568 = new Integer(4568);
+ public Object testField4569 = new Integer(4569);
+ public Object testField4570 = new Integer(4570);
+ public Object testField4571 = new Integer(4571);
+ public Object testField4572 = new Integer(4572);
+ public Object testField4573 = new Integer(4573);
+ public Object testField4574 = new Integer(4574);
+ public Object testField4575 = new Integer(4575);
+ public Object testField4576 = new Integer(4576);
+ public Object testField4577 = new Integer(4577);
+ public Object testField4578 = new Integer(4578);
+ public Object testField4579 = new Integer(4579);
+ public Object testField4580 = new Integer(4580);
+ public Object testField4581 = new Integer(4581);
+ public Object testField4582 = new Integer(4582);
+ public Object testField4583 = new Integer(4583);
+ public Object testField4584 = new Integer(4584);
+ public Object testField4585 = new Integer(4585);
+ public Object testField4586 = new Integer(4586);
+ public Object testField4587 = new Integer(4587);
+ public Object testField4588 = new Integer(4588);
+ public Object testField4589 = new Integer(4589);
+ public Object testField4590 = new Integer(4590);
+ public Object testField4591 = new Integer(4591);
+ public Object testField4592 = new Integer(4592);
+ public Object testField4593 = new Integer(4593);
+ public Object testField4594 = new Integer(4594);
+ public Object testField4595 = new Integer(4595);
+ public Object testField4596 = new Integer(4596);
+ public Object testField4597 = new Integer(4597);
+ public Object testField4598 = new Integer(4598);
+ public Object testField4599 = new Integer(4599);
+ public Object testField4600 = new Integer(4600);
+ public Object testField4601 = new Integer(4601);
+ public Object testField4602 = new Integer(4602);
+ public Object testField4603 = new Integer(4603);
+ public Object testField4604 = new Integer(4604);
+ public Object testField4605 = new Integer(4605);
+ public Object testField4606 = new Integer(4606);
+ public Object testField4607 = new Integer(4607);
+ public Object testField4608 = new Integer(4608);
+ public Object testField4609 = new Integer(4609);
+ public Object testField4610 = new Integer(4610);
+ public Object testField4611 = new Integer(4611);
+ public Object testField4612 = new Integer(4612);
+ public Object testField4613 = new Integer(4613);
+ public Object testField4614 = new Integer(4614);
+ public Object testField4615 = new Integer(4615);
+ public Object testField4616 = new Integer(4616);
+ public Object testField4617 = new Integer(4617);
+ public Object testField4618 = new Integer(4618);
+ public Object testField4619 = new Integer(4619);
+ public Object testField4620 = new Integer(4620);
+ public Object testField4621 = new Integer(4621);
+ public Object testField4622 = new Integer(4622);
+ public Object testField4623 = new Integer(4623);
+ public Object testField4624 = new Integer(4624);
+ public Object testField4625 = new Integer(4625);
+ public Object testField4626 = new Integer(4626);
+ public Object testField4627 = new Integer(4627);
+ public Object testField4628 = new Integer(4628);
+ public Object testField4629 = new Integer(4629);
+ public Object testField4630 = new Integer(4630);
+ public Object testField4631 = new Integer(4631);
+ public Object testField4632 = new Integer(4632);
+ public Object testField4633 = new Integer(4633);
+ public Object testField4634 = new Integer(4634);
+ public Object testField4635 = new Integer(4635);
+ public Object testField4636 = new Integer(4636);
+ public Object testField4637 = new Integer(4637);
+ public Object testField4638 = new Integer(4638);
+ public Object testField4639 = new Integer(4639);
+ public Object testField4640 = new Integer(4640);
+ public Object testField4641 = new Integer(4641);
+ public Object testField4642 = new Integer(4642);
+ public Object testField4643 = new Integer(4643);
+ public Object testField4644 = new Integer(4644);
+ public Object testField4645 = new Integer(4645);
+ public Object testField4646 = new Integer(4646);
+ public Object testField4647 = new Integer(4647);
+ public Object testField4648 = new Integer(4648);
+ public Object testField4649 = new Integer(4649);
+ public Object testField4650 = new Integer(4650);
+ public Object testField4651 = new Integer(4651);
+ public Object testField4652 = new Integer(4652);
+ public Object testField4653 = new Integer(4653);
+ public Object testField4654 = new Integer(4654);
+ public Object testField4655 = new Integer(4655);
+ public Object testField4656 = new Integer(4656);
+ public Object testField4657 = new Integer(4657);
+ public Object testField4658 = new Integer(4658);
+ public Object testField4659 = new Integer(4659);
+ public Object testField4660 = new Integer(4660);
+ public Object testField4661 = new Integer(4661);
+ public Object testField4662 = new Integer(4662);
+ public Object testField4663 = new Integer(4663);
+ public Object testField4664 = new Integer(4664);
+ public Object testField4665 = new Integer(4665);
+ public Object testField4666 = new Integer(4666);
+ public Object testField4667 = new Integer(4667);
+ public Object testField4668 = new Integer(4668);
+ public Object testField4669 = new Integer(4669);
+ public Object testField4670 = new Integer(4670);
+ public Object testField4671 = new Integer(4671);
+ public Object testField4672 = new Integer(4672);
+ public Object testField4673 = new Integer(4673);
+ public Object testField4674 = new Integer(4674);
+ public Object testField4675 = new Integer(4675);
+ public Object testField4676 = new Integer(4676);
+ public Object testField4677 = new Integer(4677);
+ public Object testField4678 = new Integer(4678);
+ public Object testField4679 = new Integer(4679);
+ public Object testField4680 = new Integer(4680);
+ public Object testField4681 = new Integer(4681);
+ public Object testField4682 = new Integer(4682);
+ public Object testField4683 = new Integer(4683);
+ public Object testField4684 = new Integer(4684);
+ public Object testField4685 = new Integer(4685);
+ public Object testField4686 = new Integer(4686);
+ public Object testField4687 = new Integer(4687);
+ public Object testField4688 = new Integer(4688);
+ public Object testField4689 = new Integer(4689);
+ public Object testField4690 = new Integer(4690);
+ public Object testField4691 = new Integer(4691);
+ public Object testField4692 = new Integer(4692);
+ public Object testField4693 = new Integer(4693);
+ public Object testField4694 = new Integer(4694);
+ public Object testField4695 = new Integer(4695);
+ public Object testField4696 = new Integer(4696);
+ public Object testField4697 = new Integer(4697);
+ public Object testField4698 = new Integer(4698);
+ public Object testField4699 = new Integer(4699);
+ public Object testField4700 = new Integer(4700);
+ public Object testField4701 = new Integer(4701);
+ public Object testField4702 = new Integer(4702);
+ public Object testField4703 = new Integer(4703);
+ public Object testField4704 = new Integer(4704);
+ public Object testField4705 = new Integer(4705);
+ public Object testField4706 = new Integer(4706);
+ public Object testField4707 = new Integer(4707);
+ public Object testField4708 = new Integer(4708);
+ public Object testField4709 = new Integer(4709);
+ public Object testField4710 = new Integer(4710);
+ public Object testField4711 = new Integer(4711);
+ public Object testField4712 = new Integer(4712);
+ public Object testField4713 = new Integer(4713);
+ public Object testField4714 = new Integer(4714);
+ public Object testField4715 = new Integer(4715);
+ public Object testField4716 = new Integer(4716);
+ public Object testField4717 = new Integer(4717);
+ public Object testField4718 = new Integer(4718);
+ public Object testField4719 = new Integer(4719);
+ public Object testField4720 = new Integer(4720);
+ public Object testField4721 = new Integer(4721);
+ public Object testField4722 = new Integer(4722);
+ public Object testField4723 = new Integer(4723);
+ public Object testField4724 = new Integer(4724);
+ public Object testField4725 = new Integer(4725);
+ public Object testField4726 = new Integer(4726);
+ public Object testField4727 = new Integer(4727);
+ public Object testField4728 = new Integer(4728);
+ public Object testField4729 = new Integer(4729);
+ public Object testField4730 = new Integer(4730);
+ public Object testField4731 = new Integer(4731);
+ public Object testField4732 = new Integer(4732);
+ public Object testField4733 = new Integer(4733);
+ public Object testField4734 = new Integer(4734);
+ public Object testField4735 = new Integer(4735);
+ public Object testField4736 = new Integer(4736);
+ public Object testField4737 = new Integer(4737);
+ public Object testField4738 = new Integer(4738);
+ public Object testField4739 = new Integer(4739);
+ public Object testField4740 = new Integer(4740);
+ public Object testField4741 = new Integer(4741);
+ public Object testField4742 = new Integer(4742);
+ public Object testField4743 = new Integer(4743);
+ public Object testField4744 = new Integer(4744);
+ public Object testField4745 = new Integer(4745);
+ public Object testField4746 = new Integer(4746);
+ public Object testField4747 = new Integer(4747);
+ public Object testField4748 = new Integer(4748);
+ public Object testField4749 = new Integer(4749);
+ public Object testField4750 = new Integer(4750);
+ public Object testField4751 = new Integer(4751);
+ public Object testField4752 = new Integer(4752);
+ public Object testField4753 = new Integer(4753);
+ public Object testField4754 = new Integer(4754);
+ public Object testField4755 = new Integer(4755);
+ public Object testField4756 = new Integer(4756);
+ public Object testField4757 = new Integer(4757);
+ public Object testField4758 = new Integer(4758);
+ public Object testField4759 = new Integer(4759);
+ public Object testField4760 = new Integer(4760);
+ public Object testField4761 = new Integer(4761);
+ public Object testField4762 = new Integer(4762);
+ public Object testField4763 = new Integer(4763);
+ public Object testField4764 = new Integer(4764);
+ public Object testField4765 = new Integer(4765);
+ public Object testField4766 = new Integer(4766);
+ public Object testField4767 = new Integer(4767);
+ public Object testField4768 = new Integer(4768);
+ public Object testField4769 = new Integer(4769);
+ public Object testField4770 = new Integer(4770);
+ public Object testField4771 = new Integer(4771);
+ public Object testField4772 = new Integer(4772);
+ public Object testField4773 = new Integer(4773);
+ public Object testField4774 = new Integer(4774);
+ public Object testField4775 = new Integer(4775);
+ public Object testField4776 = new Integer(4776);
+ public Object testField4777 = new Integer(4777);
+ public Object testField4778 = new Integer(4778);
+ public Object testField4779 = new Integer(4779);
+ public Object testField4780 = new Integer(4780);
+ public Object testField4781 = new Integer(4781);
+ public Object testField4782 = new Integer(4782);
+ public Object testField4783 = new Integer(4783);
+ public Object testField4784 = new Integer(4784);
+ public Object testField4785 = new Integer(4785);
+ public Object testField4786 = new Integer(4786);
+ public Object testField4787 = new Integer(4787);
+ public Object testField4788 = new Integer(4788);
+ public Object testField4789 = new Integer(4789);
+ public Object testField4790 = new Integer(4790);
+ public Object testField4791 = new Integer(4791);
+ public Object testField4792 = new Integer(4792);
+ public Object testField4793 = new Integer(4793);
+ public Object testField4794 = new Integer(4794);
+ public Object testField4795 = new Integer(4795);
+ public Object testField4796 = new Integer(4796);
+ public Object testField4797 = new Integer(4797);
+ public Object testField4798 = new Integer(4798);
+ public Object testField4799 = new Integer(4799);
+ public Object testField4800 = new Integer(4800);
+ public Object testField4801 = new Integer(4801);
+ public Object testField4802 = new Integer(4802);
+ public Object testField4803 = new Integer(4803);
+ public Object testField4804 = new Integer(4804);
+ public Object testField4805 = new Integer(4805);
+ public Object testField4806 = new Integer(4806);
+ public Object testField4807 = new Integer(4807);
+ public Object testField4808 = new Integer(4808);
+ public Object testField4809 = new Integer(4809);
+ public Object testField4810 = new Integer(4810);
+ public Object testField4811 = new Integer(4811);
+ public Object testField4812 = new Integer(4812);
+ public Object testField4813 = new Integer(4813);
+ public Object testField4814 = new Integer(4814);
+ public Object testField4815 = new Integer(4815);
+ public Object testField4816 = new Integer(4816);
+ public Object testField4817 = new Integer(4817);
+ public Object testField4818 = new Integer(4818);
+ public Object testField4819 = new Integer(4819);
+ public Object testField4820 = new Integer(4820);
+ public Object testField4821 = new Integer(4821);
+ public Object testField4822 = new Integer(4822);
+ public Object testField4823 = new Integer(4823);
+ public Object testField4824 = new Integer(4824);
+ public Object testField4825 = new Integer(4825);
+ public Object testField4826 = new Integer(4826);
+ public Object testField4827 = new Integer(4827);
+ public Object testField4828 = new Integer(4828);
+ public Object testField4829 = new Integer(4829);
+ public Object testField4830 = new Integer(4830);
+ public Object testField4831 = new Integer(4831);
+ public Object testField4832 = new Integer(4832);
+ public Object testField4833 = new Integer(4833);
+ public Object testField4834 = new Integer(4834);
+ public Object testField4835 = new Integer(4835);
+ public Object testField4836 = new Integer(4836);
+ public Object testField4837 = new Integer(4837);
+ public Object testField4838 = new Integer(4838);
+ public Object testField4839 = new Integer(4839);
+ public Object testField4840 = new Integer(4840);
+ public Object testField4841 = new Integer(4841);
+ public Object testField4842 = new Integer(4842);
+ public Object testField4843 = new Integer(4843);
+ public Object testField4844 = new Integer(4844);
+ public Object testField4845 = new Integer(4845);
+ public Object testField4846 = new Integer(4846);
+ public Object testField4847 = new Integer(4847);
+ public Object testField4848 = new Integer(4848);
+ public Object testField4849 = new Integer(4849);
+ public Object testField4850 = new Integer(4850);
+ public Object testField4851 = new Integer(4851);
+ public Object testField4852 = new Integer(4852);
+ public Object testField4853 = new Integer(4853);
+ public Object testField4854 = new Integer(4854);
+ public Object testField4855 = new Integer(4855);
+ public Object testField4856 = new Integer(4856);
+ public Object testField4857 = new Integer(4857);
+ public Object testField4858 = new Integer(4858);
+ public Object testField4859 = new Integer(4859);
+ public Object testField4860 = new Integer(4860);
+ public Object testField4861 = new Integer(4861);
+ public Object testField4862 = new Integer(4862);
+ public Object testField4863 = new Integer(4863);
+ public Object testField4864 = new Integer(4864);
+ public Object testField4865 = new Integer(4865);
+ public Object testField4866 = new Integer(4866);
+ public Object testField4867 = new Integer(4867);
+ public Object testField4868 = new Integer(4868);
+ public Object testField4869 = new Integer(4869);
+ public Object testField4870 = new Integer(4870);
+ public Object testField4871 = new Integer(4871);
+ public Object testField4872 = new Integer(4872);
+ public Object testField4873 = new Integer(4873);
+ public Object testField4874 = new Integer(4874);
+ public Object testField4875 = new Integer(4875);
+ public Object testField4876 = new Integer(4876);
+ public Object testField4877 = new Integer(4877);
+ public Object testField4878 = new Integer(4878);
+ public Object testField4879 = new Integer(4879);
+ public Object testField4880 = new Integer(4880);
+ public Object testField4881 = new Integer(4881);
+ public Object testField4882 = new Integer(4882);
+ public Object testField4883 = new Integer(4883);
+ public Object testField4884 = new Integer(4884);
+ public Object testField4885 = new Integer(4885);
+ public Object testField4886 = new Integer(4886);
+ public Object testField4887 = new Integer(4887);
+ public Object testField4888 = new Integer(4888);
+ public Object testField4889 = new Integer(4889);
+ public Object testField4890 = new Integer(4890);
+ public Object testField4891 = new Integer(4891);
+ public Object testField4892 = new Integer(4892);
+ public Object testField4893 = new Integer(4893);
+ public Object testField4894 = new Integer(4894);
+ public Object testField4895 = new Integer(4895);
+ public Object testField4896 = new Integer(4896);
+ public Object testField4897 = new Integer(4897);
+ public Object testField4898 = new Integer(4898);
+ public Object testField4899 = new Integer(4899);
+ public Object testField4900 = new Integer(4900);
+ public Object testField4901 = new Integer(4901);
+ public Object testField4902 = new Integer(4902);
+ public Object testField4903 = new Integer(4903);
+ public Object testField4904 = new Integer(4904);
+ public Object testField4905 = new Integer(4905);
+ public Object testField4906 = new Integer(4906);
+ public Object testField4907 = new Integer(4907);
+ public Object testField4908 = new Integer(4908);
+ public Object testField4909 = new Integer(4909);
+ public Object testField4910 = new Integer(4910);
+ public Object testField4911 = new Integer(4911);
+ public Object testField4912 = new Integer(4912);
+ public Object testField4913 = new Integer(4913);
+ public Object testField4914 = new Integer(4914);
+ public Object testField4915 = new Integer(4915);
+ public Object testField4916 = new Integer(4916);
+ public Object testField4917 = new Integer(4917);
+ public Object testField4918 = new Integer(4918);
+ public Object testField4919 = new Integer(4919);
+ public Object testField4920 = new Integer(4920);
+ public Object testField4921 = new Integer(4921);
+ public Object testField4922 = new Integer(4922);
+ public Object testField4923 = new Integer(4923);
+ public Object testField4924 = new Integer(4924);
+ public Object testField4925 = new Integer(4925);
+ public Object testField4926 = new Integer(4926);
+ public Object testField4927 = new Integer(4927);
+ public Object testField4928 = new Integer(4928);
+ public Object testField4929 = new Integer(4929);
+ public Object testField4930 = new Integer(4930);
+ public Object testField4931 = new Integer(4931);
+ public Object testField4932 = new Integer(4932);
+ public Object testField4933 = new Integer(4933);
+ public Object testField4934 = new Integer(4934);
+ public Object testField4935 = new Integer(4935);
+ public Object testField4936 = new Integer(4936);
+ public Object testField4937 = new Integer(4937);
+ public Object testField4938 = new Integer(4938);
+ public Object testField4939 = new Integer(4939);
+ public Object testField4940 = new Integer(4940);
+ public Object testField4941 = new Integer(4941);
+ public Object testField4942 = new Integer(4942);
+ public Object testField4943 = new Integer(4943);
+ public Object testField4944 = new Integer(4944);
+ public Object testField4945 = new Integer(4945);
+ public Object testField4946 = new Integer(4946);
+ public Object testField4947 = new Integer(4947);
+ public Object testField4948 = new Integer(4948);
+ public Object testField4949 = new Integer(4949);
+ public Object testField4950 = new Integer(4950);
+ public Object testField4951 = new Integer(4951);
+ public Object testField4952 = new Integer(4952);
+ public Object testField4953 = new Integer(4953);
+ public Object testField4954 = new Integer(4954);
+ public Object testField4955 = new Integer(4955);
+ public Object testField4956 = new Integer(4956);
+ public Object testField4957 = new Integer(4957);
+ public Object testField4958 = new Integer(4958);
+ public Object testField4959 = new Integer(4959);
+ public Object testField4960 = new Integer(4960);
+ public Object testField4961 = new Integer(4961);
+ public Object testField4962 = new Integer(4962);
+ public Object testField4963 = new Integer(4963);
+ public Object testField4964 = new Integer(4964);
+ public Object testField4965 = new Integer(4965);
+ public Object testField4966 = new Integer(4966);
+ public Object testField4967 = new Integer(4967);
+ public Object testField4968 = new Integer(4968);
+ public Object testField4969 = new Integer(4969);
+ public Object testField4970 = new Integer(4970);
+ public Object testField4971 = new Integer(4971);
+ public Object testField4972 = new Integer(4972);
+ public Object testField4973 = new Integer(4973);
+ public Object testField4974 = new Integer(4974);
+ public Object testField4975 = new Integer(4975);
+ public Object testField4976 = new Integer(4976);
+ public Object testField4977 = new Integer(4977);
+ public Object testField4978 = new Integer(4978);
+ public Object testField4979 = new Integer(4979);
+ public Object testField4980 = new Integer(4980);
+ public Object testField4981 = new Integer(4981);
+ public Object testField4982 = new Integer(4982);
+ public Object testField4983 = new Integer(4983);
+ public Object testField4984 = new Integer(4984);
+ public Object testField4985 = new Integer(4985);
+ public Object testField4986 = new Integer(4986);
+ public Object testField4987 = new Integer(4987);
+ public Object testField4988 = new Integer(4988);
+ public Object testField4989 = new Integer(4989);
+ public Object testField4990 = new Integer(4990);
+ public Object testField4991 = new Integer(4991);
+ public Object testField4992 = new Integer(4992);
+ public Object testField4993 = new Integer(4993);
+ public Object testField4994 = new Integer(4994);
+ public Object testField4995 = new Integer(4995);
+ public Object testField4996 = new Integer(4996);
+ public Object testField4997 = new Integer(4997);
+ public Object testField4998 = new Integer(4998);
+ public Object testField4999 = new Integer(4999);
+}
diff --git a/test/160-read-barrier-stress/src/ManyFieldsBase0.java b/test/160-read-barrier-stress/src/ManyFieldsBase0.java
new file mode 100644
index 0000000..1b6c2a6
--- /dev/null
+++ b/test/160-read-barrier-stress/src/ManyFieldsBase0.java
@@ -0,0 +1,1018 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+class ManyFieldsBase0 {
+ public Object testField0000 = new Integer(0);
+ public Object testField0001 = new Integer(1);
+ public Object testField0002 = new Integer(2);
+ public Object testField0003 = new Integer(3);
+ public Object testField0004 = new Integer(4);
+ public Object testField0005 = new Integer(5);
+ public Object testField0006 = new Integer(6);
+ public Object testField0007 = new Integer(7);
+ public Object testField0008 = new Integer(8);
+ public Object testField0009 = new Integer(9);
+ public Object testField0010 = new Integer(10);
+ public Object testField0011 = new Integer(11);
+ public Object testField0012 = new Integer(12);
+ public Object testField0013 = new Integer(13);
+ public Object testField0014 = new Integer(14);
+ public Object testField0015 = new Integer(15);
+ public Object testField0016 = new Integer(16);
+ public Object testField0017 = new Integer(17);
+ public Object testField0018 = new Integer(18);
+ public Object testField0019 = new Integer(19);
+ public Object testField0020 = new Integer(20);
+ public Object testField0021 = new Integer(21);
+ public Object testField0022 = new Integer(22);
+ public Object testField0023 = new Integer(23);
+ public Object testField0024 = new Integer(24);
+ public Object testField0025 = new Integer(25);
+ public Object testField0026 = new Integer(26);
+ public Object testField0027 = new Integer(27);
+ public Object testField0028 = new Integer(28);
+ public Object testField0029 = new Integer(29);
+ public Object testField0030 = new Integer(30);
+ public Object testField0031 = new Integer(31);
+ public Object testField0032 = new Integer(32);
+ public Object testField0033 = new Integer(33);
+ public Object testField0034 = new Integer(34);
+ public Object testField0035 = new Integer(35);
+ public Object testField0036 = new Integer(36);
+ public Object testField0037 = new Integer(37);
+ public Object testField0038 = new Integer(38);
+ public Object testField0039 = new Integer(39);
+ public Object testField0040 = new Integer(40);
+ public Object testField0041 = new Integer(41);
+ public Object testField0042 = new Integer(42);
+ public Object testField0043 = new Integer(43);
+ public Object testField0044 = new Integer(44);
+ public Object testField0045 = new Integer(45);
+ public Object testField0046 = new Integer(46);
+ public Object testField0047 = new Integer(47);
+ public Object testField0048 = new Integer(48);
+ public Object testField0049 = new Integer(49);
+ public Object testField0050 = new Integer(50);
+ public Object testField0051 = new Integer(51);
+ public Object testField0052 = new Integer(52);
+ public Object testField0053 = new Integer(53);
+ public Object testField0054 = new Integer(54);
+ public Object testField0055 = new Integer(55);
+ public Object testField0056 = new Integer(56);
+ public Object testField0057 = new Integer(57);
+ public Object testField0058 = new Integer(58);
+ public Object testField0059 = new Integer(59);
+ public Object testField0060 = new Integer(60);
+ public Object testField0061 = new Integer(61);
+ public Object testField0062 = new Integer(62);
+ public Object testField0063 = new Integer(63);
+ public Object testField0064 = new Integer(64);
+ public Object testField0065 = new Integer(65);
+ public Object testField0066 = new Integer(66);
+ public Object testField0067 = new Integer(67);
+ public Object testField0068 = new Integer(68);
+ public Object testField0069 = new Integer(69);
+ public Object testField0070 = new Integer(70);
+ public Object testField0071 = new Integer(71);
+ public Object testField0072 = new Integer(72);
+ public Object testField0073 = new Integer(73);
+ public Object testField0074 = new Integer(74);
+ public Object testField0075 = new Integer(75);
+ public Object testField0076 = new Integer(76);
+ public Object testField0077 = new Integer(77);
+ public Object testField0078 = new Integer(78);
+ public Object testField0079 = new Integer(79);
+ public Object testField0080 = new Integer(80);
+ public Object testField0081 = new Integer(81);
+ public Object testField0082 = new Integer(82);
+ public Object testField0083 = new Integer(83);
+ public Object testField0084 = new Integer(84);
+ public Object testField0085 = new Integer(85);
+ public Object testField0086 = new Integer(86);
+ public Object testField0087 = new Integer(87);
+ public Object testField0088 = new Integer(88);
+ public Object testField0089 = new Integer(89);
+ public Object testField0090 = new Integer(90);
+ public Object testField0091 = new Integer(91);
+ public Object testField0092 = new Integer(92);
+ public Object testField0093 = new Integer(93);
+ public Object testField0094 = new Integer(94);
+ public Object testField0095 = new Integer(95);
+ public Object testField0096 = new Integer(96);
+ public Object testField0097 = new Integer(97);
+ public Object testField0098 = new Integer(98);
+ public Object testField0099 = new Integer(99);
+ public Object testField0100 = new Integer(100);
+ public Object testField0101 = new Integer(101);
+ public Object testField0102 = new Integer(102);
+ public Object testField0103 = new Integer(103);
+ public Object testField0104 = new Integer(104);
+ public Object testField0105 = new Integer(105);
+ public Object testField0106 = new Integer(106);
+ public Object testField0107 = new Integer(107);
+ public Object testField0108 = new Integer(108);
+ public Object testField0109 = new Integer(109);
+ public Object testField0110 = new Integer(110);
+ public Object testField0111 = new Integer(111);
+ public Object testField0112 = new Integer(112);
+ public Object testField0113 = new Integer(113);
+ public Object testField0114 = new Integer(114);
+ public Object testField0115 = new Integer(115);
+ public Object testField0116 = new Integer(116);
+ public Object testField0117 = new Integer(117);
+ public Object testField0118 = new Integer(118);
+ public Object testField0119 = new Integer(119);
+ public Object testField0120 = new Integer(120);
+ public Object testField0121 = new Integer(121);
+ public Object testField0122 = new Integer(122);
+ public Object testField0123 = new Integer(123);
+ public Object testField0124 = new Integer(124);
+ public Object testField0125 = new Integer(125);
+ public Object testField0126 = new Integer(126);
+ public Object testField0127 = new Integer(127);
+ public Object testField0128 = new Integer(128);
+ public Object testField0129 = new Integer(129);
+ public Object testField0130 = new Integer(130);
+ public Object testField0131 = new Integer(131);
+ public Object testField0132 = new Integer(132);
+ public Object testField0133 = new Integer(133);
+ public Object testField0134 = new Integer(134);
+ public Object testField0135 = new Integer(135);
+ public Object testField0136 = new Integer(136);
+ public Object testField0137 = new Integer(137);
+ public Object testField0138 = new Integer(138);
+ public Object testField0139 = new Integer(139);
+ public Object testField0140 = new Integer(140);
+ public Object testField0141 = new Integer(141);
+ public Object testField0142 = new Integer(142);
+ public Object testField0143 = new Integer(143);
+ public Object testField0144 = new Integer(144);
+ public Object testField0145 = new Integer(145);
+ public Object testField0146 = new Integer(146);
+ public Object testField0147 = new Integer(147);
+ public Object testField0148 = new Integer(148);
+ public Object testField0149 = new Integer(149);
+ public Object testField0150 = new Integer(150);
+ public Object testField0151 = new Integer(151);
+ public Object testField0152 = new Integer(152);
+ public Object testField0153 = new Integer(153);
+ public Object testField0154 = new Integer(154);
+ public Object testField0155 = new Integer(155);
+ public Object testField0156 = new Integer(156);
+ public Object testField0157 = new Integer(157);
+ public Object testField0158 = new Integer(158);
+ public Object testField0159 = new Integer(159);
+ public Object testField0160 = new Integer(160);
+ public Object testField0161 = new Integer(161);
+ public Object testField0162 = new Integer(162);
+ public Object testField0163 = new Integer(163);
+ public Object testField0164 = new Integer(164);
+ public Object testField0165 = new Integer(165);
+ public Object testField0166 = new Integer(166);
+ public Object testField0167 = new Integer(167);
+ public Object testField0168 = new Integer(168);
+ public Object testField0169 = new Integer(169);
+ public Object testField0170 = new Integer(170);
+ public Object testField0171 = new Integer(171);
+ public Object testField0172 = new Integer(172);
+ public Object testField0173 = new Integer(173);
+ public Object testField0174 = new Integer(174);
+ public Object testField0175 = new Integer(175);
+ public Object testField0176 = new Integer(176);
+ public Object testField0177 = new Integer(177);
+ public Object testField0178 = new Integer(178);
+ public Object testField0179 = new Integer(179);
+ public Object testField0180 = new Integer(180);
+ public Object testField0181 = new Integer(181);
+ public Object testField0182 = new Integer(182);
+ public Object testField0183 = new Integer(183);
+ public Object testField0184 = new Integer(184);
+ public Object testField0185 = new Integer(185);
+ public Object testField0186 = new Integer(186);
+ public Object testField0187 = new Integer(187);
+ public Object testField0188 = new Integer(188);
+ public Object testField0189 = new Integer(189);
+ public Object testField0190 = new Integer(190);
+ public Object testField0191 = new Integer(191);
+ public Object testField0192 = new Integer(192);
+ public Object testField0193 = new Integer(193);
+ public Object testField0194 = new Integer(194);
+ public Object testField0195 = new Integer(195);
+ public Object testField0196 = new Integer(196);
+ public Object testField0197 = new Integer(197);
+ public Object testField0198 = new Integer(198);
+ public Object testField0199 = new Integer(199);
+ public Object testField0200 = new Integer(200);
+ public Object testField0201 = new Integer(201);
+ public Object testField0202 = new Integer(202);
+ public Object testField0203 = new Integer(203);
+ public Object testField0204 = new Integer(204);
+ public Object testField0205 = new Integer(205);
+ public Object testField0206 = new Integer(206);
+ public Object testField0207 = new Integer(207);
+ public Object testField0208 = new Integer(208);
+ public Object testField0209 = new Integer(209);
+ public Object testField0210 = new Integer(210);
+ public Object testField0211 = new Integer(211);
+ public Object testField0212 = new Integer(212);
+ public Object testField0213 = new Integer(213);
+ public Object testField0214 = new Integer(214);
+ public Object testField0215 = new Integer(215);
+ public Object testField0216 = new Integer(216);
+ public Object testField0217 = new Integer(217);
+ public Object testField0218 = new Integer(218);
+ public Object testField0219 = new Integer(219);
+ public Object testField0220 = new Integer(220);
+ public Object testField0221 = new Integer(221);
+ public Object testField0222 = new Integer(222);
+ public Object testField0223 = new Integer(223);
+ public Object testField0224 = new Integer(224);
+ public Object testField0225 = new Integer(225);
+ public Object testField0226 = new Integer(226);
+ public Object testField0227 = new Integer(227);
+ public Object testField0228 = new Integer(228);
+ public Object testField0229 = new Integer(229);
+ public Object testField0230 = new Integer(230);
+ public Object testField0231 = new Integer(231);
+ public Object testField0232 = new Integer(232);
+ public Object testField0233 = new Integer(233);
+ public Object testField0234 = new Integer(234);
+ public Object testField0235 = new Integer(235);
+ public Object testField0236 = new Integer(236);
+ public Object testField0237 = new Integer(237);
+ public Object testField0238 = new Integer(238);
+ public Object testField0239 = new Integer(239);
+ public Object testField0240 = new Integer(240);
+ public Object testField0241 = new Integer(241);
+ public Object testField0242 = new Integer(242);
+ public Object testField0243 = new Integer(243);
+ public Object testField0244 = new Integer(244);
+ public Object testField0245 = new Integer(245);
+ public Object testField0246 = new Integer(246);
+ public Object testField0247 = new Integer(247);
+ public Object testField0248 = new Integer(248);
+ public Object testField0249 = new Integer(249);
+ public Object testField0250 = new Integer(250);
+ public Object testField0251 = new Integer(251);
+ public Object testField0252 = new Integer(252);
+ public Object testField0253 = new Integer(253);
+ public Object testField0254 = new Integer(254);
+ public Object testField0255 = new Integer(255);
+ public Object testField0256 = new Integer(256);
+ public Object testField0257 = new Integer(257);
+ public Object testField0258 = new Integer(258);
+ public Object testField0259 = new Integer(259);
+ public Object testField0260 = new Integer(260);
+ public Object testField0261 = new Integer(261);
+ public Object testField0262 = new Integer(262);
+ public Object testField0263 = new Integer(263);
+ public Object testField0264 = new Integer(264);
+ public Object testField0265 = new Integer(265);
+ public Object testField0266 = new Integer(266);
+ public Object testField0267 = new Integer(267);
+ public Object testField0268 = new Integer(268);
+ public Object testField0269 = new Integer(269);
+ public Object testField0270 = new Integer(270);
+ public Object testField0271 = new Integer(271);
+ public Object testField0272 = new Integer(272);
+ public Object testField0273 = new Integer(273);
+ public Object testField0274 = new Integer(274);
+ public Object testField0275 = new Integer(275);
+ public Object testField0276 = new Integer(276);
+ public Object testField0277 = new Integer(277);
+ public Object testField0278 = new Integer(278);
+ public Object testField0279 = new Integer(279);
+ public Object testField0280 = new Integer(280);
+ public Object testField0281 = new Integer(281);
+ public Object testField0282 = new Integer(282);
+ public Object testField0283 = new Integer(283);
+ public Object testField0284 = new Integer(284);
+ public Object testField0285 = new Integer(285);
+ public Object testField0286 = new Integer(286);
+ public Object testField0287 = new Integer(287);
+ public Object testField0288 = new Integer(288);
+ public Object testField0289 = new Integer(289);
+ public Object testField0290 = new Integer(290);
+ public Object testField0291 = new Integer(291);
+ public Object testField0292 = new Integer(292);
+ public Object testField0293 = new Integer(293);
+ public Object testField0294 = new Integer(294);
+ public Object testField0295 = new Integer(295);
+ public Object testField0296 = new Integer(296);
+ public Object testField0297 = new Integer(297);
+ public Object testField0298 = new Integer(298);
+ public Object testField0299 = new Integer(299);
+ public Object testField0300 = new Integer(300);
+ public Object testField0301 = new Integer(301);
+ public Object testField0302 = new Integer(302);
+ public Object testField0303 = new Integer(303);
+ public Object testField0304 = new Integer(304);
+ public Object testField0305 = new Integer(305);
+ public Object testField0306 = new Integer(306);
+ public Object testField0307 = new Integer(307);
+ public Object testField0308 = new Integer(308);
+ public Object testField0309 = new Integer(309);
+ public Object testField0310 = new Integer(310);
+ public Object testField0311 = new Integer(311);
+ public Object testField0312 = new Integer(312);
+ public Object testField0313 = new Integer(313);
+ public Object testField0314 = new Integer(314);
+ public Object testField0315 = new Integer(315);
+ public Object testField0316 = new Integer(316);
+ public Object testField0317 = new Integer(317);
+ public Object testField0318 = new Integer(318);
+ public Object testField0319 = new Integer(319);
+ public Object testField0320 = new Integer(320);
+ public Object testField0321 = new Integer(321);
+ public Object testField0322 = new Integer(322);
+ public Object testField0323 = new Integer(323);
+ public Object testField0324 = new Integer(324);
+ public Object testField0325 = new Integer(325);
+ public Object testField0326 = new Integer(326);
+ public Object testField0327 = new Integer(327);
+ public Object testField0328 = new Integer(328);
+ public Object testField0329 = new Integer(329);
+ public Object testField0330 = new Integer(330);
+ public Object testField0331 = new Integer(331);
+ public Object testField0332 = new Integer(332);
+ public Object testField0333 = new Integer(333);
+ public Object testField0334 = new Integer(334);
+ public Object testField0335 = new Integer(335);
+ public Object testField0336 = new Integer(336);
+ public Object testField0337 = new Integer(337);
+ public Object testField0338 = new Integer(338);
+ public Object testField0339 = new Integer(339);
+ public Object testField0340 = new Integer(340);
+ public Object testField0341 = new Integer(341);
+ public Object testField0342 = new Integer(342);
+ public Object testField0343 = new Integer(343);
+ public Object testField0344 = new Integer(344);
+ public Object testField0345 = new Integer(345);
+ public Object testField0346 = new Integer(346);
+ public Object testField0347 = new Integer(347);
+ public Object testField0348 = new Integer(348);
+ public Object testField0349 = new Integer(349);
+ public Object testField0350 = new Integer(350);
+ public Object testField0351 = new Integer(351);
+ public Object testField0352 = new Integer(352);
+ public Object testField0353 = new Integer(353);
+ public Object testField0354 = new Integer(354);
+ public Object testField0355 = new Integer(355);
+ public Object testField0356 = new Integer(356);
+ public Object testField0357 = new Integer(357);
+ public Object testField0358 = new Integer(358);
+ public Object testField0359 = new Integer(359);
+ public Object testField0360 = new Integer(360);
+ public Object testField0361 = new Integer(361);
+ public Object testField0362 = new Integer(362);
+ public Object testField0363 = new Integer(363);
+ public Object testField0364 = new Integer(364);
+ public Object testField0365 = new Integer(365);
+ public Object testField0366 = new Integer(366);
+ public Object testField0367 = new Integer(367);
+ public Object testField0368 = new Integer(368);
+ public Object testField0369 = new Integer(369);
+ public Object testField0370 = new Integer(370);
+ public Object testField0371 = new Integer(371);
+ public Object testField0372 = new Integer(372);
+ public Object testField0373 = new Integer(373);
+ public Object testField0374 = new Integer(374);
+ public Object testField0375 = new Integer(375);
+ public Object testField0376 = new Integer(376);
+ public Object testField0377 = new Integer(377);
+ public Object testField0378 = new Integer(378);
+ public Object testField0379 = new Integer(379);
+ public Object testField0380 = new Integer(380);
+ public Object testField0381 = new Integer(381);
+ public Object testField0382 = new Integer(382);
+ public Object testField0383 = new Integer(383);
+ public Object testField0384 = new Integer(384);
+ public Object testField0385 = new Integer(385);
+ public Object testField0386 = new Integer(386);
+ public Object testField0387 = new Integer(387);
+ public Object testField0388 = new Integer(388);
+ public Object testField0389 = new Integer(389);
+ public Object testField0390 = new Integer(390);
+ public Object testField0391 = new Integer(391);
+ public Object testField0392 = new Integer(392);
+ public Object testField0393 = new Integer(393);
+ public Object testField0394 = new Integer(394);
+ public Object testField0395 = new Integer(395);
+ public Object testField0396 = new Integer(396);
+ public Object testField0397 = new Integer(397);
+ public Object testField0398 = new Integer(398);
+ public Object testField0399 = new Integer(399);
+ public Object testField0400 = new Integer(400);
+ public Object testField0401 = new Integer(401);
+ public Object testField0402 = new Integer(402);
+ public Object testField0403 = new Integer(403);
+ public Object testField0404 = new Integer(404);
+ public Object testField0405 = new Integer(405);
+ public Object testField0406 = new Integer(406);
+ public Object testField0407 = new Integer(407);
+ public Object testField0408 = new Integer(408);
+ public Object testField0409 = new Integer(409);
+ public Object testField0410 = new Integer(410);
+ public Object testField0411 = new Integer(411);
+ public Object testField0412 = new Integer(412);
+ public Object testField0413 = new Integer(413);
+ public Object testField0414 = new Integer(414);
+ public Object testField0415 = new Integer(415);
+ public Object testField0416 = new Integer(416);
+ public Object testField0417 = new Integer(417);
+ public Object testField0418 = new Integer(418);
+ public Object testField0419 = new Integer(419);
+ public Object testField0420 = new Integer(420);
+ public Object testField0421 = new Integer(421);
+ public Object testField0422 = new Integer(422);
+ public Object testField0423 = new Integer(423);
+ public Object testField0424 = new Integer(424);
+ public Object testField0425 = new Integer(425);
+ public Object testField0426 = new Integer(426);
+ public Object testField0427 = new Integer(427);
+ public Object testField0428 = new Integer(428);
+ public Object testField0429 = new Integer(429);
+ public Object testField0430 = new Integer(430);
+ public Object testField0431 = new Integer(431);
+ public Object testField0432 = new Integer(432);
+ public Object testField0433 = new Integer(433);
+ public Object testField0434 = new Integer(434);
+ public Object testField0435 = new Integer(435);
+ public Object testField0436 = new Integer(436);
+ public Object testField0437 = new Integer(437);
+ public Object testField0438 = new Integer(438);
+ public Object testField0439 = new Integer(439);
+ public Object testField0440 = new Integer(440);
+ public Object testField0441 = new Integer(441);
+ public Object testField0442 = new Integer(442);
+ public Object testField0443 = new Integer(443);
+ public Object testField0444 = new Integer(444);
+ public Object testField0445 = new Integer(445);
+ public Object testField0446 = new Integer(446);
+ public Object testField0447 = new Integer(447);
+ public Object testField0448 = new Integer(448);
+ public Object testField0449 = new Integer(449);
+ public Object testField0450 = new Integer(450);
+ public Object testField0451 = new Integer(451);
+ public Object testField0452 = new Integer(452);
+ public Object testField0453 = new Integer(453);
+ public Object testField0454 = new Integer(454);
+ public Object testField0455 = new Integer(455);
+ public Object testField0456 = new Integer(456);
+ public Object testField0457 = new Integer(457);
+ public Object testField0458 = new Integer(458);
+ public Object testField0459 = new Integer(459);
+ public Object testField0460 = new Integer(460);
+ public Object testField0461 = new Integer(461);
+ public Object testField0462 = new Integer(462);
+ public Object testField0463 = new Integer(463);
+ public Object testField0464 = new Integer(464);
+ public Object testField0465 = new Integer(465);
+ public Object testField0466 = new Integer(466);
+ public Object testField0467 = new Integer(467);
+ public Object testField0468 = new Integer(468);
+ public Object testField0469 = new Integer(469);
+ public Object testField0470 = new Integer(470);
+ public Object testField0471 = new Integer(471);
+ public Object testField0472 = new Integer(472);
+ public Object testField0473 = new Integer(473);
+ public Object testField0474 = new Integer(474);
+ public Object testField0475 = new Integer(475);
+ public Object testField0476 = new Integer(476);
+ public Object testField0477 = new Integer(477);
+ public Object testField0478 = new Integer(478);
+ public Object testField0479 = new Integer(479);
+ public Object testField0480 = new Integer(480);
+ public Object testField0481 = new Integer(481);
+ public Object testField0482 = new Integer(482);
+ public Object testField0483 = new Integer(483);
+ public Object testField0484 = new Integer(484);
+ public Object testField0485 = new Integer(485);
+ public Object testField0486 = new Integer(486);
+ public Object testField0487 = new Integer(487);
+ public Object testField0488 = new Integer(488);
+ public Object testField0489 = new Integer(489);
+ public Object testField0490 = new Integer(490);
+ public Object testField0491 = new Integer(491);
+ public Object testField0492 = new Integer(492);
+ public Object testField0493 = new Integer(493);
+ public Object testField0494 = new Integer(494);
+ public Object testField0495 = new Integer(495);
+ public Object testField0496 = new Integer(496);
+ public Object testField0497 = new Integer(497);
+ public Object testField0498 = new Integer(498);
+ public Object testField0499 = new Integer(499);
+ public Object testField0500 = new Integer(500);
+ public Object testField0501 = new Integer(501);
+ public Object testField0502 = new Integer(502);
+ public Object testField0503 = new Integer(503);
+ public Object testField0504 = new Integer(504);
+ public Object testField0505 = new Integer(505);
+ public Object testField0506 = new Integer(506);
+ public Object testField0507 = new Integer(507);
+ public Object testField0508 = new Integer(508);
+ public Object testField0509 = new Integer(509);
+ public Object testField0510 = new Integer(510);
+ public Object testField0511 = new Integer(511);
+ public Object testField0512 = new Integer(512);
+ public Object testField0513 = new Integer(513);
+ public Object testField0514 = new Integer(514);
+ public Object testField0515 = new Integer(515);
+ public Object testField0516 = new Integer(516);
+ public Object testField0517 = new Integer(517);
+ public Object testField0518 = new Integer(518);
+ public Object testField0519 = new Integer(519);
+ public Object testField0520 = new Integer(520);
+ public Object testField0521 = new Integer(521);
+ public Object testField0522 = new Integer(522);
+ public Object testField0523 = new Integer(523);
+ public Object testField0524 = new Integer(524);
+ public Object testField0525 = new Integer(525);
+ public Object testField0526 = new Integer(526);
+ public Object testField0527 = new Integer(527);
+ public Object testField0528 = new Integer(528);
+ public Object testField0529 = new Integer(529);
+ public Object testField0530 = new Integer(530);
+ public Object testField0531 = new Integer(531);
+ public Object testField0532 = new Integer(532);
+ public Object testField0533 = new Integer(533);
+ public Object testField0534 = new Integer(534);
+ public Object testField0535 = new Integer(535);
+ public Object testField0536 = new Integer(536);
+ public Object testField0537 = new Integer(537);
+ public Object testField0538 = new Integer(538);
+ public Object testField0539 = new Integer(539);
+ public Object testField0540 = new Integer(540);
+ public Object testField0541 = new Integer(541);
+ public Object testField0542 = new Integer(542);
+ public Object testField0543 = new Integer(543);
+ public Object testField0544 = new Integer(544);
+ public Object testField0545 = new Integer(545);
+ public Object testField0546 = new Integer(546);
+ public Object testField0547 = new Integer(547);
+ public Object testField0548 = new Integer(548);
+ public Object testField0549 = new Integer(549);
+ public Object testField0550 = new Integer(550);
+ public Object testField0551 = new Integer(551);
+ public Object testField0552 = new Integer(552);
+ public Object testField0553 = new Integer(553);
+ public Object testField0554 = new Integer(554);
+ public Object testField0555 = new Integer(555);
+ public Object testField0556 = new Integer(556);
+ public Object testField0557 = new Integer(557);
+ public Object testField0558 = new Integer(558);
+ public Object testField0559 = new Integer(559);
+ public Object testField0560 = new Integer(560);
+ public Object testField0561 = new Integer(561);
+ public Object testField0562 = new Integer(562);
+ public Object testField0563 = new Integer(563);
+ public Object testField0564 = new Integer(564);
+ public Object testField0565 = new Integer(565);
+ public Object testField0566 = new Integer(566);
+ public Object testField0567 = new Integer(567);
+ public Object testField0568 = new Integer(568);
+ public Object testField0569 = new Integer(569);
+ public Object testField0570 = new Integer(570);
+ public Object testField0571 = new Integer(571);
+ public Object testField0572 = new Integer(572);
+ public Object testField0573 = new Integer(573);
+ public Object testField0574 = new Integer(574);
+ public Object testField0575 = new Integer(575);
+ public Object testField0576 = new Integer(576);
+ public Object testField0577 = new Integer(577);
+ public Object testField0578 = new Integer(578);
+ public Object testField0579 = new Integer(579);
+ public Object testField0580 = new Integer(580);
+ public Object testField0581 = new Integer(581);
+ public Object testField0582 = new Integer(582);
+ public Object testField0583 = new Integer(583);
+ public Object testField0584 = new Integer(584);
+ public Object testField0585 = new Integer(585);
+ public Object testField0586 = new Integer(586);
+ public Object testField0587 = new Integer(587);
+ public Object testField0588 = new Integer(588);
+ public Object testField0589 = new Integer(589);
+ public Object testField0590 = new Integer(590);
+ public Object testField0591 = new Integer(591);
+ public Object testField0592 = new Integer(592);
+ public Object testField0593 = new Integer(593);
+ public Object testField0594 = new Integer(594);
+ public Object testField0595 = new Integer(595);
+ public Object testField0596 = new Integer(596);
+ public Object testField0597 = new Integer(597);
+ public Object testField0598 = new Integer(598);
+ public Object testField0599 = new Integer(599);
+ public Object testField0600 = new Integer(600);
+ public Object testField0601 = new Integer(601);
+ public Object testField0602 = new Integer(602);
+ public Object testField0603 = new Integer(603);
+ public Object testField0604 = new Integer(604);
+ public Object testField0605 = new Integer(605);
+ public Object testField0606 = new Integer(606);
+ public Object testField0607 = new Integer(607);
+ public Object testField0608 = new Integer(608);
+ public Object testField0609 = new Integer(609);
+ public Object testField0610 = new Integer(610);
+ public Object testField0611 = new Integer(611);
+ public Object testField0612 = new Integer(612);
+ public Object testField0613 = new Integer(613);
+ public Object testField0614 = new Integer(614);
+ public Object testField0615 = new Integer(615);
+ public Object testField0616 = new Integer(616);
+ public Object testField0617 = new Integer(617);
+ public Object testField0618 = new Integer(618);
+ public Object testField0619 = new Integer(619);
+ public Object testField0620 = new Integer(620);
+ public Object testField0621 = new Integer(621);
+ public Object testField0622 = new Integer(622);
+ public Object testField0623 = new Integer(623);
+ public Object testField0624 = new Integer(624);
+ public Object testField0625 = new Integer(625);
+ public Object testField0626 = new Integer(626);
+ public Object testField0627 = new Integer(627);
+ public Object testField0628 = new Integer(628);
+ public Object testField0629 = new Integer(629);
+ public Object testField0630 = new Integer(630);
+ public Object testField0631 = new Integer(631);
+ public Object testField0632 = new Integer(632);
+ public Object testField0633 = new Integer(633);
+ public Object testField0634 = new Integer(634);
+ public Object testField0635 = new Integer(635);
+ public Object testField0636 = new Integer(636);
+ public Object testField0637 = new Integer(637);
+ public Object testField0638 = new Integer(638);
+ public Object testField0639 = new Integer(639);
+ public Object testField0640 = new Integer(640);
+ public Object testField0641 = new Integer(641);
+ public Object testField0642 = new Integer(642);
+ public Object testField0643 = new Integer(643);
+ public Object testField0644 = new Integer(644);
+ public Object testField0645 = new Integer(645);
+ public Object testField0646 = new Integer(646);
+ public Object testField0647 = new Integer(647);
+ public Object testField0648 = new Integer(648);
+ public Object testField0649 = new Integer(649);
+ public Object testField0650 = new Integer(650);
+ public Object testField0651 = new Integer(651);
+ public Object testField0652 = new Integer(652);
+ public Object testField0653 = new Integer(653);
+ public Object testField0654 = new Integer(654);
+ public Object testField0655 = new Integer(655);
+ public Object testField0656 = new Integer(656);
+ public Object testField0657 = new Integer(657);
+ public Object testField0658 = new Integer(658);
+ public Object testField0659 = new Integer(659);
+ public Object testField0660 = new Integer(660);
+ public Object testField0661 = new Integer(661);
+ public Object testField0662 = new Integer(662);
+ public Object testField0663 = new Integer(663);
+ public Object testField0664 = new Integer(664);
+ public Object testField0665 = new Integer(665);
+ public Object testField0666 = new Integer(666);
+ public Object testField0667 = new Integer(667);
+ public Object testField0668 = new Integer(668);
+ public Object testField0669 = new Integer(669);
+ public Object testField0670 = new Integer(670);
+ public Object testField0671 = new Integer(671);
+ public Object testField0672 = new Integer(672);
+ public Object testField0673 = new Integer(673);
+ public Object testField0674 = new Integer(674);
+ public Object testField0675 = new Integer(675);
+ public Object testField0676 = new Integer(676);
+ public Object testField0677 = new Integer(677);
+ public Object testField0678 = new Integer(678);
+ public Object testField0679 = new Integer(679);
+ public Object testField0680 = new Integer(680);
+ public Object testField0681 = new Integer(681);
+ public Object testField0682 = new Integer(682);
+ public Object testField0683 = new Integer(683);
+ public Object testField0684 = new Integer(684);
+ public Object testField0685 = new Integer(685);
+ public Object testField0686 = new Integer(686);
+ public Object testField0687 = new Integer(687);
+ public Object testField0688 = new Integer(688);
+ public Object testField0689 = new Integer(689);
+ public Object testField0690 = new Integer(690);
+ public Object testField0691 = new Integer(691);
+ public Object testField0692 = new Integer(692);
+ public Object testField0693 = new Integer(693);
+ public Object testField0694 = new Integer(694);
+ public Object testField0695 = new Integer(695);
+ public Object testField0696 = new Integer(696);
+ public Object testField0697 = new Integer(697);
+ public Object testField0698 = new Integer(698);
+ public Object testField0699 = new Integer(699);
+ public Object testField0700 = new Integer(700);
+ public Object testField0701 = new Integer(701);
+ public Object testField0702 = new Integer(702);
+ public Object testField0703 = new Integer(703);
+ public Object testField0704 = new Integer(704);
+ public Object testField0705 = new Integer(705);
+ public Object testField0706 = new Integer(706);
+ public Object testField0707 = new Integer(707);
+ public Object testField0708 = new Integer(708);
+ public Object testField0709 = new Integer(709);
+ public Object testField0710 = new Integer(710);
+ public Object testField0711 = new Integer(711);
+ public Object testField0712 = new Integer(712);
+ public Object testField0713 = new Integer(713);
+ public Object testField0714 = new Integer(714);
+ public Object testField0715 = new Integer(715);
+ public Object testField0716 = new Integer(716);
+ public Object testField0717 = new Integer(717);
+ public Object testField0718 = new Integer(718);
+ public Object testField0719 = new Integer(719);
+ public Object testField0720 = new Integer(720);
+ public Object testField0721 = new Integer(721);
+ public Object testField0722 = new Integer(722);
+ public Object testField0723 = new Integer(723);
+ public Object testField0724 = new Integer(724);
+ public Object testField0725 = new Integer(725);
+ public Object testField0726 = new Integer(726);
+ public Object testField0727 = new Integer(727);
+ public Object testField0728 = new Integer(728);
+ public Object testField0729 = new Integer(729);
+ public Object testField0730 = new Integer(730);
+ public Object testField0731 = new Integer(731);
+ public Object testField0732 = new Integer(732);
+ public Object testField0733 = new Integer(733);
+ public Object testField0734 = new Integer(734);
+ public Object testField0735 = new Integer(735);
+ public Object testField0736 = new Integer(736);
+ public Object testField0737 = new Integer(737);
+ public Object testField0738 = new Integer(738);
+ public Object testField0739 = new Integer(739);
+ public Object testField0740 = new Integer(740);
+ public Object testField0741 = new Integer(741);
+ public Object testField0742 = new Integer(742);
+ public Object testField0743 = new Integer(743);
+ public Object testField0744 = new Integer(744);
+ public Object testField0745 = new Integer(745);
+ public Object testField0746 = new Integer(746);
+ public Object testField0747 = new Integer(747);
+ public Object testField0748 = new Integer(748);
+ public Object testField0749 = new Integer(749);
+ public Object testField0750 = new Integer(750);
+ public Object testField0751 = new Integer(751);
+ public Object testField0752 = new Integer(752);
+ public Object testField0753 = new Integer(753);
+ public Object testField0754 = new Integer(754);
+ public Object testField0755 = new Integer(755);
+ public Object testField0756 = new Integer(756);
+ public Object testField0757 = new Integer(757);
+ public Object testField0758 = new Integer(758);
+ public Object testField0759 = new Integer(759);
+ public Object testField0760 = new Integer(760);
+ public Object testField0761 = new Integer(761);
+ public Object testField0762 = new Integer(762);
+ public Object testField0763 = new Integer(763);
+ public Object testField0764 = new Integer(764);
+ public Object testField0765 = new Integer(765);
+ public Object testField0766 = new Integer(766);
+ public Object testField0767 = new Integer(767);
+ public Object testField0768 = new Integer(768);
+ public Object testField0769 = new Integer(769);
+ public Object testField0770 = new Integer(770);
+ public Object testField0771 = new Integer(771);
+ public Object testField0772 = new Integer(772);
+ public Object testField0773 = new Integer(773);
+ public Object testField0774 = new Integer(774);
+ public Object testField0775 = new Integer(775);
+ public Object testField0776 = new Integer(776);
+ public Object testField0777 = new Integer(777);
+ public Object testField0778 = new Integer(778);
+ public Object testField0779 = new Integer(779);
+ public Object testField0780 = new Integer(780);
+ public Object testField0781 = new Integer(781);
+ public Object testField0782 = new Integer(782);
+ public Object testField0783 = new Integer(783);
+ public Object testField0784 = new Integer(784);
+ public Object testField0785 = new Integer(785);
+ public Object testField0786 = new Integer(786);
+ public Object testField0787 = new Integer(787);
+ public Object testField0788 = new Integer(788);
+ public Object testField0789 = new Integer(789);
+ public Object testField0790 = new Integer(790);
+ public Object testField0791 = new Integer(791);
+ public Object testField0792 = new Integer(792);
+ public Object testField0793 = new Integer(793);
+ public Object testField0794 = new Integer(794);
+ public Object testField0795 = new Integer(795);
+ public Object testField0796 = new Integer(796);
+ public Object testField0797 = new Integer(797);
+ public Object testField0798 = new Integer(798);
+ public Object testField0799 = new Integer(799);
+ public Object testField0800 = new Integer(800);
+ public Object testField0801 = new Integer(801);
+ public Object testField0802 = new Integer(802);
+ public Object testField0803 = new Integer(803);
+ public Object testField0804 = new Integer(804);
+ public Object testField0805 = new Integer(805);
+ public Object testField0806 = new Integer(806);
+ public Object testField0807 = new Integer(807);
+ public Object testField0808 = new Integer(808);
+ public Object testField0809 = new Integer(809);
+ public Object testField0810 = new Integer(810);
+ public Object testField0811 = new Integer(811);
+ public Object testField0812 = new Integer(812);
+ public Object testField0813 = new Integer(813);
+ public Object testField0814 = new Integer(814);
+ public Object testField0815 = new Integer(815);
+ public Object testField0816 = new Integer(816);
+ public Object testField0817 = new Integer(817);
+ public Object testField0818 = new Integer(818);
+ public Object testField0819 = new Integer(819);
+ public Object testField0820 = new Integer(820);
+ public Object testField0821 = new Integer(821);
+ public Object testField0822 = new Integer(822);
+ public Object testField0823 = new Integer(823);
+ public Object testField0824 = new Integer(824);
+ public Object testField0825 = new Integer(825);
+ public Object testField0826 = new Integer(826);
+ public Object testField0827 = new Integer(827);
+ public Object testField0828 = new Integer(828);
+ public Object testField0829 = new Integer(829);
+ public Object testField0830 = new Integer(830);
+ public Object testField0831 = new Integer(831);
+ public Object testField0832 = new Integer(832);
+ public Object testField0833 = new Integer(833);
+ public Object testField0834 = new Integer(834);
+ public Object testField0835 = new Integer(835);
+ public Object testField0836 = new Integer(836);
+ public Object testField0837 = new Integer(837);
+ public Object testField0838 = new Integer(838);
+ public Object testField0839 = new Integer(839);
+ public Object testField0840 = new Integer(840);
+ public Object testField0841 = new Integer(841);
+ public Object testField0842 = new Integer(842);
+ public Object testField0843 = new Integer(843);
+ public Object testField0844 = new Integer(844);
+ public Object testField0845 = new Integer(845);
+ public Object testField0846 = new Integer(846);
+ public Object testField0847 = new Integer(847);
+ public Object testField0848 = new Integer(848);
+ public Object testField0849 = new Integer(849);
+ public Object testField0850 = new Integer(850);
+ public Object testField0851 = new Integer(851);
+ public Object testField0852 = new Integer(852);
+ public Object testField0853 = new Integer(853);
+ public Object testField0854 = new Integer(854);
+ public Object testField0855 = new Integer(855);
+ public Object testField0856 = new Integer(856);
+ public Object testField0857 = new Integer(857);
+ public Object testField0858 = new Integer(858);
+ public Object testField0859 = new Integer(859);
+ public Object testField0860 = new Integer(860);
+ public Object testField0861 = new Integer(861);
+ public Object testField0862 = new Integer(862);
+ public Object testField0863 = new Integer(863);
+ public Object testField0864 = new Integer(864);
+ public Object testField0865 = new Integer(865);
+ public Object testField0866 = new Integer(866);
+ public Object testField0867 = new Integer(867);
+ public Object testField0868 = new Integer(868);
+ public Object testField0869 = new Integer(869);
+ public Object testField0870 = new Integer(870);
+ public Object testField0871 = new Integer(871);
+ public Object testField0872 = new Integer(872);
+ public Object testField0873 = new Integer(873);
+ public Object testField0874 = new Integer(874);
+ public Object testField0875 = new Integer(875);
+ public Object testField0876 = new Integer(876);
+ public Object testField0877 = new Integer(877);
+ public Object testField0878 = new Integer(878);
+ public Object testField0879 = new Integer(879);
+ public Object testField0880 = new Integer(880);
+ public Object testField0881 = new Integer(881);
+ public Object testField0882 = new Integer(882);
+ public Object testField0883 = new Integer(883);
+ public Object testField0884 = new Integer(884);
+ public Object testField0885 = new Integer(885);
+ public Object testField0886 = new Integer(886);
+ public Object testField0887 = new Integer(887);
+ public Object testField0888 = new Integer(888);
+ public Object testField0889 = new Integer(889);
+ public Object testField0890 = new Integer(890);
+ public Object testField0891 = new Integer(891);
+ public Object testField0892 = new Integer(892);
+ public Object testField0893 = new Integer(893);
+ public Object testField0894 = new Integer(894);
+ public Object testField0895 = new Integer(895);
+ public Object testField0896 = new Integer(896);
+ public Object testField0897 = new Integer(897);
+ public Object testField0898 = new Integer(898);
+ public Object testField0899 = new Integer(899);
+ public Object testField0900 = new Integer(900);
+ public Object testField0901 = new Integer(901);
+ public Object testField0902 = new Integer(902);
+ public Object testField0903 = new Integer(903);
+ public Object testField0904 = new Integer(904);
+ public Object testField0905 = new Integer(905);
+ public Object testField0906 = new Integer(906);
+ public Object testField0907 = new Integer(907);
+ public Object testField0908 = new Integer(908);
+ public Object testField0909 = new Integer(909);
+ public Object testField0910 = new Integer(910);
+ public Object testField0911 = new Integer(911);
+ public Object testField0912 = new Integer(912);
+ public Object testField0913 = new Integer(913);
+ public Object testField0914 = new Integer(914);
+ public Object testField0915 = new Integer(915);
+ public Object testField0916 = new Integer(916);
+ public Object testField0917 = new Integer(917);
+ public Object testField0918 = new Integer(918);
+ public Object testField0919 = new Integer(919);
+ public Object testField0920 = new Integer(920);
+ public Object testField0921 = new Integer(921);
+ public Object testField0922 = new Integer(922);
+ public Object testField0923 = new Integer(923);
+ public Object testField0924 = new Integer(924);
+ public Object testField0925 = new Integer(925);
+ public Object testField0926 = new Integer(926);
+ public Object testField0927 = new Integer(927);
+ public Object testField0928 = new Integer(928);
+ public Object testField0929 = new Integer(929);
+ public Object testField0930 = new Integer(930);
+ public Object testField0931 = new Integer(931);
+ public Object testField0932 = new Integer(932);
+ public Object testField0933 = new Integer(933);
+ public Object testField0934 = new Integer(934);
+ public Object testField0935 = new Integer(935);
+ public Object testField0936 = new Integer(936);
+ public Object testField0937 = new Integer(937);
+ public Object testField0938 = new Integer(938);
+ public Object testField0939 = new Integer(939);
+ public Object testField0940 = new Integer(940);
+ public Object testField0941 = new Integer(941);
+ public Object testField0942 = new Integer(942);
+ public Object testField0943 = new Integer(943);
+ public Object testField0944 = new Integer(944);
+ public Object testField0945 = new Integer(945);
+ public Object testField0946 = new Integer(946);
+ public Object testField0947 = new Integer(947);
+ public Object testField0948 = new Integer(948);
+ public Object testField0949 = new Integer(949);
+ public Object testField0950 = new Integer(950);
+ public Object testField0951 = new Integer(951);
+ public Object testField0952 = new Integer(952);
+ public Object testField0953 = new Integer(953);
+ public Object testField0954 = new Integer(954);
+ public Object testField0955 = new Integer(955);
+ public Object testField0956 = new Integer(956);
+ public Object testField0957 = new Integer(957);
+ public Object testField0958 = new Integer(958);
+ public Object testField0959 = new Integer(959);
+ public Object testField0960 = new Integer(960);
+ public Object testField0961 = new Integer(961);
+ public Object testField0962 = new Integer(962);
+ public Object testField0963 = new Integer(963);
+ public Object testField0964 = new Integer(964);
+ public Object testField0965 = new Integer(965);
+ public Object testField0966 = new Integer(966);
+ public Object testField0967 = new Integer(967);
+ public Object testField0968 = new Integer(968);
+ public Object testField0969 = new Integer(969);
+ public Object testField0970 = new Integer(970);
+ public Object testField0971 = new Integer(971);
+ public Object testField0972 = new Integer(972);
+ public Object testField0973 = new Integer(973);
+ public Object testField0974 = new Integer(974);
+ public Object testField0975 = new Integer(975);
+ public Object testField0976 = new Integer(976);
+ public Object testField0977 = new Integer(977);
+ public Object testField0978 = new Integer(978);
+ public Object testField0979 = new Integer(979);
+ public Object testField0980 = new Integer(980);
+ public Object testField0981 = new Integer(981);
+ public Object testField0982 = new Integer(982);
+ public Object testField0983 = new Integer(983);
+ public Object testField0984 = new Integer(984);
+ public Object testField0985 = new Integer(985);
+ public Object testField0986 = new Integer(986);
+ public Object testField0987 = new Integer(987);
+ public Object testField0988 = new Integer(988);
+ public Object testField0989 = new Integer(989);
+ public Object testField0990 = new Integer(990);
+ public Object testField0991 = new Integer(991);
+ public Object testField0992 = new Integer(992);
+ public Object testField0993 = new Integer(993);
+ public Object testField0994 = new Integer(994);
+ public Object testField0995 = new Integer(995);
+ public Object testField0996 = new Integer(996);
+ public Object testField0997 = new Integer(997);
+ public Object testField0998 = new Integer(998);
+ public Object testField0999 = new Integer(999);
+}
diff --git a/test/160-read-barrier-stress/src/ManyFieldsBase1.java b/test/160-read-barrier-stress/src/ManyFieldsBase1.java
new file mode 100644
index 0000000..8680c6b
--- /dev/null
+++ b/test/160-read-barrier-stress/src/ManyFieldsBase1.java
@@ -0,0 +1,1018 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+class ManyFieldsBase1 extends ManyFieldsBase0 {
+ public Object testField1000 = new Integer(1000);
+ public Object testField1001 = new Integer(1001);
+ public Object testField1002 = new Integer(1002);
+ public Object testField1003 = new Integer(1003);
+ public Object testField1004 = new Integer(1004);
+ public Object testField1005 = new Integer(1005);
+ public Object testField1006 = new Integer(1006);
+ public Object testField1007 = new Integer(1007);
+ public Object testField1008 = new Integer(1008);
+ public Object testField1009 = new Integer(1009);
+ public Object testField1010 = new Integer(1010);
+ public Object testField1011 = new Integer(1011);
+ public Object testField1012 = new Integer(1012);
+ public Object testField1013 = new Integer(1013);
+ public Object testField1014 = new Integer(1014);
+ public Object testField1015 = new Integer(1015);
+ public Object testField1016 = new Integer(1016);
+ public Object testField1017 = new Integer(1017);
+ public Object testField1018 = new Integer(1018);
+ public Object testField1019 = new Integer(1019);
+ public Object testField1020 = new Integer(1020);
+ public Object testField1021 = new Integer(1021);
+ public Object testField1022 = new Integer(1022);
+ public Object testField1023 = new Integer(1023);
+ public Object testField1024 = new Integer(1024);
+ public Object testField1025 = new Integer(1025);
+ public Object testField1026 = new Integer(1026);
+ public Object testField1027 = new Integer(1027);
+ public Object testField1028 = new Integer(1028);
+ public Object testField1029 = new Integer(1029);
+ public Object testField1030 = new Integer(1030);
+ public Object testField1031 = new Integer(1031);
+ public Object testField1032 = new Integer(1032);
+ public Object testField1033 = new Integer(1033);
+ public Object testField1034 = new Integer(1034);
+ public Object testField1035 = new Integer(1035);
+ public Object testField1036 = new Integer(1036);
+ public Object testField1037 = new Integer(1037);
+ public Object testField1038 = new Integer(1038);
+ public Object testField1039 = new Integer(1039);
+ public Object testField1040 = new Integer(1040);
+ public Object testField1041 = new Integer(1041);
+ public Object testField1042 = new Integer(1042);
+ public Object testField1043 = new Integer(1043);
+ public Object testField1044 = new Integer(1044);
+ public Object testField1045 = new Integer(1045);
+ public Object testField1046 = new Integer(1046);
+ public Object testField1047 = new Integer(1047);
+ public Object testField1048 = new Integer(1048);
+ public Object testField1049 = new Integer(1049);
+ public Object testField1050 = new Integer(1050);
+ public Object testField1051 = new Integer(1051);
+ public Object testField1052 = new Integer(1052);
+ public Object testField1053 = new Integer(1053);
+ public Object testField1054 = new Integer(1054);
+ public Object testField1055 = new Integer(1055);
+ public Object testField1056 = new Integer(1056);
+ public Object testField1057 = new Integer(1057);
+ public Object testField1058 = new Integer(1058);
+ public Object testField1059 = new Integer(1059);
+ public Object testField1060 = new Integer(1060);
+ public Object testField1061 = new Integer(1061);
+ public Object testField1062 = new Integer(1062);
+ public Object testField1063 = new Integer(1063);
+ public Object testField1064 = new Integer(1064);
+ public Object testField1065 = new Integer(1065);
+ public Object testField1066 = new Integer(1066);
+ public Object testField1067 = new Integer(1067);
+ public Object testField1068 = new Integer(1068);
+ public Object testField1069 = new Integer(1069);
+ public Object testField1070 = new Integer(1070);
+ public Object testField1071 = new Integer(1071);
+ public Object testField1072 = new Integer(1072);
+ public Object testField1073 = new Integer(1073);
+ public Object testField1074 = new Integer(1074);
+ public Object testField1075 = new Integer(1075);
+ public Object testField1076 = new Integer(1076);
+ public Object testField1077 = new Integer(1077);
+ public Object testField1078 = new Integer(1078);
+ public Object testField1079 = new Integer(1079);
+ public Object testField1080 = new Integer(1080);
+ public Object testField1081 = new Integer(1081);
+ public Object testField1082 = new Integer(1082);
+ public Object testField1083 = new Integer(1083);
+ public Object testField1084 = new Integer(1084);
+ public Object testField1085 = new Integer(1085);
+ public Object testField1086 = new Integer(1086);
+ public Object testField1087 = new Integer(1087);
+ public Object testField1088 = new Integer(1088);
+ public Object testField1089 = new Integer(1089);
+ public Object testField1090 = new Integer(1090);
+ public Object testField1091 = new Integer(1091);
+ public Object testField1092 = new Integer(1092);
+ public Object testField1093 = new Integer(1093);
+ public Object testField1094 = new Integer(1094);
+ public Object testField1095 = new Integer(1095);
+ public Object testField1096 = new Integer(1096);
+ public Object testField1097 = new Integer(1097);
+ public Object testField1098 = new Integer(1098);
+ public Object testField1099 = new Integer(1099);
+ public Object testField1100 = new Integer(1100);
+ public Object testField1101 = new Integer(1101);
+ public Object testField1102 = new Integer(1102);
+ public Object testField1103 = new Integer(1103);
+ public Object testField1104 = new Integer(1104);
+ public Object testField1105 = new Integer(1105);
+ public Object testField1106 = new Integer(1106);
+ public Object testField1107 = new Integer(1107);
+ public Object testField1108 = new Integer(1108);
+ public Object testField1109 = new Integer(1109);
+ public Object testField1110 = new Integer(1110);
+ public Object testField1111 = new Integer(1111);
+ public Object testField1112 = new Integer(1112);
+ public Object testField1113 = new Integer(1113);
+ public Object testField1114 = new Integer(1114);
+ public Object testField1115 = new Integer(1115);
+ public Object testField1116 = new Integer(1116);
+ public Object testField1117 = new Integer(1117);
+ public Object testField1118 = new Integer(1118);
+ public Object testField1119 = new Integer(1119);
+ public Object testField1120 = new Integer(1120);
+ public Object testField1121 = new Integer(1121);
+ public Object testField1122 = new Integer(1122);
+ public Object testField1123 = new Integer(1123);
+ public Object testField1124 = new Integer(1124);
+ public Object testField1125 = new Integer(1125);
+ public Object testField1126 = new Integer(1126);
+ public Object testField1127 = new Integer(1127);
+ public Object testField1128 = new Integer(1128);
+ public Object testField1129 = new Integer(1129);
+ public Object testField1130 = new Integer(1130);
+ public Object testField1131 = new Integer(1131);
+ public Object testField1132 = new Integer(1132);
+ public Object testField1133 = new Integer(1133);
+ public Object testField1134 = new Integer(1134);
+ public Object testField1135 = new Integer(1135);
+ public Object testField1136 = new Integer(1136);
+ public Object testField1137 = new Integer(1137);
+ public Object testField1138 = new Integer(1138);
+ public Object testField1139 = new Integer(1139);
+ public Object testField1140 = new Integer(1140);
+ public Object testField1141 = new Integer(1141);
+ public Object testField1142 = new Integer(1142);
+ public Object testField1143 = new Integer(1143);
+ public Object testField1144 = new Integer(1144);
+ public Object testField1145 = new Integer(1145);
+ public Object testField1146 = new Integer(1146);
+ public Object testField1147 = new Integer(1147);
+ public Object testField1148 = new Integer(1148);
+ public Object testField1149 = new Integer(1149);
+ public Object testField1150 = new Integer(1150);
+ public Object testField1151 = new Integer(1151);
+ public Object testField1152 = new Integer(1152);
+ public Object testField1153 = new Integer(1153);
+ public Object testField1154 = new Integer(1154);
+ public Object testField1155 = new Integer(1155);
+ public Object testField1156 = new Integer(1156);
+ public Object testField1157 = new Integer(1157);
+ public Object testField1158 = new Integer(1158);
+ public Object testField1159 = new Integer(1159);
+ public Object testField1160 = new Integer(1160);
+ public Object testField1161 = new Integer(1161);
+ public Object testField1162 = new Integer(1162);
+ public Object testField1163 = new Integer(1163);
+ public Object testField1164 = new Integer(1164);
+ public Object testField1165 = new Integer(1165);
+ public Object testField1166 = new Integer(1166);
+ public Object testField1167 = new Integer(1167);
+ public Object testField1168 = new Integer(1168);
+ public Object testField1169 = new Integer(1169);
+ public Object testField1170 = new Integer(1170);
+ public Object testField1171 = new Integer(1171);
+ public Object testField1172 = new Integer(1172);
+ public Object testField1173 = new Integer(1173);
+ public Object testField1174 = new Integer(1174);
+ public Object testField1175 = new Integer(1175);
+ public Object testField1176 = new Integer(1176);
+ public Object testField1177 = new Integer(1177);
+ public Object testField1178 = new Integer(1178);
+ public Object testField1179 = new Integer(1179);
+ public Object testField1180 = new Integer(1180);
+ public Object testField1181 = new Integer(1181);
+ public Object testField1182 = new Integer(1182);
+ public Object testField1183 = new Integer(1183);
+ public Object testField1184 = new Integer(1184);
+ public Object testField1185 = new Integer(1185);
+ public Object testField1186 = new Integer(1186);
+ public Object testField1187 = new Integer(1187);
+ public Object testField1188 = new Integer(1188);
+ public Object testField1189 = new Integer(1189);
+ public Object testField1190 = new Integer(1190);
+ public Object testField1191 = new Integer(1191);
+ public Object testField1192 = new Integer(1192);
+ public Object testField1193 = new Integer(1193);
+ public Object testField1194 = new Integer(1194);
+ public Object testField1195 = new Integer(1195);
+ public Object testField1196 = new Integer(1196);
+ public Object testField1197 = new Integer(1197);
+ public Object testField1198 = new Integer(1198);
+ public Object testField1199 = new Integer(1199);
+ public Object testField1200 = new Integer(1200);
+ public Object testField1201 = new Integer(1201);
+ public Object testField1202 = new Integer(1202);
+ public Object testField1203 = new Integer(1203);
+ public Object testField1204 = new Integer(1204);
+ public Object testField1205 = new Integer(1205);
+ public Object testField1206 = new Integer(1206);
+ public Object testField1207 = new Integer(1207);
+ public Object testField1208 = new Integer(1208);
+ public Object testField1209 = new Integer(1209);
+ public Object testField1210 = new Integer(1210);
+ public Object testField1211 = new Integer(1211);
+ public Object testField1212 = new Integer(1212);
+ public Object testField1213 = new Integer(1213);
+ public Object testField1214 = new Integer(1214);
+ public Object testField1215 = new Integer(1215);
+ public Object testField1216 = new Integer(1216);
+ public Object testField1217 = new Integer(1217);
+ public Object testField1218 = new Integer(1218);
+ public Object testField1219 = new Integer(1219);
+ public Object testField1220 = new Integer(1220);
+ public Object testField1221 = new Integer(1221);
+ public Object testField1222 = new Integer(1222);
+ public Object testField1223 = new Integer(1223);
+ public Object testField1224 = new Integer(1224);
+ public Object testField1225 = new Integer(1225);
+ public Object testField1226 = new Integer(1226);
+ public Object testField1227 = new Integer(1227);
+ public Object testField1228 = new Integer(1228);
+ public Object testField1229 = new Integer(1229);
+ public Object testField1230 = new Integer(1230);
+ public Object testField1231 = new Integer(1231);
+ public Object testField1232 = new Integer(1232);
+ public Object testField1233 = new Integer(1233);
+ public Object testField1234 = new Integer(1234);
+ public Object testField1235 = new Integer(1235);
+ public Object testField1236 = new Integer(1236);
+ public Object testField1237 = new Integer(1237);
+ public Object testField1238 = new Integer(1238);
+ public Object testField1239 = new Integer(1239);
+ public Object testField1240 = new Integer(1240);
+ public Object testField1241 = new Integer(1241);
+ public Object testField1242 = new Integer(1242);
+ public Object testField1243 = new Integer(1243);
+ public Object testField1244 = new Integer(1244);
+ public Object testField1245 = new Integer(1245);
+ public Object testField1246 = new Integer(1246);
+ public Object testField1247 = new Integer(1247);
+ public Object testField1248 = new Integer(1248);
+ public Object testField1249 = new Integer(1249);
+ public Object testField1250 = new Integer(1250);
+ public Object testField1251 = new Integer(1251);
+ public Object testField1252 = new Integer(1252);
+ public Object testField1253 = new Integer(1253);
+ public Object testField1254 = new Integer(1254);
+ public Object testField1255 = new Integer(1255);
+ public Object testField1256 = new Integer(1256);
+ public Object testField1257 = new Integer(1257);
+ public Object testField1258 = new Integer(1258);
+ public Object testField1259 = new Integer(1259);
+ public Object testField1260 = new Integer(1260);
+ public Object testField1261 = new Integer(1261);
+ public Object testField1262 = new Integer(1262);
+ public Object testField1263 = new Integer(1263);
+ public Object testField1264 = new Integer(1264);
+ public Object testField1265 = new Integer(1265);
+ public Object testField1266 = new Integer(1266);
+ public Object testField1267 = new Integer(1267);
+ public Object testField1268 = new Integer(1268);
+ public Object testField1269 = new Integer(1269);
+ public Object testField1270 = new Integer(1270);
+ public Object testField1271 = new Integer(1271);
+ public Object testField1272 = new Integer(1272);
+ public Object testField1273 = new Integer(1273);
+ public Object testField1274 = new Integer(1274);
+ public Object testField1275 = new Integer(1275);
+ public Object testField1276 = new Integer(1276);
+ public Object testField1277 = new Integer(1277);
+ public Object testField1278 = new Integer(1278);
+ public Object testField1279 = new Integer(1279);
+ public Object testField1280 = new Integer(1280);
+ public Object testField1281 = new Integer(1281);
+ public Object testField1282 = new Integer(1282);
+ public Object testField1283 = new Integer(1283);
+ public Object testField1284 = new Integer(1284);
+ public Object testField1285 = new Integer(1285);
+ public Object testField1286 = new Integer(1286);
+ public Object testField1287 = new Integer(1287);
+ public Object testField1288 = new Integer(1288);
+ public Object testField1289 = new Integer(1289);
+ public Object testField1290 = new Integer(1290);
+ public Object testField1291 = new Integer(1291);
+ public Object testField1292 = new Integer(1292);
+ public Object testField1293 = new Integer(1293);
+ public Object testField1294 = new Integer(1294);
+ public Object testField1295 = new Integer(1295);
+ public Object testField1296 = new Integer(1296);
+ public Object testField1297 = new Integer(1297);
+ public Object testField1298 = new Integer(1298);
+ public Object testField1299 = new Integer(1299);
+ public Object testField1300 = new Integer(1300);
+ public Object testField1301 = new Integer(1301);
+ public Object testField1302 = new Integer(1302);
+ public Object testField1303 = new Integer(1303);
+ public Object testField1304 = new Integer(1304);
+ public Object testField1305 = new Integer(1305);
+ public Object testField1306 = new Integer(1306);
+ public Object testField1307 = new Integer(1307);
+ public Object testField1308 = new Integer(1308);
+ public Object testField1309 = new Integer(1309);
+ public Object testField1310 = new Integer(1310);
+ public Object testField1311 = new Integer(1311);
+ public Object testField1312 = new Integer(1312);
+ public Object testField1313 = new Integer(1313);
+ public Object testField1314 = new Integer(1314);
+ public Object testField1315 = new Integer(1315);
+ public Object testField1316 = new Integer(1316);
+ public Object testField1317 = new Integer(1317);
+ public Object testField1318 = new Integer(1318);
+ public Object testField1319 = new Integer(1319);
+ public Object testField1320 = new Integer(1320);
+ public Object testField1321 = new Integer(1321);
+ public Object testField1322 = new Integer(1322);
+ public Object testField1323 = new Integer(1323);
+ public Object testField1324 = new Integer(1324);
+ public Object testField1325 = new Integer(1325);
+ public Object testField1326 = new Integer(1326);
+ public Object testField1327 = new Integer(1327);
+ public Object testField1328 = new Integer(1328);
+ public Object testField1329 = new Integer(1329);
+ public Object testField1330 = new Integer(1330);
+ public Object testField1331 = new Integer(1331);
+ public Object testField1332 = new Integer(1332);
+ public Object testField1333 = new Integer(1333);
+ public Object testField1334 = new Integer(1334);
+ public Object testField1335 = new Integer(1335);
+ public Object testField1336 = new Integer(1336);
+ public Object testField1337 = new Integer(1337);
+ public Object testField1338 = new Integer(1338);
+ public Object testField1339 = new Integer(1339);
+ public Object testField1340 = new Integer(1340);
+ public Object testField1341 = new Integer(1341);
+ public Object testField1342 = new Integer(1342);
+ public Object testField1343 = new Integer(1343);
+ public Object testField1344 = new Integer(1344);
+ public Object testField1345 = new Integer(1345);
+ public Object testField1346 = new Integer(1346);
+ public Object testField1347 = new Integer(1347);
+ public Object testField1348 = new Integer(1348);
+ public Object testField1349 = new Integer(1349);
+ public Object testField1350 = new Integer(1350);
+ public Object testField1351 = new Integer(1351);
+ public Object testField1352 = new Integer(1352);
+ public Object testField1353 = new Integer(1353);
+ public Object testField1354 = new Integer(1354);
+ public Object testField1355 = new Integer(1355);
+ public Object testField1356 = new Integer(1356);
+ public Object testField1357 = new Integer(1357);
+ public Object testField1358 = new Integer(1358);
+ public Object testField1359 = new Integer(1359);
+ public Object testField1360 = new Integer(1360);
+ public Object testField1361 = new Integer(1361);
+ public Object testField1362 = new Integer(1362);
+ public Object testField1363 = new Integer(1363);
+ public Object testField1364 = new Integer(1364);
+ public Object testField1365 = new Integer(1365);
+ public Object testField1366 = new Integer(1366);
+ public Object testField1367 = new Integer(1367);
+ public Object testField1368 = new Integer(1368);
+ public Object testField1369 = new Integer(1369);
+ public Object testField1370 = new Integer(1370);
+ public Object testField1371 = new Integer(1371);
+ public Object testField1372 = new Integer(1372);
+ public Object testField1373 = new Integer(1373);
+ public Object testField1374 = new Integer(1374);
+ public Object testField1375 = new Integer(1375);
+ public Object testField1376 = new Integer(1376);
+ public Object testField1377 = new Integer(1377);
+ public Object testField1378 = new Integer(1378);
+ public Object testField1379 = new Integer(1379);
+ public Object testField1380 = new Integer(1380);
+ public Object testField1381 = new Integer(1381);
+ public Object testField1382 = new Integer(1382);
+ public Object testField1383 = new Integer(1383);
+ public Object testField1384 = new Integer(1384);
+ public Object testField1385 = new Integer(1385);
+ public Object testField1386 = new Integer(1386);
+ public Object testField1387 = new Integer(1387);
+ public Object testField1388 = new Integer(1388);
+ public Object testField1389 = new Integer(1389);
+ public Object testField1390 = new Integer(1390);
+ public Object testField1391 = new Integer(1391);
+ public Object testField1392 = new Integer(1392);
+ public Object testField1393 = new Integer(1393);
+ public Object testField1394 = new Integer(1394);
+ public Object testField1395 = new Integer(1395);
+ public Object testField1396 = new Integer(1396);
+ public Object testField1397 = new Integer(1397);
+ public Object testField1398 = new Integer(1398);
+ public Object testField1399 = new Integer(1399);
+ public Object testField1400 = new Integer(1400);
+ public Object testField1401 = new Integer(1401);
+ public Object testField1402 = new Integer(1402);
+ public Object testField1403 = new Integer(1403);
+ public Object testField1404 = new Integer(1404);
+ public Object testField1405 = new Integer(1405);
+ public Object testField1406 = new Integer(1406);
+ public Object testField1407 = new Integer(1407);
+ public Object testField1408 = new Integer(1408);
+ public Object testField1409 = new Integer(1409);
+ public Object testField1410 = new Integer(1410);
+ public Object testField1411 = new Integer(1411);
+ public Object testField1412 = new Integer(1412);
+ public Object testField1413 = new Integer(1413);
+ public Object testField1414 = new Integer(1414);
+ public Object testField1415 = new Integer(1415);
+ public Object testField1416 = new Integer(1416);
+ public Object testField1417 = new Integer(1417);
+ public Object testField1418 = new Integer(1418);
+ public Object testField1419 = new Integer(1419);
+ public Object testField1420 = new Integer(1420);
+ public Object testField1421 = new Integer(1421);
+ public Object testField1422 = new Integer(1422);
+ public Object testField1423 = new Integer(1423);
+ public Object testField1424 = new Integer(1424);
+ public Object testField1425 = new Integer(1425);
+ public Object testField1426 = new Integer(1426);
+ public Object testField1427 = new Integer(1427);
+ public Object testField1428 = new Integer(1428);
+ public Object testField1429 = new Integer(1429);
+ public Object testField1430 = new Integer(1430);
+ public Object testField1431 = new Integer(1431);
+ public Object testField1432 = new Integer(1432);
+ public Object testField1433 = new Integer(1433);
+ public Object testField1434 = new Integer(1434);
+ public Object testField1435 = new Integer(1435);
+ public Object testField1436 = new Integer(1436);
+ public Object testField1437 = new Integer(1437);
+ public Object testField1438 = new Integer(1438);
+ public Object testField1439 = new Integer(1439);
+ public Object testField1440 = new Integer(1440);
+ public Object testField1441 = new Integer(1441);
+ public Object testField1442 = new Integer(1442);
+ public Object testField1443 = new Integer(1443);
+ public Object testField1444 = new Integer(1444);
+ public Object testField1445 = new Integer(1445);
+ public Object testField1446 = new Integer(1446);
+ public Object testField1447 = new Integer(1447);
+ public Object testField1448 = new Integer(1448);
+ public Object testField1449 = new Integer(1449);
+ public Object testField1450 = new Integer(1450);
+ public Object testField1451 = new Integer(1451);
+ public Object testField1452 = new Integer(1452);
+ public Object testField1453 = new Integer(1453);
+ public Object testField1454 = new Integer(1454);
+ public Object testField1455 = new Integer(1455);
+ public Object testField1456 = new Integer(1456);
+ public Object testField1457 = new Integer(1457);
+ public Object testField1458 = new Integer(1458);
+ public Object testField1459 = new Integer(1459);
+ public Object testField1460 = new Integer(1460);
+ public Object testField1461 = new Integer(1461);
+ public Object testField1462 = new Integer(1462);
+ public Object testField1463 = new Integer(1463);
+ public Object testField1464 = new Integer(1464);
+ public Object testField1465 = new Integer(1465);
+ public Object testField1466 = new Integer(1466);
+ public Object testField1467 = new Integer(1467);
+ public Object testField1468 = new Integer(1468);
+ public Object testField1469 = new Integer(1469);
+ public Object testField1470 = new Integer(1470);
+ public Object testField1471 = new Integer(1471);
+ public Object testField1472 = new Integer(1472);
+ public Object testField1473 = new Integer(1473);
+ public Object testField1474 = new Integer(1474);
+ public Object testField1475 = new Integer(1475);
+ public Object testField1476 = new Integer(1476);
+ public Object testField1477 = new Integer(1477);
+ public Object testField1478 = new Integer(1478);
+ public Object testField1479 = new Integer(1479);
+ public Object testField1480 = new Integer(1480);
+ public Object testField1481 = new Integer(1481);
+ public Object testField1482 = new Integer(1482);
+ public Object testField1483 = new Integer(1483);
+ public Object testField1484 = new Integer(1484);
+ public Object testField1485 = new Integer(1485);
+ public Object testField1486 = new Integer(1486);
+ public Object testField1487 = new Integer(1487);
+ public Object testField1488 = new Integer(1488);
+ public Object testField1489 = new Integer(1489);
+ public Object testField1490 = new Integer(1490);
+ public Object testField1491 = new Integer(1491);
+ public Object testField1492 = new Integer(1492);
+ public Object testField1493 = new Integer(1493);
+ public Object testField1494 = new Integer(1494);
+ public Object testField1495 = new Integer(1495);
+ public Object testField1496 = new Integer(1496);
+ public Object testField1497 = new Integer(1497);
+ public Object testField1498 = new Integer(1498);
+ public Object testField1499 = new Integer(1499);
+ public Object testField1500 = new Integer(1500);
+ public Object testField1501 = new Integer(1501);
+ public Object testField1502 = new Integer(1502);
+ public Object testField1503 = new Integer(1503);
+ public Object testField1504 = new Integer(1504);
+ public Object testField1505 = new Integer(1505);
+ public Object testField1506 = new Integer(1506);
+ public Object testField1507 = new Integer(1507);
+ public Object testField1508 = new Integer(1508);
+ public Object testField1509 = new Integer(1509);
+ public Object testField1510 = new Integer(1510);
+ public Object testField1511 = new Integer(1511);
+ public Object testField1512 = new Integer(1512);
+ public Object testField1513 = new Integer(1513);
+ public Object testField1514 = new Integer(1514);
+ public Object testField1515 = new Integer(1515);
+ public Object testField1516 = new Integer(1516);
+ public Object testField1517 = new Integer(1517);
+ public Object testField1518 = new Integer(1518);
+ public Object testField1519 = new Integer(1519);
+ public Object testField1520 = new Integer(1520);
+ public Object testField1521 = new Integer(1521);
+ public Object testField1522 = new Integer(1522);
+ public Object testField1523 = new Integer(1523);
+ public Object testField1524 = new Integer(1524);
+ public Object testField1525 = new Integer(1525);
+ public Object testField1526 = new Integer(1526);
+ public Object testField1527 = new Integer(1527);
+ public Object testField1528 = new Integer(1528);
+ public Object testField1529 = new Integer(1529);
+ public Object testField1530 = new Integer(1530);
+ public Object testField1531 = new Integer(1531);
+ public Object testField1532 = new Integer(1532);
+ public Object testField1533 = new Integer(1533);
+ public Object testField1534 = new Integer(1534);
+ public Object testField1535 = new Integer(1535);
+ public Object testField1536 = new Integer(1536);
+ public Object testField1537 = new Integer(1537);
+ public Object testField1538 = new Integer(1538);
+ public Object testField1539 = new Integer(1539);
+ public Object testField1540 = new Integer(1540);
+ public Object testField1541 = new Integer(1541);
+ public Object testField1542 = new Integer(1542);
+ public Object testField1543 = new Integer(1543);
+ public Object testField1544 = new Integer(1544);
+ public Object testField1545 = new Integer(1545);
+ public Object testField1546 = new Integer(1546);
+ public Object testField1547 = new Integer(1547);
+ public Object testField1548 = new Integer(1548);
+ public Object testField1549 = new Integer(1549);
+ public Object testField1550 = new Integer(1550);
+ public Object testField1551 = new Integer(1551);
+ public Object testField1552 = new Integer(1552);
+ public Object testField1553 = new Integer(1553);
+ public Object testField1554 = new Integer(1554);
+ public Object testField1555 = new Integer(1555);
+ public Object testField1556 = new Integer(1556);
+ public Object testField1557 = new Integer(1557);
+ public Object testField1558 = new Integer(1558);
+ public Object testField1559 = new Integer(1559);
+ public Object testField1560 = new Integer(1560);
+ public Object testField1561 = new Integer(1561);
+ public Object testField1562 = new Integer(1562);
+ public Object testField1563 = new Integer(1563);
+ public Object testField1564 = new Integer(1564);
+ public Object testField1565 = new Integer(1565);
+ public Object testField1566 = new Integer(1566);
+ public Object testField1567 = new Integer(1567);
+ public Object testField1568 = new Integer(1568);
+ public Object testField1569 = new Integer(1569);
+ public Object testField1570 = new Integer(1570);
+ public Object testField1571 = new Integer(1571);
+ public Object testField1572 = new Integer(1572);
+ public Object testField1573 = new Integer(1573);
+ public Object testField1574 = new Integer(1574);
+ public Object testField1575 = new Integer(1575);
+ public Object testField1576 = new Integer(1576);
+ public Object testField1577 = new Integer(1577);
+ public Object testField1578 = new Integer(1578);
+ public Object testField1579 = new Integer(1579);
+ public Object testField1580 = new Integer(1580);
+ public Object testField1581 = new Integer(1581);
+ public Object testField1582 = new Integer(1582);
+ public Object testField1583 = new Integer(1583);
+ public Object testField1584 = new Integer(1584);
+ public Object testField1585 = new Integer(1585);
+ public Object testField1586 = new Integer(1586);
+ public Object testField1587 = new Integer(1587);
+ public Object testField1588 = new Integer(1588);
+ public Object testField1589 = new Integer(1589);
+ public Object testField1590 = new Integer(1590);
+ public Object testField1591 = new Integer(1591);
+ public Object testField1592 = new Integer(1592);
+ public Object testField1593 = new Integer(1593);
+ public Object testField1594 = new Integer(1594);
+ public Object testField1595 = new Integer(1595);
+ public Object testField1596 = new Integer(1596);
+ public Object testField1597 = new Integer(1597);
+ public Object testField1598 = new Integer(1598);
+ public Object testField1599 = new Integer(1599);
+ public Object testField1600 = new Integer(1600);
+ public Object testField1601 = new Integer(1601);
+ public Object testField1602 = new Integer(1602);
+ public Object testField1603 = new Integer(1603);
+ public Object testField1604 = new Integer(1604);
+ public Object testField1605 = new Integer(1605);
+ public Object testField1606 = new Integer(1606);
+ public Object testField1607 = new Integer(1607);
+ public Object testField1608 = new Integer(1608);
+ public Object testField1609 = new Integer(1609);
+ public Object testField1610 = new Integer(1610);
+ public Object testField1611 = new Integer(1611);
+ public Object testField1612 = new Integer(1612);
+ public Object testField1613 = new Integer(1613);
+ public Object testField1614 = new Integer(1614);
+ public Object testField1615 = new Integer(1615);
+ public Object testField1616 = new Integer(1616);
+ public Object testField1617 = new Integer(1617);
+ public Object testField1618 = new Integer(1618);
+ public Object testField1619 = new Integer(1619);
+ public Object testField1620 = new Integer(1620);
+ public Object testField1621 = new Integer(1621);
+ public Object testField1622 = new Integer(1622);
+ public Object testField1623 = new Integer(1623);
+ public Object testField1624 = new Integer(1624);
+ public Object testField1625 = new Integer(1625);
+ public Object testField1626 = new Integer(1626);
+ public Object testField1627 = new Integer(1627);
+ public Object testField1628 = new Integer(1628);
+ public Object testField1629 = new Integer(1629);
+ public Object testField1630 = new Integer(1630);
+ public Object testField1631 = new Integer(1631);
+ public Object testField1632 = new Integer(1632);
+ public Object testField1633 = new Integer(1633);
+ public Object testField1634 = new Integer(1634);
+ public Object testField1635 = new Integer(1635);
+ public Object testField1636 = new Integer(1636);
+ public Object testField1637 = new Integer(1637);
+ public Object testField1638 = new Integer(1638);
+ public Object testField1639 = new Integer(1639);
+ public Object testField1640 = new Integer(1640);
+ public Object testField1641 = new Integer(1641);
+ public Object testField1642 = new Integer(1642);
+ public Object testField1643 = new Integer(1643);
+ public Object testField1644 = new Integer(1644);
+ public Object testField1645 = new Integer(1645);
+ public Object testField1646 = new Integer(1646);
+ public Object testField1647 = new Integer(1647);
+ public Object testField1648 = new Integer(1648);
+ public Object testField1649 = new Integer(1649);
+ public Object testField1650 = new Integer(1650);
+ public Object testField1651 = new Integer(1651);
+ public Object testField1652 = new Integer(1652);
+ public Object testField1653 = new Integer(1653);
+ public Object testField1654 = new Integer(1654);
+ public Object testField1655 = new Integer(1655);
+ public Object testField1656 = new Integer(1656);
+ public Object testField1657 = new Integer(1657);
+ public Object testField1658 = new Integer(1658);
+ public Object testField1659 = new Integer(1659);
+ public Object testField1660 = new Integer(1660);
+ public Object testField1661 = new Integer(1661);
+ public Object testField1662 = new Integer(1662);
+ public Object testField1663 = new Integer(1663);
+ public Object testField1664 = new Integer(1664);
+ public Object testField1665 = new Integer(1665);
+ public Object testField1666 = new Integer(1666);
+ public Object testField1667 = new Integer(1667);
+ public Object testField1668 = new Integer(1668);
+ public Object testField1669 = new Integer(1669);
+ public Object testField1670 = new Integer(1670);
+ public Object testField1671 = new Integer(1671);
+ public Object testField1672 = new Integer(1672);
+ public Object testField1673 = new Integer(1673);
+ public Object testField1674 = new Integer(1674);
+ public Object testField1675 = new Integer(1675);
+ public Object testField1676 = new Integer(1676);
+ public Object testField1677 = new Integer(1677);
+ public Object testField1678 = new Integer(1678);
+ public Object testField1679 = new Integer(1679);
+ public Object testField1680 = new Integer(1680);
+ public Object testField1681 = new Integer(1681);
+ public Object testField1682 = new Integer(1682);
+ public Object testField1683 = new Integer(1683);
+ public Object testField1684 = new Integer(1684);
+ public Object testField1685 = new Integer(1685);
+ public Object testField1686 = new Integer(1686);
+ public Object testField1687 = new Integer(1687);
+ public Object testField1688 = new Integer(1688);
+ public Object testField1689 = new Integer(1689);
+ public Object testField1690 = new Integer(1690);
+ public Object testField1691 = new Integer(1691);
+ public Object testField1692 = new Integer(1692);
+ public Object testField1693 = new Integer(1693);
+ public Object testField1694 = new Integer(1694);
+ public Object testField1695 = new Integer(1695);
+ public Object testField1696 = new Integer(1696);
+ public Object testField1697 = new Integer(1697);
+ public Object testField1698 = new Integer(1698);
+ public Object testField1699 = new Integer(1699);
+ public Object testField1700 = new Integer(1700);
+ public Object testField1701 = new Integer(1701);
+ public Object testField1702 = new Integer(1702);
+ public Object testField1703 = new Integer(1703);
+ public Object testField1704 = new Integer(1704);
+ public Object testField1705 = new Integer(1705);
+ public Object testField1706 = new Integer(1706);
+ public Object testField1707 = new Integer(1707);
+ public Object testField1708 = new Integer(1708);
+ public Object testField1709 = new Integer(1709);
+ public Object testField1710 = new Integer(1710);
+ public Object testField1711 = new Integer(1711);
+ public Object testField1712 = new Integer(1712);
+ public Object testField1713 = new Integer(1713);
+ public Object testField1714 = new Integer(1714);
+ public Object testField1715 = new Integer(1715);
+ public Object testField1716 = new Integer(1716);
+ public Object testField1717 = new Integer(1717);
+ public Object testField1718 = new Integer(1718);
+ public Object testField1719 = new Integer(1719);
+ public Object testField1720 = new Integer(1720);
+ public Object testField1721 = new Integer(1721);
+ public Object testField1722 = new Integer(1722);
+ public Object testField1723 = new Integer(1723);
+ public Object testField1724 = new Integer(1724);
+ public Object testField1725 = new Integer(1725);
+ public Object testField1726 = new Integer(1726);
+ public Object testField1727 = new Integer(1727);
+ public Object testField1728 = new Integer(1728);
+ public Object testField1729 = new Integer(1729);
+ public Object testField1730 = new Integer(1730);
+ public Object testField1731 = new Integer(1731);
+ public Object testField1732 = new Integer(1732);
+ public Object testField1733 = new Integer(1733);
+ public Object testField1734 = new Integer(1734);
+ public Object testField1735 = new Integer(1735);
+ public Object testField1736 = new Integer(1736);
+ public Object testField1737 = new Integer(1737);
+ public Object testField1738 = new Integer(1738);
+ public Object testField1739 = new Integer(1739);
+ public Object testField1740 = new Integer(1740);
+ public Object testField1741 = new Integer(1741);
+ public Object testField1742 = new Integer(1742);
+ public Object testField1743 = new Integer(1743);
+ public Object testField1744 = new Integer(1744);
+ public Object testField1745 = new Integer(1745);
+ public Object testField1746 = new Integer(1746);
+ public Object testField1747 = new Integer(1747);
+ public Object testField1748 = new Integer(1748);
+ public Object testField1749 = new Integer(1749);
+ public Object testField1750 = new Integer(1750);
+ public Object testField1751 = new Integer(1751);
+ public Object testField1752 = new Integer(1752);
+ public Object testField1753 = new Integer(1753);
+ public Object testField1754 = new Integer(1754);
+ public Object testField1755 = new Integer(1755);
+ public Object testField1756 = new Integer(1756);
+ public Object testField1757 = new Integer(1757);
+ public Object testField1758 = new Integer(1758);
+ public Object testField1759 = new Integer(1759);
+ public Object testField1760 = new Integer(1760);
+ public Object testField1761 = new Integer(1761);
+ public Object testField1762 = new Integer(1762);
+ public Object testField1763 = new Integer(1763);
+ public Object testField1764 = new Integer(1764);
+ public Object testField1765 = new Integer(1765);
+ public Object testField1766 = new Integer(1766);
+ public Object testField1767 = new Integer(1767);
+ public Object testField1768 = new Integer(1768);
+ public Object testField1769 = new Integer(1769);
+ public Object testField1770 = new Integer(1770);
+ public Object testField1771 = new Integer(1771);
+ public Object testField1772 = new Integer(1772);
+ public Object testField1773 = new Integer(1773);
+ public Object testField1774 = new Integer(1774);
+ public Object testField1775 = new Integer(1775);
+ public Object testField1776 = new Integer(1776);
+ public Object testField1777 = new Integer(1777);
+ public Object testField1778 = new Integer(1778);
+ public Object testField1779 = new Integer(1779);
+ public Object testField1780 = new Integer(1780);
+ public Object testField1781 = new Integer(1781);
+ public Object testField1782 = new Integer(1782);
+ public Object testField1783 = new Integer(1783);
+ public Object testField1784 = new Integer(1784);
+ public Object testField1785 = new Integer(1785);
+ public Object testField1786 = new Integer(1786);
+ public Object testField1787 = new Integer(1787);
+ public Object testField1788 = new Integer(1788);
+ public Object testField1789 = new Integer(1789);
+ public Object testField1790 = new Integer(1790);
+ public Object testField1791 = new Integer(1791);
+ public Object testField1792 = new Integer(1792);
+ public Object testField1793 = new Integer(1793);
+ public Object testField1794 = new Integer(1794);
+ public Object testField1795 = new Integer(1795);
+ public Object testField1796 = new Integer(1796);
+ public Object testField1797 = new Integer(1797);
+ public Object testField1798 = new Integer(1798);
+ public Object testField1799 = new Integer(1799);
+ public Object testField1800 = new Integer(1800);
+ public Object testField1801 = new Integer(1801);
+ public Object testField1802 = new Integer(1802);
+ public Object testField1803 = new Integer(1803);
+ public Object testField1804 = new Integer(1804);
+ public Object testField1805 = new Integer(1805);
+ public Object testField1806 = new Integer(1806);
+ public Object testField1807 = new Integer(1807);
+ public Object testField1808 = new Integer(1808);
+ public Object testField1809 = new Integer(1809);
+ public Object testField1810 = new Integer(1810);
+ public Object testField1811 = new Integer(1811);
+ public Object testField1812 = new Integer(1812);
+ public Object testField1813 = new Integer(1813);
+ public Object testField1814 = new Integer(1814);
+ public Object testField1815 = new Integer(1815);
+ public Object testField1816 = new Integer(1816);
+ public Object testField1817 = new Integer(1817);
+ public Object testField1818 = new Integer(1818);
+ public Object testField1819 = new Integer(1819);
+ public Object testField1820 = new Integer(1820);
+ public Object testField1821 = new Integer(1821);
+ public Object testField1822 = new Integer(1822);
+ public Object testField1823 = new Integer(1823);
+ public Object testField1824 = new Integer(1824);
+ public Object testField1825 = new Integer(1825);
+ public Object testField1826 = new Integer(1826);
+ public Object testField1827 = new Integer(1827);
+ public Object testField1828 = new Integer(1828);
+ public Object testField1829 = new Integer(1829);
+ public Object testField1830 = new Integer(1830);
+ public Object testField1831 = new Integer(1831);
+ public Object testField1832 = new Integer(1832);
+ public Object testField1833 = new Integer(1833);
+ public Object testField1834 = new Integer(1834);
+ public Object testField1835 = new Integer(1835);
+ public Object testField1836 = new Integer(1836);
+ public Object testField1837 = new Integer(1837);
+ public Object testField1838 = new Integer(1838);
+ public Object testField1839 = new Integer(1839);
+ public Object testField1840 = new Integer(1840);
+ public Object testField1841 = new Integer(1841);
+ public Object testField1842 = new Integer(1842);
+ public Object testField1843 = new Integer(1843);
+ public Object testField1844 = new Integer(1844);
+ public Object testField1845 = new Integer(1845);
+ public Object testField1846 = new Integer(1846);
+ public Object testField1847 = new Integer(1847);
+ public Object testField1848 = new Integer(1848);
+ public Object testField1849 = new Integer(1849);
+ public Object testField1850 = new Integer(1850);
+ public Object testField1851 = new Integer(1851);
+ public Object testField1852 = new Integer(1852);
+ public Object testField1853 = new Integer(1853);
+ public Object testField1854 = new Integer(1854);
+ public Object testField1855 = new Integer(1855);
+ public Object testField1856 = new Integer(1856);
+ public Object testField1857 = new Integer(1857);
+ public Object testField1858 = new Integer(1858);
+ public Object testField1859 = new Integer(1859);
+ public Object testField1860 = new Integer(1860);
+ public Object testField1861 = new Integer(1861);
+ public Object testField1862 = new Integer(1862);
+ public Object testField1863 = new Integer(1863);
+ public Object testField1864 = new Integer(1864);
+ public Object testField1865 = new Integer(1865);
+ public Object testField1866 = new Integer(1866);
+ public Object testField1867 = new Integer(1867);
+ public Object testField1868 = new Integer(1868);
+ public Object testField1869 = new Integer(1869);
+ public Object testField1870 = new Integer(1870);
+ public Object testField1871 = new Integer(1871);
+ public Object testField1872 = new Integer(1872);
+ public Object testField1873 = new Integer(1873);
+ public Object testField1874 = new Integer(1874);
+ public Object testField1875 = new Integer(1875);
+ public Object testField1876 = new Integer(1876);
+ public Object testField1877 = new Integer(1877);
+ public Object testField1878 = new Integer(1878);
+ public Object testField1879 = new Integer(1879);
+ public Object testField1880 = new Integer(1880);
+ public Object testField1881 = new Integer(1881);
+ public Object testField1882 = new Integer(1882);
+ public Object testField1883 = new Integer(1883);
+ public Object testField1884 = new Integer(1884);
+ public Object testField1885 = new Integer(1885);
+ public Object testField1886 = new Integer(1886);
+ public Object testField1887 = new Integer(1887);
+ public Object testField1888 = new Integer(1888);
+ public Object testField1889 = new Integer(1889);
+ public Object testField1890 = new Integer(1890);
+ public Object testField1891 = new Integer(1891);
+ public Object testField1892 = new Integer(1892);
+ public Object testField1893 = new Integer(1893);
+ public Object testField1894 = new Integer(1894);
+ public Object testField1895 = new Integer(1895);
+ public Object testField1896 = new Integer(1896);
+ public Object testField1897 = new Integer(1897);
+ public Object testField1898 = new Integer(1898);
+ public Object testField1899 = new Integer(1899);
+ public Object testField1900 = new Integer(1900);
+ public Object testField1901 = new Integer(1901);
+ public Object testField1902 = new Integer(1902);
+ public Object testField1903 = new Integer(1903);
+ public Object testField1904 = new Integer(1904);
+ public Object testField1905 = new Integer(1905);
+ public Object testField1906 = new Integer(1906);
+ public Object testField1907 = new Integer(1907);
+ public Object testField1908 = new Integer(1908);
+ public Object testField1909 = new Integer(1909);
+ public Object testField1910 = new Integer(1910);
+ public Object testField1911 = new Integer(1911);
+ public Object testField1912 = new Integer(1912);
+ public Object testField1913 = new Integer(1913);
+ public Object testField1914 = new Integer(1914);
+ public Object testField1915 = new Integer(1915);
+ public Object testField1916 = new Integer(1916);
+ public Object testField1917 = new Integer(1917);
+ public Object testField1918 = new Integer(1918);
+ public Object testField1919 = new Integer(1919);
+ public Object testField1920 = new Integer(1920);
+ public Object testField1921 = new Integer(1921);
+ public Object testField1922 = new Integer(1922);
+ public Object testField1923 = new Integer(1923);
+ public Object testField1924 = new Integer(1924);
+ public Object testField1925 = new Integer(1925);
+ public Object testField1926 = new Integer(1926);
+ public Object testField1927 = new Integer(1927);
+ public Object testField1928 = new Integer(1928);
+ public Object testField1929 = new Integer(1929);
+ public Object testField1930 = new Integer(1930);
+ public Object testField1931 = new Integer(1931);
+ public Object testField1932 = new Integer(1932);
+ public Object testField1933 = new Integer(1933);
+ public Object testField1934 = new Integer(1934);
+ public Object testField1935 = new Integer(1935);
+ public Object testField1936 = new Integer(1936);
+ public Object testField1937 = new Integer(1937);
+ public Object testField1938 = new Integer(1938);
+ public Object testField1939 = new Integer(1939);
+ public Object testField1940 = new Integer(1940);
+ public Object testField1941 = new Integer(1941);
+ public Object testField1942 = new Integer(1942);
+ public Object testField1943 = new Integer(1943);
+ public Object testField1944 = new Integer(1944);
+ public Object testField1945 = new Integer(1945);
+ public Object testField1946 = new Integer(1946);
+ public Object testField1947 = new Integer(1947);
+ public Object testField1948 = new Integer(1948);
+ public Object testField1949 = new Integer(1949);
+ public Object testField1950 = new Integer(1950);
+ public Object testField1951 = new Integer(1951);
+ public Object testField1952 = new Integer(1952);
+ public Object testField1953 = new Integer(1953);
+ public Object testField1954 = new Integer(1954);
+ public Object testField1955 = new Integer(1955);
+ public Object testField1956 = new Integer(1956);
+ public Object testField1957 = new Integer(1957);
+ public Object testField1958 = new Integer(1958);
+ public Object testField1959 = new Integer(1959);
+ public Object testField1960 = new Integer(1960);
+ public Object testField1961 = new Integer(1961);
+ public Object testField1962 = new Integer(1962);
+ public Object testField1963 = new Integer(1963);
+ public Object testField1964 = new Integer(1964);
+ public Object testField1965 = new Integer(1965);
+ public Object testField1966 = new Integer(1966);
+ public Object testField1967 = new Integer(1967);
+ public Object testField1968 = new Integer(1968);
+ public Object testField1969 = new Integer(1969);
+ public Object testField1970 = new Integer(1970);
+ public Object testField1971 = new Integer(1971);
+ public Object testField1972 = new Integer(1972);
+ public Object testField1973 = new Integer(1973);
+ public Object testField1974 = new Integer(1974);
+ public Object testField1975 = new Integer(1975);
+ public Object testField1976 = new Integer(1976);
+ public Object testField1977 = new Integer(1977);
+ public Object testField1978 = new Integer(1978);
+ public Object testField1979 = new Integer(1979);
+ public Object testField1980 = new Integer(1980);
+ public Object testField1981 = new Integer(1981);
+ public Object testField1982 = new Integer(1982);
+ public Object testField1983 = new Integer(1983);
+ public Object testField1984 = new Integer(1984);
+ public Object testField1985 = new Integer(1985);
+ public Object testField1986 = new Integer(1986);
+ public Object testField1987 = new Integer(1987);
+ public Object testField1988 = new Integer(1988);
+ public Object testField1989 = new Integer(1989);
+ public Object testField1990 = new Integer(1990);
+ public Object testField1991 = new Integer(1991);
+ public Object testField1992 = new Integer(1992);
+ public Object testField1993 = new Integer(1993);
+ public Object testField1994 = new Integer(1994);
+ public Object testField1995 = new Integer(1995);
+ public Object testField1996 = new Integer(1996);
+ public Object testField1997 = new Integer(1997);
+ public Object testField1998 = new Integer(1998);
+ public Object testField1999 = new Integer(1999);
+}
diff --git a/test/160-read-barrier-stress/src/ManyFieldsBase2.java b/test/160-read-barrier-stress/src/ManyFieldsBase2.java
new file mode 100644
index 0000000..54bbe99
--- /dev/null
+++ b/test/160-read-barrier-stress/src/ManyFieldsBase2.java
@@ -0,0 +1,1018 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+class ManyFieldsBase2 extends ManyFieldsBase1 {
+ public Object testField2000 = new Integer(2000);
+ public Object testField2001 = new Integer(2001);
+ public Object testField2002 = new Integer(2002);
+ public Object testField2003 = new Integer(2003);
+ public Object testField2004 = new Integer(2004);
+ public Object testField2005 = new Integer(2005);
+ public Object testField2006 = new Integer(2006);
+ public Object testField2007 = new Integer(2007);
+ public Object testField2008 = new Integer(2008);
+ public Object testField2009 = new Integer(2009);
+ public Object testField2010 = new Integer(2010);
+ public Object testField2011 = new Integer(2011);
+ public Object testField2012 = new Integer(2012);
+ public Object testField2013 = new Integer(2013);
+ public Object testField2014 = new Integer(2014);
+ public Object testField2015 = new Integer(2015);
+ public Object testField2016 = new Integer(2016);
+ public Object testField2017 = new Integer(2017);
+ public Object testField2018 = new Integer(2018);
+ public Object testField2019 = new Integer(2019);
+ public Object testField2020 = new Integer(2020);
+ public Object testField2021 = new Integer(2021);
+ public Object testField2022 = new Integer(2022);
+ public Object testField2023 = new Integer(2023);
+ public Object testField2024 = new Integer(2024);
+ public Object testField2025 = new Integer(2025);
+ public Object testField2026 = new Integer(2026);
+ public Object testField2027 = new Integer(2027);
+ public Object testField2028 = new Integer(2028);
+ public Object testField2029 = new Integer(2029);
+ public Object testField2030 = new Integer(2030);
+ public Object testField2031 = new Integer(2031);
+ public Object testField2032 = new Integer(2032);
+ public Object testField2033 = new Integer(2033);
+ public Object testField2034 = new Integer(2034);
+ public Object testField2035 = new Integer(2035);
+ public Object testField2036 = new Integer(2036);
+ public Object testField2037 = new Integer(2037);
+ public Object testField2038 = new Integer(2038);
+ public Object testField2039 = new Integer(2039);
+ public Object testField2040 = new Integer(2040);
+ public Object testField2041 = new Integer(2041);
+ public Object testField2042 = new Integer(2042);
+ public Object testField2043 = new Integer(2043);
+ public Object testField2044 = new Integer(2044);
+ public Object testField2045 = new Integer(2045);
+ public Object testField2046 = new Integer(2046);
+ public Object testField2047 = new Integer(2047);
+ public Object testField2048 = new Integer(2048);
+ public Object testField2049 = new Integer(2049);
+ public Object testField2050 = new Integer(2050);
+ public Object testField2051 = new Integer(2051);
+ public Object testField2052 = new Integer(2052);
+ public Object testField2053 = new Integer(2053);
+ public Object testField2054 = new Integer(2054);
+ public Object testField2055 = new Integer(2055);
+ public Object testField2056 = new Integer(2056);
+ public Object testField2057 = new Integer(2057);
+ public Object testField2058 = new Integer(2058);
+ public Object testField2059 = new Integer(2059);
+ public Object testField2060 = new Integer(2060);
+ public Object testField2061 = new Integer(2061);
+ public Object testField2062 = new Integer(2062);
+ public Object testField2063 = new Integer(2063);
+ public Object testField2064 = new Integer(2064);
+ public Object testField2065 = new Integer(2065);
+ public Object testField2066 = new Integer(2066);
+ public Object testField2067 = new Integer(2067);
+ public Object testField2068 = new Integer(2068);
+ public Object testField2069 = new Integer(2069);
+ public Object testField2070 = new Integer(2070);
+ public Object testField2071 = new Integer(2071);
+ public Object testField2072 = new Integer(2072);
+ public Object testField2073 = new Integer(2073);
+ public Object testField2074 = new Integer(2074);
+ public Object testField2075 = new Integer(2075);
+ public Object testField2076 = new Integer(2076);
+ public Object testField2077 = new Integer(2077);
+ public Object testField2078 = new Integer(2078);
+ public Object testField2079 = new Integer(2079);
+ public Object testField2080 = new Integer(2080);
+ public Object testField2081 = new Integer(2081);
+ public Object testField2082 = new Integer(2082);
+ public Object testField2083 = new Integer(2083);
+ public Object testField2084 = new Integer(2084);
+ public Object testField2085 = new Integer(2085);
+ public Object testField2086 = new Integer(2086);
+ public Object testField2087 = new Integer(2087);
+ public Object testField2088 = new Integer(2088);
+ public Object testField2089 = new Integer(2089);
+ public Object testField2090 = new Integer(2090);
+ public Object testField2091 = new Integer(2091);
+ public Object testField2092 = new Integer(2092);
+ public Object testField2093 = new Integer(2093);
+ public Object testField2094 = new Integer(2094);
+ public Object testField2095 = new Integer(2095);
+ public Object testField2096 = new Integer(2096);
+ public Object testField2097 = new Integer(2097);
+ public Object testField2098 = new Integer(2098);
+ public Object testField2099 = new Integer(2099);
+ public Object testField2100 = new Integer(2100);
+ public Object testField2101 = new Integer(2101);
+ public Object testField2102 = new Integer(2102);
+ public Object testField2103 = new Integer(2103);
+ public Object testField2104 = new Integer(2104);
+ public Object testField2105 = new Integer(2105);
+ public Object testField2106 = new Integer(2106);
+ public Object testField2107 = new Integer(2107);
+ public Object testField2108 = new Integer(2108);
+ public Object testField2109 = new Integer(2109);
+ public Object testField2110 = new Integer(2110);
+ public Object testField2111 = new Integer(2111);
+ public Object testField2112 = new Integer(2112);
+ public Object testField2113 = new Integer(2113);
+ public Object testField2114 = new Integer(2114);
+ public Object testField2115 = new Integer(2115);
+ public Object testField2116 = new Integer(2116);
+ public Object testField2117 = new Integer(2117);
+ public Object testField2118 = new Integer(2118);
+ public Object testField2119 = new Integer(2119);
+ public Object testField2120 = new Integer(2120);
+ public Object testField2121 = new Integer(2121);
+ public Object testField2122 = new Integer(2122);
+ public Object testField2123 = new Integer(2123);
+ public Object testField2124 = new Integer(2124);
+ public Object testField2125 = new Integer(2125);
+ public Object testField2126 = new Integer(2126);
+ public Object testField2127 = new Integer(2127);
+ public Object testField2128 = new Integer(2128);
+ public Object testField2129 = new Integer(2129);
+ public Object testField2130 = new Integer(2130);
+ public Object testField2131 = new Integer(2131);
+ public Object testField2132 = new Integer(2132);
+ public Object testField2133 = new Integer(2133);
+ public Object testField2134 = new Integer(2134);
+ public Object testField2135 = new Integer(2135);
+ public Object testField2136 = new Integer(2136);
+ public Object testField2137 = new Integer(2137);
+ public Object testField2138 = new Integer(2138);
+ public Object testField2139 = new Integer(2139);
+ public Object testField2140 = new Integer(2140);
+ public Object testField2141 = new Integer(2141);
+ public Object testField2142 = new Integer(2142);
+ public Object testField2143 = new Integer(2143);
+ public Object testField2144 = new Integer(2144);
+ public Object testField2145 = new Integer(2145);
+ public Object testField2146 = new Integer(2146);
+ public Object testField2147 = new Integer(2147);
+ public Object testField2148 = new Integer(2148);
+ public Object testField2149 = new Integer(2149);
+ public Object testField2150 = new Integer(2150);
+ public Object testField2151 = new Integer(2151);
+ public Object testField2152 = new Integer(2152);
+ public Object testField2153 = new Integer(2153);
+ public Object testField2154 = new Integer(2154);
+ public Object testField2155 = new Integer(2155);
+ public Object testField2156 = new Integer(2156);
+ public Object testField2157 = new Integer(2157);
+ public Object testField2158 = new Integer(2158);
+ public Object testField2159 = new Integer(2159);
+ public Object testField2160 = new Integer(2160);
+ public Object testField2161 = new Integer(2161);
+ public Object testField2162 = new Integer(2162);
+ public Object testField2163 = new Integer(2163);
+ public Object testField2164 = new Integer(2164);
+ public Object testField2165 = new Integer(2165);
+ public Object testField2166 = new Integer(2166);
+ public Object testField2167 = new Integer(2167);
+ public Object testField2168 = new Integer(2168);
+ public Object testField2169 = new Integer(2169);
+ public Object testField2170 = new Integer(2170);
+ public Object testField2171 = new Integer(2171);
+ public Object testField2172 = new Integer(2172);
+ public Object testField2173 = new Integer(2173);
+ public Object testField2174 = new Integer(2174);
+ public Object testField2175 = new Integer(2175);
+ public Object testField2176 = new Integer(2176);
+ public Object testField2177 = new Integer(2177);
+ public Object testField2178 = new Integer(2178);
+ public Object testField2179 = new Integer(2179);
+ public Object testField2180 = new Integer(2180);
+ public Object testField2181 = new Integer(2181);
+ public Object testField2182 = new Integer(2182);
+ public Object testField2183 = new Integer(2183);
+ public Object testField2184 = new Integer(2184);
+ public Object testField2185 = new Integer(2185);
+ public Object testField2186 = new Integer(2186);
+ public Object testField2187 = new Integer(2187);
+ public Object testField2188 = new Integer(2188);
+ public Object testField2189 = new Integer(2189);
+ public Object testField2190 = new Integer(2190);
+ public Object testField2191 = new Integer(2191);
+ public Object testField2192 = new Integer(2192);
+ public Object testField2193 = new Integer(2193);
+ public Object testField2194 = new Integer(2194);
+ public Object testField2195 = new Integer(2195);
+ public Object testField2196 = new Integer(2196);
+ public Object testField2197 = new Integer(2197);
+ public Object testField2198 = new Integer(2198);
+ public Object testField2199 = new Integer(2199);
+ public Object testField2200 = new Integer(2200);
+ public Object testField2201 = new Integer(2201);
+ public Object testField2202 = new Integer(2202);
+ public Object testField2203 = new Integer(2203);
+ public Object testField2204 = new Integer(2204);
+ public Object testField2205 = new Integer(2205);
+ public Object testField2206 = new Integer(2206);
+ public Object testField2207 = new Integer(2207);
+ public Object testField2208 = new Integer(2208);
+ public Object testField2209 = new Integer(2209);
+ public Object testField2210 = new Integer(2210);
+ public Object testField2211 = new Integer(2211);
+ public Object testField2212 = new Integer(2212);
+ public Object testField2213 = new Integer(2213);
+ public Object testField2214 = new Integer(2214);
+ public Object testField2215 = new Integer(2215);
+ public Object testField2216 = new Integer(2216);
+ public Object testField2217 = new Integer(2217);
+ public Object testField2218 = new Integer(2218);
+ public Object testField2219 = new Integer(2219);
+ public Object testField2220 = new Integer(2220);
+ public Object testField2221 = new Integer(2221);
+ public Object testField2222 = new Integer(2222);
+ public Object testField2223 = new Integer(2223);
+ public Object testField2224 = new Integer(2224);
+ public Object testField2225 = new Integer(2225);
+ public Object testField2226 = new Integer(2226);
+ public Object testField2227 = new Integer(2227);
+ public Object testField2228 = new Integer(2228);
+ public Object testField2229 = new Integer(2229);
+ public Object testField2230 = new Integer(2230);
+ public Object testField2231 = new Integer(2231);
+ public Object testField2232 = new Integer(2232);
+ public Object testField2233 = new Integer(2233);
+ public Object testField2234 = new Integer(2234);
+ public Object testField2235 = new Integer(2235);
+ public Object testField2236 = new Integer(2236);
+ public Object testField2237 = new Integer(2237);
+ public Object testField2238 = new Integer(2238);
+ public Object testField2239 = new Integer(2239);
+ public Object testField2240 = new Integer(2240);
+ public Object testField2241 = new Integer(2241);
+ public Object testField2242 = new Integer(2242);
+ public Object testField2243 = new Integer(2243);
+ public Object testField2244 = new Integer(2244);
+ public Object testField2245 = new Integer(2245);
+ public Object testField2246 = new Integer(2246);
+ public Object testField2247 = new Integer(2247);
+ public Object testField2248 = new Integer(2248);
+ public Object testField2249 = new Integer(2249);
+ public Object testField2250 = new Integer(2250);
+ public Object testField2251 = new Integer(2251);
+ public Object testField2252 = new Integer(2252);
+ public Object testField2253 = new Integer(2253);
+ public Object testField2254 = new Integer(2254);
+ public Object testField2255 = new Integer(2255);
+ public Object testField2256 = new Integer(2256);
+ public Object testField2257 = new Integer(2257);
+ public Object testField2258 = new Integer(2258);
+ public Object testField2259 = new Integer(2259);
+ public Object testField2260 = new Integer(2260);
+ public Object testField2261 = new Integer(2261);
+ public Object testField2262 = new Integer(2262);
+ public Object testField2263 = new Integer(2263);
+ public Object testField2264 = new Integer(2264);
+ public Object testField2265 = new Integer(2265);
+ public Object testField2266 = new Integer(2266);
+ public Object testField2267 = new Integer(2267);
+ public Object testField2268 = new Integer(2268);
+ public Object testField2269 = new Integer(2269);
+ public Object testField2270 = new Integer(2270);
+ public Object testField2271 = new Integer(2271);
+ public Object testField2272 = new Integer(2272);
+ public Object testField2273 = new Integer(2273);
+ public Object testField2274 = new Integer(2274);
+ public Object testField2275 = new Integer(2275);
+ public Object testField2276 = new Integer(2276);
+ public Object testField2277 = new Integer(2277);
+ public Object testField2278 = new Integer(2278);
+ public Object testField2279 = new Integer(2279);
+ public Object testField2280 = new Integer(2280);
+ public Object testField2281 = new Integer(2281);
+ public Object testField2282 = new Integer(2282);
+ public Object testField2283 = new Integer(2283);
+ public Object testField2284 = new Integer(2284);
+ public Object testField2285 = new Integer(2285);
+ public Object testField2286 = new Integer(2286);
+ public Object testField2287 = new Integer(2287);
+ public Object testField2288 = new Integer(2288);
+ public Object testField2289 = new Integer(2289);
+ public Object testField2290 = new Integer(2290);
+ public Object testField2291 = new Integer(2291);
+ public Object testField2292 = new Integer(2292);
+ public Object testField2293 = new Integer(2293);
+ public Object testField2294 = new Integer(2294);
+ public Object testField2295 = new Integer(2295);
+ public Object testField2296 = new Integer(2296);
+ public Object testField2297 = new Integer(2297);
+ public Object testField2298 = new Integer(2298);
+ public Object testField2299 = new Integer(2299);
+ public Object testField2300 = new Integer(2300);
+ public Object testField2301 = new Integer(2301);
+ public Object testField2302 = new Integer(2302);
+ public Object testField2303 = new Integer(2303);
+ public Object testField2304 = new Integer(2304);
+ public Object testField2305 = new Integer(2305);
+ public Object testField2306 = new Integer(2306);
+ public Object testField2307 = new Integer(2307);
+ public Object testField2308 = new Integer(2308);
+ public Object testField2309 = new Integer(2309);
+ public Object testField2310 = new Integer(2310);
+ public Object testField2311 = new Integer(2311);
+ public Object testField2312 = new Integer(2312);
+ public Object testField2313 = new Integer(2313);
+ public Object testField2314 = new Integer(2314);
+ public Object testField2315 = new Integer(2315);
+ public Object testField2316 = new Integer(2316);
+ public Object testField2317 = new Integer(2317);
+ public Object testField2318 = new Integer(2318);
+ public Object testField2319 = new Integer(2319);
+ public Object testField2320 = new Integer(2320);
+ public Object testField2321 = new Integer(2321);
+ public Object testField2322 = new Integer(2322);
+ public Object testField2323 = new Integer(2323);
+ public Object testField2324 = new Integer(2324);
+ public Object testField2325 = new Integer(2325);
+ public Object testField2326 = new Integer(2326);
+ public Object testField2327 = new Integer(2327);
+ public Object testField2328 = new Integer(2328);
+ public Object testField2329 = new Integer(2329);
+ public Object testField2330 = new Integer(2330);
+ public Object testField2331 = new Integer(2331);
+ public Object testField2332 = new Integer(2332);
+ public Object testField2333 = new Integer(2333);
+ public Object testField2334 = new Integer(2334);
+ public Object testField2335 = new Integer(2335);
+ public Object testField2336 = new Integer(2336);
+ public Object testField2337 = new Integer(2337);
+ public Object testField2338 = new Integer(2338);
+ public Object testField2339 = new Integer(2339);
+ public Object testField2340 = new Integer(2340);
+ public Object testField2341 = new Integer(2341);
+ public Object testField2342 = new Integer(2342);
+ public Object testField2343 = new Integer(2343);
+ public Object testField2344 = new Integer(2344);
+ public Object testField2345 = new Integer(2345);
+ public Object testField2346 = new Integer(2346);
+ public Object testField2347 = new Integer(2347);
+ public Object testField2348 = new Integer(2348);
+ public Object testField2349 = new Integer(2349);
+ public Object testField2350 = new Integer(2350);
+ public Object testField2351 = new Integer(2351);
+ public Object testField2352 = new Integer(2352);
+ public Object testField2353 = new Integer(2353);
+ public Object testField2354 = new Integer(2354);
+ public Object testField2355 = new Integer(2355);
+ public Object testField2356 = new Integer(2356);
+ public Object testField2357 = new Integer(2357);
+ public Object testField2358 = new Integer(2358);
+ public Object testField2359 = new Integer(2359);
+ public Object testField2360 = new Integer(2360);
+ public Object testField2361 = new Integer(2361);
+ public Object testField2362 = new Integer(2362);
+ public Object testField2363 = new Integer(2363);
+ public Object testField2364 = new Integer(2364);
+ public Object testField2365 = new Integer(2365);
+ public Object testField2366 = new Integer(2366);
+ public Object testField2367 = new Integer(2367);
+ public Object testField2368 = new Integer(2368);
+ public Object testField2369 = new Integer(2369);
+ public Object testField2370 = new Integer(2370);
+ public Object testField2371 = new Integer(2371);
+ public Object testField2372 = new Integer(2372);
+ public Object testField2373 = new Integer(2373);
+ public Object testField2374 = new Integer(2374);
+ public Object testField2375 = new Integer(2375);
+ public Object testField2376 = new Integer(2376);
+ public Object testField2377 = new Integer(2377);
+ public Object testField2378 = new Integer(2378);
+ public Object testField2379 = new Integer(2379);
+ public Object testField2380 = new Integer(2380);
+ public Object testField2381 = new Integer(2381);
+ public Object testField2382 = new Integer(2382);
+ public Object testField2383 = new Integer(2383);
+ public Object testField2384 = new Integer(2384);
+ public Object testField2385 = new Integer(2385);
+ public Object testField2386 = new Integer(2386);
+ public Object testField2387 = new Integer(2387);
+ public Object testField2388 = new Integer(2388);
+ public Object testField2389 = new Integer(2389);
+ public Object testField2390 = new Integer(2390);
+ public Object testField2391 = new Integer(2391);
+ public Object testField2392 = new Integer(2392);
+ public Object testField2393 = new Integer(2393);
+ public Object testField2394 = new Integer(2394);
+ public Object testField2395 = new Integer(2395);
+ public Object testField2396 = new Integer(2396);
+ public Object testField2397 = new Integer(2397);
+ public Object testField2398 = new Integer(2398);
+ public Object testField2399 = new Integer(2399);
+ public Object testField2400 = new Integer(2400);
+ public Object testField2401 = new Integer(2401);
+ public Object testField2402 = new Integer(2402);
+ public Object testField2403 = new Integer(2403);
+ public Object testField2404 = new Integer(2404);
+ public Object testField2405 = new Integer(2405);
+ public Object testField2406 = new Integer(2406);
+ public Object testField2407 = new Integer(2407);
+ public Object testField2408 = new Integer(2408);
+ public Object testField2409 = new Integer(2409);
+ public Object testField2410 = new Integer(2410);
+ public Object testField2411 = new Integer(2411);
+ public Object testField2412 = new Integer(2412);
+ public Object testField2413 = new Integer(2413);
+ public Object testField2414 = new Integer(2414);
+ public Object testField2415 = new Integer(2415);
+ public Object testField2416 = new Integer(2416);
+ public Object testField2417 = new Integer(2417);
+ public Object testField2418 = new Integer(2418);
+ public Object testField2419 = new Integer(2419);
+ public Object testField2420 = new Integer(2420);
+ public Object testField2421 = new Integer(2421);
+ public Object testField2422 = new Integer(2422);
+ public Object testField2423 = new Integer(2423);
+ public Object testField2424 = new Integer(2424);
+ public Object testField2425 = new Integer(2425);
+ public Object testField2426 = new Integer(2426);
+ public Object testField2427 = new Integer(2427);
+ public Object testField2428 = new Integer(2428);
+ public Object testField2429 = new Integer(2429);
+ public Object testField2430 = new Integer(2430);
+ public Object testField2431 = new Integer(2431);
+ public Object testField2432 = new Integer(2432);
+ public Object testField2433 = new Integer(2433);
+ public Object testField2434 = new Integer(2434);
+ public Object testField2435 = new Integer(2435);
+ public Object testField2436 = new Integer(2436);
+ public Object testField2437 = new Integer(2437);
+ public Object testField2438 = new Integer(2438);
+ public Object testField2439 = new Integer(2439);
+ public Object testField2440 = new Integer(2440);
+ public Object testField2441 = new Integer(2441);
+ public Object testField2442 = new Integer(2442);
+ public Object testField2443 = new Integer(2443);
+ public Object testField2444 = new Integer(2444);
+ public Object testField2445 = new Integer(2445);
+ public Object testField2446 = new Integer(2446);
+ public Object testField2447 = new Integer(2447);
+ public Object testField2448 = new Integer(2448);
+ public Object testField2449 = new Integer(2449);
+ public Object testField2450 = new Integer(2450);
+ public Object testField2451 = new Integer(2451);
+ public Object testField2452 = new Integer(2452);
+ public Object testField2453 = new Integer(2453);
+ public Object testField2454 = new Integer(2454);
+ public Object testField2455 = new Integer(2455);
+ public Object testField2456 = new Integer(2456);
+ public Object testField2457 = new Integer(2457);
+ public Object testField2458 = new Integer(2458);
+ public Object testField2459 = new Integer(2459);
+ public Object testField2460 = new Integer(2460);
+ public Object testField2461 = new Integer(2461);
+ public Object testField2462 = new Integer(2462);
+ public Object testField2463 = new Integer(2463);
+ public Object testField2464 = new Integer(2464);
+ public Object testField2465 = new Integer(2465);
+ public Object testField2466 = new Integer(2466);
+ public Object testField2467 = new Integer(2467);
+ public Object testField2468 = new Integer(2468);
+ public Object testField2469 = new Integer(2469);
+ public Object testField2470 = new Integer(2470);
+ public Object testField2471 = new Integer(2471);
+ public Object testField2472 = new Integer(2472);
+ public Object testField2473 = new Integer(2473);
+ public Object testField2474 = new Integer(2474);
+ public Object testField2475 = new Integer(2475);
+ public Object testField2476 = new Integer(2476);
+ public Object testField2477 = new Integer(2477);
+ public Object testField2478 = new Integer(2478);
+ public Object testField2479 = new Integer(2479);
+ public Object testField2480 = new Integer(2480);
+ public Object testField2481 = new Integer(2481);
+ public Object testField2482 = new Integer(2482);
+ public Object testField2483 = new Integer(2483);
+ public Object testField2484 = new Integer(2484);
+ public Object testField2485 = new Integer(2485);
+ public Object testField2486 = new Integer(2486);
+ public Object testField2487 = new Integer(2487);
+ public Object testField2488 = new Integer(2488);
+ public Object testField2489 = new Integer(2489);
+ public Object testField2490 = new Integer(2490);
+ public Object testField2491 = new Integer(2491);
+ public Object testField2492 = new Integer(2492);
+ public Object testField2493 = new Integer(2493);
+ public Object testField2494 = new Integer(2494);
+ public Object testField2495 = new Integer(2495);
+ public Object testField2496 = new Integer(2496);
+ public Object testField2497 = new Integer(2497);
+ public Object testField2498 = new Integer(2498);
+ public Object testField2499 = new Integer(2499);
+ public Object testField2500 = new Integer(2500);
+ public Object testField2501 = new Integer(2501);
+ public Object testField2502 = new Integer(2502);
+ public Object testField2503 = new Integer(2503);
+ public Object testField2504 = new Integer(2504);
+ public Object testField2505 = new Integer(2505);
+ public Object testField2506 = new Integer(2506);
+ public Object testField2507 = new Integer(2507);
+ public Object testField2508 = new Integer(2508);
+ public Object testField2509 = new Integer(2509);
+ public Object testField2510 = new Integer(2510);
+ public Object testField2511 = new Integer(2511);
+ public Object testField2512 = new Integer(2512);
+ public Object testField2513 = new Integer(2513);
+ public Object testField2514 = new Integer(2514);
+ public Object testField2515 = new Integer(2515);
+ public Object testField2516 = new Integer(2516);
+ public Object testField2517 = new Integer(2517);
+ public Object testField2518 = new Integer(2518);
+ public Object testField2519 = new Integer(2519);
+ public Object testField2520 = new Integer(2520);
+ public Object testField2521 = new Integer(2521);
+ public Object testField2522 = new Integer(2522);
+ public Object testField2523 = new Integer(2523);
+ public Object testField2524 = new Integer(2524);
+ public Object testField2525 = new Integer(2525);
+ public Object testField2526 = new Integer(2526);
+ public Object testField2527 = new Integer(2527);
+ public Object testField2528 = new Integer(2528);
+ public Object testField2529 = new Integer(2529);
+ public Object testField2530 = new Integer(2530);
+ public Object testField2531 = new Integer(2531);
+ public Object testField2532 = new Integer(2532);
+ public Object testField2533 = new Integer(2533);
+ public Object testField2534 = new Integer(2534);
+ public Object testField2535 = new Integer(2535);
+ public Object testField2536 = new Integer(2536);
+ public Object testField2537 = new Integer(2537);
+ public Object testField2538 = new Integer(2538);
+ public Object testField2539 = new Integer(2539);
+ public Object testField2540 = new Integer(2540);
+ public Object testField2541 = new Integer(2541);
+ public Object testField2542 = new Integer(2542);
+ public Object testField2543 = new Integer(2543);
+ public Object testField2544 = new Integer(2544);
+ public Object testField2545 = new Integer(2545);
+ public Object testField2546 = new Integer(2546);
+ public Object testField2547 = new Integer(2547);
+ public Object testField2548 = new Integer(2548);
+ public Object testField2549 = new Integer(2549);
+ public Object testField2550 = new Integer(2550);
+ public Object testField2551 = new Integer(2551);
+ public Object testField2552 = new Integer(2552);
+ public Object testField2553 = new Integer(2553);
+ public Object testField2554 = new Integer(2554);
+ public Object testField2555 = new Integer(2555);
+ public Object testField2556 = new Integer(2556);
+ public Object testField2557 = new Integer(2557);
+ public Object testField2558 = new Integer(2558);
+ public Object testField2559 = new Integer(2559);
+ public Object testField2560 = new Integer(2560);
+ public Object testField2561 = new Integer(2561);
+ public Object testField2562 = new Integer(2562);
+ public Object testField2563 = new Integer(2563);
+ public Object testField2564 = new Integer(2564);
+ public Object testField2565 = new Integer(2565);
+ public Object testField2566 = new Integer(2566);
+ public Object testField2567 = new Integer(2567);
+ public Object testField2568 = new Integer(2568);
+ public Object testField2569 = new Integer(2569);
+ public Object testField2570 = new Integer(2570);
+ public Object testField2571 = new Integer(2571);
+ public Object testField2572 = new Integer(2572);
+ public Object testField2573 = new Integer(2573);
+ public Object testField2574 = new Integer(2574);
+ public Object testField2575 = new Integer(2575);
+ public Object testField2576 = new Integer(2576);
+ public Object testField2577 = new Integer(2577);
+ public Object testField2578 = new Integer(2578);
+ public Object testField2579 = new Integer(2579);
+ public Object testField2580 = new Integer(2580);
+ public Object testField2581 = new Integer(2581);
+ public Object testField2582 = new Integer(2582);
+ public Object testField2583 = new Integer(2583);
+ public Object testField2584 = new Integer(2584);
+ public Object testField2585 = new Integer(2585);
+ public Object testField2586 = new Integer(2586);
+ public Object testField2587 = new Integer(2587);
+ public Object testField2588 = new Integer(2588);
+ public Object testField2589 = new Integer(2589);
+ public Object testField2590 = new Integer(2590);
+ public Object testField2591 = new Integer(2591);
+ public Object testField2592 = new Integer(2592);
+ public Object testField2593 = new Integer(2593);
+ public Object testField2594 = new Integer(2594);
+ public Object testField2595 = new Integer(2595);
+ public Object testField2596 = new Integer(2596);
+ public Object testField2597 = new Integer(2597);
+ public Object testField2598 = new Integer(2598);
+ public Object testField2599 = new Integer(2599);
+ public Object testField2600 = new Integer(2600);
+ public Object testField2601 = new Integer(2601);
+ public Object testField2602 = new Integer(2602);
+ public Object testField2603 = new Integer(2603);
+ public Object testField2604 = new Integer(2604);
+ public Object testField2605 = new Integer(2605);
+ public Object testField2606 = new Integer(2606);
+ public Object testField2607 = new Integer(2607);
+ public Object testField2608 = new Integer(2608);
+ public Object testField2609 = new Integer(2609);
+ public Object testField2610 = new Integer(2610);
+ public Object testField2611 = new Integer(2611);
+ public Object testField2612 = new Integer(2612);
+ public Object testField2613 = new Integer(2613);
+ public Object testField2614 = new Integer(2614);
+ public Object testField2615 = new Integer(2615);
+ public Object testField2616 = new Integer(2616);
+ public Object testField2617 = new Integer(2617);
+ public Object testField2618 = new Integer(2618);
+ public Object testField2619 = new Integer(2619);
+ public Object testField2620 = new Integer(2620);
+ public Object testField2621 = new Integer(2621);
+ public Object testField2622 = new Integer(2622);
+ public Object testField2623 = new Integer(2623);
+ public Object testField2624 = new Integer(2624);
+ public Object testField2625 = new Integer(2625);
+ public Object testField2626 = new Integer(2626);
+ public Object testField2627 = new Integer(2627);
+ public Object testField2628 = new Integer(2628);
+ public Object testField2629 = new Integer(2629);
+ public Object testField2630 = new Integer(2630);
+ public Object testField2631 = new Integer(2631);
+ public Object testField2632 = new Integer(2632);
+ public Object testField2633 = new Integer(2633);
+ public Object testField2634 = new Integer(2634);
+ public Object testField2635 = new Integer(2635);
+ public Object testField2636 = new Integer(2636);
+ public Object testField2637 = new Integer(2637);
+ public Object testField2638 = new Integer(2638);
+ public Object testField2639 = new Integer(2639);
+ public Object testField2640 = new Integer(2640);
+ public Object testField2641 = new Integer(2641);
+ public Object testField2642 = new Integer(2642);
+ public Object testField2643 = new Integer(2643);
+ public Object testField2644 = new Integer(2644);
+ public Object testField2645 = new Integer(2645);
+ public Object testField2646 = new Integer(2646);
+ public Object testField2647 = new Integer(2647);
+ public Object testField2648 = new Integer(2648);
+ public Object testField2649 = new Integer(2649);
+ public Object testField2650 = new Integer(2650);
+ public Object testField2651 = new Integer(2651);
+ public Object testField2652 = new Integer(2652);
+ public Object testField2653 = new Integer(2653);
+ public Object testField2654 = new Integer(2654);
+ public Object testField2655 = new Integer(2655);
+ public Object testField2656 = new Integer(2656);
+ public Object testField2657 = new Integer(2657);
+ public Object testField2658 = new Integer(2658);
+ public Object testField2659 = new Integer(2659);
+ public Object testField2660 = new Integer(2660);
+ public Object testField2661 = new Integer(2661);
+ public Object testField2662 = new Integer(2662);
+ public Object testField2663 = new Integer(2663);
+ public Object testField2664 = new Integer(2664);
+ public Object testField2665 = new Integer(2665);
+ public Object testField2666 = new Integer(2666);
+ public Object testField2667 = new Integer(2667);
+ public Object testField2668 = new Integer(2668);
+ public Object testField2669 = new Integer(2669);
+ public Object testField2670 = new Integer(2670);
+ public Object testField2671 = new Integer(2671);
+ public Object testField2672 = new Integer(2672);
+ public Object testField2673 = new Integer(2673);
+ public Object testField2674 = new Integer(2674);
+ public Object testField2675 = new Integer(2675);
+ public Object testField2676 = new Integer(2676);
+ public Object testField2677 = new Integer(2677);
+ public Object testField2678 = new Integer(2678);
+ public Object testField2679 = new Integer(2679);
+ public Object testField2680 = new Integer(2680);
+ public Object testField2681 = new Integer(2681);
+ public Object testField2682 = new Integer(2682);
+ public Object testField2683 = new Integer(2683);
+ public Object testField2684 = new Integer(2684);
+ public Object testField2685 = new Integer(2685);
+ public Object testField2686 = new Integer(2686);
+ public Object testField2687 = new Integer(2687);
+ public Object testField2688 = new Integer(2688);
+ public Object testField2689 = new Integer(2689);
+ public Object testField2690 = new Integer(2690);
+ public Object testField2691 = new Integer(2691);
+ public Object testField2692 = new Integer(2692);
+ public Object testField2693 = new Integer(2693);
+ public Object testField2694 = new Integer(2694);
+ public Object testField2695 = new Integer(2695);
+ public Object testField2696 = new Integer(2696);
+ public Object testField2697 = new Integer(2697);
+ public Object testField2698 = new Integer(2698);
+ public Object testField2699 = new Integer(2699);
+ public Object testField2700 = new Integer(2700);
+ public Object testField2701 = new Integer(2701);
+ public Object testField2702 = new Integer(2702);
+ public Object testField2703 = new Integer(2703);
+ public Object testField2704 = new Integer(2704);
+ public Object testField2705 = new Integer(2705);
+ public Object testField2706 = new Integer(2706);
+ public Object testField2707 = new Integer(2707);
+ public Object testField2708 = new Integer(2708);
+ public Object testField2709 = new Integer(2709);
+ public Object testField2710 = new Integer(2710);
+ public Object testField2711 = new Integer(2711);
+ public Object testField2712 = new Integer(2712);
+ public Object testField2713 = new Integer(2713);
+ public Object testField2714 = new Integer(2714);
+ public Object testField2715 = new Integer(2715);
+ public Object testField2716 = new Integer(2716);
+ public Object testField2717 = new Integer(2717);
+ public Object testField2718 = new Integer(2718);
+ public Object testField2719 = new Integer(2719);
+ public Object testField2720 = new Integer(2720);
+ public Object testField2721 = new Integer(2721);
+ public Object testField2722 = new Integer(2722);
+ public Object testField2723 = new Integer(2723);
+ public Object testField2724 = new Integer(2724);
+ public Object testField2725 = new Integer(2725);
+ public Object testField2726 = new Integer(2726);
+ public Object testField2727 = new Integer(2727);
+ public Object testField2728 = new Integer(2728);
+ public Object testField2729 = new Integer(2729);
+ public Object testField2730 = new Integer(2730);
+ public Object testField2731 = new Integer(2731);
+ public Object testField2732 = new Integer(2732);
+ public Object testField2733 = new Integer(2733);
+ public Object testField2734 = new Integer(2734);
+ public Object testField2735 = new Integer(2735);
+ public Object testField2736 = new Integer(2736);
+ public Object testField2737 = new Integer(2737);
+ public Object testField2738 = new Integer(2738);
+ public Object testField2739 = new Integer(2739);
+ public Object testField2740 = new Integer(2740);
+ public Object testField2741 = new Integer(2741);
+ public Object testField2742 = new Integer(2742);
+ public Object testField2743 = new Integer(2743);
+ public Object testField2744 = new Integer(2744);
+ public Object testField2745 = new Integer(2745);
+ public Object testField2746 = new Integer(2746);
+ public Object testField2747 = new Integer(2747);
+ public Object testField2748 = new Integer(2748);
+ public Object testField2749 = new Integer(2749);
+ public Object testField2750 = new Integer(2750);
+ public Object testField2751 = new Integer(2751);
+ public Object testField2752 = new Integer(2752);
+ public Object testField2753 = new Integer(2753);
+ public Object testField2754 = new Integer(2754);
+ public Object testField2755 = new Integer(2755);
+ public Object testField2756 = new Integer(2756);
+ public Object testField2757 = new Integer(2757);
+ public Object testField2758 = new Integer(2758);
+ public Object testField2759 = new Integer(2759);
+ public Object testField2760 = new Integer(2760);
+ public Object testField2761 = new Integer(2761);
+ public Object testField2762 = new Integer(2762);
+ public Object testField2763 = new Integer(2763);
+ public Object testField2764 = new Integer(2764);
+ public Object testField2765 = new Integer(2765);
+ public Object testField2766 = new Integer(2766);
+ public Object testField2767 = new Integer(2767);
+ public Object testField2768 = new Integer(2768);
+ public Object testField2769 = new Integer(2769);
+ public Object testField2770 = new Integer(2770);
+ public Object testField2771 = new Integer(2771);
+ public Object testField2772 = new Integer(2772);
+ public Object testField2773 = new Integer(2773);
+ public Object testField2774 = new Integer(2774);
+ public Object testField2775 = new Integer(2775);
+ public Object testField2776 = new Integer(2776);
+ public Object testField2777 = new Integer(2777);
+ public Object testField2778 = new Integer(2778);
+ public Object testField2779 = new Integer(2779);
+ public Object testField2780 = new Integer(2780);
+ public Object testField2781 = new Integer(2781);
+ public Object testField2782 = new Integer(2782);
+ public Object testField2783 = new Integer(2783);
+ public Object testField2784 = new Integer(2784);
+ public Object testField2785 = new Integer(2785);
+ public Object testField2786 = new Integer(2786);
+ public Object testField2787 = new Integer(2787);
+ public Object testField2788 = new Integer(2788);
+ public Object testField2789 = new Integer(2789);
+ public Object testField2790 = new Integer(2790);
+ public Object testField2791 = new Integer(2791);
+ public Object testField2792 = new Integer(2792);
+ public Object testField2793 = new Integer(2793);
+ public Object testField2794 = new Integer(2794);
+ public Object testField2795 = new Integer(2795);
+ public Object testField2796 = new Integer(2796);
+ public Object testField2797 = new Integer(2797);
+ public Object testField2798 = new Integer(2798);
+ public Object testField2799 = new Integer(2799);
+ public Object testField2800 = new Integer(2800);
+ public Object testField2801 = new Integer(2801);
+ public Object testField2802 = new Integer(2802);
+ public Object testField2803 = new Integer(2803);
+ public Object testField2804 = new Integer(2804);
+ public Object testField2805 = new Integer(2805);
+ public Object testField2806 = new Integer(2806);
+ public Object testField2807 = new Integer(2807);
+ public Object testField2808 = new Integer(2808);
+ public Object testField2809 = new Integer(2809);
+ public Object testField2810 = new Integer(2810);
+ public Object testField2811 = new Integer(2811);
+ public Object testField2812 = new Integer(2812);
+ public Object testField2813 = new Integer(2813);
+ public Object testField2814 = new Integer(2814);
+ public Object testField2815 = new Integer(2815);
+ public Object testField2816 = new Integer(2816);
+ public Object testField2817 = new Integer(2817);
+ public Object testField2818 = new Integer(2818);
+ public Object testField2819 = new Integer(2819);
+ public Object testField2820 = new Integer(2820);
+ public Object testField2821 = new Integer(2821);
+ public Object testField2822 = new Integer(2822);
+ public Object testField2823 = new Integer(2823);
+ public Object testField2824 = new Integer(2824);
+ public Object testField2825 = new Integer(2825);
+ public Object testField2826 = new Integer(2826);
+ public Object testField2827 = new Integer(2827);
+ public Object testField2828 = new Integer(2828);
+ public Object testField2829 = new Integer(2829);
+ public Object testField2830 = new Integer(2830);
+ public Object testField2831 = new Integer(2831);
+ public Object testField2832 = new Integer(2832);
+ public Object testField2833 = new Integer(2833);
+ public Object testField2834 = new Integer(2834);
+ public Object testField2835 = new Integer(2835);
+ public Object testField2836 = new Integer(2836);
+ public Object testField2837 = new Integer(2837);
+ public Object testField2838 = new Integer(2838);
+ public Object testField2839 = new Integer(2839);
+ public Object testField2840 = new Integer(2840);
+ public Object testField2841 = new Integer(2841);
+ public Object testField2842 = new Integer(2842);
+ public Object testField2843 = new Integer(2843);
+ public Object testField2844 = new Integer(2844);
+ public Object testField2845 = new Integer(2845);
+ public Object testField2846 = new Integer(2846);
+ public Object testField2847 = new Integer(2847);
+ public Object testField2848 = new Integer(2848);
+ public Object testField2849 = new Integer(2849);
+ public Object testField2850 = new Integer(2850);
+ public Object testField2851 = new Integer(2851);
+ public Object testField2852 = new Integer(2852);
+ public Object testField2853 = new Integer(2853);
+ public Object testField2854 = new Integer(2854);
+ public Object testField2855 = new Integer(2855);
+ public Object testField2856 = new Integer(2856);
+ public Object testField2857 = new Integer(2857);
+ public Object testField2858 = new Integer(2858);
+ public Object testField2859 = new Integer(2859);
+ public Object testField2860 = new Integer(2860);
+ public Object testField2861 = new Integer(2861);
+ public Object testField2862 = new Integer(2862);
+ public Object testField2863 = new Integer(2863);
+ public Object testField2864 = new Integer(2864);
+ public Object testField2865 = new Integer(2865);
+ public Object testField2866 = new Integer(2866);
+ public Object testField2867 = new Integer(2867);
+ public Object testField2868 = new Integer(2868);
+ public Object testField2869 = new Integer(2869);
+ public Object testField2870 = new Integer(2870);
+ public Object testField2871 = new Integer(2871);
+ public Object testField2872 = new Integer(2872);
+ public Object testField2873 = new Integer(2873);
+ public Object testField2874 = new Integer(2874);
+ public Object testField2875 = new Integer(2875);
+ public Object testField2876 = new Integer(2876);
+ public Object testField2877 = new Integer(2877);
+ public Object testField2878 = new Integer(2878);
+ public Object testField2879 = new Integer(2879);
+ public Object testField2880 = new Integer(2880);
+ public Object testField2881 = new Integer(2881);
+ public Object testField2882 = new Integer(2882);
+ public Object testField2883 = new Integer(2883);
+ public Object testField2884 = new Integer(2884);
+ public Object testField2885 = new Integer(2885);
+ public Object testField2886 = new Integer(2886);
+ public Object testField2887 = new Integer(2887);
+ public Object testField2888 = new Integer(2888);
+ public Object testField2889 = new Integer(2889);
+ public Object testField2890 = new Integer(2890);
+ public Object testField2891 = new Integer(2891);
+ public Object testField2892 = new Integer(2892);
+ public Object testField2893 = new Integer(2893);
+ public Object testField2894 = new Integer(2894);
+ public Object testField2895 = new Integer(2895);
+ public Object testField2896 = new Integer(2896);
+ public Object testField2897 = new Integer(2897);
+ public Object testField2898 = new Integer(2898);
+ public Object testField2899 = new Integer(2899);
+ public Object testField2900 = new Integer(2900);
+ public Object testField2901 = new Integer(2901);
+ public Object testField2902 = new Integer(2902);
+ public Object testField2903 = new Integer(2903);
+ public Object testField2904 = new Integer(2904);
+ public Object testField2905 = new Integer(2905);
+ public Object testField2906 = new Integer(2906);
+ public Object testField2907 = new Integer(2907);
+ public Object testField2908 = new Integer(2908);
+ public Object testField2909 = new Integer(2909);
+ public Object testField2910 = new Integer(2910);
+ public Object testField2911 = new Integer(2911);
+ public Object testField2912 = new Integer(2912);
+ public Object testField2913 = new Integer(2913);
+ public Object testField2914 = new Integer(2914);
+ public Object testField2915 = new Integer(2915);
+ public Object testField2916 = new Integer(2916);
+ public Object testField2917 = new Integer(2917);
+ public Object testField2918 = new Integer(2918);
+ public Object testField2919 = new Integer(2919);
+ public Object testField2920 = new Integer(2920);
+ public Object testField2921 = new Integer(2921);
+ public Object testField2922 = new Integer(2922);
+ public Object testField2923 = new Integer(2923);
+ public Object testField2924 = new Integer(2924);
+ public Object testField2925 = new Integer(2925);
+ public Object testField2926 = new Integer(2926);
+ public Object testField2927 = new Integer(2927);
+ public Object testField2928 = new Integer(2928);
+ public Object testField2929 = new Integer(2929);
+ public Object testField2930 = new Integer(2930);
+ public Object testField2931 = new Integer(2931);
+ public Object testField2932 = new Integer(2932);
+ public Object testField2933 = new Integer(2933);
+ public Object testField2934 = new Integer(2934);
+ public Object testField2935 = new Integer(2935);
+ public Object testField2936 = new Integer(2936);
+ public Object testField2937 = new Integer(2937);
+ public Object testField2938 = new Integer(2938);
+ public Object testField2939 = new Integer(2939);
+ public Object testField2940 = new Integer(2940);
+ public Object testField2941 = new Integer(2941);
+ public Object testField2942 = new Integer(2942);
+ public Object testField2943 = new Integer(2943);
+ public Object testField2944 = new Integer(2944);
+ public Object testField2945 = new Integer(2945);
+ public Object testField2946 = new Integer(2946);
+ public Object testField2947 = new Integer(2947);
+ public Object testField2948 = new Integer(2948);
+ public Object testField2949 = new Integer(2949);
+ public Object testField2950 = new Integer(2950);
+ public Object testField2951 = new Integer(2951);
+ public Object testField2952 = new Integer(2952);
+ public Object testField2953 = new Integer(2953);
+ public Object testField2954 = new Integer(2954);
+ public Object testField2955 = new Integer(2955);
+ public Object testField2956 = new Integer(2956);
+ public Object testField2957 = new Integer(2957);
+ public Object testField2958 = new Integer(2958);
+ public Object testField2959 = new Integer(2959);
+ public Object testField2960 = new Integer(2960);
+ public Object testField2961 = new Integer(2961);
+ public Object testField2962 = new Integer(2962);
+ public Object testField2963 = new Integer(2963);
+ public Object testField2964 = new Integer(2964);
+ public Object testField2965 = new Integer(2965);
+ public Object testField2966 = new Integer(2966);
+ public Object testField2967 = new Integer(2967);
+ public Object testField2968 = new Integer(2968);
+ public Object testField2969 = new Integer(2969);
+ public Object testField2970 = new Integer(2970);
+ public Object testField2971 = new Integer(2971);
+ public Object testField2972 = new Integer(2972);
+ public Object testField2973 = new Integer(2973);
+ public Object testField2974 = new Integer(2974);
+ public Object testField2975 = new Integer(2975);
+ public Object testField2976 = new Integer(2976);
+ public Object testField2977 = new Integer(2977);
+ public Object testField2978 = new Integer(2978);
+ public Object testField2979 = new Integer(2979);
+ public Object testField2980 = new Integer(2980);
+ public Object testField2981 = new Integer(2981);
+ public Object testField2982 = new Integer(2982);
+ public Object testField2983 = new Integer(2983);
+ public Object testField2984 = new Integer(2984);
+ public Object testField2985 = new Integer(2985);
+ public Object testField2986 = new Integer(2986);
+ public Object testField2987 = new Integer(2987);
+ public Object testField2988 = new Integer(2988);
+ public Object testField2989 = new Integer(2989);
+ public Object testField2990 = new Integer(2990);
+ public Object testField2991 = new Integer(2991);
+ public Object testField2992 = new Integer(2992);
+ public Object testField2993 = new Integer(2993);
+ public Object testField2994 = new Integer(2994);
+ public Object testField2995 = new Integer(2995);
+ public Object testField2996 = new Integer(2996);
+ public Object testField2997 = new Integer(2997);
+ public Object testField2998 = new Integer(2998);
+ public Object testField2999 = new Integer(2999);
+}
diff --git a/test/160-read-barrier-stress/src/ManyFieldsBase3.java b/test/160-read-barrier-stress/src/ManyFieldsBase3.java
new file mode 100644
index 0000000..e7cfaac
--- /dev/null
+++ b/test/160-read-barrier-stress/src/ManyFieldsBase3.java
@@ -0,0 +1,1018 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+class ManyFieldsBase3 extends ManyFieldsBase2 {
+ public Object testField3000 = new Integer(3000);
+ public Object testField3001 = new Integer(3001);
+ public Object testField3002 = new Integer(3002);
+ public Object testField3003 = new Integer(3003);
+ public Object testField3004 = new Integer(3004);
+ public Object testField3005 = new Integer(3005);
+ public Object testField3006 = new Integer(3006);
+ public Object testField3007 = new Integer(3007);
+ public Object testField3008 = new Integer(3008);
+ public Object testField3009 = new Integer(3009);
+ public Object testField3010 = new Integer(3010);
+ public Object testField3011 = new Integer(3011);
+ public Object testField3012 = new Integer(3012);
+ public Object testField3013 = new Integer(3013);
+ public Object testField3014 = new Integer(3014);
+ public Object testField3015 = new Integer(3015);
+ public Object testField3016 = new Integer(3016);
+ public Object testField3017 = new Integer(3017);
+ public Object testField3018 = new Integer(3018);
+ public Object testField3019 = new Integer(3019);
+ public Object testField3020 = new Integer(3020);
+ public Object testField3021 = new Integer(3021);
+ public Object testField3022 = new Integer(3022);
+ public Object testField3023 = new Integer(3023);
+ public Object testField3024 = new Integer(3024);
+ public Object testField3025 = new Integer(3025);
+ public Object testField3026 = new Integer(3026);
+ public Object testField3027 = new Integer(3027);
+ public Object testField3028 = new Integer(3028);
+ public Object testField3029 = new Integer(3029);
+ public Object testField3030 = new Integer(3030);
+ public Object testField3031 = new Integer(3031);
+ public Object testField3032 = new Integer(3032);
+ public Object testField3033 = new Integer(3033);
+ public Object testField3034 = new Integer(3034);
+ public Object testField3035 = new Integer(3035);
+ public Object testField3036 = new Integer(3036);
+ public Object testField3037 = new Integer(3037);
+ public Object testField3038 = new Integer(3038);
+ public Object testField3039 = new Integer(3039);
+ public Object testField3040 = new Integer(3040);
+ public Object testField3041 = new Integer(3041);
+ public Object testField3042 = new Integer(3042);
+ public Object testField3043 = new Integer(3043);
+ public Object testField3044 = new Integer(3044);
+ public Object testField3045 = new Integer(3045);
+ public Object testField3046 = new Integer(3046);
+ public Object testField3047 = new Integer(3047);
+ public Object testField3048 = new Integer(3048);
+ public Object testField3049 = new Integer(3049);
+ public Object testField3050 = new Integer(3050);
+ public Object testField3051 = new Integer(3051);
+ public Object testField3052 = new Integer(3052);
+ public Object testField3053 = new Integer(3053);
+ public Object testField3054 = new Integer(3054);
+ public Object testField3055 = new Integer(3055);
+ public Object testField3056 = new Integer(3056);
+ public Object testField3057 = new Integer(3057);
+ public Object testField3058 = new Integer(3058);
+ public Object testField3059 = new Integer(3059);
+ public Object testField3060 = new Integer(3060);
+ public Object testField3061 = new Integer(3061);
+ public Object testField3062 = new Integer(3062);
+ public Object testField3063 = new Integer(3063);
+ public Object testField3064 = new Integer(3064);
+ public Object testField3065 = new Integer(3065);
+ public Object testField3066 = new Integer(3066);
+ public Object testField3067 = new Integer(3067);
+ public Object testField3068 = new Integer(3068);
+ public Object testField3069 = new Integer(3069);
+ public Object testField3070 = new Integer(3070);
+ public Object testField3071 = new Integer(3071);
+ public Object testField3072 = new Integer(3072);
+ public Object testField3073 = new Integer(3073);
+ public Object testField3074 = new Integer(3074);
+ public Object testField3075 = new Integer(3075);
+ public Object testField3076 = new Integer(3076);
+ public Object testField3077 = new Integer(3077);
+ public Object testField3078 = new Integer(3078);
+ public Object testField3079 = new Integer(3079);
+ public Object testField3080 = new Integer(3080);
+ public Object testField3081 = new Integer(3081);
+ public Object testField3082 = new Integer(3082);
+ public Object testField3083 = new Integer(3083);
+ public Object testField3084 = new Integer(3084);
+ public Object testField3085 = new Integer(3085);
+ public Object testField3086 = new Integer(3086);
+ public Object testField3087 = new Integer(3087);
+ public Object testField3088 = new Integer(3088);
+ public Object testField3089 = new Integer(3089);
+ public Object testField3090 = new Integer(3090);
+ public Object testField3091 = new Integer(3091);
+ public Object testField3092 = new Integer(3092);
+ public Object testField3093 = new Integer(3093);
+ public Object testField3094 = new Integer(3094);
+ public Object testField3095 = new Integer(3095);
+ public Object testField3096 = new Integer(3096);
+ public Object testField3097 = new Integer(3097);
+ public Object testField3098 = new Integer(3098);
+ public Object testField3099 = new Integer(3099);
+ public Object testField3100 = new Integer(3100);
+ public Object testField3101 = new Integer(3101);
+ public Object testField3102 = new Integer(3102);
+ public Object testField3103 = new Integer(3103);
+ public Object testField3104 = new Integer(3104);
+ public Object testField3105 = new Integer(3105);
+ public Object testField3106 = new Integer(3106);
+ public Object testField3107 = new Integer(3107);
+ public Object testField3108 = new Integer(3108);
+ public Object testField3109 = new Integer(3109);
+ public Object testField3110 = new Integer(3110);
+ public Object testField3111 = new Integer(3111);
+ public Object testField3112 = new Integer(3112);
+ public Object testField3113 = new Integer(3113);
+ public Object testField3114 = new Integer(3114);
+ public Object testField3115 = new Integer(3115);
+ public Object testField3116 = new Integer(3116);
+ public Object testField3117 = new Integer(3117);
+ public Object testField3118 = new Integer(3118);
+ public Object testField3119 = new Integer(3119);
+ public Object testField3120 = new Integer(3120);
+ public Object testField3121 = new Integer(3121);
+ public Object testField3122 = new Integer(3122);
+ public Object testField3123 = new Integer(3123);
+ public Object testField3124 = new Integer(3124);
+ public Object testField3125 = new Integer(3125);
+ public Object testField3126 = new Integer(3126);
+ public Object testField3127 = new Integer(3127);
+ public Object testField3128 = new Integer(3128);
+ public Object testField3129 = new Integer(3129);
+ public Object testField3130 = new Integer(3130);
+ public Object testField3131 = new Integer(3131);
+ public Object testField3132 = new Integer(3132);
+ public Object testField3133 = new Integer(3133);
+ public Object testField3134 = new Integer(3134);
+ public Object testField3135 = new Integer(3135);
+ public Object testField3136 = new Integer(3136);
+ public Object testField3137 = new Integer(3137);
+ public Object testField3138 = new Integer(3138);
+ public Object testField3139 = new Integer(3139);
+ public Object testField3140 = new Integer(3140);
+ public Object testField3141 = new Integer(3141);
+ public Object testField3142 = new Integer(3142);
+ public Object testField3143 = new Integer(3143);
+ public Object testField3144 = new Integer(3144);
+ public Object testField3145 = new Integer(3145);
+ public Object testField3146 = new Integer(3146);
+ public Object testField3147 = new Integer(3147);
+ public Object testField3148 = new Integer(3148);
+ public Object testField3149 = new Integer(3149);
+ public Object testField3150 = new Integer(3150);
+ public Object testField3151 = new Integer(3151);
+ public Object testField3152 = new Integer(3152);
+ public Object testField3153 = new Integer(3153);
+ public Object testField3154 = new Integer(3154);
+ public Object testField3155 = new Integer(3155);
+ public Object testField3156 = new Integer(3156);
+ public Object testField3157 = new Integer(3157);
+ public Object testField3158 = new Integer(3158);
+ public Object testField3159 = new Integer(3159);
+ public Object testField3160 = new Integer(3160);
+ public Object testField3161 = new Integer(3161);
+ public Object testField3162 = new Integer(3162);
+ public Object testField3163 = new Integer(3163);
+ public Object testField3164 = new Integer(3164);
+ public Object testField3165 = new Integer(3165);
+ public Object testField3166 = new Integer(3166);
+ public Object testField3167 = new Integer(3167);
+ public Object testField3168 = new Integer(3168);
+ public Object testField3169 = new Integer(3169);
+ public Object testField3170 = new Integer(3170);
+ public Object testField3171 = new Integer(3171);
+ public Object testField3172 = new Integer(3172);
+ public Object testField3173 = new Integer(3173);
+ public Object testField3174 = new Integer(3174);
+ public Object testField3175 = new Integer(3175);
+ public Object testField3176 = new Integer(3176);
+ public Object testField3177 = new Integer(3177);
+ public Object testField3178 = new Integer(3178);
+ public Object testField3179 = new Integer(3179);
+ public Object testField3180 = new Integer(3180);
+ public Object testField3181 = new Integer(3181);
+ public Object testField3182 = new Integer(3182);
+ public Object testField3183 = new Integer(3183);
+ public Object testField3184 = new Integer(3184);
+ public Object testField3185 = new Integer(3185);
+ public Object testField3186 = new Integer(3186);
+ public Object testField3187 = new Integer(3187);
+ public Object testField3188 = new Integer(3188);
+ public Object testField3189 = new Integer(3189);
+ public Object testField3190 = new Integer(3190);
+ public Object testField3191 = new Integer(3191);
+ public Object testField3192 = new Integer(3192);
+ public Object testField3193 = new Integer(3193);
+ public Object testField3194 = new Integer(3194);
+ public Object testField3195 = new Integer(3195);
+ public Object testField3196 = new Integer(3196);
+ public Object testField3197 = new Integer(3197);
+ public Object testField3198 = new Integer(3198);
+ public Object testField3199 = new Integer(3199);
+ public Object testField3200 = new Integer(3200);
+ public Object testField3201 = new Integer(3201);
+ public Object testField3202 = new Integer(3202);
+ public Object testField3203 = new Integer(3203);
+ public Object testField3204 = new Integer(3204);
+ public Object testField3205 = new Integer(3205);
+ public Object testField3206 = new Integer(3206);
+ public Object testField3207 = new Integer(3207);
+ public Object testField3208 = new Integer(3208);
+ public Object testField3209 = new Integer(3209);
+ public Object testField3210 = new Integer(3210);
+ public Object testField3211 = new Integer(3211);
+ public Object testField3212 = new Integer(3212);
+ public Object testField3213 = new Integer(3213);
+ public Object testField3214 = new Integer(3214);
+ public Object testField3215 = new Integer(3215);
+ public Object testField3216 = new Integer(3216);
+ public Object testField3217 = new Integer(3217);
+ public Object testField3218 = new Integer(3218);
+ public Object testField3219 = new Integer(3219);
+ public Object testField3220 = new Integer(3220);
+ public Object testField3221 = new Integer(3221);
+ public Object testField3222 = new Integer(3222);
+ public Object testField3223 = new Integer(3223);
+ public Object testField3224 = new Integer(3224);
+ public Object testField3225 = new Integer(3225);
+ public Object testField3226 = new Integer(3226);
+ public Object testField3227 = new Integer(3227);
+ public Object testField3228 = new Integer(3228);
+ public Object testField3229 = new Integer(3229);
+ public Object testField3230 = new Integer(3230);
+ public Object testField3231 = new Integer(3231);
+ public Object testField3232 = new Integer(3232);
+ public Object testField3233 = new Integer(3233);
+ public Object testField3234 = new Integer(3234);
+ public Object testField3235 = new Integer(3235);
+ public Object testField3236 = new Integer(3236);
+ public Object testField3237 = new Integer(3237);
+ public Object testField3238 = new Integer(3238);
+ public Object testField3239 = new Integer(3239);
+ public Object testField3240 = new Integer(3240);
+ public Object testField3241 = new Integer(3241);
+ public Object testField3242 = new Integer(3242);
+ public Object testField3243 = new Integer(3243);
+ public Object testField3244 = new Integer(3244);
+ public Object testField3245 = new Integer(3245);
+ public Object testField3246 = new Integer(3246);
+ public Object testField3247 = new Integer(3247);
+ public Object testField3248 = new Integer(3248);
+ public Object testField3249 = new Integer(3249);
+ public Object testField3250 = new Integer(3250);
+ public Object testField3251 = new Integer(3251);
+ public Object testField3252 = new Integer(3252);
+ public Object testField3253 = new Integer(3253);
+ public Object testField3254 = new Integer(3254);
+ public Object testField3255 = new Integer(3255);
+ public Object testField3256 = new Integer(3256);
+ public Object testField3257 = new Integer(3257);
+ public Object testField3258 = new Integer(3258);
+ public Object testField3259 = new Integer(3259);
+ public Object testField3260 = new Integer(3260);
+ public Object testField3261 = new Integer(3261);
+ public Object testField3262 = new Integer(3262);
+ public Object testField3263 = new Integer(3263);
+ public Object testField3264 = new Integer(3264);
+ public Object testField3265 = new Integer(3265);
+ public Object testField3266 = new Integer(3266);
+ public Object testField3267 = new Integer(3267);
+ public Object testField3268 = new Integer(3268);
+ public Object testField3269 = new Integer(3269);
+ public Object testField3270 = new Integer(3270);
+ public Object testField3271 = new Integer(3271);
+ public Object testField3272 = new Integer(3272);
+ public Object testField3273 = new Integer(3273);
+ public Object testField3274 = new Integer(3274);
+ public Object testField3275 = new Integer(3275);
+ public Object testField3276 = new Integer(3276);
+ public Object testField3277 = new Integer(3277);
+ public Object testField3278 = new Integer(3278);
+ public Object testField3279 = new Integer(3279);
+ public Object testField3280 = new Integer(3280);
+ public Object testField3281 = new Integer(3281);
+ public Object testField3282 = new Integer(3282);
+ public Object testField3283 = new Integer(3283);
+ public Object testField3284 = new Integer(3284);
+ public Object testField3285 = new Integer(3285);
+ public Object testField3286 = new Integer(3286);
+ public Object testField3287 = new Integer(3287);
+ public Object testField3288 = new Integer(3288);
+ public Object testField3289 = new Integer(3289);
+ public Object testField3290 = new Integer(3290);
+ public Object testField3291 = new Integer(3291);
+ public Object testField3292 = new Integer(3292);
+ public Object testField3293 = new Integer(3293);
+ public Object testField3294 = new Integer(3294);
+ public Object testField3295 = new Integer(3295);
+ public Object testField3296 = new Integer(3296);
+ public Object testField3297 = new Integer(3297);
+ public Object testField3298 = new Integer(3298);
+ public Object testField3299 = new Integer(3299);
+ public Object testField3300 = new Integer(3300);
+ public Object testField3301 = new Integer(3301);
+ public Object testField3302 = new Integer(3302);
+ public Object testField3303 = new Integer(3303);
+ public Object testField3304 = new Integer(3304);
+ public Object testField3305 = new Integer(3305);
+ public Object testField3306 = new Integer(3306);
+ public Object testField3307 = new Integer(3307);
+ public Object testField3308 = new Integer(3308);
+ public Object testField3309 = new Integer(3309);
+ public Object testField3310 = new Integer(3310);
+ public Object testField3311 = new Integer(3311);
+ public Object testField3312 = new Integer(3312);
+ public Object testField3313 = new Integer(3313);
+ public Object testField3314 = new Integer(3314);
+ public Object testField3315 = new Integer(3315);
+ public Object testField3316 = new Integer(3316);
+ public Object testField3317 = new Integer(3317);
+ public Object testField3318 = new Integer(3318);
+ public Object testField3319 = new Integer(3319);
+ public Object testField3320 = new Integer(3320);
+ public Object testField3321 = new Integer(3321);
+ public Object testField3322 = new Integer(3322);
+ public Object testField3323 = new Integer(3323);
+ public Object testField3324 = new Integer(3324);
+ public Object testField3325 = new Integer(3325);
+ public Object testField3326 = new Integer(3326);
+ public Object testField3327 = new Integer(3327);
+ public Object testField3328 = new Integer(3328);
+ public Object testField3329 = new Integer(3329);
+ public Object testField3330 = new Integer(3330);
+ public Object testField3331 = new Integer(3331);
+ public Object testField3332 = new Integer(3332);
+ public Object testField3333 = new Integer(3333);
+ public Object testField3334 = new Integer(3334);
+ public Object testField3335 = new Integer(3335);
+ public Object testField3336 = new Integer(3336);
+ public Object testField3337 = new Integer(3337);
+ public Object testField3338 = new Integer(3338);
+ public Object testField3339 = new Integer(3339);
+ public Object testField3340 = new Integer(3340);
+ public Object testField3341 = new Integer(3341);
+ public Object testField3342 = new Integer(3342);
+ public Object testField3343 = new Integer(3343);
+ public Object testField3344 = new Integer(3344);
+ public Object testField3345 = new Integer(3345);
+ public Object testField3346 = new Integer(3346);
+ public Object testField3347 = new Integer(3347);
+ public Object testField3348 = new Integer(3348);
+ public Object testField3349 = new Integer(3349);
+ public Object testField3350 = new Integer(3350);
+ public Object testField3351 = new Integer(3351);
+ public Object testField3352 = new Integer(3352);
+ public Object testField3353 = new Integer(3353);
+ public Object testField3354 = new Integer(3354);
+ public Object testField3355 = new Integer(3355);
+ public Object testField3356 = new Integer(3356);
+ public Object testField3357 = new Integer(3357);
+ public Object testField3358 = new Integer(3358);
+ public Object testField3359 = new Integer(3359);
+ public Object testField3360 = new Integer(3360);
+ public Object testField3361 = new Integer(3361);
+ public Object testField3362 = new Integer(3362);
+ public Object testField3363 = new Integer(3363);
+ public Object testField3364 = new Integer(3364);
+ public Object testField3365 = new Integer(3365);
+ public Object testField3366 = new Integer(3366);
+ public Object testField3367 = new Integer(3367);
+ public Object testField3368 = new Integer(3368);
+ public Object testField3369 = new Integer(3369);
+ public Object testField3370 = new Integer(3370);
+ public Object testField3371 = new Integer(3371);
+ public Object testField3372 = new Integer(3372);
+ public Object testField3373 = new Integer(3373);
+ public Object testField3374 = new Integer(3374);
+ public Object testField3375 = new Integer(3375);
+ public Object testField3376 = new Integer(3376);
+ public Object testField3377 = new Integer(3377);
+ public Object testField3378 = new Integer(3378);
+ public Object testField3379 = new Integer(3379);
+ public Object testField3380 = new Integer(3380);
+ public Object testField3381 = new Integer(3381);
+ public Object testField3382 = new Integer(3382);
+ public Object testField3383 = new Integer(3383);
+ public Object testField3384 = new Integer(3384);
+ public Object testField3385 = new Integer(3385);
+ public Object testField3386 = new Integer(3386);
+ public Object testField3387 = new Integer(3387);
+ public Object testField3388 = new Integer(3388);
+ public Object testField3389 = new Integer(3389);
+ public Object testField3390 = new Integer(3390);
+ public Object testField3391 = new Integer(3391);
+ public Object testField3392 = new Integer(3392);
+ public Object testField3393 = new Integer(3393);
+ public Object testField3394 = new Integer(3394);
+ public Object testField3395 = new Integer(3395);
+ public Object testField3396 = new Integer(3396);
+ public Object testField3397 = new Integer(3397);
+ public Object testField3398 = new Integer(3398);
+ public Object testField3399 = new Integer(3399);
+ public Object testField3400 = new Integer(3400);
+ public Object testField3401 = new Integer(3401);
+ public Object testField3402 = new Integer(3402);
+ public Object testField3403 = new Integer(3403);
+ public Object testField3404 = new Integer(3404);
+ public Object testField3405 = new Integer(3405);
+ public Object testField3406 = new Integer(3406);
+ public Object testField3407 = new Integer(3407);
+ public Object testField3408 = new Integer(3408);
+ public Object testField3409 = new Integer(3409);
+ public Object testField3410 = new Integer(3410);
+ public Object testField3411 = new Integer(3411);
+ public Object testField3412 = new Integer(3412);
+ public Object testField3413 = new Integer(3413);
+ public Object testField3414 = new Integer(3414);
+ public Object testField3415 = new Integer(3415);
+ public Object testField3416 = new Integer(3416);
+ public Object testField3417 = new Integer(3417);
+ public Object testField3418 = new Integer(3418);
+ public Object testField3419 = new Integer(3419);
+ public Object testField3420 = new Integer(3420);
+ public Object testField3421 = new Integer(3421);
+ public Object testField3422 = new Integer(3422);
+ public Object testField3423 = new Integer(3423);
+ public Object testField3424 = new Integer(3424);
+ public Object testField3425 = new Integer(3425);
+ public Object testField3426 = new Integer(3426);
+ public Object testField3427 = new Integer(3427);
+ public Object testField3428 = new Integer(3428);
+ public Object testField3429 = new Integer(3429);
+ public Object testField3430 = new Integer(3430);
+ public Object testField3431 = new Integer(3431);
+ public Object testField3432 = new Integer(3432);
+ public Object testField3433 = new Integer(3433);
+ public Object testField3434 = new Integer(3434);
+ public Object testField3435 = new Integer(3435);
+ public Object testField3436 = new Integer(3436);
+ public Object testField3437 = new Integer(3437);
+ public Object testField3438 = new Integer(3438);
+ public Object testField3439 = new Integer(3439);
+ public Object testField3440 = new Integer(3440);
+ public Object testField3441 = new Integer(3441);
+ public Object testField3442 = new Integer(3442);
+ public Object testField3443 = new Integer(3443);
+ public Object testField3444 = new Integer(3444);
+ public Object testField3445 = new Integer(3445);
+ public Object testField3446 = new Integer(3446);
+ public Object testField3447 = new Integer(3447);
+ public Object testField3448 = new Integer(3448);
+ public Object testField3449 = new Integer(3449);
+ public Object testField3450 = new Integer(3450);
+ public Object testField3451 = new Integer(3451);
+ public Object testField3452 = new Integer(3452);
+ public Object testField3453 = new Integer(3453);
+ public Object testField3454 = new Integer(3454);
+ public Object testField3455 = new Integer(3455);
+ public Object testField3456 = new Integer(3456);
+ public Object testField3457 = new Integer(3457);
+ public Object testField3458 = new Integer(3458);
+ public Object testField3459 = new Integer(3459);
+ public Object testField3460 = new Integer(3460);
+ public Object testField3461 = new Integer(3461);
+ public Object testField3462 = new Integer(3462);
+ public Object testField3463 = new Integer(3463);
+ public Object testField3464 = new Integer(3464);
+ public Object testField3465 = new Integer(3465);
+ public Object testField3466 = new Integer(3466);
+ public Object testField3467 = new Integer(3467);
+ public Object testField3468 = new Integer(3468);
+ public Object testField3469 = new Integer(3469);
+ public Object testField3470 = new Integer(3470);
+ public Object testField3471 = new Integer(3471);
+ public Object testField3472 = new Integer(3472);
+ public Object testField3473 = new Integer(3473);
+ public Object testField3474 = new Integer(3474);
+ public Object testField3475 = new Integer(3475);
+ public Object testField3476 = new Integer(3476);
+ public Object testField3477 = new Integer(3477);
+ public Object testField3478 = new Integer(3478);
+ public Object testField3479 = new Integer(3479);
+ public Object testField3480 = new Integer(3480);
+ public Object testField3481 = new Integer(3481);
+ public Object testField3482 = new Integer(3482);
+ public Object testField3483 = new Integer(3483);
+ public Object testField3484 = new Integer(3484);
+ public Object testField3485 = new Integer(3485);
+ public Object testField3486 = new Integer(3486);
+ public Object testField3487 = new Integer(3487);
+ public Object testField3488 = new Integer(3488);
+ public Object testField3489 = new Integer(3489);
+ public Object testField3490 = new Integer(3490);
+ public Object testField3491 = new Integer(3491);
+ public Object testField3492 = new Integer(3492);
+ public Object testField3493 = new Integer(3493);
+ public Object testField3494 = new Integer(3494);
+ public Object testField3495 = new Integer(3495);
+ public Object testField3496 = new Integer(3496);
+ public Object testField3497 = new Integer(3497);
+ public Object testField3498 = new Integer(3498);
+ public Object testField3499 = new Integer(3499);
+ public Object testField3500 = new Integer(3500);
+ public Object testField3501 = new Integer(3501);
+ public Object testField3502 = new Integer(3502);
+ public Object testField3503 = new Integer(3503);
+ public Object testField3504 = new Integer(3504);
+ public Object testField3505 = new Integer(3505);
+ public Object testField3506 = new Integer(3506);
+ public Object testField3507 = new Integer(3507);
+ public Object testField3508 = new Integer(3508);
+ public Object testField3509 = new Integer(3509);
+ public Object testField3510 = new Integer(3510);
+ public Object testField3511 = new Integer(3511);
+ public Object testField3512 = new Integer(3512);
+ public Object testField3513 = new Integer(3513);
+ public Object testField3514 = new Integer(3514);
+ public Object testField3515 = new Integer(3515);
+ public Object testField3516 = new Integer(3516);
+ public Object testField3517 = new Integer(3517);
+ public Object testField3518 = new Integer(3518);
+ public Object testField3519 = new Integer(3519);
+ public Object testField3520 = new Integer(3520);
+ public Object testField3521 = new Integer(3521);
+ public Object testField3522 = new Integer(3522);
+ public Object testField3523 = new Integer(3523);
+ public Object testField3524 = new Integer(3524);
+ public Object testField3525 = new Integer(3525);
+ public Object testField3526 = new Integer(3526);
+ public Object testField3527 = new Integer(3527);
+ public Object testField3528 = new Integer(3528);
+ public Object testField3529 = new Integer(3529);
+ public Object testField3530 = new Integer(3530);
+ public Object testField3531 = new Integer(3531);
+ public Object testField3532 = new Integer(3532);
+ public Object testField3533 = new Integer(3533);
+ public Object testField3534 = new Integer(3534);
+ public Object testField3535 = new Integer(3535);
+ public Object testField3536 = new Integer(3536);
+ public Object testField3537 = new Integer(3537);
+ public Object testField3538 = new Integer(3538);
+ public Object testField3539 = new Integer(3539);
+ public Object testField3540 = new Integer(3540);
+ public Object testField3541 = new Integer(3541);
+ public Object testField3542 = new Integer(3542);
+ public Object testField3543 = new Integer(3543);
+ public Object testField3544 = new Integer(3544);
+ public Object testField3545 = new Integer(3545);
+ public Object testField3546 = new Integer(3546);
+ public Object testField3547 = new Integer(3547);
+ public Object testField3548 = new Integer(3548);
+ public Object testField3549 = new Integer(3549);
+ public Object testField3550 = new Integer(3550);
+ public Object testField3551 = new Integer(3551);
+ public Object testField3552 = new Integer(3552);
+ public Object testField3553 = new Integer(3553);
+ public Object testField3554 = new Integer(3554);
+ public Object testField3555 = new Integer(3555);
+ public Object testField3556 = new Integer(3556);
+ public Object testField3557 = new Integer(3557);
+ public Object testField3558 = new Integer(3558);
+ public Object testField3559 = new Integer(3559);
+ public Object testField3560 = new Integer(3560);
+ public Object testField3561 = new Integer(3561);
+ public Object testField3562 = new Integer(3562);
+ public Object testField3563 = new Integer(3563);
+ public Object testField3564 = new Integer(3564);
+ public Object testField3565 = new Integer(3565);
+ public Object testField3566 = new Integer(3566);
+ public Object testField3567 = new Integer(3567);
+ public Object testField3568 = new Integer(3568);
+ public Object testField3569 = new Integer(3569);
+ public Object testField3570 = new Integer(3570);
+ public Object testField3571 = new Integer(3571);
+ public Object testField3572 = new Integer(3572);
+ public Object testField3573 = new Integer(3573);
+ public Object testField3574 = new Integer(3574);
+ public Object testField3575 = new Integer(3575);
+ public Object testField3576 = new Integer(3576);
+ public Object testField3577 = new Integer(3577);
+ public Object testField3578 = new Integer(3578);
+ public Object testField3579 = new Integer(3579);
+ public Object testField3580 = new Integer(3580);
+ public Object testField3581 = new Integer(3581);
+ public Object testField3582 = new Integer(3582);
+ public Object testField3583 = new Integer(3583);
+ public Object testField3584 = new Integer(3584);
+ public Object testField3585 = new Integer(3585);
+ public Object testField3586 = new Integer(3586);
+ public Object testField3587 = new Integer(3587);
+ public Object testField3588 = new Integer(3588);
+ public Object testField3589 = new Integer(3589);
+ public Object testField3590 = new Integer(3590);
+ public Object testField3591 = new Integer(3591);
+ public Object testField3592 = new Integer(3592);
+ public Object testField3593 = new Integer(3593);
+ public Object testField3594 = new Integer(3594);
+ public Object testField3595 = new Integer(3595);
+ public Object testField3596 = new Integer(3596);
+ public Object testField3597 = new Integer(3597);
+ public Object testField3598 = new Integer(3598);
+ public Object testField3599 = new Integer(3599);
+ public Object testField3600 = new Integer(3600);
+ public Object testField3601 = new Integer(3601);
+ public Object testField3602 = new Integer(3602);
+ public Object testField3603 = new Integer(3603);
+ public Object testField3604 = new Integer(3604);
+ public Object testField3605 = new Integer(3605);
+ public Object testField3606 = new Integer(3606);
+ public Object testField3607 = new Integer(3607);
+ public Object testField3608 = new Integer(3608);
+ public Object testField3609 = new Integer(3609);
+ public Object testField3610 = new Integer(3610);
+ public Object testField3611 = new Integer(3611);
+ public Object testField3612 = new Integer(3612);
+ public Object testField3613 = new Integer(3613);
+ public Object testField3614 = new Integer(3614);
+ public Object testField3615 = new Integer(3615);
+ public Object testField3616 = new Integer(3616);
+ public Object testField3617 = new Integer(3617);
+ public Object testField3618 = new Integer(3618);
+ public Object testField3619 = new Integer(3619);
+ public Object testField3620 = new Integer(3620);
+ public Object testField3621 = new Integer(3621);
+ public Object testField3622 = new Integer(3622);
+ public Object testField3623 = new Integer(3623);
+ public Object testField3624 = new Integer(3624);
+ public Object testField3625 = new Integer(3625);
+ public Object testField3626 = new Integer(3626);
+ public Object testField3627 = new Integer(3627);
+ public Object testField3628 = new Integer(3628);
+ public Object testField3629 = new Integer(3629);
+ public Object testField3630 = new Integer(3630);
+ public Object testField3631 = new Integer(3631);
+ public Object testField3632 = new Integer(3632);
+ public Object testField3633 = new Integer(3633);
+ public Object testField3634 = new Integer(3634);
+ public Object testField3635 = new Integer(3635);
+ public Object testField3636 = new Integer(3636);
+ public Object testField3637 = new Integer(3637);
+ public Object testField3638 = new Integer(3638);
+ public Object testField3639 = new Integer(3639);
+ public Object testField3640 = new Integer(3640);
+ public Object testField3641 = new Integer(3641);
+ public Object testField3642 = new Integer(3642);
+ public Object testField3643 = new Integer(3643);
+ public Object testField3644 = new Integer(3644);
+ public Object testField3645 = new Integer(3645);
+ public Object testField3646 = new Integer(3646);
+ public Object testField3647 = new Integer(3647);
+ public Object testField3648 = new Integer(3648);
+ public Object testField3649 = new Integer(3649);
+ public Object testField3650 = new Integer(3650);
+ public Object testField3651 = new Integer(3651);
+ public Object testField3652 = new Integer(3652);
+ public Object testField3653 = new Integer(3653);
+ public Object testField3654 = new Integer(3654);
+ public Object testField3655 = new Integer(3655);
+ public Object testField3656 = new Integer(3656);
+ public Object testField3657 = new Integer(3657);
+ public Object testField3658 = new Integer(3658);
+ public Object testField3659 = new Integer(3659);
+ public Object testField3660 = new Integer(3660);
+ public Object testField3661 = new Integer(3661);
+ public Object testField3662 = new Integer(3662);
+ public Object testField3663 = new Integer(3663);
+ public Object testField3664 = new Integer(3664);
+ public Object testField3665 = new Integer(3665);
+ public Object testField3666 = new Integer(3666);
+ public Object testField3667 = new Integer(3667);
+ public Object testField3668 = new Integer(3668);
+ public Object testField3669 = new Integer(3669);
+ public Object testField3670 = new Integer(3670);
+ public Object testField3671 = new Integer(3671);
+ public Object testField3672 = new Integer(3672);
+ public Object testField3673 = new Integer(3673);
+ public Object testField3674 = new Integer(3674);
+ public Object testField3675 = new Integer(3675);
+ public Object testField3676 = new Integer(3676);
+ public Object testField3677 = new Integer(3677);
+ public Object testField3678 = new Integer(3678);
+ public Object testField3679 = new Integer(3679);
+ public Object testField3680 = new Integer(3680);
+ public Object testField3681 = new Integer(3681);
+ public Object testField3682 = new Integer(3682);
+ public Object testField3683 = new Integer(3683);
+ public Object testField3684 = new Integer(3684);
+ public Object testField3685 = new Integer(3685);
+ public Object testField3686 = new Integer(3686);
+ public Object testField3687 = new Integer(3687);
+ public Object testField3688 = new Integer(3688);
+ public Object testField3689 = new Integer(3689);
+ public Object testField3690 = new Integer(3690);
+ public Object testField3691 = new Integer(3691);
+ public Object testField3692 = new Integer(3692);
+ public Object testField3693 = new Integer(3693);
+ public Object testField3694 = new Integer(3694);
+ public Object testField3695 = new Integer(3695);
+ public Object testField3696 = new Integer(3696);
+ public Object testField3697 = new Integer(3697);
+ public Object testField3698 = new Integer(3698);
+ public Object testField3699 = new Integer(3699);
+ public Object testField3700 = new Integer(3700);
+ public Object testField3701 = new Integer(3701);
+ public Object testField3702 = new Integer(3702);
+ public Object testField3703 = new Integer(3703);
+ public Object testField3704 = new Integer(3704);
+ public Object testField3705 = new Integer(3705);
+ public Object testField3706 = new Integer(3706);
+ public Object testField3707 = new Integer(3707);
+ public Object testField3708 = new Integer(3708);
+ public Object testField3709 = new Integer(3709);
+ public Object testField3710 = new Integer(3710);
+ public Object testField3711 = new Integer(3711);
+ public Object testField3712 = new Integer(3712);
+ public Object testField3713 = new Integer(3713);
+ public Object testField3714 = new Integer(3714);
+ public Object testField3715 = new Integer(3715);
+ public Object testField3716 = new Integer(3716);
+ public Object testField3717 = new Integer(3717);
+ public Object testField3718 = new Integer(3718);
+ public Object testField3719 = new Integer(3719);
+ public Object testField3720 = new Integer(3720);
+ public Object testField3721 = new Integer(3721);
+ public Object testField3722 = new Integer(3722);
+ public Object testField3723 = new Integer(3723);
+ public Object testField3724 = new Integer(3724);
+ public Object testField3725 = new Integer(3725);
+ public Object testField3726 = new Integer(3726);
+ public Object testField3727 = new Integer(3727);
+ public Object testField3728 = new Integer(3728);
+ public Object testField3729 = new Integer(3729);
+ public Object testField3730 = new Integer(3730);
+ public Object testField3731 = new Integer(3731);
+ public Object testField3732 = new Integer(3732);
+ public Object testField3733 = new Integer(3733);
+ public Object testField3734 = new Integer(3734);
+ public Object testField3735 = new Integer(3735);
+ public Object testField3736 = new Integer(3736);
+ public Object testField3737 = new Integer(3737);
+ public Object testField3738 = new Integer(3738);
+ public Object testField3739 = new Integer(3739);
+ public Object testField3740 = new Integer(3740);
+ public Object testField3741 = new Integer(3741);
+ public Object testField3742 = new Integer(3742);
+ public Object testField3743 = new Integer(3743);
+ public Object testField3744 = new Integer(3744);
+ public Object testField3745 = new Integer(3745);
+ public Object testField3746 = new Integer(3746);
+ public Object testField3747 = new Integer(3747);
+ public Object testField3748 = new Integer(3748);
+ public Object testField3749 = new Integer(3749);
+ public Object testField3750 = new Integer(3750);
+ public Object testField3751 = new Integer(3751);
+ public Object testField3752 = new Integer(3752);
+ public Object testField3753 = new Integer(3753);
+ public Object testField3754 = new Integer(3754);
+ public Object testField3755 = new Integer(3755);
+ public Object testField3756 = new Integer(3756);
+ public Object testField3757 = new Integer(3757);
+ public Object testField3758 = new Integer(3758);
+ public Object testField3759 = new Integer(3759);
+ public Object testField3760 = new Integer(3760);
+ public Object testField3761 = new Integer(3761);
+ public Object testField3762 = new Integer(3762);
+ public Object testField3763 = new Integer(3763);
+ public Object testField3764 = new Integer(3764);
+ public Object testField3765 = new Integer(3765);
+ public Object testField3766 = new Integer(3766);
+ public Object testField3767 = new Integer(3767);
+ public Object testField3768 = new Integer(3768);
+ public Object testField3769 = new Integer(3769);
+ public Object testField3770 = new Integer(3770);
+ public Object testField3771 = new Integer(3771);
+ public Object testField3772 = new Integer(3772);
+ public Object testField3773 = new Integer(3773);
+ public Object testField3774 = new Integer(3774);
+ public Object testField3775 = new Integer(3775);
+ public Object testField3776 = new Integer(3776);
+ public Object testField3777 = new Integer(3777);
+ public Object testField3778 = new Integer(3778);
+ public Object testField3779 = new Integer(3779);
+ public Object testField3780 = new Integer(3780);
+ public Object testField3781 = new Integer(3781);
+ public Object testField3782 = new Integer(3782);
+ public Object testField3783 = new Integer(3783);
+ public Object testField3784 = new Integer(3784);
+ public Object testField3785 = new Integer(3785);
+ public Object testField3786 = new Integer(3786);
+ public Object testField3787 = new Integer(3787);
+ public Object testField3788 = new Integer(3788);
+ public Object testField3789 = new Integer(3789);
+ public Object testField3790 = new Integer(3790);
+ public Object testField3791 = new Integer(3791);
+ public Object testField3792 = new Integer(3792);
+ public Object testField3793 = new Integer(3793);
+ public Object testField3794 = new Integer(3794);
+ public Object testField3795 = new Integer(3795);
+ public Object testField3796 = new Integer(3796);
+ public Object testField3797 = new Integer(3797);
+ public Object testField3798 = new Integer(3798);
+ public Object testField3799 = new Integer(3799);
+ public Object testField3800 = new Integer(3800);
+ public Object testField3801 = new Integer(3801);
+ public Object testField3802 = new Integer(3802);
+ public Object testField3803 = new Integer(3803);
+ public Object testField3804 = new Integer(3804);
+ public Object testField3805 = new Integer(3805);
+ public Object testField3806 = new Integer(3806);
+ public Object testField3807 = new Integer(3807);
+ public Object testField3808 = new Integer(3808);
+ public Object testField3809 = new Integer(3809);
+ public Object testField3810 = new Integer(3810);
+ public Object testField3811 = new Integer(3811);
+ public Object testField3812 = new Integer(3812);
+ public Object testField3813 = new Integer(3813);
+ public Object testField3814 = new Integer(3814);
+ public Object testField3815 = new Integer(3815);
+ public Object testField3816 = new Integer(3816);
+ public Object testField3817 = new Integer(3817);
+ public Object testField3818 = new Integer(3818);
+ public Object testField3819 = new Integer(3819);
+ public Object testField3820 = new Integer(3820);
+ public Object testField3821 = new Integer(3821);
+ public Object testField3822 = new Integer(3822);
+ public Object testField3823 = new Integer(3823);
+ public Object testField3824 = new Integer(3824);
+ public Object testField3825 = new Integer(3825);
+ public Object testField3826 = new Integer(3826);
+ public Object testField3827 = new Integer(3827);
+ public Object testField3828 = new Integer(3828);
+ public Object testField3829 = new Integer(3829);
+ public Object testField3830 = new Integer(3830);
+ public Object testField3831 = new Integer(3831);
+ public Object testField3832 = new Integer(3832);
+ public Object testField3833 = new Integer(3833);
+ public Object testField3834 = new Integer(3834);
+ public Object testField3835 = new Integer(3835);
+ public Object testField3836 = new Integer(3836);
+ public Object testField3837 = new Integer(3837);
+ public Object testField3838 = new Integer(3838);
+ public Object testField3839 = new Integer(3839);
+ public Object testField3840 = new Integer(3840);
+ public Object testField3841 = new Integer(3841);
+ public Object testField3842 = new Integer(3842);
+ public Object testField3843 = new Integer(3843);
+ public Object testField3844 = new Integer(3844);
+ public Object testField3845 = new Integer(3845);
+ public Object testField3846 = new Integer(3846);
+ public Object testField3847 = new Integer(3847);
+ public Object testField3848 = new Integer(3848);
+ public Object testField3849 = new Integer(3849);
+ public Object testField3850 = new Integer(3850);
+ public Object testField3851 = new Integer(3851);
+ public Object testField3852 = new Integer(3852);
+ public Object testField3853 = new Integer(3853);
+ public Object testField3854 = new Integer(3854);
+ public Object testField3855 = new Integer(3855);
+ public Object testField3856 = new Integer(3856);
+ public Object testField3857 = new Integer(3857);
+ public Object testField3858 = new Integer(3858);
+ public Object testField3859 = new Integer(3859);
+ public Object testField3860 = new Integer(3860);
+ public Object testField3861 = new Integer(3861);
+ public Object testField3862 = new Integer(3862);
+ public Object testField3863 = new Integer(3863);
+ public Object testField3864 = new Integer(3864);
+ public Object testField3865 = new Integer(3865);
+ public Object testField3866 = new Integer(3866);
+ public Object testField3867 = new Integer(3867);
+ public Object testField3868 = new Integer(3868);
+ public Object testField3869 = new Integer(3869);
+ public Object testField3870 = new Integer(3870);
+ public Object testField3871 = new Integer(3871);
+ public Object testField3872 = new Integer(3872);
+ public Object testField3873 = new Integer(3873);
+ public Object testField3874 = new Integer(3874);
+ public Object testField3875 = new Integer(3875);
+ public Object testField3876 = new Integer(3876);
+ public Object testField3877 = new Integer(3877);
+ public Object testField3878 = new Integer(3878);
+ public Object testField3879 = new Integer(3879);
+ public Object testField3880 = new Integer(3880);
+ public Object testField3881 = new Integer(3881);
+ public Object testField3882 = new Integer(3882);
+ public Object testField3883 = new Integer(3883);
+ public Object testField3884 = new Integer(3884);
+ public Object testField3885 = new Integer(3885);
+ public Object testField3886 = new Integer(3886);
+ public Object testField3887 = new Integer(3887);
+ public Object testField3888 = new Integer(3888);
+ public Object testField3889 = new Integer(3889);
+ public Object testField3890 = new Integer(3890);
+ public Object testField3891 = new Integer(3891);
+ public Object testField3892 = new Integer(3892);
+ public Object testField3893 = new Integer(3893);
+ public Object testField3894 = new Integer(3894);
+ public Object testField3895 = new Integer(3895);
+ public Object testField3896 = new Integer(3896);
+ public Object testField3897 = new Integer(3897);
+ public Object testField3898 = new Integer(3898);
+ public Object testField3899 = new Integer(3899);
+ public Object testField3900 = new Integer(3900);
+ public Object testField3901 = new Integer(3901);
+ public Object testField3902 = new Integer(3902);
+ public Object testField3903 = new Integer(3903);
+ public Object testField3904 = new Integer(3904);
+ public Object testField3905 = new Integer(3905);
+ public Object testField3906 = new Integer(3906);
+ public Object testField3907 = new Integer(3907);
+ public Object testField3908 = new Integer(3908);
+ public Object testField3909 = new Integer(3909);
+ public Object testField3910 = new Integer(3910);
+ public Object testField3911 = new Integer(3911);
+ public Object testField3912 = new Integer(3912);
+ public Object testField3913 = new Integer(3913);
+ public Object testField3914 = new Integer(3914);
+ public Object testField3915 = new Integer(3915);
+ public Object testField3916 = new Integer(3916);
+ public Object testField3917 = new Integer(3917);
+ public Object testField3918 = new Integer(3918);
+ public Object testField3919 = new Integer(3919);
+ public Object testField3920 = new Integer(3920);
+ public Object testField3921 = new Integer(3921);
+ public Object testField3922 = new Integer(3922);
+ public Object testField3923 = new Integer(3923);
+ public Object testField3924 = new Integer(3924);
+ public Object testField3925 = new Integer(3925);
+ public Object testField3926 = new Integer(3926);
+ public Object testField3927 = new Integer(3927);
+ public Object testField3928 = new Integer(3928);
+ public Object testField3929 = new Integer(3929);
+ public Object testField3930 = new Integer(3930);
+ public Object testField3931 = new Integer(3931);
+ public Object testField3932 = new Integer(3932);
+ public Object testField3933 = new Integer(3933);
+ public Object testField3934 = new Integer(3934);
+ public Object testField3935 = new Integer(3935);
+ public Object testField3936 = new Integer(3936);
+ public Object testField3937 = new Integer(3937);
+ public Object testField3938 = new Integer(3938);
+ public Object testField3939 = new Integer(3939);
+ public Object testField3940 = new Integer(3940);
+ public Object testField3941 = new Integer(3941);
+ public Object testField3942 = new Integer(3942);
+ public Object testField3943 = new Integer(3943);
+ public Object testField3944 = new Integer(3944);
+ public Object testField3945 = new Integer(3945);
+ public Object testField3946 = new Integer(3946);
+ public Object testField3947 = new Integer(3947);
+ public Object testField3948 = new Integer(3948);
+ public Object testField3949 = new Integer(3949);
+ public Object testField3950 = new Integer(3950);
+ public Object testField3951 = new Integer(3951);
+ public Object testField3952 = new Integer(3952);
+ public Object testField3953 = new Integer(3953);
+ public Object testField3954 = new Integer(3954);
+ public Object testField3955 = new Integer(3955);
+ public Object testField3956 = new Integer(3956);
+ public Object testField3957 = new Integer(3957);
+ public Object testField3958 = new Integer(3958);
+ public Object testField3959 = new Integer(3959);
+ public Object testField3960 = new Integer(3960);
+ public Object testField3961 = new Integer(3961);
+ public Object testField3962 = new Integer(3962);
+ public Object testField3963 = new Integer(3963);
+ public Object testField3964 = new Integer(3964);
+ public Object testField3965 = new Integer(3965);
+ public Object testField3966 = new Integer(3966);
+ public Object testField3967 = new Integer(3967);
+ public Object testField3968 = new Integer(3968);
+ public Object testField3969 = new Integer(3969);
+ public Object testField3970 = new Integer(3970);
+ public Object testField3971 = new Integer(3971);
+ public Object testField3972 = new Integer(3972);
+ public Object testField3973 = new Integer(3973);
+ public Object testField3974 = new Integer(3974);
+ public Object testField3975 = new Integer(3975);
+ public Object testField3976 = new Integer(3976);
+ public Object testField3977 = new Integer(3977);
+ public Object testField3978 = new Integer(3978);
+ public Object testField3979 = new Integer(3979);
+ public Object testField3980 = new Integer(3980);
+ public Object testField3981 = new Integer(3981);
+ public Object testField3982 = new Integer(3982);
+ public Object testField3983 = new Integer(3983);
+ public Object testField3984 = new Integer(3984);
+ public Object testField3985 = new Integer(3985);
+ public Object testField3986 = new Integer(3986);
+ public Object testField3987 = new Integer(3987);
+ public Object testField3988 = new Integer(3988);
+ public Object testField3989 = new Integer(3989);
+ public Object testField3990 = new Integer(3990);
+ public Object testField3991 = new Integer(3991);
+ public Object testField3992 = new Integer(3992);
+ public Object testField3993 = new Integer(3993);
+ public Object testField3994 = new Integer(3994);
+ public Object testField3995 = new Integer(3995);
+ public Object testField3996 = new Integer(3996);
+ public Object testField3997 = new Integer(3997);
+ public Object testField3998 = new Integer(3998);
+ public Object testField3999 = new Integer(3999);
+}
diff --git a/test/623-checker-loop-regressions/src/Main.java b/test/623-checker-loop-regressions/src/Main.java
index 182c07d..2b30986 100644
--- a/test/623-checker-loop-regressions/src/Main.java
+++ b/test/623-checker-loop-regressions/src/Main.java
@@ -280,6 +280,36 @@
}
}
+ // If vectorized, string encoding should be dealt with.
+ private static void string2Bytes(char[] a, String b) {
+ int min = Math.min(a.length, b.length());
+ for (int i = 0; i < min; i++) {
+ a[i] = b.charAt(i);
+ }
+ }
+
+ // A strange function that does not inline.
+ private static void $noinline$foo(boolean x, int n) {
+ if (n < 0)
+ throw new Error("oh no");
+ if (n > 100) {
+ $noinline$foo(!x, n - 1);
+ $noinline$foo(!x, n - 2);
+ $noinline$foo(!x, n - 3);
+ $noinline$foo(!x, n - 4);
+ }
+ }
+
+ // A loop with environment uses of x (the terminating condition). As exposed by bug
+ // b/37247891, the loop can be unrolled, but should handle the (unlikely, but clearly
+ // not impossible) environment uses of the terminating condition in a correct manner.
+ private static void envUsesInCond() {
+ boolean x = false;
+ for (int i = 0; !(x = i >= 1); i++) {
+ $noinline$foo(true, i);
+ }
+ }
+
public static void main(String[] args) {
expectEquals(10, earlyExitFirst(-1));
for (int i = 0; i <= 10; i++) {
@@ -354,6 +384,15 @@
expectEquals(2, yy[i]);
}
+ char[] aa = new char[23];
+ String bb = "hello world how are you";
+ string2Bytes(aa, bb);
+ for (int i = 0; i < aa.length; i++) {
+ expectEquals(aa[i], bb.charAt(i));
+ }
+
+ envUsesInCond();
+
System.out.println("passed");
}
diff --git a/test/640-checker-double-simd/src/Main.java b/test/640-checker-double-simd/src/Main.java
index 43f65f1..0d4f87a 100644
--- a/test/640-checker-double-simd/src/Main.java
+++ b/test/640-checker-double-simd/src/Main.java
@@ -32,8 +32,10 @@
/// CHECK-DAG: ArraySet loop:<<Loop>> outer_loop:none
//
/// CHECK-START-ARM64: void Main.add(double) loop_optimization (after)
- //
- // TODO: fill in when supported
+ /// CHECK-DAG: Phi loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: VecLoad loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecAdd loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
static void add(double x) {
for (int i = 0; i < 128; i++)
a[i] += x;
@@ -45,8 +47,10 @@
/// CHECK-DAG: ArraySet loop:<<Loop>> outer_loop:none
//
/// CHECK-START-ARM64: void Main.sub(double) loop_optimization (after)
- //
- // TODO: fill in when supported
+ /// CHECK-DAG: Phi loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: VecLoad loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecSub loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
static void sub(double x) {
for (int i = 0; i < 128; i++)
a[i] -= x;
@@ -58,8 +62,10 @@
/// CHECK-DAG: ArraySet loop:<<Loop>> outer_loop:none
//
/// CHECK-START-ARM64: void Main.mul(double) loop_optimization (after)
- //
- // TODO: fill in when supported
+ /// CHECK-DAG: Phi loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: VecLoad loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecMul loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
static void mul(double x) {
for (int i = 0; i < 128; i++)
a[i] *= x;
@@ -71,8 +77,10 @@
/// CHECK-DAG: ArraySet loop:<<Loop>> outer_loop:none
//
/// CHECK-START-ARM64: void Main.div(double) loop_optimization (after)
- //
- // TODO: fill in when supported
+ /// CHECK-DAG: Phi loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: VecLoad loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecDiv loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
static void div(double x) {
for (int i = 0; i < 128; i++)
a[i] /= x;
@@ -84,8 +92,10 @@
/// CHECK-DAG: ArraySet loop:<<Loop>> outer_loop:none
//
/// CHECK-START-ARM64: void Main.neg() loop_optimization (after)
- //
- // TODO: fill in when supported
+ /// CHECK-DAG: Phi loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: VecLoad loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecNeg loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
static void neg() {
for (int i = 0; i < 128; i++)
a[i] = -a[i];
@@ -97,8 +107,10 @@
/// CHECK-DAG: ArraySet loop:<<Loop>> outer_loop:none
//
/// CHECK-START-ARM64: void Main.abs() loop_optimization (after)
- //
- // TODO: fill in when supported
+ /// CHECK-DAG: Phi loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: VecLoad loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecAbs loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
static void abs() {
for (int i = 0; i < 128; i++)
a[i] = Math.abs(a[i]);
diff --git a/test/640-checker-long-simd/src/Main.java b/test/640-checker-long-simd/src/Main.java
index 90a2e76..5641182 100644
--- a/test/640-checker-long-simd/src/Main.java
+++ b/test/640-checker-long-simd/src/Main.java
@@ -31,8 +31,10 @@
/// CHECK-DAG: ArraySet loop:<<Loop>> outer_loop:none
//
/// CHECK-START-ARM64: void Main.add(long) loop_optimization (after)
- //
- // TODO: fill in when supported
+ /// CHECK-DAG: Phi loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: VecLoad loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecAdd loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
static void add(long x) {
for (int i = 0; i < 128; i++)
a[i] += x;
@@ -44,8 +46,10 @@
/// CHECK-DAG: ArraySet loop:<<Loop>> outer_loop:none
//
/// CHECK-START-ARM64: void Main.sub(long) loop_optimization (after)
- //
- // TODO: fill in when supported
+ /// CHECK-DAG: Phi loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: VecLoad loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecSub loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
static void sub(long x) {
for (int i = 0; i < 128; i++)
a[i] -= x;
@@ -56,9 +60,9 @@
/// CHECK-DAG: ArrayGet loop:<<Loop>> outer_loop:none
/// CHECK-DAG: ArraySet loop:<<Loop>> outer_loop:none
//
+ // Not supported for longs.
/// CHECK-START-ARM64: void Main.mul(long) loop_optimization (after)
- //
- // TODO: fill in when supported
+ /// CHECK-NOT: VecMul
static void mul(long x) {
for (int i = 0; i < 128; i++)
a[i] *= x;
@@ -84,8 +88,10 @@
/// CHECK-DAG: ArraySet loop:<<Loop>> outer_loop:none
//
/// CHECK-START-ARM64: void Main.neg() loop_optimization (after)
- //
- // TODO: fill in when supported
+ /// CHECK-DAG: Phi loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: VecLoad loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecNeg loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
static void neg() {
for (int i = 0; i < 128; i++)
a[i] = -a[i];
@@ -97,8 +103,10 @@
/// CHECK-DAG: ArraySet loop:<<Loop>> outer_loop:none
//
/// CHECK-START-ARM64: void Main.not() loop_optimization (after)
- //
- // TODO: fill in when supported
+ /// CHECK-DAG: Phi loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: VecLoad loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecNot loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
static void not() {
for (int i = 0; i < 128; i++)
a[i] = ~a[i];
@@ -110,8 +118,10 @@
/// CHECK-DAG: ArraySet loop:<<Loop>> outer_loop:none
//
/// CHECK-START-ARM64: void Main.shl4() loop_optimization (after)
- //
- // TODO: fill in when supported
+ /// CHECK-DAG: Phi loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: VecLoad loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecShl loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
static void shl4() {
for (int i = 0; i < 128; i++)
a[i] <<= 4;
diff --git a/test/646-checker-arraycopy-large-cst-pos/expected.txt b/test/646-checker-arraycopy-large-cst-pos/expected.txt
new file mode 100644
index 0000000..b0aad4d
--- /dev/null
+++ b/test/646-checker-arraycopy-large-cst-pos/expected.txt
@@ -0,0 +1 @@
+passed
diff --git a/test/646-checker-arraycopy-large-cst-pos/info.txt b/test/646-checker-arraycopy-large-cst-pos/info.txt
new file mode 100644
index 0000000..9ac21db
--- /dev/null
+++ b/test/646-checker-arraycopy-large-cst-pos/info.txt
@@ -0,0 +1,4 @@
+Regression test for an issue with a depleted VIXL scratch register
+pool during the emission of a SystemArrayCopy intrinsic with a large
+constant destination position, on ARM64, with read barriers
+(b/37256530).
diff --git a/test/646-checker-arraycopy-large-cst-pos/src/Main.java b/test/646-checker-arraycopy-large-cst-pos/src/Main.java
new file mode 100644
index 0000000..3144fc1
--- /dev/null
+++ b/test/646-checker-arraycopy-large-cst-pos/src/Main.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+public class Main {
+
+ public static void main(String[] args) {
+ System.out.println("passed");
+ }
+
+ /// CHECK-START-ARM64: void Main.test() disassembly (after)
+ /// CHECK: InvokeStaticOrDirect method_name:java.lang.System.arraycopy intrinsic:SystemArrayCopy
+ /// CHECK-NOT: blr
+ /// CHECK: ReturnVoid
+
+ static void test() {
+ Object[] src = new Object[1024];
+ Object[] dst = new Object[2048];
+ // The length of the copied data must not be too large (smaller
+ // than kSystemArrayCopyThreshold = 128) for the call to
+ // System.arraycopy to be intrinsified.
+ System.arraycopy(src, 0, dst, 1024, 64);
+ }
+
+}
diff --git a/test/646-checker-long-const-to-int/expected.txt b/test/646-checker-long-const-to-int/expected.txt
new file mode 100644
index 0000000..9abd696
--- /dev/null
+++ b/test/646-checker-long-const-to-int/expected.txt
@@ -0,0 +1 @@
+305419896
diff --git a/test/646-checker-long-const-to-int/info.txt b/test/646-checker-long-const-to-int/info.txt
new file mode 100644
index 0000000..3f560c3
--- /dev/null
+++ b/test/646-checker-long-const-to-int/info.txt
@@ -0,0 +1 @@
+Regression test for bogus checks that a constant input of long-to-int conversion fits into int.
diff --git a/test/646-checker-long-const-to-int/src/Main.java b/test/646-checker-long-const-to-int/src/Main.java
new file mode 100644
index 0000000..85738dc
--- /dev/null
+++ b/test/646-checker-long-const-to-int/src/Main.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+public class Main {
+
+ public static void main(String[] args) {
+ System.out.println(test());
+ }
+
+ public static long testField = 0;
+ public static long longField0 = 0;
+ public static long longField1 = 0;
+ public static long longField2 = 0;
+ public static long longField3 = 0;
+ public static long longField4 = 0;
+ public static long longField5 = 0;
+ public static long longField6 = 0;
+ public static long longField7 = 0;
+
+ /// CHECK-START-ARM: int Main.test() register (after)
+ /// CHECK: TypeConversion locations:[#-8690466096623102344]->{{.*}}
+ public static int test() {
+ // To avoid constant folding TypeConversion(const), hide the constant in a field.
+ // We do not run constant folding after load-store-elimination.
+ testField = 0x8765432112345678L;
+ long value = testField;
+ // Now, the `value` is in a register because of the store but we need
+ // a constant location to trigger the bug, so load a bunch of other fields.
+ long l0 = longField0;
+ long l1 = longField1;
+ long l2 = longField2;
+ long l3 = longField3;
+ long l4 = longField4;
+ long l5 = longField5;
+ long l6 = longField6;
+ long l7 = longField7;
+ if (l0 != 0 || l1 != 0 || l2 != 0 || l3 != 0 || l4 != 0 || l5 != 0 || l6 != 0 || l7 != 0) {
+ throw new Error();
+ }
+ // Do the conversion from constant location.
+ return (int)value;
+ }
+}
diff --git a/test/902-hello-transformation/src/Main.java b/test/902-hello-transformation/src/Main.java
index ed8a500..af49cb4 100644
--- a/test/902-hello-transformation/src/Main.java
+++ b/test/902-hello-transformation/src/Main.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,53 +14,8 @@
* limitations under the License.
*/
-import java.util.Base64;
public class Main {
-
- /**
- * base64 encoded class/dex file for
- * class Transform {
- * public void sayHi() {
- * System.out.println("Goodbye");
- * }
- * }
- */
- private static final byte[] CLASS_BYTES = Base64.getDecoder().decode(
- "yv66vgAAADQAHAoABgAOCQAPABAIABEKABIAEwcAFAcAFQEABjxpbml0PgEAAygpVgEABENvZGUB" +
- "AA9MaW5lTnVtYmVyVGFibGUBAAVzYXlIaQEAClNvdXJjZUZpbGUBAA5UcmFuc2Zvcm0uamF2YQwA" +
- "BwAIBwAWDAAXABgBAAdHb29kYnllBwAZDAAaABsBAAlUcmFuc2Zvcm0BABBqYXZhL2xhbmcvT2Jq" +
- "ZWN0AQAQamF2YS9sYW5nL1N5c3RlbQEAA291dAEAFUxqYXZhL2lvL1ByaW50U3RyZWFtOwEAE2ph" +
- "dmEvaW8vUHJpbnRTdHJlYW0BAAdwcmludGxuAQAVKExqYXZhL2xhbmcvU3RyaW5nOylWACAABQAG" +
- "AAAAAAACAAAABwAIAAEACQAAAB0AAQABAAAABSq3AAGxAAAAAQAKAAAABgABAAAAEQABAAsACAAB" +
- "AAkAAAAlAAIAAQAAAAmyAAISA7YABLEAAAABAAoAAAAKAAIAAAATAAgAFAABAAwAAAACAA0=");
- private static final byte[] DEX_BYTES = Base64.getDecoder().decode(
- "ZGV4CjAzNQCLXSBQ5FiS3f16krSYZFF8xYZtFVp0GRXMAgAAcAAAAHhWNBIAAAAAAAAAACwCAAAO" +
- "AAAAcAAAAAYAAACoAAAAAgAAAMAAAAABAAAA2AAAAAQAAADgAAAAAQAAAAABAACsAQAAIAEAAGIB" +
- "AABqAQAAcwEAAIABAACXAQAAqwEAAL8BAADTAQAA4wEAAOYBAADqAQAA/gEAAAMCAAAMAgAAAgAA" +
- "AAMAAAAEAAAABQAAAAYAAAAIAAAACAAAAAUAAAAAAAAACQAAAAUAAABcAQAABAABAAsAAAAAAAAA" +
- "AAAAAAAAAAANAAAAAQABAAwAAAACAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAHAAAAAAAAAB4CAAAA" +
- "AAAAAQABAAEAAAATAgAABAAAAHAQAwAAAA4AAwABAAIAAAAYAgAACQAAAGIAAAAbAQEAAABuIAIA" +
- "EAAOAAAAAQAAAAMABjxpbml0PgAHR29vZGJ5ZQALTFRyYW5zZm9ybTsAFUxqYXZhL2lvL1ByaW50" +
- "U3RyZWFtOwASTGphdmEvbGFuZy9PYmplY3Q7ABJMamF2YS9sYW5nL1N0cmluZzsAEkxqYXZhL2xh" +
- "bmcvU3lzdGVtOwAOVHJhbnNmb3JtLmphdmEAAVYAAlZMABJlbWl0dGVyOiBqYWNrLTMuMzYAA291" +
- "dAAHcHJpbnRsbgAFc2F5SGkAEQAHDgATAAcOhQAAAAEBAICABKACAQG4Ag0AAAAAAAAAAQAAAAAA" +
- "AAABAAAADgAAAHAAAAACAAAABgAAAKgAAAADAAAAAgAAAMAAAAAEAAAAAQAAANgAAAAFAAAABAAA" +
- "AOAAAAAGAAAAAQAAAAABAAABIAAAAgAAACABAAABEAAAAQAAAFwBAAACIAAADgAAAGIBAAADIAAA" +
- "AgAAABMCAAAAIAAAAQAAAB4CAAAAEAAAAQAAACwCAAA=");
-
- public static void main(String[] args) {
- art.Main.bindAgentJNIForClass(Main.class);
- doTest(new Transform());
+ public static void main(String[] args) throws Exception {
+ art.Test902.run();
}
-
- public static void doTest(Transform t) {
- t.sayHi();
- doCommonClassRedefinition(Transform.class, CLASS_BYTES, DEX_BYTES);
- t.sayHi();
- }
-
- // Transforms the class
- private static native void doCommonClassRedefinition(Class<?> target,
- byte[] class_file,
- byte[] dex_file);
}
diff --git a/test/902-hello-transformation/src/Transform.java b/test/902-hello-transformation/src/Transform.java
deleted file mode 100644
index 8e8af35..0000000
--- a/test/902-hello-transformation/src/Transform.java
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-class Transform {
- public void sayHi() {
- // Use lower 'h' to make sure the string will have a different string id
- // than the transformation (the transformation code is the same except
- // the actual printed String, which was making the test inacurately passing
- // in JIT mode when loading the string from the dex cache, as the string ids
- // of the two different strings were the same).
- // We know the string ids will be different because lexicographically:
- // "Goodbye" < "LTransform;" < "hello".
- System.out.println("hello");
- }
-}
diff --git a/test/902-hello-transformation/src/art/Redefinition.java b/test/902-hello-transformation/src/art/Redefinition.java
new file mode 100644
index 0000000..0350ab4
--- /dev/null
+++ b/test/902-hello-transformation/src/art/Redefinition.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package art;
+
+import java.util.ArrayList;
+// Common Redefinition functions. Placed here for use by CTS
+public class Redefinition {
+ // Bind native functions.
+ static {
+ Main.bindAgentJNIForClass(Redefinition.class);
+ }
+
+ public static final class CommonClassDefinition {
+ public final Class<?> target;
+ public final byte[] class_file_bytes;
+ public final byte[] dex_file_bytes;
+
+ public CommonClassDefinition(Class<?> target, byte[] class_file_bytes, byte[] dex_file_bytes) {
+ this.target = target;
+ this.class_file_bytes = class_file_bytes;
+ this.dex_file_bytes = dex_file_bytes;
+ }
+ }
+
+ // A set of possible test configurations. Test should set this if they need to.
+ // This must be kept in sync with the defines in ti-agent/common_helper.cc
+ public static enum Config {
+ COMMON_REDEFINE(0),
+ COMMON_RETRANSFORM(1),
+ COMMON_TRANSFORM(2);
+
+ private final int val;
+ private Config(int val) {
+ this.val = val;
+ }
+ }
+
+ public static void setTestConfiguration(Config type) {
+ nativeSetTestConfiguration(type.val);
+ }
+
+ private static native void nativeSetTestConfiguration(int type);
+
+ // Transforms the class
+ public static native void doCommonClassRedefinition(Class<?> target,
+ byte[] classfile,
+ byte[] dexfile);
+
+ public static void doMultiClassRedefinition(CommonClassDefinition... defs) {
+ ArrayList<Class<?>> classes = new ArrayList<>();
+ ArrayList<byte[]> class_files = new ArrayList<>();
+ ArrayList<byte[]> dex_files = new ArrayList<>();
+
+ for (CommonClassDefinition d : defs) {
+ classes.add(d.target);
+ class_files.add(d.class_file_bytes);
+ dex_files.add(d.dex_file_bytes);
+ }
+ doCommonMultiClassRedefinition(classes.toArray(new Class<?>[0]),
+ class_files.toArray(new byte[0][]),
+ dex_files.toArray(new byte[0][]));
+ }
+
+ public static void addMultiTransformationResults(CommonClassDefinition... defs) {
+ for (CommonClassDefinition d : defs) {
+ addCommonTransformationResult(d.target.getCanonicalName(),
+ d.class_file_bytes,
+ d.dex_file_bytes);
+ }
+ }
+
+ public static native void doCommonMultiClassRedefinition(Class<?>[] targets,
+ byte[][] classfiles,
+ byte[][] dexfiles);
+ public static native void doCommonClassRetransformation(Class<?>... target);
+ public static native void setPopRetransformations(boolean pop);
+ public static native void popTransformationFor(String name);
+ public static native void enableCommonRetransformation(boolean enable);
+ public static native void addCommonTransformationResult(String target_name,
+ byte[] class_bytes,
+ byte[] dex_bytes);
+}
diff --git a/test/902-hello-transformation/src/art/Test902.java b/test/902-hello-transformation/src/art/Test902.java
new file mode 100644
index 0000000..e95558f
--- /dev/null
+++ b/test/902-hello-transformation/src/art/Test902.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package art;
+
+import java.util.Base64;
+public class Test902 {
+
+ static class Transform {
+ public void sayHi() {
+ // Use lower 'h' to make sure the string will have a different string id
+ // than the transformation (the transformation code is the same except
+ // the actual printed String, which was making the test inacurately passing
+ // in JIT mode when loading the string from the dex cache, as the string ids
+ // of the two different strings were the same).
+ // We know the string ids will be different because lexicographically:
+ // "Goodbye" < "LTransform;" < "hello".
+ System.out.println("hello");
+ }
+ }
+
+ /**
+ * base64 encoded class/dex file for
+ * class Transform {
+ * public void sayHi() {
+ * System.out.println("Goodbye");
+ * }
+ * }
+ */
+ private static final byte[] CLASS_BYTES = Base64.getDecoder().decode(
+ "yv66vgAAADQAIAoABgAOCQAPABAIABEKABIAEwcAFQcAGAEABjxpbml0PgEAAygpVgEABENvZGUB" +
+ "AA9MaW5lTnVtYmVyVGFibGUBAAVzYXlIaQEAClNvdXJjZUZpbGUBAAxUZXN0OTAyLmphdmEMAAcA" +
+ "CAcAGQwAGgAbAQAHR29vZGJ5ZQcAHAwAHQAeBwAfAQAVYXJ0L1Rlc3Q5MDIkVHJhbnNmb3JtAQAJ" +
+ "VHJhbnNmb3JtAQAMSW5uZXJDbGFzc2VzAQAQamF2YS9sYW5nL09iamVjdAEAEGphdmEvbGFuZy9T" +
+ "eXN0ZW0BAANvdXQBABVMamF2YS9pby9QcmludFN0cmVhbTsBABNqYXZhL2lvL1ByaW50U3RyZWFt" +
+ "AQAHcHJpbnRsbgEAFShMamF2YS9sYW5nL1N0cmluZzspVgEAC2FydC9UZXN0OTAyACAABQAGAAAA" +
+ "AAACAAAABwAIAAEACQAAAB0AAQABAAAABSq3AAGxAAAAAQAKAAAABgABAAAAJQABAAsACAABAAkA" +
+ "AAAlAAIAAQAAAAmyAAISA7YABLEAAAABAAoAAAAKAAIAAAAnAAgAKAACAAwAAAACAA0AFwAAAAoA" +
+ "AQAFABQAFgAI");
+ private static final byte[] DEX_BYTES = Base64.getDecoder().decode(
+ "ZGV4CjAzNQCpghS3AAAAAAAAAAAAAAAAAAAAAAAAAAC4AwAAcAAAAHhWNBIAAAAAAAAAAPQCAAAU" +
+ "AAAAcAAAAAkAAADAAAAAAgAAAOQAAAABAAAA/AAAAAQAAAAEAQAAAQAAACQBAAB0AgAARAEAAEQB" +
+ "AABMAQAAVQEAAG4BAAB9AQAAoQEAAMEBAADYAQAA7AEAAAACAAAUAgAAIgIAAC0CAAAwAgAANAIA" +
+ "AEECAABHAgAATAIAAFUCAABcAgAAAgAAAAMAAAAEAAAABQAAAAYAAAAHAAAACAAAAAkAAAAMAAAA" +
+ "DAAAAAgAAAAAAAAADQAAAAgAAABkAgAABwAEABAAAAAAAAAAAAAAAAAAAAASAAAABAABABEAAAAF" +
+ "AAAAAAAAAAAAAAAAAAAABQAAAAAAAAAKAAAA5AIAALgCAAAAAAAABjxpbml0PgAHR29vZGJ5ZQAX" +
+ "TGFydC9UZXN0OTAyJFRyYW5zZm9ybTsADUxhcnQvVGVzdDkwMjsAIkxkYWx2aWsvYW5ub3RhdGlv" +
+ "bi9FbmNsb3NpbmdDbGFzczsAHkxkYWx2aWsvYW5ub3RhdGlvbi9Jbm5lckNsYXNzOwAVTGphdmEv" +
+ "aW8vUHJpbnRTdHJlYW07ABJMamF2YS9sYW5nL09iamVjdDsAEkxqYXZhL2xhbmcvU3RyaW5nOwAS" +
+ "TGphdmEvbGFuZy9TeXN0ZW07AAxUZXN0OTAyLmphdmEACVRyYW5zZm9ybQABVgACVkwAC2FjY2Vz" +
+ "c0ZsYWdzAARuYW1lAANvdXQAB3ByaW50bG4ABXNheUhpAAV2YWx1ZQAAAQAAAAYAAAAlAAcOACcA" +
+ "Bw4BCA8AAAAAAQABAAEAAABsAgAABAAAAHAQAwAAAA4AAwABAAIAAABxAgAACQAAAGIAAAAbAQEA" +
+ "AABuIAIAEAAOAAAAAAABAQCAgAT8BAEBlAUAAAICARMYAQIDAg4ECA8XCwACAAAAyAIAAM4CAADY" +
+ "AgAAAAAAAAAAAAAAAAAAEAAAAAAAAAABAAAAAAAAAAEAAAAUAAAAcAAAAAIAAAAJAAAAwAAAAAMA" +
+ "AAACAAAA5AAAAAQAAAABAAAA/AAAAAUAAAAEAAAABAEAAAYAAAABAAAAJAEAAAIgAAAUAAAARAEA" +
+ "AAEQAAABAAAAZAIAAAMgAAACAAAAbAIAAAEgAAACAAAAfAIAAAAgAAABAAAAuAIAAAQgAAACAAAA" +
+ "yAIAAAMQAAABAAAA2AIAAAYgAAABAAAA5AIAAAAQAAABAAAA9AIAAA==");
+
+ public static void run() {
+ Redefinition.setTestConfiguration(Redefinition.Config.COMMON_REDEFINE);
+ doTest(new Transform());
+ }
+
+ public static void doTest(Transform t) {
+ t.sayHi();
+ Redefinition.doCommonClassRedefinition(Transform.class, CLASS_BYTES, DEX_BYTES);
+ t.sayHi();
+ }
+}
diff --git a/test/904-object-allocation/expected.txt b/test/904-object-allocation/expected.txt
index 371d2b7..fdec470 100644
--- a/test/904-object-allocation/expected.txt
+++ b/test/904-object-allocation/expected.txt
@@ -1,8 +1,8 @@
-ObjectAllocated type java.lang.Object/java.lang.Object size 8
-ObjectAllocated type java.lang.Integer/java.lang.Integer size 16
-ObjectAllocated type java.lang.Short/java.lang.Short size 16
+[]
+[ObjectAllocated type java.lang.Object/java.lang.Object size 8, ObjectAllocated type java.lang.Integer/java.lang.Integer size 16, ObjectAllocated type java.lang.Short/java.lang.Short size 16]
Tracking on same thread
-ObjectAllocated type java.lang.Double/java.lang.Double size 16
+[ObjectAllocated type java.lang.Double/java.lang.Double size 16]
Tracking on same thread, not disabling tracking
-ObjectAllocated type java.lang.Double/java.lang.Double size 16
+[ObjectAllocated type java.lang.Double/java.lang.Double size 16]
Tracking on different thread
+[]
diff --git a/test/904-object-allocation/src/art/Test904.java b/test/904-object-allocation/src/art/Test904.java
index 31e0c8c..70a4b98 100644
--- a/test/904-object-allocation/src/art/Test904.java
+++ b/test/904-object-allocation/src/art/Test904.java
@@ -17,6 +17,7 @@
package art;
import java.util.ArrayList;
+import java.util.Arrays;
public class Test904 {
public static void run() throws Exception {
@@ -48,6 +49,8 @@
// Enable actual logging callback.
setupObjectAllocCallback(true);
+ System.out.println(Arrays.toString(getTrackingEventMessages()));
+
enableAllocationTracking(null, true);
l.add(new Object());
@@ -65,16 +68,19 @@
l.add(new Byte((byte)0));
+ System.out.println(Arrays.toString(getTrackingEventMessages()));
System.out.println("Tracking on same thread");
testThread(l, true, true);
l.add(new Byte((byte)0));
+ System.out.println(Arrays.toString(getTrackingEventMessages()));
System.out.println("Tracking on same thread, not disabling tracking");
testThread(l, true, false);
+ System.out.println(Arrays.toString(getTrackingEventMessages()));
System.out.println("Tracking on different thread");
testThread(l, false, true);
@@ -84,6 +90,9 @@
// Disable actual logging callback and re-enable tracking, so we can keep the event enabled and
// check that shutdown works correctly.
setupObjectAllocCallback(false);
+
+ System.out.println(Arrays.toString(getTrackingEventMessages()));
+
enableAllocationTracking(null, true);
}
@@ -142,4 +151,5 @@
private static native void setupObjectAllocCallback(boolean enable);
private static native void enableAllocationTracking(Thread thread, boolean enable);
+ private static native String[] getTrackingEventMessages();
}
diff --git a/test/904-object-allocation/tracking.cc b/test/904-object-allocation/tracking.cc
index 8de350b..20b5328 100644
--- a/test/904-object-allocation/tracking.cc
+++ b/test/904-object-allocation/tracking.cc
@@ -15,11 +15,13 @@
*/
#include <iostream>
+#include <mutex>
#include <pthread.h>
#include <stdio.h>
#include <vector>
#include "android-base/logging.h"
+#include "android-base/stringprintf.h"
#include "jni.h"
#include "jvmti.h"
#include "scoped_local_ref.h"
@@ -41,6 +43,9 @@
return utf_chars.c_str();
}
+static std::mutex gEventsMutex;
+static std::vector<std::string> gEvents;
+
static void JNICALL ObjectAllocated(jvmtiEnv* ti_env ATTRIBUTE_UNUSED,
JNIEnv* jni_env,
jthread thread ATTRIBUTE_UNUSED,
@@ -51,10 +56,11 @@
ScopedLocalRef<jclass> object_klass2(jni_env, jni_env->GetObjectClass(object));
std::string object_klass_descriptor2 = GetClassName(jni_env, object_klass2.get());
- printf("ObjectAllocated type %s/%s size %zu\n",
- object_klass_descriptor.c_str(),
- object_klass_descriptor2.c_str(),
- static_cast<size_t>(size));
+ std::lock_guard<std::mutex> guard(gEventsMutex);
+ gEvents.push_back(android::base::StringPrintf("ObjectAllocated type %s/%s size %zu",
+ object_klass_descriptor.c_str(),
+ object_klass_descriptor2.c_str(),
+ static_cast<size_t>(size)));
}
extern "C" JNIEXPORT void JNICALL Java_art_Test904_setupObjectAllocCallback(
@@ -76,5 +82,18 @@
JvmtiErrorToException(env, jvmti_env, ret);
}
+extern "C" JNIEXPORT jobjectArray JNICALL Java_art_Test904_getTrackingEventMessages(
+ JNIEnv* env, jclass Main_klass ATTRIBUTE_UNUSED) {
+ std::lock_guard<std::mutex> guard(gEventsMutex);
+ jobjectArray ret = CreateObjectArray(env,
+ static_cast<jint>(gEvents.size()),
+ "java/lang/String",
+ [&](jint i) {
+ return env->NewStringUTF(gEvents[i].c_str());
+ });
+ gEvents.clear();
+ return ret;
+}
+
} // namespace Test904ObjectAllocation
} // namespace art
diff --git a/test/910-methods/expected.txt b/test/910-methods/expected.txt
index 8e6b6e7..c14c6c4 100644
--- a/test/910-methods/expected.txt
+++ b/test/910-methods/expected.txt
@@ -32,19 +32,19 @@
interface java.util.List
1025
Max locals: 0
-Argument size: 0
-Location start: 0
-Location end: 0
+Argument size: 2
+Location start: -1
+Location end: -1
Is native: false
Is obsolete: false
Is synthetic: false
[run, ()V, null]
-class $Proxy0
+class $Proxy20
17
Max locals: 0
-Argument size: 0
-Location start: 0
-Location end: 0
+Argument size: 1
+Location start: -1
+Location end: -1
Is native: false
Is obsolete: false
Is synthetic: false
diff --git a/test/910-methods/src/art/Test910.java b/test/910-methods/src/art/Test910.java
index b3490e9..aa6d13a 100644
--- a/test/910-methods/src/art/Test910.java
+++ b/test/910-methods/src/art/Test910.java
@@ -39,17 +39,6 @@
testMethod(findSyntheticMethod(), NestedSynthetic.class, false);
}
- private static Class<?> proxyClass = null;
-
- private static Class<?> getProxyClass() throws Exception {
- if (proxyClass != null) {
- return proxyClass;
- }
-
- proxyClass = Proxy.getProxyClass(Main.class.getClassLoader(), new Class[] { Runnable.class });
- return proxyClass;
- }
-
private static void testMethod(String className, String methodName, Class<?>... types)
throws Exception {
Class<?> base = Class.forName(className);
@@ -145,4 +134,62 @@
private static native boolean isMethodNative(Method m);
private static native boolean isMethodObsolete(Method m);
private static native boolean isMethodSynthetic(Method m);
+
+ // We need this machinery for a consistent proxy name. Names of proxy classes include a
+ // unique number (derived by counting). This means that a simple call to getProxyClass
+ // depends on the test environment.
+ //
+ // To work around this, we assume that at most twenty proxies have been created before
+ // the test is run, and canonicalize on "$Proxy20". We add infrastructure to create
+ // as many proxy classes but cycling through subsets of the test-provided interfaces
+ // I0...I4.
+ //
+ //
+ // (This is made under the judgment that we do not want to have proxy-specific behavior
+ // for testMethod.)
+
+ private static Class<?> proxyClass = null;
+
+ private static Class<?> getProxyClass() throws Exception {
+ if (proxyClass != null) {
+ return proxyClass;
+ }
+
+ for (int i = 1; i <= 21; i++) {
+ proxyClass = createProxyClass(i);
+ String name = proxyClass.getName();
+ if (name.equals("$Proxy20")) {
+ return proxyClass;
+ }
+ }
+ return proxyClass;
+ }
+
+ private static Class<?> createProxyClass(int i) throws Exception {
+ int count = Integer.bitCount(i);
+ Class<?>[] input = new Class<?>[count + 1];
+ input[0] = Runnable.class;
+ int inputIndex = 1;
+ int bitIndex = 0;
+ while (i != 0) {
+ if ((i & 1) != 0) {
+ input[inputIndex++] = Class.forName("art.Test910$I" + bitIndex);
+ }
+ i >>>= 1;
+ bitIndex++;
+ }
+ return Proxy.getProxyClass(Test910.class.getClassLoader(), input);
+ }
+
+ // Need this for the proxy naming.
+ public static interface I0 {
+ }
+ public static interface I1 {
+ }
+ public static interface I2 {
+ }
+ public static interface I3 {
+ }
+ public static interface I4 {
+ }
}
diff --git a/test/913-heaps/expected.txt b/test/913-heaps/expected.txt
index 2a183ee..702b247 100644
--- a/test/913-heaps/expected.txt
+++ b/test/913-heaps/expected.txt
@@ -1,9 +1,10 @@
---
true true
+root@root --(jni-local[id=1,tag=3000,depth=0,method=followReferences])--> 3000@0 [size=136, length=-1]
root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestNonRoot,vreg=13,location= 32])--> 1@1000 [size=16, length=-1]
-root@root --(stack-local[id=1,tag=3000,depth=3,method=doFollowReferencesTest,vreg=1,location= 28])--> 3000@0 [size=132, length=-1]
-root@root --(thread)--> 3000@0 [size=132, length=-1]
-0@0 --(array-element@0)--> 1@1000 [size=16, length=-1]
+root@root --(stack-local[id=1,tag=3000,depth=3,method=doFollowReferencesTest,vreg=1,location= 28])--> 3000@0 [size=136, length=-1]
+root@root --(stack-local[id=1,tag=3000,depth=5,method=run,vreg=2,location= 0])--> 3000@0 [size=136, length=-1]
+root@root --(thread)--> 3000@0 [size=136, length=-1]
1001@0 --(superclass)--> 1000@0 [size=123, length=-1]
1002@0 --(interface)--> 2001@0 [size=124, length=-1]
1002@0 --(superclass)--> 1001@0 [size=123, length=-1]
@@ -14,11 +15,13 @@
2@1000 --(class)--> 1000@0 [size=123, length=-1]
3@1001 --(class)--> 1001@0 [size=123, length=-1]
3@1001 --(field@4)--> 4@1000 [size=16, length=-1]
-3@1001 --(field@5)--> 5@1002 [size=32, length=-1]
+3@1001 --(field@5)--> 5@1002 [size=36, length=-1]
4@1000 --(class)--> 1000@0 [size=123, length=-1]
+500@0 --(array-element@1)--> 2@1000 [size=16, length=-1]
5@1002 --(class)--> 1002@0 [size=123, length=-1]
-5@1002 --(field@8)--> 6@1000 [size=16, length=-1]
-5@1002 --(field@9)--> 1@1000 [size=16, length=-1]
+5@1002 --(field@10)--> 1@1000 [size=16, length=-1]
+5@1002 --(field@8)--> 500@0 [size=20, length=2]
+5@1002 --(field@9)--> 6@1000 [size=16, length=-1]
6@1000 --(class)--> 1000@0 [size=123, length=-1]
---
1001@0 --(superclass)--> 1000@0 [size=123, length=-1]
@@ -31,20 +34,24 @@
2@1000 --(class)--> 1000@0 [size=123, length=-1]
3@1001 --(class)--> 1001@0 [size=123, length=-1]
3@1001 --(field@4)--> 4@1000 [size=16, length=-1]
-3@1001 --(field@5)--> 5@1002 [size=32, length=-1]
+3@1001 --(field@5)--> 5@1002 [size=36, length=-1]
4@1000 --(class)--> 1000@0 [size=123, length=-1]
+500@0 --(array-element@1)--> 2@1000 [size=16, length=-1]
5@1002 --(class)--> 1002@0 [size=123, length=-1]
-5@1002 --(field@8)--> 6@1000 [size=16, length=-1]
-5@1002 --(field@9)--> 1@1000 [size=16, length=-1]
+5@1002 --(field@10)--> 1@1000 [size=16, length=-1]
+5@1002 --(field@8)--> 500@0 [size=20, length=2]
+5@1002 --(field@9)--> 6@1000 [size=16, length=-1]
6@1000 --(class)--> 1000@0 [size=123, length=-1]
---
root@root --(jni-global)--> 1@1000 [size=16, length=-1]
root@root --(jni-local[id=1,tag=3000,depth=0,method=followReferences])--> 1@1000 [size=16, length=-1]
+root@root --(jni-local[id=1,tag=3000,depth=0,method=followReferences])--> 3000@0 [size=136, length=-1]
root@root --(stack-local[id=1,tag=3000,depth=1,method=doFollowReferencesTestImpl,vreg=13,location= 10])--> 1@1000 [size=16, length=-1]
root@root --(stack-local[id=1,tag=3000,depth=1,method=doFollowReferencesTestImpl,vreg=5,location= 10])--> 1@1000 [size=16, length=-1]
root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestRoot,vreg=4,location= 19])--> 1@1000 [size=16, length=-1]
+root@root --(stack-local[id=1,tag=3000,depth=5,method=run,vreg=2,location= 0])--> 3000@0 [size=136, length=-1]
root@root --(thread)--> 1@1000 [size=16, length=-1]
-root@root --(thread)--> 3000@0 [size=132, length=-1]
+root@root --(thread)--> 3000@0 [size=136, length=-1]
1001@0 --(superclass)--> 1000@0 [size=123, length=-1]
1002@0 --(interface)--> 2001@0 [size=124, length=-1]
1002@0 --(superclass)--> 1001@0 [size=123, length=-1]
@@ -55,11 +62,13 @@
2@1000 --(class)--> 1000@0 [size=123, length=-1]
3@1001 --(class)--> 1001@0 [size=123, length=-1]
3@1001 --(field@4)--> 4@1000 [size=16, length=-1]
-3@1001 --(field@5)--> 5@1002 [size=32, length=-1]
+3@1001 --(field@5)--> 5@1002 [size=36, length=-1]
4@1000 --(class)--> 1000@0 [size=123, length=-1]
+500@0 --(array-element@1)--> 2@1000 [size=16, length=-1]
5@1002 --(class)--> 1002@0 [size=123, length=-1]
-5@1002 --(field@8)--> 6@1000 [size=16, length=-1]
-5@1002 --(field@9)--> 1@1000 [size=16, length=-1]
+5@1002 --(field@10)--> 1@1000 [size=16, length=-1]
+5@1002 --(field@8)--> 500@0 [size=20, length=2]
+5@1002 --(field@9)--> 6@1000 [size=16, length=-1]
6@1000 --(class)--> 1000@0 [size=123, length=-1]
---
1001@0 --(superclass)--> 1000@0 [size=123, length=-1]
@@ -72,43 +81,48 @@
2@1000 --(class)--> 1000@0 [size=123, length=-1]
3@1001 --(class)--> 1001@0 [size=123, length=-1]
3@1001 --(field@4)--> 4@1000 [size=16, length=-1]
-3@1001 --(field@5)--> 5@1002 [size=32, length=-1]
+3@1001 --(field@5)--> 5@1002 [size=36, length=-1]
4@1000 --(class)--> 1000@0 [size=123, length=-1]
+500@0 --(array-element@1)--> 2@1000 [size=16, length=-1]
5@1002 --(class)--> 1002@0 [size=123, length=-1]
-5@1002 --(field@8)--> 6@1000 [size=16, length=-1]
-5@1002 --(field@9)--> 1@1000 [size=16, length=-1]
+5@1002 --(field@10)--> 1@1000 [size=16, length=-1]
+5@1002 --(field@8)--> 500@0 [size=20, length=2]
+5@1002 --(field@9)--> 6@1000 [size=16, length=-1]
6@1000 --(class)--> 1000@0 [size=123, length=-1]
---
-root@root --(thread)--> 3000@0 [size=132, length=-1]
+root@root --(thread)--> 3000@0 [size=136, length=-1]
---
3@1001 --(class)--> 1001@0 [size=123, length=-1]
---
-root@root --(thread)--> 3000@0 [size=132, length=-1]
+root@root --(thread)--> 3000@0 [size=136, length=-1]
---
3@1001 --(class)--> 1001@0 [size=123, length=-1]
---
+root@root --(jni-local[id=1,tag=3000,depth=0,method=followReferences])--> 3000@0 [size=136, length=-1]
root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestNonRoot,vreg=13,location= 32])--> 1@1000 [size=16, length=-1]
-root@root --(stack-local[id=1,tag=3000,depth=3,method=doFollowReferencesTest,vreg=1,location= 28])--> 3000@0 [size=132, length=-1]
-root@root --(thread)--> 3000@0 [size=132, length=-1]
-0@0 --(array-element@0)--> 1@1000 [size=16, length=-1]
+root@root --(stack-local[id=1,tag=3000,depth=3,method=doFollowReferencesTest,vreg=1,location= 28])--> 3000@0 [size=136, length=-1]
+root@root --(stack-local[id=1,tag=3000,depth=5,method=run,vreg=2,location= 0])--> 3000@0 [size=136, length=-1]
+root@root --(thread)--> 3000@0 [size=136, length=-1]
---
1001@0 --(superclass)--> 1000@0 [size=123, length=-1]
3@1001 --(class)--> 1001@0 [size=123, length=-1]
3@1001 --(field@4)--> 4@1000 [size=16, length=-1]
-3@1001 --(field@5)--> 5@1002 [size=32, length=-1]
+3@1001 --(field@5)--> 5@1002 [size=36, length=-1]
---
root@root --(jni-global)--> 1@1000 [size=16, length=-1]
root@root --(jni-local[id=1,tag=3000,depth=0,method=followReferences])--> 1@1000 [size=16, length=-1]
+root@root --(jni-local[id=1,tag=3000,depth=0,method=followReferences])--> 3000@0 [size=136, length=-1]
root@root --(stack-local[id=1,tag=3000,depth=1,method=doFollowReferencesTestImpl,vreg=13,location= 10])--> 1@1000 [size=16, length=-1]
root@root --(stack-local[id=1,tag=3000,depth=1,method=doFollowReferencesTestImpl,vreg=5,location= 10])--> 1@1000 [size=16, length=-1]
root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestRoot,vreg=4,location= 19])--> 1@1000 [size=16, length=-1]
+root@root --(stack-local[id=1,tag=3000,depth=5,method=run,vreg=2,location= 0])--> 3000@0 [size=136, length=-1]
root@root --(thread)--> 1@1000 [size=16, length=-1]
-root@root --(thread)--> 3000@0 [size=132, length=-1]
+root@root --(thread)--> 3000@0 [size=136, length=-1]
---
1001@0 --(superclass)--> 1000@0 [size=123, length=-1]
3@1001 --(class)--> 1001@0 [size=123, length=-1]
3@1001 --(field@4)--> 4@1000 [size=16, length=-1]
-3@1001 --(field@5)--> 5@1002 [size=32, length=-1]
+3@1001 --(field@5)--> 5@1002 [size=36, length=-1]
---
[1@0 (32, 'HelloWorld'), 2@0 (16, '')]
2
@@ -148,16 +162,17 @@
10008
--- klass ---
root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestNonRoot,vreg=13,location= 32])--> 1@1000 [size=16, length=-1]
-0@0 --(array-element@0)--> 1@1000 [size=16, length=-1]
1@1000 --(field@2)--> 2@1000 [size=16, length=-1]
3@1001 --(field@4)--> 4@1000 [size=16, length=-1]
-5@1002 --(field@8)--> 6@1000 [size=16, length=-1]
-5@1002 --(field@9)--> 1@1000 [size=16, length=-1]
+500@0 --(array-element@1)--> 2@1000 [size=16, length=-1]
+5@1002 --(field@10)--> 1@1000 [size=16, length=-1]
+5@1002 --(field@9)--> 6@1000 [size=16, length=-1]
---
1@1000 --(field@2)--> 2@1000 [size=16, length=-1]
3@1001 --(field@4)--> 4@1000 [size=16, length=-1]
-5@1002 --(field@8)--> 6@1000 [size=16, length=-1]
-5@1002 --(field@9)--> 1@1000 [size=16, length=-1]
+500@0 --(array-element@1)--> 2@1000 [size=16, length=-1]
+5@1002 --(field@10)--> 1@1000 [size=16, length=-1]
+5@1002 --(field@9)--> 6@1000 [size=16, length=-1]
---
root@root --(jni-global)--> 1@1000 [size=16, length=-1]
root@root --(jni-local[id=1,tag=3000,depth=0,method=followReferences])--> 1@1000 [size=16, length=-1]
@@ -167,13 +182,15 @@
root@root --(thread)--> 1@1000 [size=16, length=-1]
1@1000 --(field@2)--> 2@1000 [size=16, length=-1]
3@1001 --(field@4)--> 4@1000 [size=16, length=-1]
-5@1002 --(field@8)--> 6@1000 [size=16, length=-1]
-5@1002 --(field@9)--> 1@1000 [size=16, length=-1]
+500@0 --(array-element@1)--> 2@1000 [size=16, length=-1]
+5@1002 --(field@10)--> 1@1000 [size=16, length=-1]
+5@1002 --(field@9)--> 6@1000 [size=16, length=-1]
---
1@1000 --(field@2)--> 2@1000 [size=16, length=-1]
3@1001 --(field@4)--> 4@1000 [size=16, length=-1]
-5@1002 --(field@8)--> 6@1000 [size=16, length=-1]
-5@1002 --(field@9)--> 1@1000 [size=16, length=-1]
+500@0 --(array-element@1)--> 2@1000 [size=16, length=-1]
+5@1002 --(field@10)--> 1@1000 [size=16, length=-1]
+5@1002 --(field@9)--> 6@1000 [size=16, length=-1]
---
--- heap_filter ---
---- tagged objects
@@ -182,10 +199,11 @@
---
---
---- untagged objects
+root@root --(jni-local[id=1,tag=3000,depth=0,method=followReferences])--> 3000@0 [size=136, length=-1]
root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestNonRoot,vreg=13,location= 32])--> 1@1000 [size=16, length=-1]
-root@root --(stack-local[id=1,tag=3000,depth=3,method=doFollowReferencesTest,vreg=1,location= 28])--> 3000@0 [size=132, length=-1]
-root@root --(thread)--> 3000@0 [size=132, length=-1]
-0@0 --(array-element@0)--> 1@1000 [size=16, length=-1]
+root@root --(stack-local[id=1,tag=3000,depth=3,method=doFollowReferencesTest,vreg=1,location= 28])--> 3000@0 [size=136, length=-1]
+root@root --(stack-local[id=1,tag=3000,depth=5,method=run,vreg=2,location= 0])--> 3000@0 [size=136, length=-1]
+root@root --(thread)--> 3000@0 [size=136, length=-1]
1001@0 --(superclass)--> 1000@0 [size=123, length=-1]
1002@0 --(interface)--> 2001@0 [size=124, length=-1]
1002@0 --(superclass)--> 1001@0 [size=123, length=-1]
@@ -196,11 +214,13 @@
2@1000 --(class)--> 1000@0 [size=123, length=-1]
3@1001 --(class)--> 1001@0 [size=123, length=-1]
3@1001 --(field@4)--> 4@1000 [size=16, length=-1]
-3@1001 --(field@5)--> 5@1002 [size=32, length=-1]
+3@1001 --(field@5)--> 5@1002 [size=36, length=-1]
4@1000 --(class)--> 1000@0 [size=123, length=-1]
+500@0 --(array-element@1)--> 2@1000 [size=16, length=-1]
5@1002 --(class)--> 1002@0 [size=123, length=-1]
-5@1002 --(field@8)--> 6@1000 [size=16, length=-1]
-5@1002 --(field@9)--> 1@1000 [size=16, length=-1]
+5@1002 --(field@10)--> 1@1000 [size=16, length=-1]
+5@1002 --(field@8)--> 500@0 [size=20, length=2]
+5@1002 --(field@9)--> 6@1000 [size=16, length=-1]
6@1000 --(class)--> 1000@0 [size=123, length=-1]
---
1001@0 --(superclass)--> 1000@0 [size=123, length=-1]
@@ -213,20 +233,24 @@
2@1000 --(class)--> 1000@0 [size=123, length=-1]
3@1001 --(class)--> 1001@0 [size=123, length=-1]
3@1001 --(field@4)--> 4@1000 [size=16, length=-1]
-3@1001 --(field@5)--> 5@1002 [size=32, length=-1]
+3@1001 --(field@5)--> 5@1002 [size=36, length=-1]
4@1000 --(class)--> 1000@0 [size=123, length=-1]
+500@0 --(array-element@1)--> 2@1000 [size=16, length=-1]
5@1002 --(class)--> 1002@0 [size=123, length=-1]
-5@1002 --(field@8)--> 6@1000 [size=16, length=-1]
-5@1002 --(field@9)--> 1@1000 [size=16, length=-1]
+5@1002 --(field@10)--> 1@1000 [size=16, length=-1]
+5@1002 --(field@8)--> 500@0 [size=20, length=2]
+5@1002 --(field@9)--> 6@1000 [size=16, length=-1]
6@1000 --(class)--> 1000@0 [size=123, length=-1]
---
root@root --(jni-global)--> 1@1000 [size=16, length=-1]
root@root --(jni-local[id=1,tag=3000,depth=0,method=followReferences])--> 1@1000 [size=16, length=-1]
+root@root --(jni-local[id=1,tag=3000,depth=0,method=followReferences])--> 3000@0 [size=136, length=-1]
root@root --(stack-local[id=1,tag=3000,depth=1,method=doFollowReferencesTestImpl,vreg=13,location= 10])--> 1@1000 [size=16, length=-1]
root@root --(stack-local[id=1,tag=3000,depth=1,method=doFollowReferencesTestImpl,vreg=5,location= 10])--> 1@1000 [size=16, length=-1]
root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestRoot,vreg=4,location= 19])--> 1@1000 [size=16, length=-1]
+root@root --(stack-local[id=1,tag=3000,depth=5,method=run,vreg=2,location= 0])--> 3000@0 [size=136, length=-1]
root@root --(thread)--> 1@1000 [size=16, length=-1]
-root@root --(thread)--> 3000@0 [size=132, length=-1]
+root@root --(thread)--> 3000@0 [size=136, length=-1]
1001@0 --(superclass)--> 1000@0 [size=123, length=-1]
1002@0 --(interface)--> 2001@0 [size=124, length=-1]
1002@0 --(superclass)--> 1001@0 [size=123, length=-1]
@@ -237,11 +261,13 @@
2@1000 --(class)--> 1000@0 [size=123, length=-1]
3@1001 --(class)--> 1001@0 [size=123, length=-1]
3@1001 --(field@4)--> 4@1000 [size=16, length=-1]
-3@1001 --(field@5)--> 5@1002 [size=32, length=-1]
+3@1001 --(field@5)--> 5@1002 [size=36, length=-1]
4@1000 --(class)--> 1000@0 [size=123, length=-1]
+500@0 --(array-element@1)--> 2@1000 [size=16, length=-1]
5@1002 --(class)--> 1002@0 [size=123, length=-1]
-5@1002 --(field@8)--> 6@1000 [size=16, length=-1]
-5@1002 --(field@9)--> 1@1000 [size=16, length=-1]
+5@1002 --(field@10)--> 1@1000 [size=16, length=-1]
+5@1002 --(field@8)--> 500@0 [size=20, length=2]
+5@1002 --(field@9)--> 6@1000 [size=16, length=-1]
6@1000 --(class)--> 1000@0 [size=123, length=-1]
---
1001@0 --(superclass)--> 1000@0 [size=123, length=-1]
@@ -254,16 +280,20 @@
2@1000 --(class)--> 1000@0 [size=123, length=-1]
3@1001 --(class)--> 1001@0 [size=123, length=-1]
3@1001 --(field@4)--> 4@1000 [size=16, length=-1]
-3@1001 --(field@5)--> 5@1002 [size=32, length=-1]
+3@1001 --(field@5)--> 5@1002 [size=36, length=-1]
4@1000 --(class)--> 1000@0 [size=123, length=-1]
+500@0 --(array-element@1)--> 2@1000 [size=16, length=-1]
5@1002 --(class)--> 1002@0 [size=123, length=-1]
-5@1002 --(field@8)--> 6@1000 [size=16, length=-1]
-5@1002 --(field@9)--> 1@1000 [size=16, length=-1]
+5@1002 --(field@10)--> 1@1000 [size=16, length=-1]
+5@1002 --(field@8)--> 500@0 [size=20, length=2]
+5@1002 --(field@9)--> 6@1000 [size=16, length=-1]
6@1000 --(class)--> 1000@0 [size=123, length=-1]
---
---- tagged classes
-root@root --(stack-local[id=1,tag=3000,depth=3,method=doFollowReferencesTest,vreg=1,location= 28])--> 3000@0 [size=132, length=-1]
-root@root --(thread)--> 3000@0 [size=132, length=-1]
+root@root --(jni-local[id=1,tag=3000,depth=0,method=followReferences])--> 3000@0 [size=136, length=-1]
+root@root --(stack-local[id=1,tag=3000,depth=3,method=doFollowReferencesTest,vreg=1,location= 28])--> 3000@0 [size=136, length=-1]
+root@root --(stack-local[id=1,tag=3000,depth=5,method=run,vreg=2,location= 0])--> 3000@0 [size=136, length=-1]
+root@root --(thread)--> 3000@0 [size=136, length=-1]
1001@0 --(superclass)--> 1000@0 [size=123, length=-1]
1002@0 --(interface)--> 2001@0 [size=124, length=-1]
1002@0 --(superclass)--> 1001@0 [size=123, length=-1]
@@ -273,6 +303,7 @@
3@1001 --(class)--> 1001@0 [size=123, length=-1]
4@1000 --(class)--> 1000@0 [size=123, length=-1]
5@1002 --(class)--> 1002@0 [size=123, length=-1]
+5@1002 --(field@8)--> 500@0 [size=20, length=2]
6@1000 --(class)--> 1000@0 [size=123, length=-1]
---
1001@0 --(superclass)--> 1000@0 [size=123, length=-1]
@@ -284,9 +315,12 @@
3@1001 --(class)--> 1001@0 [size=123, length=-1]
4@1000 --(class)--> 1000@0 [size=123, length=-1]
5@1002 --(class)--> 1002@0 [size=123, length=-1]
+5@1002 --(field@8)--> 500@0 [size=20, length=2]
6@1000 --(class)--> 1000@0 [size=123, length=-1]
---
-root@root --(thread)--> 3000@0 [size=132, length=-1]
+root@root --(jni-local[id=1,tag=3000,depth=0,method=followReferences])--> 3000@0 [size=136, length=-1]
+root@root --(stack-local[id=1,tag=3000,depth=5,method=run,vreg=2,location= 0])--> 3000@0 [size=136, length=-1]
+root@root --(thread)--> 3000@0 [size=136, length=-1]
1001@0 --(superclass)--> 1000@0 [size=123, length=-1]
1002@0 --(interface)--> 2001@0 [size=124, length=-1]
1002@0 --(superclass)--> 1001@0 [size=123, length=-1]
@@ -296,6 +330,7 @@
3@1001 --(class)--> 1001@0 [size=123, length=-1]
4@1000 --(class)--> 1000@0 [size=123, length=-1]
5@1002 --(class)--> 1002@0 [size=123, length=-1]
+5@1002 --(field@8)--> 500@0 [size=20, length=2]
6@1000 --(class)--> 1000@0 [size=123, length=-1]
---
1001@0 --(superclass)--> 1000@0 [size=123, length=-1]
@@ -307,24 +342,26 @@
3@1001 --(class)--> 1001@0 [size=123, length=-1]
4@1000 --(class)--> 1000@0 [size=123, length=-1]
5@1002 --(class)--> 1002@0 [size=123, length=-1]
+5@1002 --(field@8)--> 500@0 [size=20, length=2]
6@1000 --(class)--> 1000@0 [size=123, length=-1]
---
---- untagged classes
root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestNonRoot,vreg=13,location= 32])--> 1@1000 [size=16, length=-1]
-0@0 --(array-element@0)--> 1@1000 [size=16, length=-1]
1@1000 --(field@2)--> 2@1000 [size=16, length=-1]
1@1000 --(field@3)--> 3@1001 [size=24, length=-1]
3@1001 --(field@4)--> 4@1000 [size=16, length=-1]
-3@1001 --(field@5)--> 5@1002 [size=32, length=-1]
-5@1002 --(field@8)--> 6@1000 [size=16, length=-1]
-5@1002 --(field@9)--> 1@1000 [size=16, length=-1]
+3@1001 --(field@5)--> 5@1002 [size=36, length=-1]
+500@0 --(array-element@1)--> 2@1000 [size=16, length=-1]
+5@1002 --(field@10)--> 1@1000 [size=16, length=-1]
+5@1002 --(field@9)--> 6@1000 [size=16, length=-1]
---
1@1000 --(field@2)--> 2@1000 [size=16, length=-1]
1@1000 --(field@3)--> 3@1001 [size=24, length=-1]
3@1001 --(field@4)--> 4@1000 [size=16, length=-1]
-3@1001 --(field@5)--> 5@1002 [size=32, length=-1]
-5@1002 --(field@8)--> 6@1000 [size=16, length=-1]
-5@1002 --(field@9)--> 1@1000 [size=16, length=-1]
+3@1001 --(field@5)--> 5@1002 [size=36, length=-1]
+500@0 --(array-element@1)--> 2@1000 [size=16, length=-1]
+5@1002 --(field@10)--> 1@1000 [size=16, length=-1]
+5@1002 --(field@9)--> 6@1000 [size=16, length=-1]
---
root@root --(jni-global)--> 1@1000 [size=16, length=-1]
root@root --(jni-local[id=1,tag=3000,depth=0,method=followReferences])--> 1@1000 [size=16, length=-1]
@@ -335,14 +372,16 @@
1@1000 --(field@2)--> 2@1000 [size=16, length=-1]
1@1000 --(field@3)--> 3@1001 [size=24, length=-1]
3@1001 --(field@4)--> 4@1000 [size=16, length=-1]
-3@1001 --(field@5)--> 5@1002 [size=32, length=-1]
-5@1002 --(field@8)--> 6@1000 [size=16, length=-1]
-5@1002 --(field@9)--> 1@1000 [size=16, length=-1]
+3@1001 --(field@5)--> 5@1002 [size=36, length=-1]
+500@0 --(array-element@1)--> 2@1000 [size=16, length=-1]
+5@1002 --(field@10)--> 1@1000 [size=16, length=-1]
+5@1002 --(field@9)--> 6@1000 [size=16, length=-1]
---
1@1000 --(field@2)--> 2@1000 [size=16, length=-1]
1@1000 --(field@3)--> 3@1001 [size=24, length=-1]
3@1001 --(field@4)--> 4@1000 [size=16, length=-1]
-3@1001 --(field@5)--> 5@1002 [size=32, length=-1]
-5@1002 --(field@8)--> 6@1000 [size=16, length=-1]
-5@1002 --(field@9)--> 1@1000 [size=16, length=-1]
+3@1001 --(field@5)--> 5@1002 [size=36, length=-1]
+500@0 --(array-element@1)--> 2@1000 [size=16, length=-1]
+5@1002 --(field@10)--> 1@1000 [size=16, length=-1]
+5@1002 --(field@9)--> 6@1000 [size=16, length=-1]
---
diff --git a/test/913-heaps/heaps.cc b/test/913-heaps/heaps.cc
index 6a06b29..19e12ae 100644
--- a/test/913-heaps/heaps.cc
+++ b/test/913-heaps/heaps.cc
@@ -19,40 +19,35 @@
#include <string.h>
#include <iostream>
+#include <sstream>
#include <vector>
#include "android-base/macros.h"
#include "android-base/logging.h"
#include "android-base/stringprintf.h"
-#include "jit/jit.h"
#include "jni.h"
-#include "native_stack_dump.h"
#include "jvmti.h"
-#include "runtime.h"
-#include "scoped_thread_state_change-inl.h"
-#include "thread-inl.h"
-#include "thread_list.h"
// Test infrastructure
#include "jni_helper.h"
#include "jvmti_helper.h"
#include "test_env.h"
+#include "ti_utf.h"
namespace art {
namespace Test913Heaps {
using android::base::StringPrintf;
+#define FINAL final
+#define OVERRIDE override
+#define UNREACHABLE __builtin_unreachable
+
extern "C" JNIEXPORT void JNICALL Java_art_Test913_forceGarbageCollection(
- JNIEnv* env ATTRIBUTE_UNUSED, jclass klass ATTRIBUTE_UNUSED) {
+ JNIEnv* env, jclass klass ATTRIBUTE_UNUSED) {
jvmtiError ret = jvmti_env->ForceGarbageCollection();
- if (ret != JVMTI_ERROR_NONE) {
- char* err;
- jvmti_env->GetErrorName(ret, &err);
- printf("Error forcing a garbage collection: %s\n", err);
- jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(err));
- }
+ JvmtiErrorToException(env, jvmti_env, ret);
}
class IterationConfig {
@@ -92,7 +87,8 @@
user_data);
}
-static bool Run(jint heap_filter,
+static bool Run(JNIEnv* env,
+ jint heap_filter,
jclass klass_filter,
jobject initial_object,
IterationConfig* config) {
@@ -105,14 +101,7 @@
initial_object,
&callbacks,
config);
- if (ret != JVMTI_ERROR_NONE) {
- char* err;
- jvmti_env->GetErrorName(ret, &err);
- printf("Failure running FollowReferences: %s\n", err);
- jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(err));
- return false;
- }
- return true;
+ return !JvmtiErrorToException(env, jvmti_env, ret);
}
extern "C" JNIEXPORT jobjectArray JNICALL Java_art_Test913_followReferences(
@@ -142,6 +131,27 @@
jint length,
void* user_data ATTRIBUTE_UNUSED) OVERRIDE {
jlong tag = *tag_ptr;
+
+ // Ignore any jni-global roots with untagged classes. These can be from the environment,
+ // or the JIT.
+ if (reference_kind == JVMTI_HEAP_REFERENCE_JNI_GLOBAL && class_tag == 0) {
+ return 0;
+ }
+ // Ignore classes (1000-1002@0) for thread objects. These can be held by the JIT.
+ if (reference_kind == JVMTI_HEAP_REFERENCE_THREAD && class_tag == 0 &&
+ (1000 <= *tag_ptr && *tag_ptr <= 1002)) {
+ return 0;
+ }
+ // Ignore stack-locals of untagged threads. That is the environment.
+ if (reference_kind == JVMTI_HEAP_REFERENCE_STACK_LOCAL &&
+ reference_info->stack_local.thread_tag != 3000) {
+ return 0;
+ }
+ // Ignore array elements with an untagged source. These are from the environment.
+ if (reference_kind == JVMTI_HEAP_REFERENCE_ARRAY_ELEMENT && *referrer_tag_ptr == 0) {
+ return 0;
+ }
+
// Only check tagged objects.
if (tag == 0) {
return JVMTI_VISIT_OBJECTS;
@@ -201,10 +211,6 @@
reference_info,
adapted_size,
length));
-
- if (reference_kind == JVMTI_HEAP_REFERENCE_THREAD && *tag_ptr == 1000) {
- DumpStacks();
- }
}
std::vector<std::string> GetLines() const {
@@ -259,9 +265,15 @@
if (info_.jni_local.method != nullptr) {
jvmti_env->GetMethodName(info_.jni_local.method, &name, nullptr, nullptr);
}
+ // Normalize the thread id, as this depends on the number of other threads
+ // and which thread is running the test. Should be:
+ // jlong thread_id = info_.jni_local.thread_id;
+ // TODO: A pre-pass before the test should be able fetch this number, so it can
+ // be compared explicitly.
+ jlong thread_id = 1;
std::string ret = StringPrintf("jni-local[id=%" PRId64 ",tag=%" PRId64 ",depth=%d,"
"method=%s]",
- info_.jni_local.thread_id,
+ thread_id,
info_.jni_local.thread_tag,
info_.jni_local.depth,
name == nullptr ? "<null>" : name);
@@ -284,13 +296,12 @@
jlong size,
jint length,
const jvmtiHeapReferenceInfo* reference_info)
- REQUIRES_SHARED(Locks::mutator_lock_)
: Elem(referrer, referree, size, length) {
memcpy(&info_, reference_info, sizeof(jvmtiHeapReferenceInfo));
- // Debug stack trace for failure condition. Remove when done.
- if (info_.stack_local.depth == 3 && info_.stack_local.slot == 13) {
- DumpNativeStack(std::cerr, GetTid());
- Thread::Current()->DumpJavaStack(std::cerr, false, false);
+
+ // Debug code. Try to figure out where bad depth is coming from.
+ if (reference_info->stack_local.depth == 6) {
+ LOG(FATAL) << "Unexpected depth of 6";
}
}
@@ -300,9 +311,15 @@
if (info_.stack_local.method != nullptr) {
jvmti_env->GetMethodName(info_.stack_local.method, &name, nullptr, nullptr);
}
+ // Normalize the thread id, as this depends on the number of other threads
+ // and which thread is running the test. Should be:
+ // jlong thread_id = info_.stack_local.thread_id;
+ // TODO: A pre-pass before the test should be able fetch this number, so it can
+ // be compared explicitly.
+ jlong thread_id = 1;
std::string ret = StringPrintf("stack-local[id=%" PRId64 ",tag=%" PRId64 ",depth=%d,"
"method=%s,vreg=%d,location=% " PRId64 "]",
- info_.stack_local.thread_id,
+ thread_id,
info_.stack_local.thread_tag,
info_.stack_local.depth,
name == nullptr ? "<null>" : name,
@@ -361,7 +378,13 @@
tmp));
}
case JVMTI_HEAP_REFERENCE_ARRAY_ELEMENT: {
- std::string tmp = StringPrintf("array-element@%d", reference_info->array.index);
+ jint index = reference_info->array.index;
+ // Normalize if it's "0@0" -> "3000@1".
+ // TODO: A pre-pass could probably give us this index to check explicitly.
+ if (referrer == "0@0" && referree == "3000@0") {
+ index = 0;
+ }
+ std::string tmp = StringPrintf("array-element@%d", index);
return std::unique_ptr<Elem>(new StringElement(referrer,
referree,
size,
@@ -459,16 +482,6 @@
UNREACHABLE();
}
- static void DumpStacks() NO_THREAD_SAFETY_ANALYSIS {
- auto dump_function = [](art::Thread* t, void* data ATTRIBUTE_UNUSED) {
- std::string name;
- t->GetThreadName(name);
- LOG(ERROR) << name;
- art::DumpNativeStack(LOG_STREAM(ERROR), t->GetTid());
- };
- art::Runtime::Current()->GetThreadList()->ForEach(dump_function, nullptr);
- }
-
jint counter_;
const jint stop_after_;
const jint follow_set_;
@@ -476,8 +489,6 @@
std::vector<std::unique_ptr<Elem>> lines_;
};
- jit::ScopedJitSuspend sjs; // Wait to avoid JIT influence (e.g., JNI globals).
-
// If jniRef isn't null, add a local and a global ref.
ScopedLocalRef<jobject> jni_local_ref(env, nullptr);
jobject jni_global_ref = nullptr;
@@ -487,7 +498,9 @@
}
PrintIterationConfig config(stop_after, follow_set);
- Run(heap_filter, klass_filter, initial_object, &config);
+ if (!Run(env, heap_filter, klass_filter, initial_object, &config)) {
+ return nullptr;
+ }
std::vector<std::string> lines = config.GetLines();
jobjectArray ret = CreateObjectArray(env,
@@ -528,10 +541,10 @@
void* user_data) {
FindStringCallbacks* p = reinterpret_cast<FindStringCallbacks*>(user_data);
if (*tag_ptr != 0) {
- size_t utf_byte_count = CountUtf8Bytes(value, value_length);
+ size_t utf_byte_count = ti::CountUtf8Bytes(value, value_length);
std::unique_ptr<char[]> mod_utf(new char[utf_byte_count + 1]);
memset(mod_utf.get(), 0, utf_byte_count + 1);
- ConvertUtf16ToModifiedUtf8(mod_utf.get(), utf_byte_count, value, value_length);
+ ti::ConvertUtf16ToModifiedUtf8(mod_utf.get(), utf_byte_count, value, value_length);
p->data.push_back(android::base::StringPrintf("%" PRId64 "@%" PRId64 " (%" PRId64 ", '%s')",
*tag_ptr,
class_tag,
diff --git a/test/913-heaps/src/art/Test913.java b/test/913-heaps/src/art/Test913.java
index c54ecb0..d3b29cf 100644
--- a/test/913-heaps/src/art/Test913.java
+++ b/test/913-heaps/src/art/Test913.java
@@ -21,12 +21,34 @@
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
+import java.util.concurrent.CountDownLatch;
public class Test913 {
public static void run() throws Exception {
Main.bindAgentJNIForClass(Test913.class);
doTest();
+
+ // Use a countdown latch for synchronization, as join() will introduce more roots.
+ final CountDownLatch cdl1 = new CountDownLatch(1);
+
+ // Run the follow-references tests on a dedicated thread so we know the specific Thread type.
+ Thread t = new Thread() {
+ @Override
+ public void run() {
+ try {
+ Test913.runFollowReferences();
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ cdl1.countDown();
+ }
+ };
+ t.start();
+ cdl1.await();
+ }
+
+ public static void runFollowReferences() throws Exception {
new TestConfig().doFollowReferencesTest();
Runtime.getRuntime().gc();
@@ -349,6 +371,14 @@
cInst.baz2 = aInst;
v.add(cInstStr, aInstStr); // C -->(field) --> A.
+ A[] aArray = new A[2];
+ setTag(aArray, 500);
+ aArray[1] = a2Inst;
+ cInst.array = aArray;
+ String aArrayStr = "500@0";
+ v.add(cInstStr, aArrayStr);
+ v.add(aArrayStr, a2InstStr);
+
return aInst;
}
}
@@ -386,6 +416,7 @@
public static class C extends B implements I2 {
public A baz;
public A baz2;
+ public A[] array;
public C() {}
public C(A a, A b) {
@@ -481,7 +512,8 @@
if (currentHead == null) {
currentHead = referrer;
} else {
- if (!currentHead.equals(referrer)) {
+ // Ignore 0@0, as it can happen at any time (as it stands for all other objects).
+ if (!currentHead.equals(referrer) && !referrer.equals("0@0")) {
completedReferrers.add(currentHead);
currentHead = referrer;
if (completedReferrers.contains(referrer)) {
diff --git a/test/914-hello-obsolescence/src/Main.java b/test/914-hello-obsolescence/src/Main.java
index 2ec7664..ab5c7f4 100644
--- a/test/914-hello-obsolescence/src/Main.java
+++ b/test/914-hello-obsolescence/src/Main.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,60 +14,8 @@
* limitations under the License.
*/
-import java.util.Base64;
-
public class Main {
- // class Transform {
- // public void sayHi(Runnable r) {
- // System.out.println("Hello - Transformed");
- // r.run();
- // System.out.println("Goodbye - Transformed");
- // }
- // }
- private static final byte[] CLASS_BYTES = Base64.getDecoder().decode(
- "yv66vgAAADQAJAoACAARCQASABMIABQKABUAFgsAFwAYCAAZBwAaBwAbAQAGPGluaXQ+AQADKClW" +
- "AQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEABXNheUhpAQAXKExqYXZhL2xhbmcvUnVubmFibGU7" +
- "KVYBAApTb3VyY2VGaWxlAQAOVHJhbnNmb3JtLmphdmEMAAkACgcAHAwAHQAeAQATSGVsbG8gLSBU" +
- "cmFuc2Zvcm1lZAcAHwwAIAAhBwAiDAAjAAoBABVHb29kYnllIC0gVHJhbnNmb3JtZWQBAAlUcmFu" +
- "c2Zvcm0BABBqYXZhL2xhbmcvT2JqZWN0AQAQamF2YS9sYW5nL1N5c3RlbQEAA291dAEAFUxqYXZh" +
- "L2lvL1ByaW50U3RyZWFtOwEAE2phdmEvaW8vUHJpbnRTdHJlYW0BAAdwcmludGxuAQAVKExqYXZh" +
- "L2xhbmcvU3RyaW5nOylWAQASamF2YS9sYW5nL1J1bm5hYmxlAQADcnVuACAABwAIAAAAAAACAAAA" +
- "CQAKAAEACwAAAB0AAQABAAAABSq3AAGxAAAAAQAMAAAABgABAAAAAQABAA0ADgABAAsAAAA7AAIA" +
- "AgAAABeyAAISA7YABCu5AAUBALIAAhIGtgAEsQAAAAEADAAAABIABAAAAAMACAAEAA4ABQAWAAYA" +
- "AQAPAAAAAgAQ");
- private static final byte[] DEX_BYTES = Base64.getDecoder().decode(
- "ZGV4CjAzNQAYeAMMXgYWxoeSHAS9EWKCCtVRSAGpqZVQAwAAcAAAAHhWNBIAAAAAAAAAALACAAAR" +
- "AAAAcAAAAAcAAAC0AAAAAwAAANAAAAABAAAA9AAAAAUAAAD8AAAAAQAAACQBAAAMAgAARAEAAKIB" +
- "AACqAQAAwQEAANYBAADjAQAA+gEAAA4CAAAkAgAAOAIAAEwCAABcAgAAXwIAAGMCAAB3AgAAfAIA" +
- "AIUCAACKAgAAAwAAAAQAAAAFAAAABgAAAAcAAAAIAAAACgAAAAoAAAAGAAAAAAAAAAsAAAAGAAAA" +
- "lAEAAAsAAAAGAAAAnAEAAAUAAQANAAAAAAAAAAAAAAAAAAEAEAAAAAEAAgAOAAAAAgAAAAAAAAAD" +
- "AAAADwAAAAAAAAAAAAAAAgAAAAAAAAAJAAAAAAAAAJ8CAAAAAAAAAQABAAEAAACRAgAABAAAAHAQ" +
- "AwAAAA4ABAACAAIAAACWAgAAFAAAAGIAAAAbAQIAAABuIAIAEAByEAQAAwBiAAAAGwEBAAAAbiAC" +
- "ABAADgABAAAAAwAAAAEAAAAEAAY8aW5pdD4AFUdvb2RieWUgLSBUcmFuc2Zvcm1lZAATSGVsbG8g" +
- "LSBUcmFuc2Zvcm1lZAALTFRyYW5zZm9ybTsAFUxqYXZhL2lvL1ByaW50U3RyZWFtOwASTGphdmEv" +
- "bGFuZy9PYmplY3Q7ABRMamF2YS9sYW5nL1J1bm5hYmxlOwASTGphdmEvbGFuZy9TdHJpbmc7ABJM" +
- "amF2YS9sYW5nL1N5c3RlbTsADlRyYW5zZm9ybS5qYXZhAAFWAAJWTAASZW1pdHRlcjogamFjay00" +
- "LjEzAANvdXQAB3ByaW50bG4AA3J1bgAFc2F5SGkAAQAHDgADAQAHDoc8hwAAAAEBAICABMQCAQHc" +
- "AgAAAA0AAAAAAAAAAQAAAAAAAAABAAAAEQAAAHAAAAACAAAABwAAALQAAAADAAAAAwAAANAAAAAE" +
- "AAAAAQAAAPQAAAAFAAAABQAAAPwAAAAGAAAAAQAAACQBAAABIAAAAgAAAEQBAAABEAAAAgAAAJQB" +
- "AAACIAAAEQAAAKIBAAADIAAAAgAAAJECAAAAIAAAAQAAAJ8CAAAAEAAAAQAAALACAAA=");
-
- public static void main(String[] args) {
- art.Main.bindAgentJNIForClass(Main.class);
- doTest(new Transform());
+ public static void main(String[] args) throws Exception {
+ art.Test914.run();
}
-
- public static void doTest(Transform t) {
- t.sayHi(() -> { System.out.println("Not doing anything here"); });
- t.sayHi(() -> {
- System.out.println("transforming calling function");
- doCommonClassRedefinition(Transform.class, CLASS_BYTES, DEX_BYTES);
- });
- t.sayHi(() -> { System.out.println("Not doing anything here"); });
- }
-
- // Transforms the class
- private static native void doCommonClassRedefinition(Class<?> target,
- byte[] classfile,
- byte[] dexfile);
}
diff --git a/test/914-hello-obsolescence/src/Transform.java b/test/914-hello-obsolescence/src/Transform.java
deleted file mode 100644
index 8cda6cd..0000000
--- a/test/914-hello-obsolescence/src/Transform.java
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-class Transform {
- public void sayHi(Runnable r) {
- // Use lower 'h' to make sure the string will have a different string id
- // than the transformation (the transformation code is the same except
- // the actual printed String, which was making the test inacurately passing
- // in JIT mode when loading the string from the dex cache, as the string ids
- // of the two different strings were the same).
- // We know the string ids will be different because lexicographically:
- // "Hello" < "LTransform;" < "hello".
- System.out.println("hello");
- r.run();
- System.out.println("goodbye");
- }
-}
diff --git a/test/914-hello-obsolescence/src/art/Redefinition.java b/test/914-hello-obsolescence/src/art/Redefinition.java
new file mode 100644
index 0000000..0350ab4
--- /dev/null
+++ b/test/914-hello-obsolescence/src/art/Redefinition.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package art;
+
+import java.util.ArrayList;
+// Common Redefinition functions. Placed here for use by CTS
+public class Redefinition {
+ // Bind native functions.
+ static {
+ Main.bindAgentJNIForClass(Redefinition.class);
+ }
+
+ public static final class CommonClassDefinition {
+ public final Class<?> target;
+ public final byte[] class_file_bytes;
+ public final byte[] dex_file_bytes;
+
+ public CommonClassDefinition(Class<?> target, byte[] class_file_bytes, byte[] dex_file_bytes) {
+ this.target = target;
+ this.class_file_bytes = class_file_bytes;
+ this.dex_file_bytes = dex_file_bytes;
+ }
+ }
+
+ // A set of possible test configurations. Test should set this if they need to.
+ // This must be kept in sync with the defines in ti-agent/common_helper.cc
+ public static enum Config {
+ COMMON_REDEFINE(0),
+ COMMON_RETRANSFORM(1),
+ COMMON_TRANSFORM(2);
+
+ private final int val;
+ private Config(int val) {
+ this.val = val;
+ }
+ }
+
+ public static void setTestConfiguration(Config type) {
+ nativeSetTestConfiguration(type.val);
+ }
+
+ private static native void nativeSetTestConfiguration(int type);
+
+ // Transforms the class
+ public static native void doCommonClassRedefinition(Class<?> target,
+ byte[] classfile,
+ byte[] dexfile);
+
+ public static void doMultiClassRedefinition(CommonClassDefinition... defs) {
+ ArrayList<Class<?>> classes = new ArrayList<>();
+ ArrayList<byte[]> class_files = new ArrayList<>();
+ ArrayList<byte[]> dex_files = new ArrayList<>();
+
+ for (CommonClassDefinition d : defs) {
+ classes.add(d.target);
+ class_files.add(d.class_file_bytes);
+ dex_files.add(d.dex_file_bytes);
+ }
+ doCommonMultiClassRedefinition(classes.toArray(new Class<?>[0]),
+ class_files.toArray(new byte[0][]),
+ dex_files.toArray(new byte[0][]));
+ }
+
+ public static void addMultiTransformationResults(CommonClassDefinition... defs) {
+ for (CommonClassDefinition d : defs) {
+ addCommonTransformationResult(d.target.getCanonicalName(),
+ d.class_file_bytes,
+ d.dex_file_bytes);
+ }
+ }
+
+ public static native void doCommonMultiClassRedefinition(Class<?>[] targets,
+ byte[][] classfiles,
+ byte[][] dexfiles);
+ public static native void doCommonClassRetransformation(Class<?>... target);
+ public static native void setPopRetransformations(boolean pop);
+ public static native void popTransformationFor(String name);
+ public static native void enableCommonRetransformation(boolean enable);
+ public static native void addCommonTransformationResult(String target_name,
+ byte[] class_bytes,
+ byte[] dex_bytes);
+}
diff --git a/test/914-hello-obsolescence/src/art/Test914.java b/test/914-hello-obsolescence/src/art/Test914.java
new file mode 100644
index 0000000..ef2710d
--- /dev/null
+++ b/test/914-hello-obsolescence/src/art/Test914.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package art;
+
+import java.util.Base64;
+
+public class Test914 {
+
+ // The class we will be transforming.
+ static class Transform {
+ public void sayHi(Runnable r) {
+ System.out.println("hello");
+ r.run();
+ System.out.println("goodbye");
+ }
+ }
+
+ // static class Transform {
+ // public void sayHi(Runnable r) {
+ // System.out.println("Hello - Transformed");
+ // r.run();
+ // System.out.println("Goodbye - Transformed");
+ // }
+ // }
+ private static final byte[] CLASS_BYTES = Base64.getDecoder().decode(
+ "yv66vgAAADQAKAoACAARCQASABMIABQKABUAFgsAFwAYCAAZBwAbBwAeAQAGPGluaXQ+AQADKClW" +
+ "AQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEABXNheUhpAQAXKExqYXZhL2xhbmcvUnVubmFibGU7" +
+ "KVYBAApTb3VyY2VGaWxlAQAMVGVzdDkxNC5qYXZhDAAJAAoHAB8MACAAIQEAE0hlbGxvIC0gVHJh" +
+ "bnNmb3JtZWQHACIMACMAJAcAJQwAJgAKAQAVR29vZGJ5ZSAtIFRyYW5zZm9ybWVkBwAnAQAVYXJ0" +
+ "L1Rlc3Q5MTQkVHJhbnNmb3JtAQAJVHJhbnNmb3JtAQAMSW5uZXJDbGFzc2VzAQAQamF2YS9sYW5n" +
+ "L09iamVjdAEAEGphdmEvbGFuZy9TeXN0ZW0BAANvdXQBABVMamF2YS9pby9QcmludFN0cmVhbTsB" +
+ "ABNqYXZhL2lvL1ByaW50U3RyZWFtAQAHcHJpbnRsbgEAFShMamF2YS9sYW5nL1N0cmluZzspVgEA" +
+ "EmphdmEvbGFuZy9SdW5uYWJsZQEAA3J1bgEAC2FydC9UZXN0OTE0ACAABwAIAAAAAAACAAAACQAK" +
+ "AAEACwAAAB0AAQABAAAABSq3AAGxAAAAAQAMAAAABgABAAAABQABAA0ADgABAAsAAAA7AAIAAgAA" +
+ "ABeyAAISA7YABCu5AAUBALIAAhIGtgAEsQAAAAEADAAAABIABAAAAAcACAAIAA4ACQAWAAoAAgAP" +
+ "AAAAAgAQAB0AAAAKAAEABwAaABwACA==");
+ private static final byte[] DEX_BYTES = Base64.getDecoder().decode(
+ "ZGV4CjAzNQBlmxNYAAAAAAAAAAAAAAAAAAAAAAAAAAA8BAAAcAAAAHhWNBIAAAAAAAAAAHgDAAAX" +
+ "AAAAcAAAAAoAAADMAAAAAwAAAPQAAAABAAAAGAEAAAUAAAAgAQAAAQAAAEgBAADUAgAAaAEAAGgB" +
+ "AABwAQAAhwEAAJwBAAC1AQAAxAEAAOgBAAAIAgAAHwIAADMCAABJAgAAXQIAAHECAAB/AgAAigIA" +
+ "AI0CAACRAgAAngIAAKQCAACpAgAAsgIAALcCAAC+AgAAAwAAAAQAAAAFAAAABgAAAAcAAAAIAAAA" +
+ "CQAAAAoAAAALAAAADgAAAA4AAAAJAAAAAAAAAA8AAAAJAAAAyAIAAA8AAAAJAAAA0AIAAAgABAAS" +
+ "AAAAAAAAAAAAAAAAAAEAFQAAAAQAAgATAAAABQAAAAAAAAAGAAAAFAAAAAAAAAAAAAAABQAAAAAA" +
+ "AAAMAAAAaAMAADwDAAAAAAAABjxpbml0PgAVR29vZGJ5ZSAtIFRyYW5zZm9ybWVkABNIZWxsbyAt" +
+ "IFRyYW5zZm9ybWVkABdMYXJ0L1Rlc3Q5MTQkVHJhbnNmb3JtOwANTGFydC9UZXN0OTE0OwAiTGRh" +
+ "bHZpay9hbm5vdGF0aW9uL0VuY2xvc2luZ0NsYXNzOwAeTGRhbHZpay9hbm5vdGF0aW9uL0lubmVy" +
+ "Q2xhc3M7ABVMamF2YS9pby9QcmludFN0cmVhbTsAEkxqYXZhL2xhbmcvT2JqZWN0OwAUTGphdmEv" +
+ "bGFuZy9SdW5uYWJsZTsAEkxqYXZhL2xhbmcvU3RyaW5nOwASTGphdmEvbGFuZy9TeXN0ZW07AAxU" +
+ "ZXN0OTE0LmphdmEACVRyYW5zZm9ybQABVgACVkwAC2FjY2Vzc0ZsYWdzAARuYW1lAANvdXQAB3By" +
+ "aW50bG4AA3J1bgAFc2F5SGkABXZhbHVlAAAAAAEAAAAGAAAAAQAAAAcAAAAFAAcOAAcBAAcOAQgP" +
+ "AQMPAQgPAAEAAQABAAAA2AIAAAQAAABwEAMAAAAOAAQAAgACAAAA3QIAABQAAABiAAAAGwECAAAA" +
+ "biACABAAchAEAAMAYgAAABsBAQAAAG4gAgAQAA4AAAABAQCAgATsBQEBhAYAAAICARYYAQIDAhAE" +
+ "CBEXDQACAAAATAMAAFIDAABcAwAAAAAAAAAAAAAAAAAAEAAAAAAAAAABAAAAAAAAAAEAAAAXAAAA" +
+ "cAAAAAIAAAAKAAAAzAAAAAMAAAADAAAA9AAAAAQAAAABAAAAGAEAAAUAAAAFAAAAIAEAAAYAAAAB" +
+ "AAAASAEAAAIgAAAXAAAAaAEAAAEQAAACAAAAyAIAAAMgAAACAAAA2AIAAAEgAAACAAAA7AIAAAAg" +
+ "AAABAAAAPAMAAAQgAAACAAAATAMAAAMQAAABAAAAXAMAAAYgAAABAAAAaAMAAAAQAAABAAAAeAMA" +
+ "AA==");
+
+ public static void run() {
+ Redefinition.setTestConfiguration(Redefinition.Config.COMMON_REDEFINE);
+ doTest(new Transform());
+ }
+
+ public static void doTest(Transform t) {
+ t.sayHi(() -> { System.out.println("Not doing anything here"); });
+ t.sayHi(() -> {
+ System.out.println("transforming calling function");
+ Redefinition.doCommonClassRedefinition(Transform.class, CLASS_BYTES, DEX_BYTES);
+ });
+ t.sayHi(() -> { System.out.println("Not doing anything here"); });
+ }
+}
diff --git a/test/915-obsolete-2/src/Main.java b/test/915-obsolete-2/src/Main.java
index fc73ee8..be51234 100644
--- a/test/915-obsolete-2/src/Main.java
+++ b/test/915-obsolete-2/src/Main.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,86 +14,8 @@
* limitations under the License.
*/
-import java.util.Base64;
-
public class Main {
- // class Transform {
- // private void Start() {
- // System.out.println("Hello - private - Transformed");
- // }
- //
- // private void Finish() {
- // System.out.println("Goodbye - private - Transformed");
- // }
- //
- // public void sayHi(Runnable r) {
- // System.out.println("Pre Start private method call - Transformed");
- // Start();
- // System.out.println("Post Start private method call - Transformed");
- // r.run();
- // System.out.println("Pre Finish private method call - Transformed");
- // Finish();
- // System.out.println("Post Finish private method call - Transformed");
- // }
- // }
- private static final byte[] CLASS_BYTES = Base64.getDecoder().decode(
- "yv66vgAAADQAMgoADgAZCQAaABsIABwKAB0AHggAHwgAIAoADQAhCAAiCwAjACQIACUKAA0AJggA" +
- "JwcAKAcAKQEABjxpbml0PgEAAygpVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUBAAVTdGFydAEA" +
- "BkZpbmlzaAEABXNheUhpAQAXKExqYXZhL2xhbmcvUnVubmFibGU7KVYBAApTb3VyY2VGaWxlAQAO" +
- "VHJhbnNmb3JtLmphdmEMAA8AEAcAKgwAKwAsAQAdSGVsbG8gLSBwcml2YXRlIC0gVHJhbnNmb3Jt" +
- "ZWQHAC0MAC4ALwEAH0dvb2RieWUgLSBwcml2YXRlIC0gVHJhbnNmb3JtZWQBACtQcmUgU3RhcnQg" +
- "cHJpdmF0ZSBtZXRob2QgY2FsbCAtIFRyYW5zZm9ybWVkDAATABABACxQb3N0IFN0YXJ0IHByaXZh" +
- "dGUgbWV0aG9kIGNhbGwgLSBUcmFuc2Zvcm1lZAcAMAwAMQAQAQAsUHJlIEZpbmlzaCBwcml2YXRl" +
- "IG1ldGhvZCBjYWxsIC0gVHJhbnNmb3JtZWQMABQAEAEALVBvc3QgRmluaXNoIHByaXZhdGUgbWV0" +
- "aG9kIGNhbGwgLSBUcmFuc2Zvcm1lZAEACVRyYW5zZm9ybQEAEGphdmEvbGFuZy9PYmplY3QBABBq" +
- "YXZhL2xhbmcvU3lzdGVtAQADb3V0AQAVTGphdmEvaW8vUHJpbnRTdHJlYW07AQATamF2YS9pby9Q" +
- "cmludFN0cmVhbQEAB3ByaW50bG4BABUoTGphdmEvbGFuZy9TdHJpbmc7KVYBABJqYXZhL2xhbmcv" +
- "UnVubmFibGUBAANydW4AIAANAA4AAAAAAAQAAAAPABAAAQARAAAAHQABAAEAAAAFKrcAAbEAAAAB" +
- "ABIAAAAGAAEAAAABAAIAEwAQAAEAEQAAACUAAgABAAAACbIAAhIDtgAEsQAAAAEAEgAAAAoAAgAA" +
- "AAMACAAEAAIAFAAQAAEAEQAAACUAAgABAAAACbIAAhIFtgAEsQAAAAEAEgAAAAoAAgAAAAcACAAI" +
- "AAEAFQAWAAEAEQAAAGMAAgACAAAAL7IAAhIGtgAEKrcAB7IAAhIItgAEK7kACQEAsgACEgq2AAQq" +
- "twALsgACEgy2AASxAAAAAQASAAAAIgAIAAAACwAIAAwADAANABQADgAaAA8AIgAQACYAEQAuABIA" +
- "AQAXAAAAAgAY");
- private static final byte[] DEX_BYTES = Base64.getDecoder().decode(
- "ZGV4CjAzNQCM0QYTJmX+NsZXkImojgSkJtXyuew3oaXcBAAAcAAAAHhWNBIAAAAAAAAAADwEAAAX" +
- "AAAAcAAAAAcAAADMAAAAAwAAAOgAAAABAAAADAEAAAcAAAAUAQAAAQAAAEwBAABwAwAAbAEAAD4C" +
- "AABGAgAATgIAAG8CAACOAgAAmwIAALICAADGAgAA3AIAAPACAAAEAwAAMwMAAGEDAACPAwAAvAMA" +
- "AMMDAADTAwAA1gMAANoDAADuAwAA8wMAAPwDAAABBAAABAAAAAUAAAAGAAAABwAAAAgAAAAJAAAA" +
- "EAAAABAAAAAGAAAAAAAAABEAAAAGAAAAMAIAABEAAAAGAAAAOAIAAAUAAQATAAAAAAAAAAAAAAAA" +
- "AAAAAQAAAAAAAAAOAAAAAAABABYAAAABAAIAFAAAAAIAAAAAAAAAAwAAABUAAAAAAAAAAAAAAAIA" +
- "AAAAAAAADwAAAAAAAAAmBAAAAAAAAAEAAQABAAAACAQAAAQAAABwEAUAAAAOAAMAAQACAAAADQQA" +
- "AAkAAABiAAAAGwECAAAAbiAEABAADgAAAAMAAQACAAAAEwQAAAkAAABiAAAAGwEDAAAAbiAEABAA" +
- "DgAAAAQAAgACAAAAGQQAACoAAABiAAAAGwENAAAAbiAEABAAcBACAAIAYgAAABsBCwAAAG4gBAAQ" +
- "AHIQBgADAGIAAAAbAQwAAABuIAQAEABwEAEAAgBiAAAAGwEKAAAAbiAEABAADgABAAAAAwAAAAEA" +
- "AAAEAAY8aW5pdD4ABkZpbmlzaAAfR29vZGJ5ZSAtIHByaXZhdGUgLSBUcmFuc2Zvcm1lZAAdSGVs" +
- "bG8gLSBwcml2YXRlIC0gVHJhbnNmb3JtZWQAC0xUcmFuc2Zvcm07ABVMamF2YS9pby9QcmludFN0" +
- "cmVhbTsAEkxqYXZhL2xhbmcvT2JqZWN0OwAUTGphdmEvbGFuZy9SdW5uYWJsZTsAEkxqYXZhL2xh" +
- "bmcvU3RyaW5nOwASTGphdmEvbGFuZy9TeXN0ZW07AC1Qb3N0IEZpbmlzaCBwcml2YXRlIG1ldGhv" +
- "ZCBjYWxsIC0gVHJhbnNmb3JtZWQALFBvc3QgU3RhcnQgcHJpdmF0ZSBtZXRob2QgY2FsbCAtIFRy" +
- "YW5zZm9ybWVkACxQcmUgRmluaXNoIHByaXZhdGUgbWV0aG9kIGNhbGwgLSBUcmFuc2Zvcm1lZAAr" +
- "UHJlIFN0YXJ0IHByaXZhdGUgbWV0aG9kIGNhbGwgLSBUcmFuc2Zvcm1lZAAFU3RhcnQADlRyYW5z" +
- "Zm9ybS5qYXZhAAFWAAJWTAASZW1pdHRlcjogamFjay00LjEzAANvdXQAB3ByaW50bG4AA3J1bgAF" +
- "c2F5SGkAAQAHDgAHAAcOhwADAAcOhwALAQAHDoc8hzyHPIcAAAADAQCAgATsAgEChAMBAqgDAwHM" +
- "Aw0AAAAAAAAAAQAAAAAAAAABAAAAFwAAAHAAAAACAAAABwAAAMwAAAADAAAAAwAAAOgAAAAEAAAA" +
- "AQAAAAwBAAAFAAAABwAAABQBAAAGAAAAAQAAAEwBAAABIAAABAAAAGwBAAABEAAAAgAAADACAAAC" +
- "IAAAFwAAAD4CAAADIAAABAAAAAgEAAAAIAAAAQAAACYEAAAAEAAAAQAAADwEAAA=");
-
- public static void main(String[] args) {
- art.Main.bindAgentJNIForClass(Main.class);
- doTest(new Transform());
+ public static void main(String[] args) throws Exception {
+ art.Test915.run();
}
-
- public static void doTest(Transform t) {
- t.sayHi(() -> { System.out.println("Not doing anything here"); });
- t.sayHi(() -> {
- System.out.println("transforming calling function");
- doCommonClassRedefinition(Transform.class, CLASS_BYTES, DEX_BYTES);
- });
- t.sayHi(() -> { System.out.println("Not doing anything here"); });
- }
-
- // Transforms the class
- private static native void doCommonClassRedefinition(Class<?> target,
- byte[] classfile,
- byte[] dexfile);
}
diff --git a/test/915-obsolete-2/src/Transform.java b/test/915-obsolete-2/src/Transform.java
deleted file mode 100644
index e914e29..0000000
--- a/test/915-obsolete-2/src/Transform.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-class Transform {
- private void Start() {
- System.out.println("hello - private");
- }
-
- private void Finish() {
- System.out.println("goodbye - private");
- }
-
- public void sayHi(Runnable r) {
- System.out.println("Pre Start private method call");
- Start();
- System.out.println("Post Start private method call");
- r.run();
- System.out.println("Pre Finish private method call");
- Finish();
- System.out.println("Post Finish private method call");
- }
-}
diff --git a/test/915-obsolete-2/src/art/Redefinition.java b/test/915-obsolete-2/src/art/Redefinition.java
new file mode 100644
index 0000000..0350ab4
--- /dev/null
+++ b/test/915-obsolete-2/src/art/Redefinition.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package art;
+
+import java.util.ArrayList;
+// Common Redefinition functions. Placed here for use by CTS
+public class Redefinition {
+ // Bind native functions.
+ static {
+ Main.bindAgentJNIForClass(Redefinition.class);
+ }
+
+ public static final class CommonClassDefinition {
+ public final Class<?> target;
+ public final byte[] class_file_bytes;
+ public final byte[] dex_file_bytes;
+
+ public CommonClassDefinition(Class<?> target, byte[] class_file_bytes, byte[] dex_file_bytes) {
+ this.target = target;
+ this.class_file_bytes = class_file_bytes;
+ this.dex_file_bytes = dex_file_bytes;
+ }
+ }
+
+ // A set of possible test configurations. Test should set this if they need to.
+ // This must be kept in sync with the defines in ti-agent/common_helper.cc
+ public static enum Config {
+ COMMON_REDEFINE(0),
+ COMMON_RETRANSFORM(1),
+ COMMON_TRANSFORM(2);
+
+ private final int val;
+ private Config(int val) {
+ this.val = val;
+ }
+ }
+
+ public static void setTestConfiguration(Config type) {
+ nativeSetTestConfiguration(type.val);
+ }
+
+ private static native void nativeSetTestConfiguration(int type);
+
+ // Transforms the class
+ public static native void doCommonClassRedefinition(Class<?> target,
+ byte[] classfile,
+ byte[] dexfile);
+
+ public static void doMultiClassRedefinition(CommonClassDefinition... defs) {
+ ArrayList<Class<?>> classes = new ArrayList<>();
+ ArrayList<byte[]> class_files = new ArrayList<>();
+ ArrayList<byte[]> dex_files = new ArrayList<>();
+
+ for (CommonClassDefinition d : defs) {
+ classes.add(d.target);
+ class_files.add(d.class_file_bytes);
+ dex_files.add(d.dex_file_bytes);
+ }
+ doCommonMultiClassRedefinition(classes.toArray(new Class<?>[0]),
+ class_files.toArray(new byte[0][]),
+ dex_files.toArray(new byte[0][]));
+ }
+
+ public static void addMultiTransformationResults(CommonClassDefinition... defs) {
+ for (CommonClassDefinition d : defs) {
+ addCommonTransformationResult(d.target.getCanonicalName(),
+ d.class_file_bytes,
+ d.dex_file_bytes);
+ }
+ }
+
+ public static native void doCommonMultiClassRedefinition(Class<?>[] targets,
+ byte[][] classfiles,
+ byte[][] dexfiles);
+ public static native void doCommonClassRetransformation(Class<?>... target);
+ public static native void setPopRetransformations(boolean pop);
+ public static native void popTransformationFor(String name);
+ public static native void enableCommonRetransformation(boolean enable);
+ public static native void addCommonTransformationResult(String target_name,
+ byte[] class_bytes,
+ byte[] dex_bytes);
+}
diff --git a/test/915-obsolete-2/src/art/Test915.java b/test/915-obsolete-2/src/art/Test915.java
new file mode 100644
index 0000000..63c7f34
--- /dev/null
+++ b/test/915-obsolete-2/src/art/Test915.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package art;
+
+import java.util.Base64;
+
+public class Test915 {
+
+ static class Transform {
+ private void Start() {
+ System.out.println("hello - private");
+ }
+
+ private void Finish() {
+ System.out.println("goodbye - private");
+ }
+
+ public void sayHi(Runnable r) {
+ System.out.println("Pre Start private method call");
+ Start();
+ System.out.println("Post Start private method call");
+ r.run();
+ System.out.println("Pre Finish private method call");
+ Finish();
+ System.out.println("Post Finish private method call");
+ }
+ }
+
+ // static class Transform {
+ // private void Start() {
+ // System.out.println("Hello - private - Transformed");
+ // }
+ //
+ // private void Finish() {
+ // System.out.println("Goodbye - private - Transformed");
+ // }
+ //
+ // public void sayHi(Runnable r) {
+ // System.out.println("Pre Start private method call - Transformed");
+ // Start();
+ // System.out.println("Post Start private method call - Transformed");
+ // r.run();
+ // System.out.println("Pre Finish private method call - Transformed");
+ // Finish();
+ // System.out.println("Post Finish private method call - Transformed");
+ // }
+ // }
+ private static final byte[] CLASS_BYTES = Base64.getDecoder().decode(
+ "yv66vgAAADQANgoADgAZCQAaABsIABwKAB0AHggAHwgAIAoADQAhCAAiCwAjACQIACUKAA0AJggA" +
+ "JwcAKQcALAEABjxpbml0PgEAAygpVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUBAAVTdGFydAEA" +
+ "BkZpbmlzaAEABXNheUhpAQAXKExqYXZhL2xhbmcvUnVubmFibGU7KVYBAApTb3VyY2VGaWxlAQAM" +
+ "VGVzdDkxNS5qYXZhDAAPABAHAC0MAC4ALwEAHUhlbGxvIC0gcHJpdmF0ZSAtIFRyYW5zZm9ybWVk" +
+ "BwAwDAAxADIBAB9Hb29kYnllIC0gcHJpdmF0ZSAtIFRyYW5zZm9ybWVkAQArUHJlIFN0YXJ0IHBy" +
+ "aXZhdGUgbWV0aG9kIGNhbGwgLSBUcmFuc2Zvcm1lZAwAEwAQAQAsUG9zdCBTdGFydCBwcml2YXRl" +
+ "IG1ldGhvZCBjYWxsIC0gVHJhbnNmb3JtZWQHADMMADQAEAEALFByZSBGaW5pc2ggcHJpdmF0ZSBt" +
+ "ZXRob2QgY2FsbCAtIFRyYW5zZm9ybWVkDAAUABABAC1Qb3N0IEZpbmlzaCBwcml2YXRlIG1ldGhv" +
+ "ZCBjYWxsIC0gVHJhbnNmb3JtZWQHADUBABVhcnQvVGVzdDkxNSRUcmFuc2Zvcm0BAAlUcmFuc2Zv" +
+ "cm0BAAxJbm5lckNsYXNzZXMBABBqYXZhL2xhbmcvT2JqZWN0AQAQamF2YS9sYW5nL1N5c3RlbQEA" +
+ "A291dAEAFUxqYXZhL2lvL1ByaW50U3RyZWFtOwEAE2phdmEvaW8vUHJpbnRTdHJlYW0BAAdwcmlu" +
+ "dGxuAQAVKExqYXZhL2xhbmcvU3RyaW5nOylWAQASamF2YS9sYW5nL1J1bm5hYmxlAQADcnVuAQAL" +
+ "YXJ0L1Rlc3Q5MTUAIAANAA4AAAAAAAQAAAAPABAAAQARAAAAHQABAAEAAAAFKrcAAbEAAAABABIA" +
+ "AAAGAAEAAAAFAAIAEwAQAAEAEQAAACUAAgABAAAACbIAAhIDtgAEsQAAAAEAEgAAAAoAAgAAAAcA" +
+ "CAAIAAIAFAAQAAEAEQAAACUAAgABAAAACbIAAhIFtgAEsQAAAAEAEgAAAAoAAgAAAAoACAALAAEA" +
+ "FQAWAAEAEQAAAGMAAgACAAAAL7IAAhIGtgAEKrcAB7IAAhIItgAEK7kACQEAsgACEgq2AAQqtwAL" +
+ "sgACEgy2AASxAAAAAQASAAAAIgAIAAAADQAIAA4ADAAPABQAEAAaABEAIgASACYAEwAuABQAAgAX" +
+ "AAAAAgAYACsAAAAKAAEADQAoACoACA==");
+ private static final byte[] DEX_BYTES = Base64.getDecoder().decode(
+ "ZGV4CjAzNQAQ+GYcAAAAAAAAAAAAAAAAAAAAAAAAAADUBQAAcAAAAHhWNBIAAAAAAAAAABAFAAAd" +
+ "AAAAcAAAAAoAAADkAAAAAwAAAAwBAAABAAAAMAEAAAcAAAA4AQAAAQAAAHABAABEBAAAkAEAAJAB" +
+ "AACYAQAAoAEAAMEBAADgAQAA+QEAAAgCAAAsAgAATAIAAGMCAAB3AgAAjQIAAKECAAC1AgAA5AIA" +
+ "ABIDAABAAwAAbQMAAHQDAACCAwAAjQMAAJADAACUAwAAoQMAAKcDAACsAwAAtQMAALoDAADBAwAA" +
+ "BAAAAAUAAAAGAAAABwAAAAgAAAAJAAAACgAAAAsAAAAMAAAAFAAAABQAAAAJAAAAAAAAABUAAAAJ" +
+ "AAAA0AMAABUAAAAJAAAAyAMAAAgABAAYAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAARAAAAAAABABsA" +
+ "AAAEAAIAGQAAAAUAAAAAAAAABgAAABoAAAAAAAAAAAAAAAUAAAAAAAAAEgAAAAAFAADMBAAAAAAA" +
+ "AAY8aW5pdD4ABkZpbmlzaAAfR29vZGJ5ZSAtIHByaXZhdGUgLSBUcmFuc2Zvcm1lZAAdSGVsbG8g" +
+ "LSBwcml2YXRlIC0gVHJhbnNmb3JtZWQAF0xhcnQvVGVzdDkxNSRUcmFuc2Zvcm07AA1MYXJ0L1Rl" +
+ "c3Q5MTU7ACJMZGFsdmlrL2Fubm90YXRpb24vRW5jbG9zaW5nQ2xhc3M7AB5MZGFsdmlrL2Fubm90" +
+ "YXRpb24vSW5uZXJDbGFzczsAFUxqYXZhL2lvL1ByaW50U3RyZWFtOwASTGphdmEvbGFuZy9PYmpl" +
+ "Y3Q7ABRMamF2YS9sYW5nL1J1bm5hYmxlOwASTGphdmEvbGFuZy9TdHJpbmc7ABJMamF2YS9sYW5n" +
+ "L1N5c3RlbTsALVBvc3QgRmluaXNoIHByaXZhdGUgbWV0aG9kIGNhbGwgLSBUcmFuc2Zvcm1lZAAs" +
+ "UG9zdCBTdGFydCBwcml2YXRlIG1ldGhvZCBjYWxsIC0gVHJhbnNmb3JtZWQALFByZSBGaW5pc2gg" +
+ "cHJpdmF0ZSBtZXRob2QgY2FsbCAtIFRyYW5zZm9ybWVkACtQcmUgU3RhcnQgcHJpdmF0ZSBtZXRo" +
+ "b2QgY2FsbCAtIFRyYW5zZm9ybWVkAAVTdGFydAAMVGVzdDkxNS5qYXZhAAlUcmFuc2Zvcm0AAVYA" +
+ "AlZMAAthY2Nlc3NGbGFncwAEbmFtZQADb3V0AAdwcmludGxuAANydW4ABXNheUhpAAV2YWx1ZQAB" +
+ "AAAABwAAAAEAAAAGAAAABQAHDgAKAAcOAQgPAAcABw4BCA8ADQEABw4BCA8BAw8BCA8BAw8BCA8B" +
+ "Aw8BCA8AAQABAAEAAADYAwAABAAAAHAQBQAAAA4AAwABAAIAAADdAwAACQAAAGIAAAAbAQIAAABu" +
+ "IAQAEAAOAAAAAwABAAIAAADlAwAACQAAAGIAAAAbAQMAAABuIAQAEAAOAAAABAACAAIAAADtAwAA" +
+ "KgAAAGIAAAAbARAAAABuIAQAEABwEAIAAgBiAAAAGwEOAAAAbiAEABAAchAGAAMAYgAAABsBDwAA" +
+ "AG4gBAAQAHAQAQACAGIAAAAbAQ0AAABuIAQAEAAOAAAAAwEAgIAEiAgBAqAIAQLECAMB6AgAAAIC" +
+ "ARwYAQIDAhYECBcXEwACAAAA5AQAAOoEAAD0BAAAAAAAAAAAAAAAAAAAEAAAAAAAAAABAAAAAAAA" +
+ "AAEAAAAdAAAAcAAAAAIAAAAKAAAA5AAAAAMAAAADAAAADAEAAAQAAAABAAAAMAEAAAUAAAAHAAAA" +
+ "OAEAAAYAAAABAAAAcAEAAAIgAAAdAAAAkAEAAAEQAAACAAAAyAMAAAMgAAAEAAAA2AMAAAEgAAAE" +
+ "AAAACAQAAAAgAAABAAAAzAQAAAQgAAACAAAA5AQAAAMQAAABAAAA9AQAAAYgAAABAAAAAAUAAAAQ" +
+ "AAABAAAAEAUAAA==");
+
+ public static void run() {
+ Redefinition.setTestConfiguration(Redefinition.Config.COMMON_REDEFINE);
+ doTest(new Transform());
+ }
+
+ public static void doTest(Transform t) {
+ t.sayHi(() -> { System.out.println("Not doing anything here"); });
+ t.sayHi(() -> {
+ System.out.println("transforming calling function");
+ Redefinition.doCommonClassRedefinition(Transform.class, CLASS_BYTES, DEX_BYTES);
+ });
+ t.sayHi(() -> { System.out.println("Not doing anything here"); });
+ }
+}
diff --git a/test/916-obsolete-jit/src/Main.java b/test/916-obsolete-jit/src/Main.java
index 3453261..cb202e4 100644
--- a/test/916-obsolete-jit/src/Main.java
+++ b/test/916-obsolete-jit/src/Main.java
@@ -14,6 +14,9 @@
* limitations under the License.
*/
+
+import art.Redefinition;
+
import java.util.function.Consumer;
import java.lang.reflect.Method;
import java.util.Base64;
@@ -144,7 +147,7 @@
// Actually do the redefinition. The stack looks good.
retry = false;
w.accept("transforming calling function");
- doCommonClassRedefinition(Transform.class, CLASS_BYTES, DEX_BYTES);
+ Redefinition.doCommonClassRedefinition(Transform.class, CLASS_BYTES, DEX_BYTES);
}
};
// This just prints something out to show we are running the Runnable.
@@ -168,9 +171,4 @@
private static native boolean isInterpretedFunction(Method m, boolean require_deoptimizable);
private static native void ensureJitCompiled(Class c, String name);
-
- // Transforms the class
- private static native void doCommonClassRedefinition(Class<?> target,
- byte[] classfile,
- byte[] dexfile);
}
diff --git a/test/916-obsolete-jit/src/art/Redefinition.java b/test/916-obsolete-jit/src/art/Redefinition.java
new file mode 100644
index 0000000..0350ab4
--- /dev/null
+++ b/test/916-obsolete-jit/src/art/Redefinition.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package art;
+
+import java.util.ArrayList;
+// Common Redefinition functions. Placed here for use by CTS
+public class Redefinition {
+ // Bind native functions.
+ static {
+ Main.bindAgentJNIForClass(Redefinition.class);
+ }
+
+ public static final class CommonClassDefinition {
+ public final Class<?> target;
+ public final byte[] class_file_bytes;
+ public final byte[] dex_file_bytes;
+
+ public CommonClassDefinition(Class<?> target, byte[] class_file_bytes, byte[] dex_file_bytes) {
+ this.target = target;
+ this.class_file_bytes = class_file_bytes;
+ this.dex_file_bytes = dex_file_bytes;
+ }
+ }
+
+ // A set of possible test configurations. Test should set this if they need to.
+ // This must be kept in sync with the defines in ti-agent/common_helper.cc
+ public static enum Config {
+ COMMON_REDEFINE(0),
+ COMMON_RETRANSFORM(1),
+ COMMON_TRANSFORM(2);
+
+ private final int val;
+ private Config(int val) {
+ this.val = val;
+ }
+ }
+
+ public static void setTestConfiguration(Config type) {
+ nativeSetTestConfiguration(type.val);
+ }
+
+ private static native void nativeSetTestConfiguration(int type);
+
+ // Transforms the class
+ public static native void doCommonClassRedefinition(Class<?> target,
+ byte[] classfile,
+ byte[] dexfile);
+
+ public static void doMultiClassRedefinition(CommonClassDefinition... defs) {
+ ArrayList<Class<?>> classes = new ArrayList<>();
+ ArrayList<byte[]> class_files = new ArrayList<>();
+ ArrayList<byte[]> dex_files = new ArrayList<>();
+
+ for (CommonClassDefinition d : defs) {
+ classes.add(d.target);
+ class_files.add(d.class_file_bytes);
+ dex_files.add(d.dex_file_bytes);
+ }
+ doCommonMultiClassRedefinition(classes.toArray(new Class<?>[0]),
+ class_files.toArray(new byte[0][]),
+ dex_files.toArray(new byte[0][]));
+ }
+
+ public static void addMultiTransformationResults(CommonClassDefinition... defs) {
+ for (CommonClassDefinition d : defs) {
+ addCommonTransformationResult(d.target.getCanonicalName(),
+ d.class_file_bytes,
+ d.dex_file_bytes);
+ }
+ }
+
+ public static native void doCommonMultiClassRedefinition(Class<?>[] targets,
+ byte[][] classfiles,
+ byte[][] dexfiles);
+ public static native void doCommonClassRetransformation(Class<?>... target);
+ public static native void setPopRetransformations(boolean pop);
+ public static native void popTransformationFor(String name);
+ public static native void enableCommonRetransformation(boolean enable);
+ public static native void addCommonTransformationResult(String target_name,
+ byte[] class_bytes,
+ byte[] dex_bytes);
+}
diff --git a/test/917-fields-transformation/src/Main.java b/test/917-fields-transformation/src/Main.java
index 588af49..289b89f 100644
--- a/test/917-fields-transformation/src/Main.java
+++ b/test/917-fields-transformation/src/Main.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,67 +14,8 @@
* limitations under the License.
*/
-import java.util.Base64;
public class Main {
-
- // base64 encoded class/dex file for
- // class Transform {
- // public String take1;
- // public String take2;
- //
- // public Transform(String a, String b) {
- // take1 = a;
- // take2 = b;
- // }
- //
- // public String getResult() {
- // return take2;
- // }
- // }
- private static final byte[] CLASS_BYTES = Base64.getDecoder().decode(
- "yv66vgAAADQAFwoABQARCQAEABIJAAQAEwcAFAcAFQEABXRha2UxAQASTGphdmEvbGFuZy9TdHJp" +
- "bmc7AQAFdGFrZTIBAAY8aW5pdD4BACcoTGphdmEvbGFuZy9TdHJpbmc7TGphdmEvbGFuZy9TdHJp" +
- "bmc7KVYBAARDb2RlAQAPTGluZU51bWJlclRhYmxlAQAJZ2V0UmVzdWx0AQAUKClMamF2YS9sYW5n" +
- "L1N0cmluZzsBAApTb3VyY2VGaWxlAQAOVHJhbnNmb3JtLmphdmEMAAkAFgwABgAHDAAIAAcBAAlU" +
- "cmFuc2Zvcm0BABBqYXZhL2xhbmcvT2JqZWN0AQADKClWACAABAAFAAAAAgABAAYABwAAAAEACAAH" +
- "AAAAAgABAAkACgABAAsAAAAzAAIAAwAAAA8qtwABKiu1AAIqLLUAA7EAAAABAAwAAAASAAQAAAAU" +
- "AAQAFQAJABYADgAXAAEADQAOAAEACwAAAB0AAQABAAAABSq0AAOwAAAAAQAMAAAABgABAAAAGgAB" +
- "AA8AAAACABA=");
- private static final byte[] DEX_BYTES = Base64.getDecoder().decode(
- "ZGV4CjAzNQAGUTBb4jIABRlaI9rejdk7RCfyqR2kmNSkAgAAcAAAAHhWNBIAAAAAAAAAAAQCAAAM" +
- "AAAAcAAAAAQAAACgAAAAAwAAALAAAAACAAAA1AAAAAMAAADkAAAAAQAAAPwAAACIAQAAHAEAAFwB" +
- "AABkAQAAZwEAAHQBAACIAQAAnAEAAKwBAACvAQAAtAEAAMgBAADTAQAA2gEAAAIAAAADAAAABAAA" +
- "AAYAAAABAAAAAgAAAAAAAAAGAAAAAwAAAAAAAAAHAAAAAwAAAFQBAAAAAAIACgAAAAAAAgALAAAA" +
- "AAACAAAAAAAAAAAACQAAAAEAAQAAAAAAAAAAAAAAAAABAAAAAAAAAAUAAAAAAAAA8AEAAAAAAAAD" +
- "AAMAAQAAAOEBAAAIAAAAcBACAAAAWwEAAFsCAQAOAAIAAQAAAAAA6wEAAAMAAABUEAEAEQAAAAIA" +
- "AAACAAIABjxpbml0PgABTAALTFRyYW5zZm9ybTsAEkxqYXZhL2xhbmcvT2JqZWN0OwASTGphdmEv" +
- "bGFuZy9TdHJpbmc7AA5UcmFuc2Zvcm0uamF2YQABVgADVkxMABJlbWl0dGVyOiBqYWNrLTQuMTkA" +
- "CWdldFJlc3VsdAAFdGFrZTEABXRha2UyABQCAAAHDjwtLQAaAAcOAAACAQEAAQEBAIGABJwCAQG8" +
- "AgAADQAAAAAAAAABAAAAAAAAAAEAAAAMAAAAcAAAAAIAAAAEAAAAoAAAAAMAAAADAAAAsAAAAAQA" +
- "AAACAAAA1AAAAAUAAAADAAAA5AAAAAYAAAABAAAA/AAAAAEgAAACAAAAHAEAAAEQAAABAAAAVAEA" +
- "AAIgAAAMAAAAXAEAAAMgAAACAAAA4QEAAAAgAAABAAAA8AEAAAAQAAABAAAABAIAAA==");
-
- public static void main(String[] args) {
- art.Main.bindAgentJNIForClass(Main.class);
- doTest(new Transform("Hello", "Goodbye"),
- new Transform("start", "end"));
+ public static void main(String[] args) throws Exception {
+ art.Test917.run();
}
-
- private static void printTransform(Transform t) {
- System.out.println("Result is " + t.getResult());
- System.out.println("take1 is " + t.take1);
- System.out.println("take2 is " + t.take2);
- }
- public static void doTest(Transform t1, Transform t2) {
- printTransform(t1);
- printTransform(t2);
- doCommonClassRedefinition(Transform.class, CLASS_BYTES, DEX_BYTES);
- printTransform(t1);
- printTransform(t2);
- }
-
- // Transforms the class
- private static native void doCommonClassRedefinition(Class<?> target,
- byte[] class_file,
- byte[] dex_file);
}
diff --git a/test/917-fields-transformation/src/Transform.java b/test/917-fields-transformation/src/Transform.java
deleted file mode 100644
index 6fe6223..0000000
--- a/test/917-fields-transformation/src/Transform.java
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-class Transform {
- public String take1;
- public String take2;
-
- public Transform(String take1, String take2) {
- this.take1 = take1;
- this.take2 = take2;
- }
-
- public String getResult() {
- return take1;
- }
-}
diff --git a/test/917-fields-transformation/src/art/Redefinition.java b/test/917-fields-transformation/src/art/Redefinition.java
new file mode 100644
index 0000000..0350ab4
--- /dev/null
+++ b/test/917-fields-transformation/src/art/Redefinition.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package art;
+
+import java.util.ArrayList;
+// Common Redefinition functions. Placed here for use by CTS
+public class Redefinition {
+ // Bind native functions.
+ static {
+ Main.bindAgentJNIForClass(Redefinition.class);
+ }
+
+ public static final class CommonClassDefinition {
+ public final Class<?> target;
+ public final byte[] class_file_bytes;
+ public final byte[] dex_file_bytes;
+
+ public CommonClassDefinition(Class<?> target, byte[] class_file_bytes, byte[] dex_file_bytes) {
+ this.target = target;
+ this.class_file_bytes = class_file_bytes;
+ this.dex_file_bytes = dex_file_bytes;
+ }
+ }
+
+ // A set of possible test configurations. Test should set this if they need to.
+ // This must be kept in sync with the defines in ti-agent/common_helper.cc
+ public static enum Config {
+ COMMON_REDEFINE(0),
+ COMMON_RETRANSFORM(1),
+ COMMON_TRANSFORM(2);
+
+ private final int val;
+ private Config(int val) {
+ this.val = val;
+ }
+ }
+
+ public static void setTestConfiguration(Config type) {
+ nativeSetTestConfiguration(type.val);
+ }
+
+ private static native void nativeSetTestConfiguration(int type);
+
+ // Transforms the class
+ public static native void doCommonClassRedefinition(Class<?> target,
+ byte[] classfile,
+ byte[] dexfile);
+
+ public static void doMultiClassRedefinition(CommonClassDefinition... defs) {
+ ArrayList<Class<?>> classes = new ArrayList<>();
+ ArrayList<byte[]> class_files = new ArrayList<>();
+ ArrayList<byte[]> dex_files = new ArrayList<>();
+
+ for (CommonClassDefinition d : defs) {
+ classes.add(d.target);
+ class_files.add(d.class_file_bytes);
+ dex_files.add(d.dex_file_bytes);
+ }
+ doCommonMultiClassRedefinition(classes.toArray(new Class<?>[0]),
+ class_files.toArray(new byte[0][]),
+ dex_files.toArray(new byte[0][]));
+ }
+
+ public static void addMultiTransformationResults(CommonClassDefinition... defs) {
+ for (CommonClassDefinition d : defs) {
+ addCommonTransformationResult(d.target.getCanonicalName(),
+ d.class_file_bytes,
+ d.dex_file_bytes);
+ }
+ }
+
+ public static native void doCommonMultiClassRedefinition(Class<?>[] targets,
+ byte[][] classfiles,
+ byte[][] dexfiles);
+ public static native void doCommonClassRetransformation(Class<?>... target);
+ public static native void setPopRetransformations(boolean pop);
+ public static native void popTransformationFor(String name);
+ public static native void enableCommonRetransformation(boolean enable);
+ public static native void addCommonTransformationResult(String target_name,
+ byte[] class_bytes,
+ byte[] dex_bytes);
+}
diff --git a/test/917-fields-transformation/src/art/Test917.java b/test/917-fields-transformation/src/art/Test917.java
new file mode 100644
index 0000000..245e92e
--- /dev/null
+++ b/test/917-fields-transformation/src/art/Test917.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package art;
+
+import java.util.Base64;
+public class Test917 {
+
+ static class Transform {
+ public String take1;
+ public String take2;
+
+ public Transform(String take1, String take2) {
+ this.take1 = take1;
+ this.take2 = take2;
+ }
+
+ public String getResult() {
+ return take1;
+ }
+ }
+
+
+ // base64 encoded class/dex file for
+ // static class Transform {
+ // public String take1;
+ // public String take2;
+ //
+ // public Transform(String a, String b) {
+ // take1 = a;
+ // take2 = b;
+ // }
+ //
+ // public String getResult() {
+ // return take2;
+ // }
+ // }
+ private static final byte[] CLASS_BYTES = Base64.getDecoder().decode(
+ "yv66vgAAADQAGwoABQARCQAEABIJAAQAEwcAFQcAGAEABXRha2UxAQASTGphdmEvbGFuZy9TdHJp" +
+ "bmc7AQAFdGFrZTIBAAY8aW5pdD4BACcoTGphdmEvbGFuZy9TdHJpbmc7TGphdmEvbGFuZy9TdHJp" +
+ "bmc7KVYBAARDb2RlAQAPTGluZU51bWJlclRhYmxlAQAJZ2V0UmVzdWx0AQAUKClMamF2YS9sYW5n" +
+ "L1N0cmluZzsBAApTb3VyY2VGaWxlAQAMVGVzdDkxNy5qYXZhDAAJABkMAAYABwwACAAHBwAaAQAV" +
+ "YXJ0L1Rlc3Q5MTckVHJhbnNmb3JtAQAJVHJhbnNmb3JtAQAMSW5uZXJDbGFzc2VzAQAQamF2YS9s" +
+ "YW5nL09iamVjdAEAAygpVgEAC2FydC9UZXN0OTE3ACAABAAFAAAAAgABAAYABwAAAAEACAAHAAAA" +
+ "AgABAAkACgABAAsAAAAzAAIAAwAAAA8qtwABKiu1AAIqLLUAA7EAAAABAAwAAAASAAQAAAAJAAQA" +
+ "CgAJAAsADgAMAAEADQAOAAEACwAAAB0AAQABAAAABSq0AAOwAAAAAQAMAAAABgABAAAADwACAA8A" +
+ "AAACABAAFwAAAAoAAQAEABQAFgAI");
+ private static final byte[] DEX_BYTES = Base64.getDecoder().decode(
+ "ZGV4CjAzNQBdcPySAAAAAAAAAAAAAAAAAAAAAAAAAACQAwAAcAAAAHhWNBIAAAAAAAAAAMwCAAAS" +
+ "AAAAcAAAAAcAAAC4AAAAAwAAANQAAAACAAAA+AAAAAMAAAAIAQAAAQAAACABAABQAgAAQAEAAEAB" +
+ "AABIAQAASwEAAGQBAABzAQAAlwEAALcBAADLAQAA3wEAAO0BAAD4AQAA+wEAAAACAAANAgAAGAIA" +
+ "AB4CAAAlAgAALAIAAAIAAAADAAAABAAAAAUAAAAGAAAABwAAAAoAAAABAAAABQAAAAAAAAAKAAAA" +
+ "BgAAAAAAAAALAAAABgAAADQCAAAAAAUADwAAAAAABQAQAAAAAAACAAAAAAAAAAAADQAAAAQAAQAA" +
+ "AAAAAAAAAAAAAAAEAAAAAAAAAAgAAAC8AgAAjAIAAAAAAAAGPGluaXQ+AAFMABdMYXJ0L1Rlc3Q5" +
+ "MTckVHJhbnNmb3JtOwANTGFydC9UZXN0OTE3OwAiTGRhbHZpay9hbm5vdGF0aW9uL0VuY2xvc2lu" +
+ "Z0NsYXNzOwAeTGRhbHZpay9hbm5vdGF0aW9uL0lubmVyQ2xhc3M7ABJMamF2YS9sYW5nL09iamVj" +
+ "dDsAEkxqYXZhL2xhbmcvU3RyaW5nOwAMVGVzdDkxNy5qYXZhAAlUcmFuc2Zvcm0AAVYAA1ZMTAAL" +
+ "YWNjZXNzRmxhZ3MACWdldFJlc3VsdAAEbmFtZQAFdGFrZTEABXRha2UyAAV2YWx1ZQAAAgAAAAUA" +
+ "BQAJAgAABw4BAw8BAg8BAg8ADwAHDgAAAAADAAMAAQAAADwCAAAIAAAAcBACAAAAWwEAAFsCAQAO" +
+ "AAIAAQAAAAAATAIAAAMAAABUEAEAEQAAAAACAQEAAQEBAIGABNQEAQH0BAAAAgIBERgBAgMCDAQI" +
+ "DhcJAAIAAACgAgAApgIAALACAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAEAAAAAAAAAAQAAABIAAABw" +
+ "AAAAAgAAAAcAAAC4AAAAAwAAAAMAAADUAAAABAAAAAIAAAD4AAAABQAAAAMAAAAIAQAABgAAAAEA" +
+ "AAAgAQAAAiAAABIAAABAAQAAARAAAAEAAAA0AgAAAyAAAAIAAAA8AgAAASAAAAIAAABUAgAAACAA" +
+ "AAEAAACMAgAABCAAAAIAAACgAgAAAxAAAAEAAACwAgAABiAAAAEAAAC8AgAAABAAAAEAAADMAgAA");
+
+ public static void run() {
+ Redefinition.setTestConfiguration(Redefinition.Config.COMMON_REDEFINE);
+ doTest(new Transform("Hello", "Goodbye"),
+ new Transform("start", "end"));
+ }
+
+ private static void printTransform(Transform t) {
+ System.out.println("Result is " + t.getResult());
+ System.out.println("take1 is " + t.take1);
+ System.out.println("take2 is " + t.take2);
+ }
+ public static void doTest(Transform t1, Transform t2) {
+ printTransform(t1);
+ printTransform(t2);
+ Redefinition.doCommonClassRedefinition(Transform.class, CLASS_BYTES, DEX_BYTES);
+ printTransform(t1);
+ printTransform(t2);
+ }
+}
diff --git a/test/919-obsolete-fields/src/Main.java b/test/919-obsolete-fields/src/Main.java
index 34ee2a9..10eadb2 100644
--- a/test/919-obsolete-fields/src/Main.java
+++ b/test/919-obsolete-fields/src/Main.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,135 +14,8 @@
* limitations under the License.
*/
-import java.util.function.Consumer;
-import java.util.Base64;
-
public class Main {
-
- // What follows is the base64 encoded representation of the following class:
- //
- // import java.util.function.Consumer;
- //
- // class Transform {
- // private Consumer<String> reporter;
- // public Transform(Consumer<String> reporter) {
- // this.reporter = reporter;
- // }
- //
- // private void Start() {
- // reporter.accept("Hello - private - Transformed");
- // }
- //
- // private void Finish() {
- // reporter.accept("Goodbye - private - Transformed");
- // }
- //
- // public void sayHi(Runnable r) {
- // reporter.accept("pre Start private method call - Transformed");
- // Start();
- // reporter.accept("post Start private method call - Transformed");
- // r.run();
- // reporter.accept("pre Finish private method call - Transformed");
- // Finish();
- // reporter.accept("post Finish private method call - Transformed");
- // }
- // }
- private static final byte[] CLASS_BYTES = Base64.getDecoder().decode(
- "yv66vgAAADQANAoADgAfCQANACAIACELACIAIwgAJAgAJQoADQAmCAAnCwAoACkIACoKAA0AKwgA" +
- "LAcALQcALgEACHJlcG9ydGVyAQAdTGphdmEvdXRpbC9mdW5jdGlvbi9Db25zdW1lcjsBAAlTaWdu" +
- "YXR1cmUBADFMamF2YS91dGlsL2Z1bmN0aW9uL0NvbnN1bWVyPExqYXZhL2xhbmcvU3RyaW5nOz47" +
- "AQAGPGluaXQ+AQAgKExqYXZhL3V0aWwvZnVuY3Rpb24vQ29uc3VtZXI7KVYBAARDb2RlAQAPTGlu" +
- "ZU51bWJlclRhYmxlAQA0KExqYXZhL3V0aWwvZnVuY3Rpb24vQ29uc3VtZXI8TGphdmEvbGFuZy9T" +
- "dHJpbmc7PjspVgEABVN0YXJ0AQADKClWAQAGRmluaXNoAQAFc2F5SGkBABcoTGphdmEvbGFuZy9S" +
- "dW5uYWJsZTspVgEAClNvdXJjZUZpbGUBAA5UcmFuc2Zvcm0uamF2YQwAEwAZDAAPABABAB1IZWxs" +
- "byAtIHByaXZhdGUgLSBUcmFuc2Zvcm1lZAcALwwAMAAxAQAfR29vZGJ5ZSAtIHByaXZhdGUgLSBU" +
- "cmFuc2Zvcm1lZAEAK3ByZSBTdGFydCBwcml2YXRlIG1ldGhvZCBjYWxsIC0gVHJhbnNmb3JtZWQM" +
- "ABgAGQEALHBvc3QgU3RhcnQgcHJpdmF0ZSBtZXRob2QgY2FsbCAtIFRyYW5zZm9ybWVkBwAyDAAz" +
- "ABkBACxwcmUgRmluaXNoIHByaXZhdGUgbWV0aG9kIGNhbGwgLSBUcmFuc2Zvcm1lZAwAGgAZAQAt" +
- "cG9zdCBGaW5pc2ggcHJpdmF0ZSBtZXRob2QgY2FsbCAtIFRyYW5zZm9ybWVkAQAJVHJhbnNmb3Jt" +
- "AQAQamF2YS9sYW5nL09iamVjdAEAG2phdmEvdXRpbC9mdW5jdGlvbi9Db25zdW1lcgEABmFjY2Vw" +
- "dAEAFShMamF2YS9sYW5nL09iamVjdDspVgEAEmphdmEvbGFuZy9SdW5uYWJsZQEAA3J1bgAgAA0A" +
- "DgAAAAEAAgAPABAAAQARAAAAAgASAAQAAQATABQAAgAVAAAAKgACAAIAAAAKKrcAASortQACsQAA" +
- "AAEAFgAAAA4AAwAAABUABAAWAAkAFwARAAAAAgAXAAIAGAAZAAEAFQAAACgAAgABAAAADCq0AAIS" +
- "A7kABAIAsQAAAAEAFgAAAAoAAgAAABoACwAbAAIAGgAZAAEAFQAAACgAAgABAAAADCq0AAISBbkA" +
- "BAIAsQAAAAEAFgAAAAoAAgAAAB4ACwAfAAEAGwAcAAEAFQAAAG8AAgACAAAAOyq0AAISBrkABAIA" +
- "KrcAByq0AAISCLkABAIAK7kACQEAKrQAAhIKuQAEAgAqtwALKrQAAhIMuQAEAgCxAAAAAQAWAAAA" +
- "IgAIAAAAIgALACMADwAkABoAJQAgACYAKwAnAC8AKAA6ACkAAQAdAAAAAgAe");
- private static final byte[] DEX_BYTES = Base64.getDecoder().decode(
- "ZGV4CjAzNQAw/b59wCwTlSVDmuhPEezuK3oe0rtT4ujMBQAAcAAAAHhWNBIAAAAAAAAAAAgFAAAd" +
- "AAAAcAAAAAYAAADkAAAABAAAAPwAAAABAAAALAEAAAcAAAA0AQAAAQAAAGwBAABABAAAjAEAAJoC" +
- "AACdAgAAoAIAAKgCAACsAgAAsgIAALoCAADbAgAA+gIAAAcDAAAmAwAAOgMAAFADAABkAwAAggMA" +
- "AKEDAACoAwAAuAMAALsDAAC/AwAAxwMAANsDAAAKBAAAOAQAAGYEAACTBAAAnQQAAKIEAACpBAAA" +
- "CAAAAAkAAAAKAAAACwAAAA4AAAARAAAAEQAAAAUAAAAAAAAAEgAAAAUAAACEAgAAEgAAAAUAAACM" +
- "AgAAEgAAAAUAAACUAgAAAAAEABkAAAAAAAMAAgAAAAAAAAAFAAAAAAAAAA8AAAAAAAIAGwAAAAIA" +
- "AAACAAAAAwAAABoAAAAEAAEAEwAAAAAAAAAAAAAAAgAAAAAAAAAQAAAAZAIAAO8EAAAAAAAAAQAA" +
- "ANEEAAABAAAA3wQAAAIAAgABAAAAsAQAAAYAAABwEAQAAABbAQAADgADAAEAAgAAALgEAAAJAAAA" +
- "VCAAABsBBgAAAHIgBgAQAA4AAAADAAEAAgAAAL4EAAAJAAAAVCAAABsBBwAAAHIgBgAQAA4AAAAE" +
- "AAIAAgAAAMQEAAAqAAAAVCAAABsBGAAAAHIgBgAQAHAQAgACAFQgAAAbARYAAAByIAYAEAByEAUA" +
- "AwBUIAAAGwEXAAAAciAGABAAcBABAAIAVCAAABsBFQAAAHIgBgAQAA4AAAAAAAEAAAABAAAAAAAA" +
- "AAAAAACMAQAAAAAAAJQBAAABAAAAAgAAAAEAAAADAAAAAQAAAAQAASgAATwABjxpbml0PgACPjsA" +
- "BD47KVYABkZpbmlzaAAfR29vZGJ5ZSAtIHByaXZhdGUgLSBUcmFuc2Zvcm1lZAAdSGVsbG8gLSBw" +
- "cml2YXRlIC0gVHJhbnNmb3JtZWQAC0xUcmFuc2Zvcm07AB1MZGFsdmlrL2Fubm90YXRpb24vU2ln" +
- "bmF0dXJlOwASTGphdmEvbGFuZy9PYmplY3Q7ABRMamF2YS9sYW5nL1J1bm5hYmxlOwASTGphdmEv" +
- "bGFuZy9TdHJpbmc7ABxMamF2YS91dGlsL2Z1bmN0aW9uL0NvbnN1bWVyAB1MamF2YS91dGlsL2Z1" +
- "bmN0aW9uL0NvbnN1bWVyOwAFU3RhcnQADlRyYW5zZm9ybS5qYXZhAAFWAAJWTAAGYWNjZXB0ABJl" +
- "bWl0dGVyOiBqYWNrLTQuMTkALXBvc3QgRmluaXNoIHByaXZhdGUgbWV0aG9kIGNhbGwgLSBUcmFu" +
- "c2Zvcm1lZAAscG9zdCBTdGFydCBwcml2YXRlIG1ldGhvZCBjYWxsIC0gVHJhbnNmb3JtZWQALHBy" +
- "ZSBGaW5pc2ggcHJpdmF0ZSBtZXRob2QgY2FsbCAtIFRyYW5zZm9ybWVkACtwcmUgU3RhcnQgcHJp" +
- "dmF0ZSBtZXRob2QgY2FsbCAtIFRyYW5zZm9ybWVkAAhyZXBvcnRlcgADcnVuAAVzYXlIaQAFdmFs" +
- "dWUAFQEABw48LQAeAAcOhwAaAAcOhwAiAQAHDoc8hzyHPIcAAgEBHBwEFw0XARcMFwMCAQEcHAUX" +
- "ABcNFwEXDBcEAAEDAQACAIGABJwDAQK4AwEC3AMDAYAEABAAAAAAAAAAAQAAAAAAAAABAAAAHQAA" +
- "AHAAAAACAAAABgAAAOQAAAADAAAABAAAAPwAAAAEAAAAAQAAACwBAAAFAAAABwAAADQBAAAGAAAA" +
- "AQAAAGwBAAADEAAAAgAAAIwBAAABIAAABAAAAJwBAAAGIAAAAQAAAGQCAAABEAAAAwAAAIQCAAAC" +
- "IAAAHQAAAJoCAAADIAAABAAAALAEAAAEIAAAAgAAANEEAAAAIAAAAQAAAO8EAAAAEAAAAQAAAAgF" +
- "AAA=");
-
- // A class that we can use to keep track of the output of this test.
- private static class TestWatcher implements Consumer<String> {
- private StringBuilder sb;
- public TestWatcher() {
- sb = new StringBuilder();
- }
-
- @Override
- public void accept(String s) {
- sb.append(s);
- sb.append('\n');
- }
-
- public String getOutput() {
- return sb.toString();
- }
+ public static void main(String[] args) throws Exception {
+ art.Test919.run();
}
-
- public static void main(String[] args) {
- art.Main.bindAgentJNIForClass(Main.class);
- TestWatcher w = new TestWatcher();
- doTest(new Transform(w), w);
- }
-
- private static boolean interpreting = true;
- private static boolean retry = false;
-
- public static void doTest(Transform t, TestWatcher w) {
- Runnable do_redefinition = () -> {
- w.accept("transforming calling function");
- doCommonClassRedefinition(Transform.class, CLASS_BYTES, DEX_BYTES);
- };
- // This just prints something out to show we are running the Runnable.
- Runnable say_nothing = () -> { w.accept("Not doing anything here"); };
-
- // Try and redefine.
- t.sayHi(say_nothing);
- t.sayHi(do_redefinition);
- t.sayHi(say_nothing);
-
- // Print output of last run.
- System.out.print(w.getOutput());
- }
-
- // Transforms the class
- private static native void doCommonClassRedefinition(Class<?> target,
- byte[] classfile,
- byte[] dexfile);
}
diff --git a/test/919-obsolete-fields/src/Transform.java b/test/919-obsolete-fields/src/Transform.java
deleted file mode 100644
index c8e3cbd..0000000
--- a/test/919-obsolete-fields/src/Transform.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-import java.util.function.Consumer;
-
-class Transform {
- private Consumer<String> reporter;
- public Transform(Consumer<String> reporter) {
- this.reporter = reporter;
- }
-
- private void Start() {
- reporter.accept("hello - private");
- }
-
- private void Finish() {
- reporter.accept("goodbye - private");
- }
-
- public void sayHi(Runnable r) {
- reporter.accept("Pre Start private method call");
- Start();
- reporter.accept("Post Start private method call");
- r.run();
- reporter.accept("Pre Finish private method call");
- Finish();
- reporter.accept("Post Finish private method call");
- }
-}
diff --git a/test/919-obsolete-fields/src/art/Redefinition.java b/test/919-obsolete-fields/src/art/Redefinition.java
new file mode 100644
index 0000000..0350ab4
--- /dev/null
+++ b/test/919-obsolete-fields/src/art/Redefinition.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package art;
+
+import java.util.ArrayList;
+// Common Redefinition functions. Placed here for use by CTS
+public class Redefinition {
+ // Bind native functions.
+ static {
+ Main.bindAgentJNIForClass(Redefinition.class);
+ }
+
+ public static final class CommonClassDefinition {
+ public final Class<?> target;
+ public final byte[] class_file_bytes;
+ public final byte[] dex_file_bytes;
+
+ public CommonClassDefinition(Class<?> target, byte[] class_file_bytes, byte[] dex_file_bytes) {
+ this.target = target;
+ this.class_file_bytes = class_file_bytes;
+ this.dex_file_bytes = dex_file_bytes;
+ }
+ }
+
+ // A set of possible test configurations. Test should set this if they need to.
+ // This must be kept in sync with the defines in ti-agent/common_helper.cc
+ public static enum Config {
+ COMMON_REDEFINE(0),
+ COMMON_RETRANSFORM(1),
+ COMMON_TRANSFORM(2);
+
+ private final int val;
+ private Config(int val) {
+ this.val = val;
+ }
+ }
+
+ public static void setTestConfiguration(Config type) {
+ nativeSetTestConfiguration(type.val);
+ }
+
+ private static native void nativeSetTestConfiguration(int type);
+
+ // Transforms the class
+ public static native void doCommonClassRedefinition(Class<?> target,
+ byte[] classfile,
+ byte[] dexfile);
+
+ public static void doMultiClassRedefinition(CommonClassDefinition... defs) {
+ ArrayList<Class<?>> classes = new ArrayList<>();
+ ArrayList<byte[]> class_files = new ArrayList<>();
+ ArrayList<byte[]> dex_files = new ArrayList<>();
+
+ for (CommonClassDefinition d : defs) {
+ classes.add(d.target);
+ class_files.add(d.class_file_bytes);
+ dex_files.add(d.dex_file_bytes);
+ }
+ doCommonMultiClassRedefinition(classes.toArray(new Class<?>[0]),
+ class_files.toArray(new byte[0][]),
+ dex_files.toArray(new byte[0][]));
+ }
+
+ public static void addMultiTransformationResults(CommonClassDefinition... defs) {
+ for (CommonClassDefinition d : defs) {
+ addCommonTransformationResult(d.target.getCanonicalName(),
+ d.class_file_bytes,
+ d.dex_file_bytes);
+ }
+ }
+
+ public static native void doCommonMultiClassRedefinition(Class<?>[] targets,
+ byte[][] classfiles,
+ byte[][] dexfiles);
+ public static native void doCommonClassRetransformation(Class<?>... target);
+ public static native void setPopRetransformations(boolean pop);
+ public static native void popTransformationFor(String name);
+ public static native void enableCommonRetransformation(boolean enable);
+ public static native void addCommonTransformationResult(String target_name,
+ byte[] class_bytes,
+ byte[] dex_bytes);
+}
diff --git a/test/919-obsolete-fields/src/art/Test919.java b/test/919-obsolete-fields/src/art/Test919.java
new file mode 100644
index 0000000..11971ef
--- /dev/null
+++ b/test/919-obsolete-fields/src/art/Test919.java
@@ -0,0 +1,173 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package art;
+
+import java.util.function.Consumer;
+import java.util.Base64;
+
+public class Test919 {
+
+ static class Transform {
+ private Consumer<String> reporter;
+ public Transform(Consumer<String> reporter) {
+ this.reporter = reporter;
+ }
+
+ private void Start() {
+ reporter.accept("hello - private");
+ }
+
+ private void Finish() {
+ reporter.accept("goodbye - private");
+ }
+
+ public void sayHi(Runnable r) {
+ reporter.accept("Pre Start private method call");
+ Start();
+ reporter.accept("Post Start private method call");
+ r.run();
+ reporter.accept("Pre Finish private method call");
+ Finish();
+ reporter.accept("Post Finish private method call");
+ }
+ }
+
+
+ // What follows is the base64 encoded representation of the following class:
+ //
+ // import java.util.function.Consumer;
+ //
+ // static class Transform {
+ // private Consumer<String> reporter;
+ // public Transform(Consumer<String> reporter) {
+ // this.reporter = reporter;
+ // }
+ //
+ // private void Start() {
+ // reporter.accept("Hello - private - Transformed");
+ // }
+ //
+ // private void Finish() {
+ // reporter.accept("Goodbye - private - Transformed");
+ // }
+ //
+ // public void sayHi(Runnable r) {
+ // reporter.accept("pre Start private method call - Transformed");
+ // Start();
+ // reporter.accept("post Start private method call - Transformed");
+ // r.run();
+ // reporter.accept("pre Finish private method call - Transformed");
+ // Finish();
+ // reporter.accept("post Finish private method call - Transformed");
+ // }
+ // }
+ private static final byte[] CLASS_BYTES = Base64.getDecoder().decode(
+ "yv66vgAAADQAOAoADgAfCQANACAIACELACIAIwgAJAgAJQoADQAmCAAnCwAoACkIACoKAA0AKwgA" +
+ "LAcALgcAMQEACHJlcG9ydGVyAQAdTGphdmEvdXRpbC9mdW5jdGlvbi9Db25zdW1lcjsBAAlTaWdu" +
+ "YXR1cmUBADFMamF2YS91dGlsL2Z1bmN0aW9uL0NvbnN1bWVyPExqYXZhL2xhbmcvU3RyaW5nOz47" +
+ "AQAGPGluaXQ+AQAgKExqYXZhL3V0aWwvZnVuY3Rpb24vQ29uc3VtZXI7KVYBAARDb2RlAQAPTGlu" +
+ "ZU51bWJlclRhYmxlAQA0KExqYXZhL3V0aWwvZnVuY3Rpb24vQ29uc3VtZXI8TGphdmEvbGFuZy9T" +
+ "dHJpbmc7PjspVgEABVN0YXJ0AQADKClWAQAGRmluaXNoAQAFc2F5SGkBABcoTGphdmEvbGFuZy9S" +
+ "dW5uYWJsZTspVgEAClNvdXJjZUZpbGUBAAxUZXN0OTE5LmphdmEMABMAGQwADwAQAQAdSGVsbG8g" +
+ "LSBwcml2YXRlIC0gVHJhbnNmb3JtZWQHADIMADMANAEAH0dvb2RieWUgLSBwcml2YXRlIC0gVHJh" +
+ "bnNmb3JtZWQBACtwcmUgU3RhcnQgcHJpdmF0ZSBtZXRob2QgY2FsbCAtIFRyYW5zZm9ybWVkDAAY" +
+ "ABkBACxwb3N0IFN0YXJ0IHByaXZhdGUgbWV0aG9kIGNhbGwgLSBUcmFuc2Zvcm1lZAcANQwANgAZ" +
+ "AQAscHJlIEZpbmlzaCBwcml2YXRlIG1ldGhvZCBjYWxsIC0gVHJhbnNmb3JtZWQMABoAGQEALXBv" +
+ "c3QgRmluaXNoIHByaXZhdGUgbWV0aG9kIGNhbGwgLSBUcmFuc2Zvcm1lZAcANwEAFWFydC9UZXN0" +
+ "OTE5JFRyYW5zZm9ybQEACVRyYW5zZm9ybQEADElubmVyQ2xhc3NlcwEAEGphdmEvbGFuZy9PYmpl" +
+ "Y3QBABtqYXZhL3V0aWwvZnVuY3Rpb24vQ29uc3VtZXIBAAZhY2NlcHQBABUoTGphdmEvbGFuZy9P" +
+ "YmplY3Q7KVYBABJqYXZhL2xhbmcvUnVubmFibGUBAANydW4BAAthcnQvVGVzdDkxOQAgAA0ADgAA" +
+ "AAEAAgAPABAAAQARAAAAAgASAAQAAQATABQAAgAVAAAAKgACAAIAAAAKKrcAASortQACsQAAAAEA" +
+ "FgAAAA4AAwAAAAgABAAJAAkACgARAAAAAgAXAAIAGAAZAAEAFQAAACgAAgABAAAADCq0AAISA7kA" +
+ "BAIAsQAAAAEAFgAAAAoAAgAAAA0ACwAOAAIAGgAZAAEAFQAAACgAAgABAAAADCq0AAISBbkABAIA" +
+ "sQAAAAEAFgAAAAoAAgAAABEACwASAAEAGwAcAAEAFQAAAG8AAgACAAAAOyq0AAISBrkABAIAKrcA" +
+ "Byq0AAISCLkABAIAK7kACQEAKrQAAhIKuQAEAgAqtwALKrQAAhIMuQAEAgCxAAAAAQAWAAAAIgAI" +
+ "AAAAFQALABYADwAXABoAGAAgABkAKwAaAC8AGwA6ABwAAgAdAAAAAgAeADAAAAAKAAEADQAtAC8A" +
+ "CA==");
+ private static final byte[] DEX_BYTES = Base64.getDecoder().decode(
+ "ZGV4CjAzNQBeEZYBAAAAAAAAAAAAAAAAAAAAAAAAAACMBgAAcAAAAHhWNBIAAAAAAAAAAMgFAAAi" +
+ "AAAAcAAAAAkAAAD4AAAABAAAABwBAAABAAAATAEAAAcAAABUAQAAAQAAAIwBAADgBAAArAEAAKwB" +
+ "AACvAQAAsgEAALoBAAC+AQAAxAEAAMwBAADtAQAADAIAACUCAAA0AgAAWAIAAHgCAACXAgAAqwIA" +
+ "AMECAADVAgAA8wIAABIDAAAZAwAAJwMAADIDAAA1AwAAOQMAAEEDAABOAwAAVAMAAIMDAACxAwAA" +
+ "3wMAAAwEAAAWBAAAGwQAACIEAAAIAAAACQAAAAoAAAALAAAADAAAAA0AAAAOAAAAEQAAABUAAAAV" +
+ "AAAACAAAAAAAAAAWAAAACAAAADQEAAAWAAAACAAAADwEAAAWAAAACAAAACwEAAAAAAcAHgAAAAAA" +
+ "AwACAAAAAAAAAAUAAAAAAAAAEgAAAAAAAgAgAAAABQAAAAIAAAAGAAAAHwAAAAcAAQAXAAAAAAAA" +
+ "AAAAAAAFAAAAAAAAABMAAACoBQAARAUAAAAAAAABKAABPAAGPGluaXQ+AAI+OwAEPjspVgAGRmlu" +
+ "aXNoAB9Hb29kYnllIC0gcHJpdmF0ZSAtIFRyYW5zZm9ybWVkAB1IZWxsbyAtIHByaXZhdGUgLSBU" +
+ "cmFuc2Zvcm1lZAAXTGFydC9UZXN0OTE5JFRyYW5zZm9ybTsADUxhcnQvVGVzdDkxOTsAIkxkYWx2" +
+ "aWsvYW5ub3RhdGlvbi9FbmNsb3NpbmdDbGFzczsAHkxkYWx2aWsvYW5ub3RhdGlvbi9Jbm5lckNs" +
+ "YXNzOwAdTGRhbHZpay9hbm5vdGF0aW9uL1NpZ25hdHVyZTsAEkxqYXZhL2xhbmcvT2JqZWN0OwAU" +
+ "TGphdmEvbGFuZy9SdW5uYWJsZTsAEkxqYXZhL2xhbmcvU3RyaW5nOwAcTGphdmEvdXRpbC9mdW5j" +
+ "dGlvbi9Db25zdW1lcgAdTGphdmEvdXRpbC9mdW5jdGlvbi9Db25zdW1lcjsABVN0YXJ0AAxUZXN0" +
+ "OTE5LmphdmEACVRyYW5zZm9ybQABVgACVkwABmFjY2VwdAALYWNjZXNzRmxhZ3MABG5hbWUALXBv" +
+ "c3QgRmluaXNoIHByaXZhdGUgbWV0aG9kIGNhbGwgLSBUcmFuc2Zvcm1lZAAscG9zdCBTdGFydCBw" +
+ "cml2YXRlIG1ldGhvZCBjYWxsIC0gVHJhbnNmb3JtZWQALHByZSBGaW5pc2ggcHJpdmF0ZSBtZXRo" +
+ "b2QgY2FsbCAtIFRyYW5zZm9ybWVkACtwcmUgU3RhcnQgcHJpdmF0ZSBtZXRob2QgY2FsbCAtIFRy" +
+ "YW5zZm9ybWVkAAhyZXBvcnRlcgADcnVuAAVzYXlIaQAFdmFsdWUAAAAAAQAAAAcAAAABAAAABQAA" +
+ "AAEAAAAGAAAACAEABw4BAw8BAg8AEQAHDgEIDwANAAcOAQgPABUBAAcOAQgPAQMPAQgPAQMPAQgP" +
+ "AQMPAQgPAAACAAIAAQAAAEQEAAAGAAAAcBAEAAAAWwEAAA4AAwABAAIAAABQBAAACQAAAFQgAAAb" +
+ "AQYAAAByIAYAEAAOAAAAAwABAAIAAABYBAAACQAAAFQgAAAbAQcAAAByIAYAEAAOAAAABAACAAIA" +
+ "AABgBAAAKgAAAFQgAAAbAR0AAAByIAYAEABwEAIAAgBUIAAAGwEbAAAAciAGABAAchAFAAMAVCAA" +
+ "ABsBHAAAAHIgBgAQAHAQAQACAFQgAAAbARoAAAByIAYAEAAOAAABAwEAAgCBgAT8CAECmAkBArwJ" +
+ "AwHgCQICASEYAQIDAhgECBkXFAIEASEcBBcQFwEXDxcDAgQBIRwFFwAXEBcBFw8XBAAAAAIAAABc" +
+ "BQAAYgUAAAEAAABrBQAAAQAAAHkFAACMBQAAAQAAAAEAAAAAAAAAAAAAAJgFAAAAAAAAoAUAABAA" +
+ "AAAAAAAAAQAAAAAAAAABAAAAIgAAAHAAAAACAAAACQAAAPgAAAADAAAABAAAABwBAAAEAAAAAQAA" +
+ "AEwBAAAFAAAABwAAAFQBAAAGAAAAAQAAAIwBAAACIAAAIgAAAKwBAAABEAAAAwAAACwEAAADIAAA" +
+ "BAAAAEQEAAABIAAABAAAAHwEAAAAIAAAAQAAAEQFAAAEIAAABAAAAFwFAAADEAAAAwAAAIwFAAAG" +
+ "IAAAAQAAAKgFAAAAEAAAAQAAAMgFAAA=");
+
+ // A class that we can use to keep track of the output of this test.
+ private static class TestWatcher implements Consumer<String> {
+ private StringBuilder sb;
+ public TestWatcher() {
+ sb = new StringBuilder();
+ }
+
+ @Override
+ public void accept(String s) {
+ sb.append(s);
+ sb.append('\n');
+ }
+
+ public String getOutput() {
+ return sb.toString();
+ }
+ }
+
+ public static void run() {
+ Redefinition.setTestConfiguration(Redefinition.Config.COMMON_REDEFINE);
+ TestWatcher w = new TestWatcher();
+ doTest(new Transform(w), w);
+ }
+
+ public static void doTest(Transform t, TestWatcher w) {
+ Runnable do_redefinition = () -> {
+ w.accept("transforming calling function");
+ Redefinition.doCommonClassRedefinition(Transform.class, CLASS_BYTES, DEX_BYTES);
+ };
+ // This just prints something out to show we are running the Runnable.
+ Runnable say_nothing = () -> { w.accept("Not doing anything here"); };
+
+ // Try and redefine.
+ t.sayHi(say_nothing);
+ t.sayHi(do_redefinition);
+ t.sayHi(say_nothing);
+
+ // Print output of last run.
+ System.out.print(w.getOutput());
+ }
+}
diff --git a/test/921-hello-failure/src/Main.java b/test/921-hello-failure/src/Main.java
index d9a4948..cfdcdc2 100644
--- a/test/921-hello-failure/src/Main.java
+++ b/test/921-hello-failure/src/Main.java
@@ -14,12 +14,12 @@
* limitations under the License.
*/
-import java.util.ArrayList;
+import art.Redefinition;
+import java.util.Arrays;
+
public class Main {
public static void main(String[] args) {
- art.Main.bindAgentJNIForClass(Main.class);
-
Verification.doTest(new Transform());
NewName.doTest(new Transform());
DifferentAccess.doTest(new Transform());
@@ -37,40 +37,40 @@
Unmodifiable.doTest(new Transform[] { new Transform(), });
}
- // Transforms the class. This throws an exception if something goes wrong.
- public static native void doCommonClassRedefinition(Class<?> target,
- byte[] classfile,
- byte[] dexfile) throws Exception;
+ // TODO Replace this shim with a better re-write of this test.
+ private static Redefinition.CommonClassDefinition mapCCD(CommonClassDefinition d) {
+ return new Redefinition.CommonClassDefinition(d.target, d.class_file_bytes, d.dex_file_bytes);
+ }
+ private static Redefinition.CommonClassDefinition[] toCCDA(CommonClassDefinition[] ds) {
+ return Arrays.stream(ds).map(Main::mapCCD).toArray(Redefinition.CommonClassDefinition[]::new);
+ }
+
+ public static void doCommonClassRedefinition(Class<?> target,
+ byte[] classfile,
+ byte[] dexfile) throws Exception {
+ Redefinition.doCommonClassRedefinition(target, classfile, dexfile);
+ }
public static void doMultiClassRedefinition(CommonClassDefinition... defs) throws Exception {
- ArrayList<Class<?>> classes = new ArrayList<>();
- ArrayList<byte[]> class_files = new ArrayList<>();
- ArrayList<byte[]> dex_files = new ArrayList<>();
-
- for (CommonClassDefinition d : defs) {
- classes.add(d.target);
- class_files.add(d.class_file_bytes);
- dex_files.add(d.dex_file_bytes);
- }
- doCommonMultiClassRedefinition(classes.toArray(new Class<?>[0]),
- class_files.toArray(new byte[0][]),
- dex_files.toArray(new byte[0][]));
+ Redefinition.doMultiClassRedefinition(toCCDA(defs));
}
-
public static void addMultiTransformationResults(CommonClassDefinition... defs) throws Exception {
- for (CommonClassDefinition d : defs) {
- addCommonTransformationResult(d.target.getCanonicalName(),
- d.class_file_bytes,
- d.dex_file_bytes);
- }
+ Redefinition.addMultiTransformationResults(toCCDA(defs));
}
-
- public static native void doCommonMultiClassRedefinition(Class<?>[] targets,
- byte[][] classfiles,
- byte[][] dexfiles) throws Exception;
- public static native void doCommonClassRetransformation(Class<?>... target) throws Exception;
- public static native void enableCommonRetransformation(boolean enable);
- public static native void addCommonTransformationResult(String target_name,
- byte[] class_bytes,
- byte[] dex_bytes);
+ public static void doCommonMultiClassRedefinition(Class<?>[] targets,
+ byte[][] classfiles,
+ byte[][] dexfiles) throws Exception {
+ Redefinition.doCommonMultiClassRedefinition(targets, classfiles, dexfiles);
+ }
+ public static void doCommonClassRetransformation(Class<?>... target) throws Exception {
+ Redefinition.doCommonClassRetransformation(target);
+ }
+ public static void enableCommonRetransformation(boolean enable) {
+ Redefinition.enableCommonRetransformation(enable);
+ }
+ public static void addCommonTransformationResult(String target_name,
+ byte[] class_bytes,
+ byte[] dex_bytes) {
+ Redefinition.addCommonTransformationResult(target_name, class_bytes, dex_bytes);
+ }
}
diff --git a/test/921-hello-failure/src/art/Redefinition.java b/test/921-hello-failure/src/art/Redefinition.java
new file mode 100644
index 0000000..0350ab4
--- /dev/null
+++ b/test/921-hello-failure/src/art/Redefinition.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package art;
+
+import java.util.ArrayList;
+// Common Redefinition functions. Placed here for use by CTS
+public class Redefinition {
+ // Bind native functions.
+ static {
+ Main.bindAgentJNIForClass(Redefinition.class);
+ }
+
+ public static final class CommonClassDefinition {
+ public final Class<?> target;
+ public final byte[] class_file_bytes;
+ public final byte[] dex_file_bytes;
+
+ public CommonClassDefinition(Class<?> target, byte[] class_file_bytes, byte[] dex_file_bytes) {
+ this.target = target;
+ this.class_file_bytes = class_file_bytes;
+ this.dex_file_bytes = dex_file_bytes;
+ }
+ }
+
+ // A set of possible test configurations. Test should set this if they need to.
+ // This must be kept in sync with the defines in ti-agent/common_helper.cc
+ public static enum Config {
+ COMMON_REDEFINE(0),
+ COMMON_RETRANSFORM(1),
+ COMMON_TRANSFORM(2);
+
+ private final int val;
+ private Config(int val) {
+ this.val = val;
+ }
+ }
+
+ public static void setTestConfiguration(Config type) {
+ nativeSetTestConfiguration(type.val);
+ }
+
+ private static native void nativeSetTestConfiguration(int type);
+
+ // Transforms the class
+ public static native void doCommonClassRedefinition(Class<?> target,
+ byte[] classfile,
+ byte[] dexfile);
+
+ public static void doMultiClassRedefinition(CommonClassDefinition... defs) {
+ ArrayList<Class<?>> classes = new ArrayList<>();
+ ArrayList<byte[]> class_files = new ArrayList<>();
+ ArrayList<byte[]> dex_files = new ArrayList<>();
+
+ for (CommonClassDefinition d : defs) {
+ classes.add(d.target);
+ class_files.add(d.class_file_bytes);
+ dex_files.add(d.dex_file_bytes);
+ }
+ doCommonMultiClassRedefinition(classes.toArray(new Class<?>[0]),
+ class_files.toArray(new byte[0][]),
+ dex_files.toArray(new byte[0][]));
+ }
+
+ public static void addMultiTransformationResults(CommonClassDefinition... defs) {
+ for (CommonClassDefinition d : defs) {
+ addCommonTransformationResult(d.target.getCanonicalName(),
+ d.class_file_bytes,
+ d.dex_file_bytes);
+ }
+ }
+
+ public static native void doCommonMultiClassRedefinition(Class<?>[] targets,
+ byte[][] classfiles,
+ byte[][] dexfiles);
+ public static native void doCommonClassRetransformation(Class<?>... target);
+ public static native void setPopRetransformations(boolean pop);
+ public static native void popTransformationFor(String name);
+ public static native void enableCommonRetransformation(boolean enable);
+ public static native void addCommonTransformationResult(String target_name,
+ byte[] class_bytes,
+ byte[] dex_bytes);
+}
diff --git a/test/926-multi-obsolescence/src/CommonClassDefinition.java b/test/926-multi-obsolescence/src/CommonClassDefinition.java
deleted file mode 100644
index 62602a0..0000000
--- a/test/926-multi-obsolescence/src/CommonClassDefinition.java
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-class CommonClassDefinition {
- public final Class<?> target;
- public final byte[] class_file_bytes;
- public final byte[] dex_file_bytes;
-
- CommonClassDefinition(Class<?> target, byte[] class_file_bytes, byte[] dex_file_bytes) {
- this.target = target;
- this.class_file_bytes = class_file_bytes;
- this.dex_file_bytes = dex_file_bytes;
- }
-}
diff --git a/test/926-multi-obsolescence/src/Main.java b/test/926-multi-obsolescence/src/Main.java
index 2440908..8e21b8f 100644
--- a/test/926-multi-obsolescence/src/Main.java
+++ b/test/926-multi-obsolescence/src/Main.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,115 +14,8 @@
* limitations under the License.
*/
-import java.util.ArrayList;
-import java.util.Base64;
-
public class Main {
- // class Transform {
- // public void sayHi(Runnable r) {
- // System.out.println("Hello - Transformed");
- // r.run();
- // System.out.println("Goodbye - Transformed");
- // }
- // }
- private static CommonClassDefinition VALID_DEFINITION_T1 = new CommonClassDefinition(
- Transform.class,
- Base64.getDecoder().decode(
- "yv66vgAAADQAJAoACAARCQASABMIABQKABUAFgsAFwAYCAAZBwAaBwAbAQAGPGluaXQ+AQADKClW" +
- "AQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEABXNheUhpAQAXKExqYXZhL2xhbmcvUnVubmFibGU7" +
- "KVYBAApTb3VyY2VGaWxlAQAOVHJhbnNmb3JtLmphdmEMAAkACgcAHAwAHQAeAQATSGVsbG8gLSBU" +
- "cmFuc2Zvcm1lZAcAHwwAIAAhBwAiDAAjAAoBABVHb29kYnllIC0gVHJhbnNmb3JtZWQBAAlUcmFu" +
- "c2Zvcm0BABBqYXZhL2xhbmcvT2JqZWN0AQAQamF2YS9sYW5nL1N5c3RlbQEAA291dAEAFUxqYXZh" +
- "L2lvL1ByaW50U3RyZWFtOwEAE2phdmEvaW8vUHJpbnRTdHJlYW0BAAdwcmludGxuAQAVKExqYXZh" +
- "L2xhbmcvU3RyaW5nOylWAQASamF2YS9sYW5nL1J1bm5hYmxlAQADcnVuACAABwAIAAAAAAACAAAA" +
- "CQAKAAEACwAAAB0AAQABAAAABSq3AAGxAAAAAQAMAAAABgABAAAAAQABAA0ADgABAAsAAAA7AAIA" +
- "AgAAABeyAAISA7YABCu5AAUBALIAAhIGtgAEsQAAAAEADAAAABIABAAAAAMACAAEAA4ABQAWAAYA" +
- "AQAPAAAAAgAQ"),
- Base64.getDecoder().decode(
- "ZGV4CjAzNQAYeAMMXgYWxoeSHAS9EWKCCtVRSAGpqZVQAwAAcAAAAHhWNBIAAAAAAAAAALACAAAR" +
- "AAAAcAAAAAcAAAC0AAAAAwAAANAAAAABAAAA9AAAAAUAAAD8AAAAAQAAACQBAAAMAgAARAEAAKIB" +
- "AACqAQAAwQEAANYBAADjAQAA+gEAAA4CAAAkAgAAOAIAAEwCAABcAgAAXwIAAGMCAAB3AgAAfAIA" +
- "AIUCAACKAgAAAwAAAAQAAAAFAAAABgAAAAcAAAAIAAAACgAAAAoAAAAGAAAAAAAAAAsAAAAGAAAA" +
- "lAEAAAsAAAAGAAAAnAEAAAUAAQANAAAAAAAAAAAAAAAAAAEAEAAAAAEAAgAOAAAAAgAAAAAAAAAD" +
- "AAAADwAAAAAAAAAAAAAAAgAAAAAAAAAJAAAAAAAAAJ8CAAAAAAAAAQABAAEAAACRAgAABAAAAHAQ" +
- "AwAAAA4ABAACAAIAAACWAgAAFAAAAGIAAAAbAQIAAABuIAIAEAByEAQAAwBiAAAAGwEBAAAAbiAC" +
- "ABAADgABAAAAAwAAAAEAAAAEAAY8aW5pdD4AFUdvb2RieWUgLSBUcmFuc2Zvcm1lZAATSGVsbG8g" +
- "LSBUcmFuc2Zvcm1lZAALTFRyYW5zZm9ybTsAFUxqYXZhL2lvL1ByaW50U3RyZWFtOwASTGphdmEv" +
- "bGFuZy9PYmplY3Q7ABRMamF2YS9sYW5nL1J1bm5hYmxlOwASTGphdmEvbGFuZy9TdHJpbmc7ABJM" +
- "amF2YS9sYW5nL1N5c3RlbTsADlRyYW5zZm9ybS5qYXZhAAFWAAJWTAASZW1pdHRlcjogamFjay00" +
- "LjEzAANvdXQAB3ByaW50bG4AA3J1bgAFc2F5SGkAAQAHDgADAQAHDoc8hwAAAAEBAICABMQCAQHc" +
- "AgAAAA0AAAAAAAAAAQAAAAAAAAABAAAAEQAAAHAAAAACAAAABwAAALQAAAADAAAAAwAAANAAAAAE" +
- "AAAAAQAAAPQAAAAFAAAABQAAAPwAAAAGAAAAAQAAACQBAAABIAAAAgAAAEQBAAABEAAAAgAAAJQB" +
- "AAACIAAAEQAAAKIBAAADIAAAAgAAAJECAAAAIAAAAQAAAJ8CAAAAEAAAAQAAALACAAA="));
- // class Transform2 {
- // public void sayHi(Runnable r) {
- // System.out.println("Hello 2 - Transformed");
- // r.run();
- // System.out.println("Goodbye 2 - Transformed");
- // }
- // }
- private static CommonClassDefinition VALID_DEFINITION_T2 = new CommonClassDefinition(
- Transform2.class,
- Base64.getDecoder().decode(
- "yv66vgAAADQAJAoACAARCQASABMIABQKABUAFgsAFwAYCAAZBwAaBwAbAQAGPGluaXQ+AQADKClW" +
- "AQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEABXNheUhpAQAXKExqYXZhL2xhbmcvUnVubmFibGU7" +
- "KVYBAApTb3VyY2VGaWxlAQAPVHJhbnNmb3JtMi5qYXZhDAAJAAoHABwMAB0AHgEAFUhlbGxvIDIg" +
- "LSBUcmFuc2Zvcm1lZAcAHwwAIAAhBwAiDAAjAAoBABdHb29kYnllIDIgLSBUcmFuc2Zvcm1lZAEA" +
- "ClRyYW5zZm9ybTIBABBqYXZhL2xhbmcvT2JqZWN0AQAQamF2YS9sYW5nL1N5c3RlbQEAA291dAEA" +
- "FUxqYXZhL2lvL1ByaW50U3RyZWFtOwEAE2phdmEvaW8vUHJpbnRTdHJlYW0BAAdwcmludGxuAQAV" +
- "KExqYXZhL2xhbmcvU3RyaW5nOylWAQASamF2YS9sYW5nL1J1bm5hYmxlAQADcnVuACAABwAIAAAA" +
- "AAACAAAACQAKAAEACwAAAB0AAQABAAAABSq3AAGxAAAAAQAMAAAABgABAAAAAQABAA0ADgABAAsA" +
- "AAA7AAIAAgAAABeyAAISA7YABCu5AAUBALIAAhIGtgAEsQAAAAEADAAAABIABAAAAAMACAAEAA4A" +
- "BQAWAAYAAQAPAAAAAgAQ"),
- Base64.getDecoder().decode(
- "ZGV4CjAzNQCee5Z6+AuFcjnPjjn7QYgZmKSmFQCO4nxUAwAAcAAAAHhWNBIAAAAAAAAAALQCAAAR" +
- "AAAAcAAAAAcAAAC0AAAAAwAAANAAAAABAAAA9AAAAAUAAAD8AAAAAQAAACQBAAAQAgAARAEAAKIB" +
- "AACqAQAAwwEAANoBAADoAQAA/wEAABMCAAApAgAAPQIAAFECAABiAgAAZQIAAGkCAAB9AgAAggIA" +
- "AIsCAACQAgAAAwAAAAQAAAAFAAAABgAAAAcAAAAIAAAACgAAAAoAAAAGAAAAAAAAAAsAAAAGAAAA" +
- "lAEAAAsAAAAGAAAAnAEAAAUAAQANAAAAAAAAAAAAAAAAAAEAEAAAAAEAAgAOAAAAAgAAAAAAAAAD" +
- "AAAADwAAAAAAAAAAAAAAAgAAAAAAAAAJAAAAAAAAAKUCAAAAAAAAAQABAAEAAACXAgAABAAAAHAQ" +
- "AwAAAA4ABAACAAIAAACcAgAAFAAAAGIAAAAbAQIAAABuIAIAEAByEAQAAwBiAAAAGwEBAAAAbiAC" +
- "ABAADgABAAAAAwAAAAEAAAAEAAY8aW5pdD4AF0dvb2RieWUgMiAtIFRyYW5zZm9ybWVkABVIZWxs" +
- "byAyIC0gVHJhbnNmb3JtZWQADExUcmFuc2Zvcm0yOwAVTGphdmEvaW8vUHJpbnRTdHJlYW07ABJM" +
- "amF2YS9sYW5nL09iamVjdDsAFExqYXZhL2xhbmcvUnVubmFibGU7ABJMamF2YS9sYW5nL1N0cmlu" +
- "ZzsAEkxqYXZhL2xhbmcvU3lzdGVtOwAPVHJhbnNmb3JtMi5qYXZhAAFWAAJWTAASZW1pdHRlcjog" +
- "amFjay00LjIwAANvdXQAB3ByaW50bG4AA3J1bgAFc2F5SGkAAQAHDgADAQAHDoc8hwAAAAEBAICA" +
- "BMQCAQHcAgANAAAAAAAAAAEAAAAAAAAAAQAAABEAAABwAAAAAgAAAAcAAAC0AAAAAwAAAAMAAADQ" +
- "AAAABAAAAAEAAAD0AAAABQAAAAUAAAD8AAAABgAAAAEAAAAkAQAAASAAAAIAAABEAQAAARAAAAIA" +
- "AACUAQAAAiAAABEAAACiAQAAAyAAAAIAAACXAgAAACAAAAEAAAClAgAAABAAAAEAAAC0AgAA"));
-
- public static void main(String[] args) {
- art.Main.bindAgentJNIForClass(Main.class);
- doTest(new Transform(), new Transform2());
+ public static void main(String[] args) throws Exception {
+ art.Test926.run();
}
-
- public static void doTest(final Transform t1, final Transform2 t2) {
- t1.sayHi(() -> { t2.sayHi(() -> { System.out.println("Not doing anything here"); }); });
- t1.sayHi(() -> {
- t2.sayHi(() -> {
- System.out.println("transforming calling functions");
- doMultiClassRedefinition(VALID_DEFINITION_T1, VALID_DEFINITION_T2);
- });
- });
- t1.sayHi(() -> { t2.sayHi(() -> { System.out.println("Not doing anything here"); }); });
- }
-
- public static void doMultiClassRedefinition(CommonClassDefinition... defs) {
- ArrayList<Class<?>> classes = new ArrayList<>();
- ArrayList<byte[]> class_files = new ArrayList<>();
- ArrayList<byte[]> dex_files = new ArrayList<>();
-
- for (CommonClassDefinition d : defs) {
- classes.add(d.target);
- class_files.add(d.class_file_bytes);
- dex_files.add(d.dex_file_bytes);
- }
- doCommonMultiClassRedefinition(classes.toArray(new Class<?>[0]),
- class_files.toArray(new byte[0][]),
- dex_files.toArray(new byte[0][]));
- }
-
- public static native void doCommonMultiClassRedefinition(Class<?>[] targets,
- byte[][] classfiles,
- byte[][] dexfiles);
}
diff --git a/test/926-multi-obsolescence/src/Transform.java b/test/926-multi-obsolescence/src/Transform.java
deleted file mode 100644
index 8cda6cd..0000000
--- a/test/926-multi-obsolescence/src/Transform.java
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-class Transform {
- public void sayHi(Runnable r) {
- // Use lower 'h' to make sure the string will have a different string id
- // than the transformation (the transformation code is the same except
- // the actual printed String, which was making the test inacurately passing
- // in JIT mode when loading the string from the dex cache, as the string ids
- // of the two different strings were the same).
- // We know the string ids will be different because lexicographically:
- // "Hello" < "LTransform;" < "hello".
- System.out.println("hello");
- r.run();
- System.out.println("goodbye");
- }
-}
diff --git a/test/926-multi-obsolescence/src/Transform2.java b/test/926-multi-obsolescence/src/Transform2.java
deleted file mode 100644
index 4877f84..0000000
--- a/test/926-multi-obsolescence/src/Transform2.java
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-class Transform2 {
- public void sayHi(Runnable r) {
- System.out.println("hello - 2");
- r.run();
- System.out.println("goodbye - 2");
- }
-}
diff --git a/test/926-multi-obsolescence/src/art/Redefinition.java b/test/926-multi-obsolescence/src/art/Redefinition.java
new file mode 100644
index 0000000..0350ab4
--- /dev/null
+++ b/test/926-multi-obsolescence/src/art/Redefinition.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package art;
+
+import java.util.ArrayList;
+// Common Redefinition functions. Placed here for use by CTS
+public class Redefinition {
+ // Bind native functions.
+ static {
+ Main.bindAgentJNIForClass(Redefinition.class);
+ }
+
+ public static final class CommonClassDefinition {
+ public final Class<?> target;
+ public final byte[] class_file_bytes;
+ public final byte[] dex_file_bytes;
+
+ public CommonClassDefinition(Class<?> target, byte[] class_file_bytes, byte[] dex_file_bytes) {
+ this.target = target;
+ this.class_file_bytes = class_file_bytes;
+ this.dex_file_bytes = dex_file_bytes;
+ }
+ }
+
+ // A set of possible test configurations. Test should set this if they need to.
+ // This must be kept in sync with the defines in ti-agent/common_helper.cc
+ public static enum Config {
+ COMMON_REDEFINE(0),
+ COMMON_RETRANSFORM(1),
+ COMMON_TRANSFORM(2);
+
+ private final int val;
+ private Config(int val) {
+ this.val = val;
+ }
+ }
+
+ public static void setTestConfiguration(Config type) {
+ nativeSetTestConfiguration(type.val);
+ }
+
+ private static native void nativeSetTestConfiguration(int type);
+
+ // Transforms the class
+ public static native void doCommonClassRedefinition(Class<?> target,
+ byte[] classfile,
+ byte[] dexfile);
+
+ public static void doMultiClassRedefinition(CommonClassDefinition... defs) {
+ ArrayList<Class<?>> classes = new ArrayList<>();
+ ArrayList<byte[]> class_files = new ArrayList<>();
+ ArrayList<byte[]> dex_files = new ArrayList<>();
+
+ for (CommonClassDefinition d : defs) {
+ classes.add(d.target);
+ class_files.add(d.class_file_bytes);
+ dex_files.add(d.dex_file_bytes);
+ }
+ doCommonMultiClassRedefinition(classes.toArray(new Class<?>[0]),
+ class_files.toArray(new byte[0][]),
+ dex_files.toArray(new byte[0][]));
+ }
+
+ public static void addMultiTransformationResults(CommonClassDefinition... defs) {
+ for (CommonClassDefinition d : defs) {
+ addCommonTransformationResult(d.target.getCanonicalName(),
+ d.class_file_bytes,
+ d.dex_file_bytes);
+ }
+ }
+
+ public static native void doCommonMultiClassRedefinition(Class<?>[] targets,
+ byte[][] classfiles,
+ byte[][] dexfiles);
+ public static native void doCommonClassRetransformation(Class<?>... target);
+ public static native void setPopRetransformations(boolean pop);
+ public static native void popTransformationFor(String name);
+ public static native void enableCommonRetransformation(boolean enable);
+ public static native void addCommonTransformationResult(String target_name,
+ byte[] class_bytes,
+ byte[] dex_bytes);
+}
diff --git a/test/926-multi-obsolescence/src/art/Test926.java b/test/926-multi-obsolescence/src/art/Test926.java
new file mode 100644
index 0000000..843d05c
--- /dev/null
+++ b/test/926-multi-obsolescence/src/art/Test926.java
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package art;
+
+import static art.Redefinition.CommonClassDefinition;
+import java.util.ArrayList;
+import java.util.Base64;
+
+public class Test926 {
+
+ static class Transform {
+ public void sayHi(Runnable r) {
+ System.out.println("hello");
+ r.run();
+ System.out.println("goodbye");
+ }
+ }
+
+ static class Transform2 {
+ public void sayHi(Runnable r) {
+ System.out.println("hello - 2");
+ r.run();
+ System.out.println("goodbye - 2");
+ }
+ }
+ // static class Transform {
+ // public void sayHi(Runnable r) {
+ // System.out.println("Hello - Transformed");
+ // r.run();
+ // System.out.println("Goodbye - Transformed");
+ // }
+ // }
+ private static CommonClassDefinition VALID_DEFINITION_T1 = new CommonClassDefinition(
+ Transform.class,
+ Base64.getDecoder().decode(
+ "yv66vgAAADQAKAoACAARCQASABMIABQKABUAFgsAFwAYCAAZBwAbBwAeAQAGPGluaXQ+AQADKClW" +
+ "AQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEABXNheUhpAQAXKExqYXZhL2xhbmcvUnVubmFibGU7" +
+ "KVYBAApTb3VyY2VGaWxlAQAMVGVzdDkyNi5qYXZhDAAJAAoHAB8MACAAIQEAE0hlbGxvIC0gVHJh" +
+ "bnNmb3JtZWQHACIMACMAJAcAJQwAJgAKAQAVR29vZGJ5ZSAtIFRyYW5zZm9ybWVkBwAnAQAVYXJ0" +
+ "L1Rlc3Q5MjYkVHJhbnNmb3JtAQAJVHJhbnNmb3JtAQAMSW5uZXJDbGFzc2VzAQAQamF2YS9sYW5n" +
+ "L09iamVjdAEAEGphdmEvbGFuZy9TeXN0ZW0BAANvdXQBABVMamF2YS9pby9QcmludFN0cmVhbTsB" +
+ "ABNqYXZhL2lvL1ByaW50U3RyZWFtAQAHcHJpbnRsbgEAFShMamF2YS9sYW5nL1N0cmluZzspVgEA" +
+ "EmphdmEvbGFuZy9SdW5uYWJsZQEAA3J1bgEAC2FydC9UZXN0OTI2ACAABwAIAAAAAAACAAAACQAK" +
+ "AAEACwAAAB0AAQABAAAABSq3AAGxAAAAAQAMAAAABgABAAAADAABAA0ADgABAAsAAAA7AAIAAgAA" +
+ "ABeyAAISA7YABCu5AAUBALIAAhIGtgAEsQAAAAEADAAAABIABAAAAA4ACAAPAA4AEAAWABEAAgAP" +
+ "AAAAAgAQAB0AAAAKAAEABwAaABwACA=="),
+ Base64.getDecoder().decode(
+ "ZGV4CjAzNQB8m+R/AAAAAAAAAAAAAAAAAAAAAAAAAAA8BAAAcAAAAHhWNBIAAAAAAAAAAHgDAAAX" +
+ "AAAAcAAAAAoAAADMAAAAAwAAAPQAAAABAAAAGAEAAAUAAAAgAQAAAQAAAEgBAADUAgAAaAEAAGgB" +
+ "AABwAQAAhwEAAJwBAAC1AQAAxAEAAOgBAAAIAgAAHwIAADMCAABJAgAAXQIAAHECAAB/AgAAigIA" +
+ "AI0CAACRAgAAngIAAKQCAACpAgAAsgIAALcCAAC+AgAAAwAAAAQAAAAFAAAABgAAAAcAAAAIAAAA" +
+ "CQAAAAoAAAALAAAADgAAAA4AAAAJAAAAAAAAAA8AAAAJAAAAyAIAAA8AAAAJAAAA0AIAAAgABAAS" +
+ "AAAAAAAAAAAAAAAAAAEAFQAAAAQAAgATAAAABQAAAAAAAAAGAAAAFAAAAAAAAAAAAAAABQAAAAAA" +
+ "AAAMAAAAaAMAADwDAAAAAAAABjxpbml0PgAVR29vZGJ5ZSAtIFRyYW5zZm9ybWVkABNIZWxsbyAt" +
+ "IFRyYW5zZm9ybWVkABdMYXJ0L1Rlc3Q5MjYkVHJhbnNmb3JtOwANTGFydC9UZXN0OTI2OwAiTGRh" +
+ "bHZpay9hbm5vdGF0aW9uL0VuY2xvc2luZ0NsYXNzOwAeTGRhbHZpay9hbm5vdGF0aW9uL0lubmVy" +
+ "Q2xhc3M7ABVMamF2YS9pby9QcmludFN0cmVhbTsAEkxqYXZhL2xhbmcvT2JqZWN0OwAUTGphdmEv" +
+ "bGFuZy9SdW5uYWJsZTsAEkxqYXZhL2xhbmcvU3RyaW5nOwASTGphdmEvbGFuZy9TeXN0ZW07AAxU" +
+ "ZXN0OTI2LmphdmEACVRyYW5zZm9ybQABVgACVkwAC2FjY2Vzc0ZsYWdzAARuYW1lAANvdXQAB3By" +
+ "aW50bG4AA3J1bgAFc2F5SGkABXZhbHVlAAAAAAEAAAAGAAAAAQAAAAcAAAAMAAcOAA4BAAcOAQgP" +
+ "AQMPAQgPAAEAAQABAAAA2AIAAAQAAABwEAMAAAAOAAQAAgACAAAA3QIAABQAAABiAAAAGwECAAAA" +
+ "biACABAAchAEAAMAYgAAABsBAQAAAG4gAgAQAA4AAAABAQCAgATsBQEBhAYAAAICARYYAQIDAhAE" +
+ "CBEXDQACAAAATAMAAFIDAABcAwAAAAAAAAAAAAAAAAAAEAAAAAAAAAABAAAAAAAAAAEAAAAXAAAA" +
+ "cAAAAAIAAAAKAAAAzAAAAAMAAAADAAAA9AAAAAQAAAABAAAAGAEAAAUAAAAFAAAAIAEAAAYAAAAB" +
+ "AAAASAEAAAIgAAAXAAAAaAEAAAEQAAACAAAAyAIAAAMgAAACAAAA2AIAAAEgAAACAAAA7AIAAAAg" +
+ "AAABAAAAPAMAAAQgAAACAAAATAMAAAMQAAABAAAAXAMAAAYgAAABAAAAaAMAAAAQAAABAAAAeAMA" +
+ "AA=="));
+ // static class Transform2 {
+ // public void sayHi(Runnable r) {
+ // System.out.println("Hello 2 - Transformed");
+ // r.run();
+ // System.out.println("Goodbye 2 - Transformed");
+ // }
+ // }
+ private static CommonClassDefinition VALID_DEFINITION_T2 = new CommonClassDefinition(
+ Transform2.class,
+ Base64.getDecoder().decode(
+ "yv66vgAAADQAKAoACAARCQASABMIABQKABUAFgsAFwAYCAAZBwAbBwAeAQAGPGluaXQ+AQADKClW" +
+ "AQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEABXNheUhpAQAXKExqYXZhL2xhbmcvUnVubmFibGU7" +
+ "KVYBAApTb3VyY2VGaWxlAQAMVGVzdDkyNi5qYXZhDAAJAAoHAB8MACAAIQEAFUhlbGxvIDIgLSBU" +
+ "cmFuc2Zvcm1lZAcAIgwAIwAkBwAlDAAmAAoBABdHb29kYnllIDIgLSBUcmFuc2Zvcm1lZAcAJwEA" +
+ "FmFydC9UZXN0OTI2JFRyYW5zZm9ybTIBAApUcmFuc2Zvcm0yAQAMSW5uZXJDbGFzc2VzAQAQamF2" +
+ "YS9sYW5nL09iamVjdAEAEGphdmEvbGFuZy9TeXN0ZW0BAANvdXQBABVMamF2YS9pby9QcmludFN0" +
+ "cmVhbTsBABNqYXZhL2lvL1ByaW50U3RyZWFtAQAHcHJpbnRsbgEAFShMamF2YS9sYW5nL1N0cmlu" +
+ "ZzspVgEAEmphdmEvbGFuZy9SdW5uYWJsZQEAA3J1bgEAC2FydC9UZXN0OTI2ACAABwAIAAAAAAAC" +
+ "AAAACQAKAAEACwAAAB0AAQABAAAABSq3AAGxAAAAAQAMAAAABgABAAAABQABAA0ADgABAAsAAAA7" +
+ "AAIAAgAAABeyAAISA7YABCu5AAUBALIAAhIGtgAEsQAAAAEADAAAABIABAAAAAcACAAIAA4ACQAW" +
+ "AAoAAgAPAAAAAgAQAB0AAAAKAAEABwAaABwACA=="),
+ Base64.getDecoder().decode(
+ "ZGV4CjAzNQBCnaUuAAAAAAAAAAAAAAAAAAAAAAAAAABABAAAcAAAAHhWNBIAAAAAAAAAAHwDAAAX" +
+ "AAAAcAAAAAoAAADMAAAAAwAAAPQAAAABAAAAGAEAAAUAAAAgAQAAAQAAAEgBAADYAgAAaAEAAGgB" +
+ "AABwAQAAiQEAAKABAAC6AQAAyQEAAO0BAAANAgAAJAIAADgCAABOAgAAYgIAAHYCAACEAgAAkAIA" +
+ "AJMCAACXAgAApAIAAKoCAACvAgAAuAIAAL0CAADEAgAAAwAAAAQAAAAFAAAABgAAAAcAAAAIAAAA" +
+ "CQAAAAoAAAALAAAADgAAAA4AAAAJAAAAAAAAAA8AAAAJAAAAzAIAAA8AAAAJAAAA1AIAAAgABAAS" +
+ "AAAAAAAAAAAAAAAAAAEAFQAAAAQAAgATAAAABQAAAAAAAAAGAAAAFAAAAAAAAAAAAAAABQAAAAAA" +
+ "AAAMAAAAbAMAAEADAAAAAAAABjxpbml0PgAXR29vZGJ5ZSAyIC0gVHJhbnNmb3JtZWQAFUhlbGxv" +
+ "IDIgLSBUcmFuc2Zvcm1lZAAYTGFydC9UZXN0OTI2JFRyYW5zZm9ybTI7AA1MYXJ0L1Rlc3Q5MjY7" +
+ "ACJMZGFsdmlrL2Fubm90YXRpb24vRW5jbG9zaW5nQ2xhc3M7AB5MZGFsdmlrL2Fubm90YXRpb24v" +
+ "SW5uZXJDbGFzczsAFUxqYXZhL2lvL1ByaW50U3RyZWFtOwASTGphdmEvbGFuZy9PYmplY3Q7ABRM" +
+ "amF2YS9sYW5nL1J1bm5hYmxlOwASTGphdmEvbGFuZy9TdHJpbmc7ABJMamF2YS9sYW5nL1N5c3Rl" +
+ "bTsADFRlc3Q5MjYuamF2YQAKVHJhbnNmb3JtMgABVgACVkwAC2FjY2Vzc0ZsYWdzAARuYW1lAANv" +
+ "dXQAB3ByaW50bG4AA3J1bgAFc2F5SGkABXZhbHVlAAABAAAABgAAAAEAAAAHAAAABQAHDgAHAQAH" +
+ "DgEIDwEDDwEIDwABAAEAAQAAANwCAAAEAAAAcBADAAAADgAEAAIAAgAAAOECAAAUAAAAYgAAABsB" +
+ "AgAAAG4gAgAQAHIQBAADAGIAAAAbAQEAAABuIAIAEAAOAAAAAQEAgIAE8AUBAYgGAAACAgEWGAEC" +
+ "AwIQBAgRFw0AAgAAAFADAABWAwAAYAMAAAAAAAAAAAAAAAAAABAAAAAAAAAAAQAAAAAAAAABAAAA" +
+ "FwAAAHAAAAACAAAACgAAAMwAAAADAAAAAwAAAPQAAAAEAAAAAQAAABgBAAAFAAAABQAAACABAAAG" +
+ "AAAAAQAAAEgBAAACIAAAFwAAAGgBAAABEAAAAgAAAMwCAAADIAAAAgAAANwCAAABIAAAAgAAAPAC" +
+ "AAAAIAAAAQAAAEADAAAEIAAAAgAAAFADAAADEAAAAQAAAGADAAAGIAAAAQAAAGwDAAAAEAAAAQAA" +
+ "AHwDAAA="));
+
+ public static void run() throws Exception {
+ Redefinition.setTestConfiguration(Redefinition.Config.COMMON_REDEFINE);
+ doTest(new Transform(), new Transform2());
+ }
+
+ public static void doTest(final Transform t1, final Transform2 t2) throws Exception {
+ t1.sayHi(() -> { t2.sayHi(() -> { System.out.println("Not doing anything here"); }); });
+ t1.sayHi(() -> {
+ t2.sayHi(() -> {
+ System.out.println("transforming calling functions");
+ Redefinition.doMultiClassRedefinition(VALID_DEFINITION_T1, VALID_DEFINITION_T2);
+ });
+ });
+ t1.sayHi(() -> { t2.sayHi(() -> { System.out.println("Not doing anything here"); }); });
+ }
+}
diff --git a/test/930-hello-retransform/src/Main.java b/test/930-hello-retransform/src/Main.java
index da59c74..38c1d36 100644
--- a/test/930-hello-retransform/src/Main.java
+++ b/test/930-hello-retransform/src/Main.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,57 +14,8 @@
* limitations under the License.
*/
-import java.util.Base64;
public class Main {
-
- /**
- * base64 encoded class/dex file for
- * class Transform {
- * public void sayHi() {
- * System.out.println("Goodbye");
- * }
- * }
- */
- private static final byte[] CLASS_BYTES = Base64.getDecoder().decode(
- "yv66vgAAADQAHAoABgAOCQAPABAIABEKABIAEwcAFAcAFQEABjxpbml0PgEAAygpVgEABENvZGUB" +
- "AA9MaW5lTnVtYmVyVGFibGUBAAVzYXlIaQEAClNvdXJjZUZpbGUBAA5UcmFuc2Zvcm0uamF2YQwA" +
- "BwAIBwAWDAAXABgBAAdHb29kYnllBwAZDAAaABsBAAlUcmFuc2Zvcm0BABBqYXZhL2xhbmcvT2Jq" +
- "ZWN0AQAQamF2YS9sYW5nL1N5c3RlbQEAA291dAEAFUxqYXZhL2lvL1ByaW50U3RyZWFtOwEAE2ph" +
- "dmEvaW8vUHJpbnRTdHJlYW0BAAdwcmludGxuAQAVKExqYXZhL2xhbmcvU3RyaW5nOylWACAABQAG" +
- "AAAAAAACAAAABwAIAAEACQAAAB0AAQABAAAABSq3AAGxAAAAAQAKAAAABgABAAAAEQABAAsACAAB" +
- "AAkAAAAlAAIAAQAAAAmyAAISA7YABLEAAAABAAoAAAAKAAIAAAATAAgAFAABAAwAAAACAA0=");
- private static final byte[] DEX_BYTES = Base64.getDecoder().decode(
- "ZGV4CjAzNQCLXSBQ5FiS3f16krSYZFF8xYZtFVp0GRXMAgAAcAAAAHhWNBIAAAAAAAAAACwCAAAO" +
- "AAAAcAAAAAYAAACoAAAAAgAAAMAAAAABAAAA2AAAAAQAAADgAAAAAQAAAAABAACsAQAAIAEAAGIB" +
- "AABqAQAAcwEAAIABAACXAQAAqwEAAL8BAADTAQAA4wEAAOYBAADqAQAA/gEAAAMCAAAMAgAAAgAA" +
- "AAMAAAAEAAAABQAAAAYAAAAIAAAACAAAAAUAAAAAAAAACQAAAAUAAABcAQAABAABAAsAAAAAAAAA" +
- "AAAAAAAAAAANAAAAAQABAAwAAAACAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAHAAAAAAAAAB4CAAAA" +
- "AAAAAQABAAEAAAATAgAABAAAAHAQAwAAAA4AAwABAAIAAAAYAgAACQAAAGIAAAAbAQEAAABuIAIA" +
- "EAAOAAAAAQAAAAMABjxpbml0PgAHR29vZGJ5ZQALTFRyYW5zZm9ybTsAFUxqYXZhL2lvL1ByaW50" +
- "U3RyZWFtOwASTGphdmEvbGFuZy9PYmplY3Q7ABJMamF2YS9sYW5nL1N0cmluZzsAEkxqYXZhL2xh" +
- "bmcvU3lzdGVtOwAOVHJhbnNmb3JtLmphdmEAAVYAAlZMABJlbWl0dGVyOiBqYWNrLTMuMzYAA291" +
- "dAAHcHJpbnRsbgAFc2F5SGkAEQAHDgATAAcOhQAAAAEBAICABKACAQG4Ag0AAAAAAAAAAQAAAAAA" +
- "AAABAAAADgAAAHAAAAACAAAABgAAAKgAAAADAAAAAgAAAMAAAAAEAAAAAQAAANgAAAAFAAAABAAA" +
- "AOAAAAAGAAAAAQAAAAABAAABIAAAAgAAACABAAABEAAAAQAAAFwBAAACIAAADgAAAGIBAAADIAAA" +
- "AgAAABMCAAAAIAAAAQAAAB4CAAAAEAAAAQAAACwCAAA=");
-
- public static void main(String[] args) {
- art.Main.bindAgentJNIForClass(Main.class);
- doTest(new Transform());
+ public static void main(String[] args) throws Exception {
+ art.Test930.run();
}
-
- public static void doTest(Transform t) {
- t.sayHi();
- addCommonTransformationResult("Transform", CLASS_BYTES, DEX_BYTES);
- enableCommonRetransformation(true);
- doCommonClassRetransformation(Transform.class);
- t.sayHi();
- }
-
- // Transforms the class
- private static native void doCommonClassRetransformation(Class<?>... target);
- private static native void enableCommonRetransformation(boolean enable);
- private static native void addCommonTransformationResult(String target_name,
- byte[] class_bytes,
- byte[] dex_bytes);
}
diff --git a/test/930-hello-retransform/src/Transform.java b/test/930-hello-retransform/src/Transform.java
deleted file mode 100644
index 8e8af35..0000000
--- a/test/930-hello-retransform/src/Transform.java
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-class Transform {
- public void sayHi() {
- // Use lower 'h' to make sure the string will have a different string id
- // than the transformation (the transformation code is the same except
- // the actual printed String, which was making the test inacurately passing
- // in JIT mode when loading the string from the dex cache, as the string ids
- // of the two different strings were the same).
- // We know the string ids will be different because lexicographically:
- // "Goodbye" < "LTransform;" < "hello".
- System.out.println("hello");
- }
-}
diff --git a/test/930-hello-retransform/src/art/Redefinition.java b/test/930-hello-retransform/src/art/Redefinition.java
new file mode 100644
index 0000000..0350ab4
--- /dev/null
+++ b/test/930-hello-retransform/src/art/Redefinition.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package art;
+
+import java.util.ArrayList;
+// Common Redefinition functions. Placed here for use by CTS
+public class Redefinition {
+ // Bind native functions.
+ static {
+ Main.bindAgentJNIForClass(Redefinition.class);
+ }
+
+ public static final class CommonClassDefinition {
+ public final Class<?> target;
+ public final byte[] class_file_bytes;
+ public final byte[] dex_file_bytes;
+
+ public CommonClassDefinition(Class<?> target, byte[] class_file_bytes, byte[] dex_file_bytes) {
+ this.target = target;
+ this.class_file_bytes = class_file_bytes;
+ this.dex_file_bytes = dex_file_bytes;
+ }
+ }
+
+ // A set of possible test configurations. Test should set this if they need to.
+ // This must be kept in sync with the defines in ti-agent/common_helper.cc
+ public static enum Config {
+ COMMON_REDEFINE(0),
+ COMMON_RETRANSFORM(1),
+ COMMON_TRANSFORM(2);
+
+ private final int val;
+ private Config(int val) {
+ this.val = val;
+ }
+ }
+
+ public static void setTestConfiguration(Config type) {
+ nativeSetTestConfiguration(type.val);
+ }
+
+ private static native void nativeSetTestConfiguration(int type);
+
+ // Transforms the class
+ public static native void doCommonClassRedefinition(Class<?> target,
+ byte[] classfile,
+ byte[] dexfile);
+
+ public static void doMultiClassRedefinition(CommonClassDefinition... defs) {
+ ArrayList<Class<?>> classes = new ArrayList<>();
+ ArrayList<byte[]> class_files = new ArrayList<>();
+ ArrayList<byte[]> dex_files = new ArrayList<>();
+
+ for (CommonClassDefinition d : defs) {
+ classes.add(d.target);
+ class_files.add(d.class_file_bytes);
+ dex_files.add(d.dex_file_bytes);
+ }
+ doCommonMultiClassRedefinition(classes.toArray(new Class<?>[0]),
+ class_files.toArray(new byte[0][]),
+ dex_files.toArray(new byte[0][]));
+ }
+
+ public static void addMultiTransformationResults(CommonClassDefinition... defs) {
+ for (CommonClassDefinition d : defs) {
+ addCommonTransformationResult(d.target.getCanonicalName(),
+ d.class_file_bytes,
+ d.dex_file_bytes);
+ }
+ }
+
+ public static native void doCommonMultiClassRedefinition(Class<?>[] targets,
+ byte[][] classfiles,
+ byte[][] dexfiles);
+ public static native void doCommonClassRetransformation(Class<?>... target);
+ public static native void setPopRetransformations(boolean pop);
+ public static native void popTransformationFor(String name);
+ public static native void enableCommonRetransformation(boolean enable);
+ public static native void addCommonTransformationResult(String target_name,
+ byte[] class_bytes,
+ byte[] dex_bytes);
+}
diff --git a/test/930-hello-retransform/src/art/Test930.java b/test/930-hello-retransform/src/art/Test930.java
new file mode 100644
index 0000000..6c0fc16
--- /dev/null
+++ b/test/930-hello-retransform/src/art/Test930.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package art;
+
+import java.util.Base64;
+public class Test930 {
+
+ static class Transform {
+ public void sayHi() {
+ System.out.println("hello");
+ }
+ }
+
+
+ /**
+ * base64 encoded class/dex file for
+ * static class Transform {
+ * public void sayHi() {
+ * System.out.println("Goodbye");
+ * }
+ * }
+ */
+ private static final byte[] CLASS_BYTES = Base64.getDecoder().decode(
+ "yv66vgAAADQAIAoABgAOCQAPABAIABEKABIAEwcAFQcAGAEABjxpbml0PgEAAygpVgEABENvZGUB" +
+ "AA9MaW5lTnVtYmVyVGFibGUBAAVzYXlIaQEAClNvdXJjZUZpbGUBAAxUZXN0OTMwLmphdmEMAAcA" +
+ "CAcAGQwAGgAbAQAHR29vZGJ5ZQcAHAwAHQAeBwAfAQAVYXJ0L1Rlc3Q5MzAkVHJhbnNmb3JtAQAJ" +
+ "VHJhbnNmb3JtAQAMSW5uZXJDbGFzc2VzAQAQamF2YS9sYW5nL09iamVjdAEAEGphdmEvbGFuZy9T" +
+ "eXN0ZW0BAANvdXQBABVMamF2YS9pby9QcmludFN0cmVhbTsBABNqYXZhL2lvL1ByaW50U3RyZWFt" +
+ "AQAHcHJpbnRsbgEAFShMamF2YS9sYW5nL1N0cmluZzspVgEAC2FydC9UZXN0OTMwACAABQAGAAAA" +
+ "AAACAAAABwAIAAEACQAAAB0AAQABAAAABSq3AAGxAAAAAQAKAAAABgABAAAABQABAAsACAABAAkA" +
+ "AAAlAAIAAQAAAAmyAAISA7YABLEAAAABAAoAAAAKAAIAAAAHAAgACAACAAwAAAACAA0AFwAAAAoA" +
+ "AQAFABQAFgAI");
+ private static final byte[] DEX_BYTES = Base64.getDecoder().decode(
+ "ZGV4CjAzNQBsgu9qAAAAAAAAAAAAAAAAAAAAAAAAAAC4AwAAcAAAAHhWNBIAAAAAAAAAAPQCAAAU" +
+ "AAAAcAAAAAkAAADAAAAAAgAAAOQAAAABAAAA/AAAAAQAAAAEAQAAAQAAACQBAAB0AgAARAEAAEQB" +
+ "AABMAQAAVQEAAG4BAAB9AQAAoQEAAMEBAADYAQAA7AEAAAACAAAUAgAAIgIAAC0CAAAwAgAANAIA" +
+ "AEECAABHAgAATAIAAFUCAABcAgAAAgAAAAMAAAAEAAAABQAAAAYAAAAHAAAACAAAAAkAAAAMAAAA" +
+ "DAAAAAgAAAAAAAAADQAAAAgAAABkAgAABwAEABAAAAAAAAAAAAAAAAAAAAASAAAABAABABEAAAAF" +
+ "AAAAAAAAAAAAAAAAAAAABQAAAAAAAAAKAAAA5AIAALgCAAAAAAAABjxpbml0PgAHR29vZGJ5ZQAX" +
+ "TGFydC9UZXN0OTMwJFRyYW5zZm9ybTsADUxhcnQvVGVzdDkzMDsAIkxkYWx2aWsvYW5ub3RhdGlv" +
+ "bi9FbmNsb3NpbmdDbGFzczsAHkxkYWx2aWsvYW5ub3RhdGlvbi9Jbm5lckNsYXNzOwAVTGphdmEv" +
+ "aW8vUHJpbnRTdHJlYW07ABJMamF2YS9sYW5nL09iamVjdDsAEkxqYXZhL2xhbmcvU3RyaW5nOwAS" +
+ "TGphdmEvbGFuZy9TeXN0ZW07AAxUZXN0OTMwLmphdmEACVRyYW5zZm9ybQABVgACVkwAC2FjY2Vz" +
+ "c0ZsYWdzAARuYW1lAANvdXQAB3ByaW50bG4ABXNheUhpAAV2YWx1ZQAAAQAAAAYAAAAFAAcOAAcA" +
+ "Bw4BCA8AAAAAAQABAAEAAABsAgAABAAAAHAQAwAAAA4AAwABAAIAAABxAgAACQAAAGIAAAAbAQEA" +
+ "AABuIAIAEAAOAAAAAAABAQCAgAT8BAEBlAUAAAICARMYAQIDAg4ECA8XCwACAAAAyAIAAM4CAADY" +
+ "AgAAAAAAAAAAAAAAAAAAEAAAAAAAAAABAAAAAAAAAAEAAAAUAAAAcAAAAAIAAAAJAAAAwAAAAAMA" +
+ "AAACAAAA5AAAAAQAAAABAAAA/AAAAAUAAAAEAAAABAEAAAYAAAABAAAAJAEAAAIgAAAUAAAARAEA" +
+ "AAEQAAABAAAAZAIAAAMgAAACAAAAbAIAAAEgAAACAAAAfAIAAAAgAAABAAAAuAIAAAQgAAACAAAA" +
+ "yAIAAAMQAAABAAAA2AIAAAYgAAABAAAA5AIAAAAQAAABAAAA9AIAAA==");
+
+ public static void run() {
+ Redefinition.setTestConfiguration(Redefinition.Config.COMMON_RETRANSFORM);
+ doTest(new Transform());
+ }
+
+ public static void doTest(Transform t) {
+ t.sayHi();
+ Redefinition.addCommonTransformationResult("art/Test930$Transform", CLASS_BYTES, DEX_BYTES);
+ Redefinition.enableCommonRetransformation(true);
+ Redefinition.doCommonClassRetransformation(Transform.class);
+ t.sayHi();
+ }
+}
diff --git a/test/932-transform-saves/src/Main.java b/test/932-transform-saves/src/Main.java
index 14e5da0..fba40f6 100644
--- a/test/932-transform-saves/src/Main.java
+++ b/test/932-transform-saves/src/Main.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,103 +14,8 @@
* limitations under the License.
*/
-import java.util.Base64;
public class Main {
- /**
- * base64 encoded class/dex file for
- * class Transform {
- * public void sayHi() {
- * System.out.println("hello");
- * }
- * }
- */
- private static final byte[] CLASS_BYTES_A = Base64.getDecoder().decode(
- "yv66vgAAADQAHAoABgAOCQAPABAIABEKABIAEwcAFAcAFQEABjxpbml0PgEAAygpVgEABENvZGUB" +
- "AA9MaW5lTnVtYmVyVGFibGUBAAVzYXlIaQEAClNvdXJjZUZpbGUBAA5UcmFuc2Zvcm0uamF2YQwA" +
- "BwAIBwAWDAAXABgBAAVoZWxsbwcAGQwAGgAbAQAJVHJhbnNmb3JtAQAQamF2YS9sYW5nL09iamVj" +
- "dAEAEGphdmEvbGFuZy9TeXN0ZW0BAANvdXQBABVMamF2YS9pby9QcmludFN0cmVhbTsBABNqYXZh" +
- "L2lvL1ByaW50U3RyZWFtAQAHcHJpbnRsbgEAFShMamF2YS9sYW5nL1N0cmluZzspVgAgAAUABgAA" +
- "AAAAAgAAAAcACAABAAkAAAAdAAEAAQAAAAUqtwABsQAAAAEACgAAAAYAAQAAABEAAQALAAgAAQAJ" +
- "AAAAJQACAAEAAAAJsgACEgO2AASxAAAAAQAKAAAACgACAAAAGgAIABsAAQAMAAAAAgAN");
- private static final byte[] DEX_BYTES_A = Base64.getDecoder().decode(
- "ZGV4CjAzNQC6XWInnnDd1H4NdQ3P3inH8eCVmQI6W7LMAgAAcAAAAHhWNBIAAAAAAAAAACwCAAAO" +
- "AAAAcAAAAAYAAACoAAAAAgAAAMAAAAABAAAA2AAAAAQAAADgAAAAAQAAAAABAACsAQAAIAEAAGIB" +
- "AABqAQAAdwEAAI4BAACiAQAAtgEAAMoBAADaAQAA3QEAAOEBAAD1AQAA/AEAAAECAAAKAgAAAQAA" +
- "AAIAAAADAAAABAAAAAUAAAAHAAAABwAAAAUAAAAAAAAACAAAAAUAAABcAQAABAABAAsAAAAAAAAA" +
- "AAAAAAAAAAANAAAAAQABAAwAAAACAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAGAAAAAAAAABwCAAAA" +
- "AAAAAQABAAEAAAARAgAABAAAAHAQAwAAAA4AAwABAAIAAAAWAgAACQAAAGIAAAAbAQoAAABuIAIA" +
- "EAAOAAAAAQAAAAMABjxpbml0PgALTFRyYW5zZm9ybTsAFUxqYXZhL2lvL1ByaW50U3RyZWFtOwAS" +
- "TGphdmEvbGFuZy9PYmplY3Q7ABJMamF2YS9sYW5nL1N0cmluZzsAEkxqYXZhL2xhbmcvU3lzdGVt" +
- "OwAOVHJhbnNmb3JtLmphdmEAAVYAAlZMABJlbWl0dGVyOiBqYWNrLTQuMjIABWhlbGxvAANvdXQA" +
- "B3ByaW50bG4ABXNheUhpABEABw4AGgAHDocAAAABAQCAgASgAgEBuAIAAA0AAAAAAAAAAQAAAAAA" +
- "AAABAAAADgAAAHAAAAACAAAABgAAAKgAAAADAAAAAgAAAMAAAAAEAAAAAQAAANgAAAAFAAAABAAA" +
- "AOAAAAAGAAAAAQAAAAABAAABIAAAAgAAACABAAABEAAAAQAAAFwBAAACIAAADgAAAGIBAAADIAAA" +
- "AgAAABECAAAAIAAAAQAAABwCAAAAEAAAAQAAACwCAAA=");
-
- /**
- * base64 encoded class/dex file for
- * class Transform {
- * public void sayHi() {
- * System.out.println("Goodbye");
- * }
- * }
- */
- private static final byte[] CLASS_BYTES_B = Base64.getDecoder().decode(
- "yv66vgAAADQAHAoABgAOCQAPABAIABEKABIAEwcAFAcAFQEABjxpbml0PgEAAygpVgEABENvZGUB" +
- "AA9MaW5lTnVtYmVyVGFibGUBAAVzYXlIaQEAClNvdXJjZUZpbGUBAA5UcmFuc2Zvcm0uamF2YQwA" +
- "BwAIBwAWDAAXABgBAAdHb29kYnllBwAZDAAaABsBAAlUcmFuc2Zvcm0BABBqYXZhL2xhbmcvT2Jq" +
- "ZWN0AQAQamF2YS9sYW5nL1N5c3RlbQEAA291dAEAFUxqYXZhL2lvL1ByaW50U3RyZWFtOwEAE2ph" +
- "dmEvaW8vUHJpbnRTdHJlYW0BAAdwcmludGxuAQAVKExqYXZhL2xhbmcvU3RyaW5nOylWACAABQAG" +
- "AAAAAAACAAAABwAIAAEACQAAAB0AAQABAAAABSq3AAGxAAAAAQAKAAAABgABAAAAEQABAAsACAAB" +
- "AAkAAAAlAAIAAQAAAAmyAAISA7YABLEAAAABAAoAAAAKAAIAAAATAAgAFAABAAwAAAACAA0=");
- private static final byte[] DEX_BYTES_B = Base64.getDecoder().decode(
- "ZGV4CjAzNQCLXSBQ5FiS3f16krSYZFF8xYZtFVp0GRXMAgAAcAAAAHhWNBIAAAAAAAAAACwCAAAO" +
- "AAAAcAAAAAYAAACoAAAAAgAAAMAAAAABAAAA2AAAAAQAAADgAAAAAQAAAAABAACsAQAAIAEAAGIB" +
- "AABqAQAAcwEAAIABAACXAQAAqwEAAL8BAADTAQAA4wEAAOYBAADqAQAA/gEAAAMCAAAMAgAAAgAA" +
- "AAMAAAAEAAAABQAAAAYAAAAIAAAACAAAAAUAAAAAAAAACQAAAAUAAABcAQAABAABAAsAAAAAAAAA" +
- "AAAAAAAAAAANAAAAAQABAAwAAAACAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAHAAAAAAAAAB4CAAAA" +
- "AAAAAQABAAEAAAATAgAABAAAAHAQAwAAAA4AAwABAAIAAAAYAgAACQAAAGIAAAAbAQEAAABuIAIA" +
- "EAAOAAAAAQAAAAMABjxpbml0PgAHR29vZGJ5ZQALTFRyYW5zZm9ybTsAFUxqYXZhL2lvL1ByaW50" +
- "U3RyZWFtOwASTGphdmEvbGFuZy9PYmplY3Q7ABJMamF2YS9sYW5nL1N0cmluZzsAEkxqYXZhL2xh" +
- "bmcvU3lzdGVtOwAOVHJhbnNmb3JtLmphdmEAAVYAAlZMABJlbWl0dGVyOiBqYWNrLTMuMzYAA291" +
- "dAAHcHJpbnRsbgAFc2F5SGkAEQAHDgATAAcOhQAAAAEBAICABKACAQG4Ag0AAAAAAAAAAQAAAAAA" +
- "AAABAAAADgAAAHAAAAACAAAABgAAAKgAAAADAAAAAgAAAMAAAAAEAAAAAQAAANgAAAAFAAAABAAA" +
- "AOAAAAAGAAAAAQAAAAABAAABIAAAAgAAACABAAABEAAAAQAAAFwBAAACIAAADgAAAGIBAAADIAAA" +
- "AgAAABMCAAAAIAAAAQAAAB4CAAAAEAAAAQAAACwCAAA=");
-
- public static void main(String[] args) {
- art.Main.bindAgentJNIForClass(Main.class);
- doTest(new Transform());
+ public static void main(String[] args) throws Exception {
+ art.Test932.run();
}
-
- public static void doTest(Transform t) {
- // TODO We currently need to do this transform call since we don't have any way to make the
- // original-dex-file a single-class dex-file letting us restore it easily. We should use the
- // manipulation library that is being made when we store the original dex file.
- // TODO REMOVE this theoretically does nothing but it ensures the original-dex-file we have set
- // is one we can return to unaltered.
- doCommonClassRedefinition(Transform.class, CLASS_BYTES_A, DEX_BYTES_A);
- t.sayHi();
-
- // Now turn it into DEX_BYTES_B so it says 'Goodbye'
- addCommonTransformationResult("Transform", CLASS_BYTES_B, DEX_BYTES_B);
- enableCommonRetransformation(true);
- doCommonClassRetransformation(Transform.class);
- t.sayHi();
-
- // Now turn it back to normal by removing the load-hook and transforming again.
- enableCommonRetransformation(false);
- doCommonClassRetransformation(Transform.class);
- t.sayHi();
- }
-
- // Transforms the class
- private static native void doCommonClassRedefinition(Class<?> target,
- byte[] class_bytes,
- byte[] dex_bytes);
- private static native void doCommonClassRetransformation(Class<?>... target);
- private static native void enableCommonRetransformation(boolean enable);
- private static native void addCommonTransformationResult(String target_name,
- byte[] class_bytes,
- byte[] dex_bytes);
}
diff --git a/test/932-transform-saves/src/Transform.java b/test/932-transform-saves/src/Transform.java
deleted file mode 100644
index 83f7aa4..0000000
--- a/test/932-transform-saves/src/Transform.java
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-class Transform {
- public void sayHi() {
- // Use lower 'h' to make sure the string will have a different string id
- // than the transformation (the transformation code is the same except
- // the actual printed String, which was making the test inacurately passing
- // in JIT mode when loading the string from the dex cache, as the string ids
- // of the two different strings were the same).
- // We know the string ids will be different because lexicographically:
- // "Goodbye" < "LTransform;" < "hello".
- System.out.println("foobar");
- }
-}
diff --git a/test/932-transform-saves/src/art/Redefinition.java b/test/932-transform-saves/src/art/Redefinition.java
new file mode 100644
index 0000000..0350ab4
--- /dev/null
+++ b/test/932-transform-saves/src/art/Redefinition.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package art;
+
+import java.util.ArrayList;
+// Common Redefinition functions. Placed here for use by CTS
+public class Redefinition {
+ // Bind native functions.
+ static {
+ Main.bindAgentJNIForClass(Redefinition.class);
+ }
+
+ public static final class CommonClassDefinition {
+ public final Class<?> target;
+ public final byte[] class_file_bytes;
+ public final byte[] dex_file_bytes;
+
+ public CommonClassDefinition(Class<?> target, byte[] class_file_bytes, byte[] dex_file_bytes) {
+ this.target = target;
+ this.class_file_bytes = class_file_bytes;
+ this.dex_file_bytes = dex_file_bytes;
+ }
+ }
+
+ // A set of possible test configurations. Test should set this if they need to.
+ // This must be kept in sync with the defines in ti-agent/common_helper.cc
+ public static enum Config {
+ COMMON_REDEFINE(0),
+ COMMON_RETRANSFORM(1),
+ COMMON_TRANSFORM(2);
+
+ private final int val;
+ private Config(int val) {
+ this.val = val;
+ }
+ }
+
+ public static void setTestConfiguration(Config type) {
+ nativeSetTestConfiguration(type.val);
+ }
+
+ private static native void nativeSetTestConfiguration(int type);
+
+ // Transforms the class
+ public static native void doCommonClassRedefinition(Class<?> target,
+ byte[] classfile,
+ byte[] dexfile);
+
+ public static void doMultiClassRedefinition(CommonClassDefinition... defs) {
+ ArrayList<Class<?>> classes = new ArrayList<>();
+ ArrayList<byte[]> class_files = new ArrayList<>();
+ ArrayList<byte[]> dex_files = new ArrayList<>();
+
+ for (CommonClassDefinition d : defs) {
+ classes.add(d.target);
+ class_files.add(d.class_file_bytes);
+ dex_files.add(d.dex_file_bytes);
+ }
+ doCommonMultiClassRedefinition(classes.toArray(new Class<?>[0]),
+ class_files.toArray(new byte[0][]),
+ dex_files.toArray(new byte[0][]));
+ }
+
+ public static void addMultiTransformationResults(CommonClassDefinition... defs) {
+ for (CommonClassDefinition d : defs) {
+ addCommonTransformationResult(d.target.getCanonicalName(),
+ d.class_file_bytes,
+ d.dex_file_bytes);
+ }
+ }
+
+ public static native void doCommonMultiClassRedefinition(Class<?>[] targets,
+ byte[][] classfiles,
+ byte[][] dexfiles);
+ public static native void doCommonClassRetransformation(Class<?>... target);
+ public static native void setPopRetransformations(boolean pop);
+ public static native void popTransformationFor(String name);
+ public static native void enableCommonRetransformation(boolean enable);
+ public static native void addCommonTransformationResult(String target_name,
+ byte[] class_bytes,
+ byte[] dex_bytes);
+}
diff --git a/test/932-transform-saves/src/art/Test932.java b/test/932-transform-saves/src/art/Test932.java
new file mode 100644
index 0000000..3a62232
--- /dev/null
+++ b/test/932-transform-saves/src/art/Test932.java
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package art;
+
+import java.util.Base64;
+public class Test932 {
+
+ // This class is never used so just have it print out a bogus value so we can detect if something
+ // goes very wrong.
+ static class Transform {
+ public void sayHi() {
+ System.out.println("foobar");
+ }
+ }
+
+ /**
+ * base64 encoded class/dex file for
+ * static class Transform {
+ * public void sayHi() {
+ * System.out.println("hello");
+ * }
+ * }
+ */
+ private static final byte[] CLASS_BYTES_A = Base64.getDecoder().decode(
+ "yv66vgAAADQAIAoABgAOCQAPABAIABEKABIAEwcAFQcAGAEABjxpbml0PgEAAygpVgEABENvZGUB" +
+ "AA9MaW5lTnVtYmVyVGFibGUBAAVzYXlIaQEAClNvdXJjZUZpbGUBAAxUZXN0OTMyLmphdmEMAAcA" +
+ "CAcAGQwAGgAbAQAFaGVsbG8HABwMAB0AHgcAHwEAFWFydC9UZXN0OTMyJFRyYW5zZm9ybQEACVRy" +
+ "YW5zZm9ybQEADElubmVyQ2xhc3NlcwEAEGphdmEvbGFuZy9PYmplY3QBABBqYXZhL2xhbmcvU3lz" +
+ "dGVtAQADb3V0AQAVTGphdmEvaW8vUHJpbnRTdHJlYW07AQATamF2YS9pby9QcmludFN0cmVhbQEA" +
+ "B3ByaW50bG4BABUoTGphdmEvbGFuZy9TdHJpbmc7KVYBAAthcnQvVGVzdDkzMgAgAAUABgAAAAAA" +
+ "AgAAAAcACAABAAkAAAAdAAEAAQAAAAUqtwABsQAAAAEACgAAAAYAAQAAAAUAAQALAAgAAQAJAAAA" +
+ "JQACAAEAAAAJsgACEgO2AASxAAAAAQAKAAAACgACAAAABwAIAAgAAgAMAAAAAgANABcAAAAKAAEA" +
+ "BQAUABYACA==");
+ private static final byte[] DEX_BYTES_A = Base64.getDecoder().decode(
+ "ZGV4CjAzNQAngjnzAAAAAAAAAAAAAAAAAAAAAAAAAAC4AwAAcAAAAHhWNBIAAAAAAAAAAPQCAAAU" +
+ "AAAAcAAAAAkAAADAAAAAAgAAAOQAAAABAAAA/AAAAAQAAAAEAQAAAQAAACQBAAB0AgAARAEAAEQB" +
+ "AABMAQAAZQEAAHQBAACYAQAAuAEAAM8BAADjAQAA9wEAAAsCAAAZAgAAJAIAACcCAAArAgAAOAIA" +
+ "AD8CAABFAgAASgIAAFMCAABaAgAAAQAAAAIAAAADAAAABAAAAAUAAAAGAAAABwAAAAgAAAALAAAA" +
+ "CwAAAAgAAAAAAAAADAAAAAgAAABkAgAABwAEABAAAAAAAAAAAAAAAAAAAAASAAAABAABABEAAAAF" +
+ "AAAAAAAAAAAAAAAAAAAABQAAAAAAAAAJAAAA5AIAALgCAAAAAAAABjxpbml0PgAXTGFydC9UZXN0" +
+ "OTMyJFRyYW5zZm9ybTsADUxhcnQvVGVzdDkzMjsAIkxkYWx2aWsvYW5ub3RhdGlvbi9FbmNsb3Np" +
+ "bmdDbGFzczsAHkxkYWx2aWsvYW5ub3RhdGlvbi9Jbm5lckNsYXNzOwAVTGphdmEvaW8vUHJpbnRT" +
+ "dHJlYW07ABJMamF2YS9sYW5nL09iamVjdDsAEkxqYXZhL2xhbmcvU3RyaW5nOwASTGphdmEvbGFu" +
+ "Zy9TeXN0ZW07AAxUZXN0OTMyLmphdmEACVRyYW5zZm9ybQABVgACVkwAC2FjY2Vzc0ZsYWdzAAVo" +
+ "ZWxsbwAEbmFtZQADb3V0AAdwcmludGxuAAVzYXlIaQAFdmFsdWUAAAAAAQAAAAYAAAAFAAcOAAcA" +
+ "Bw4BCA8AAAAAAQABAAEAAABsAgAABAAAAHAQAwAAAA4AAwABAAIAAABxAgAACQAAAGIAAAAbAQ4A" +
+ "AABuIAIAEAAOAAAAAAABAQCAgAT8BAEBlAUAAAICARMYAQIDAg0ECA8XCgACAAAAyAIAAM4CAADY" +
+ "AgAAAAAAAAAAAAAAAAAAEAAAAAAAAAABAAAAAAAAAAEAAAAUAAAAcAAAAAIAAAAJAAAAwAAAAAMA" +
+ "AAACAAAA5AAAAAQAAAABAAAA/AAAAAUAAAAEAAAABAEAAAYAAAABAAAAJAEAAAIgAAAUAAAARAEA" +
+ "AAEQAAABAAAAZAIAAAMgAAACAAAAbAIAAAEgAAACAAAAfAIAAAAgAAABAAAAuAIAAAQgAAACAAAA" +
+ "yAIAAAMQAAABAAAA2AIAAAYgAAABAAAA5AIAAAAQAAABAAAA9AIAAA==");
+
+ /**
+ * base64 encoded class/dex file for
+ * static class Transform {
+ * public void sayHi() {
+ * System.out.println("Goodbye");
+ * }
+ * }
+ */
+ private static final byte[] CLASS_BYTES_B = Base64.getDecoder().decode(
+ "yv66vgAAADQAIAoABgAOCQAPABAIABEKABIAEwcAFQcAGAEABjxpbml0PgEAAygpVgEABENvZGUB" +
+ "AA9MaW5lTnVtYmVyVGFibGUBAAVzYXlIaQEAClNvdXJjZUZpbGUBAAxUZXN0OTMyLmphdmEMAAcA" +
+ "CAcAGQwAGgAbAQAHR29vZGJ5ZQcAHAwAHQAeBwAfAQAVYXJ0L1Rlc3Q5MzIkVHJhbnNmb3JtAQAJ" +
+ "VHJhbnNmb3JtAQAMSW5uZXJDbGFzc2VzAQAQamF2YS9sYW5nL09iamVjdAEAEGphdmEvbGFuZy9T" +
+ "eXN0ZW0BAANvdXQBABVMamF2YS9pby9QcmludFN0cmVhbTsBABNqYXZhL2lvL1ByaW50U3RyZWFt" +
+ "AQAHcHJpbnRsbgEAFShMamF2YS9sYW5nL1N0cmluZzspVgEAC2FydC9UZXN0OTMyACAABQAGAAAA" +
+ "AAACAAAABwAIAAEACQAAAB0AAQABAAAABSq3AAGxAAAAAQAKAAAABgABAAAABQABAAsACAABAAkA" +
+ "AAAlAAIAAQAAAAmyAAISA7YABLEAAAABAAoAAAAKAAIAAAAHAAgACAACAAwAAAACAA0AFwAAAAoA" +
+ "AQAFABQAFgAI");
+ private static final byte[] DEX_BYTES_B = Base64.getDecoder().decode(
+ "ZGV4CjAzNQByglN3AAAAAAAAAAAAAAAAAAAAAAAAAAC4AwAAcAAAAHhWNBIAAAAAAAAAAPQCAAAU" +
+ "AAAAcAAAAAkAAADAAAAAAgAAAOQAAAABAAAA/AAAAAQAAAAEAQAAAQAAACQBAAB0AgAARAEAAEQB" +
+ "AABMAQAAVQEAAG4BAAB9AQAAoQEAAMEBAADYAQAA7AEAAAACAAAUAgAAIgIAAC0CAAAwAgAANAIA" +
+ "AEECAABHAgAATAIAAFUCAABcAgAAAgAAAAMAAAAEAAAABQAAAAYAAAAHAAAACAAAAAkAAAAMAAAA" +
+ "DAAAAAgAAAAAAAAADQAAAAgAAABkAgAABwAEABAAAAAAAAAAAAAAAAAAAAASAAAABAABABEAAAAF" +
+ "AAAAAAAAAAAAAAAAAAAABQAAAAAAAAAKAAAA5AIAALgCAAAAAAAABjxpbml0PgAHR29vZGJ5ZQAX" +
+ "TGFydC9UZXN0OTMyJFRyYW5zZm9ybTsADUxhcnQvVGVzdDkzMjsAIkxkYWx2aWsvYW5ub3RhdGlv" +
+ "bi9FbmNsb3NpbmdDbGFzczsAHkxkYWx2aWsvYW5ub3RhdGlvbi9Jbm5lckNsYXNzOwAVTGphdmEv" +
+ "aW8vUHJpbnRTdHJlYW07ABJMamF2YS9sYW5nL09iamVjdDsAEkxqYXZhL2xhbmcvU3RyaW5nOwAS" +
+ "TGphdmEvbGFuZy9TeXN0ZW07AAxUZXN0OTMyLmphdmEACVRyYW5zZm9ybQABVgACVkwAC2FjY2Vz" +
+ "c0ZsYWdzAARuYW1lAANvdXQAB3ByaW50bG4ABXNheUhpAAV2YWx1ZQAAAQAAAAYAAAAFAAcOAAcA" +
+ "Bw4BCA8AAAAAAQABAAEAAABsAgAABAAAAHAQAwAAAA4AAwABAAIAAABxAgAACQAAAGIAAAAbAQEA" +
+ "AABuIAIAEAAOAAAAAAABAQCAgAT8BAEBlAUAAAICARMYAQIDAg4ECA8XCwACAAAAyAIAAM4CAADY" +
+ "AgAAAAAAAAAAAAAAAAAAEAAAAAAAAAABAAAAAAAAAAEAAAAUAAAAcAAAAAIAAAAJAAAAwAAAAAMA" +
+ "AAACAAAA5AAAAAQAAAABAAAA/AAAAAUAAAAEAAAABAEAAAYAAAABAAAAJAEAAAIgAAAUAAAARAEA" +
+ "AAEQAAABAAAAZAIAAAMgAAACAAAAbAIAAAEgAAACAAAAfAIAAAAgAAABAAAAuAIAAAQgAAACAAAA" +
+ "yAIAAAMQAAABAAAA2AIAAAYgAAABAAAA5AIAAAAQAAABAAAA9AIAAA==");
+
+ public static void run() {
+ Redefinition.setTestConfiguration(Redefinition.Config.COMMON_RETRANSFORM);
+ doTest(new Transform());
+ }
+
+ public static void doTest(Transform t) {
+ // TODO We currently need to do this transform call since we don't have any way to make the
+ // original-dex-file a single-class dex-file letting us restore it easily. We should use the
+ // manipulation library that is being made when we store the original dex file.
+ // TODO REMOVE this theoretically does nothing but it ensures the original-dex-file we have set
+ // is one we can return to unaltered.
+ Redefinition.doCommonClassRedefinition(Transform.class, CLASS_BYTES_A, DEX_BYTES_A);
+ t.sayHi();
+
+ // Now turn it into DEX_BYTES_B so it says 'Goodbye'
+ Redefinition.addCommonTransformationResult("art/Test932$Transform", CLASS_BYTES_B, DEX_BYTES_B);
+ Redefinition.enableCommonRetransformation(true);
+ Redefinition.doCommonClassRetransformation(Transform.class);
+ t.sayHi();
+
+ // Now turn it back to normal by removing the load-hook and transforming again.
+ Redefinition.enableCommonRetransformation(false);
+ Redefinition.doCommonClassRetransformation(Transform.class);
+ t.sayHi();
+ }
+}
diff --git a/test/934-load-transform/src/Main.java b/test/934-load-transform/src/Main.java
index 606ce78..69c839f 100644
--- a/test/934-load-transform/src/Main.java
+++ b/test/934-load-transform/src/Main.java
@@ -14,6 +14,10 @@
* limitations under the License.
*/
+import static art.Redefinition.addCommonTransformationResult;
+import static art.Redefinition.enableCommonRetransformation;
+import static art.Redefinition.setPopRetransformations;
+
import java.lang.reflect.*;
import java.util.Base64;
@@ -86,11 +90,4 @@
e.printStackTrace();
}
}
-
- private static native void setPopRetransformations(boolean should_pop);
- // Transforms the class
- private static native void enableCommonRetransformation(boolean enable);
- private static native void addCommonTransformationResult(String target_name,
- byte[] class_bytes,
- byte[] dex_bytes);
}
diff --git a/test/934-load-transform/src/art/Redefinition.java b/test/934-load-transform/src/art/Redefinition.java
new file mode 100644
index 0000000..0350ab4
--- /dev/null
+++ b/test/934-load-transform/src/art/Redefinition.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package art;
+
+import java.util.ArrayList;
+// Common Redefinition functions. Placed here for use by CTS
+public class Redefinition {
+ // Bind native functions.
+ static {
+ Main.bindAgentJNIForClass(Redefinition.class);
+ }
+
+ public static final class CommonClassDefinition {
+ public final Class<?> target;
+ public final byte[] class_file_bytes;
+ public final byte[] dex_file_bytes;
+
+ public CommonClassDefinition(Class<?> target, byte[] class_file_bytes, byte[] dex_file_bytes) {
+ this.target = target;
+ this.class_file_bytes = class_file_bytes;
+ this.dex_file_bytes = dex_file_bytes;
+ }
+ }
+
+ // A set of possible test configurations. Test should set this if they need to.
+ // This must be kept in sync with the defines in ti-agent/common_helper.cc
+ public static enum Config {
+ COMMON_REDEFINE(0),
+ COMMON_RETRANSFORM(1),
+ COMMON_TRANSFORM(2);
+
+ private final int val;
+ private Config(int val) {
+ this.val = val;
+ }
+ }
+
+ public static void setTestConfiguration(Config type) {
+ nativeSetTestConfiguration(type.val);
+ }
+
+ private static native void nativeSetTestConfiguration(int type);
+
+ // Transforms the class
+ public static native void doCommonClassRedefinition(Class<?> target,
+ byte[] classfile,
+ byte[] dexfile);
+
+ public static void doMultiClassRedefinition(CommonClassDefinition... defs) {
+ ArrayList<Class<?>> classes = new ArrayList<>();
+ ArrayList<byte[]> class_files = new ArrayList<>();
+ ArrayList<byte[]> dex_files = new ArrayList<>();
+
+ for (CommonClassDefinition d : defs) {
+ classes.add(d.target);
+ class_files.add(d.class_file_bytes);
+ dex_files.add(d.dex_file_bytes);
+ }
+ doCommonMultiClassRedefinition(classes.toArray(new Class<?>[0]),
+ class_files.toArray(new byte[0][]),
+ dex_files.toArray(new byte[0][]));
+ }
+
+ public static void addMultiTransformationResults(CommonClassDefinition... defs) {
+ for (CommonClassDefinition d : defs) {
+ addCommonTransformationResult(d.target.getCanonicalName(),
+ d.class_file_bytes,
+ d.dex_file_bytes);
+ }
+ }
+
+ public static native void doCommonMultiClassRedefinition(Class<?>[] targets,
+ byte[][] classfiles,
+ byte[][] dexfiles);
+ public static native void doCommonClassRetransformation(Class<?>... target);
+ public static native void setPopRetransformations(boolean pop);
+ public static native void popTransformationFor(String name);
+ public static native void enableCommonRetransformation(boolean enable);
+ public static native void addCommonTransformationResult(String target_name,
+ byte[] class_bytes,
+ byte[] dex_bytes);
+}
diff --git a/test/935-non-retransformable/src/Main.java b/test/935-non-retransformable/src/Main.java
index df92561..f240224 100644
--- a/test/935-non-retransformable/src/Main.java
+++ b/test/935-non-retransformable/src/Main.java
@@ -17,6 +17,8 @@
import java.lang.reflect.*;
import java.util.Base64;
+import art.Redefinition;
+
class Main {
public static String TEST_NAME = "935-non-retransformable";
@@ -74,10 +76,9 @@
}
public static void main(String[] args) {
- art.Main.bindAgentJNIForClass(Main.class);
- setPopRetransformations(false);
- addCommonTransformationResult("Transform", CLASS_BYTES, DEX_BYTES);
- enableCommonRetransformation(true);
+ Redefinition.setPopRetransformations(false);
+ Redefinition.addCommonTransformationResult("Transform", CLASS_BYTES, DEX_BYTES);
+ Redefinition.enableCommonRetransformation(true);
try {
/* this is the "alternate" DEX/Jar file */
ClassLoader new_loader = getClassLoaderFor(System.getenv("DEX_LOCATION"));
@@ -89,23 +90,14 @@
run_test.invoke(null);
// Remove the original transformation. It has been used by now.
- popTransformationFor("Transform");
+ Redefinition.popTransformationFor("Transform");
// Make sure we don't get called for transformation again.
- addCommonTransformationResult("Transform", new byte[0], new byte[0]);
- doCommonClassRetransformation(new_loader.loadClass("Transform"));
+ Redefinition.addCommonTransformationResult("Transform", new byte[0], new byte[0]);
+ Redefinition.doCommonClassRetransformation(new_loader.loadClass("Transform"));
run_test.invoke(null);
} catch (Exception e) {
System.out.println(e.toString());
e.printStackTrace();
}
}
-
- // Transforms the class
- private static native void doCommonClassRetransformation(Class<?>... classes);
- private static native void enableCommonRetransformation(boolean enable);
- private static native void addCommonTransformationResult(String target_name,
- byte[] class_bytes,
- byte[] dex_bytes);
- private static native void setPopRetransformations(boolean should_pop);
- private static native void popTransformationFor(String target_name);
}
diff --git a/test/935-non-retransformable/src/art/Redefinition.java b/test/935-non-retransformable/src/art/Redefinition.java
new file mode 100644
index 0000000..0350ab4
--- /dev/null
+++ b/test/935-non-retransformable/src/art/Redefinition.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package art;
+
+import java.util.ArrayList;
+// Common Redefinition functions. Placed here for use by CTS
+public class Redefinition {
+ // Bind native functions.
+ static {
+ Main.bindAgentJNIForClass(Redefinition.class);
+ }
+
+ public static final class CommonClassDefinition {
+ public final Class<?> target;
+ public final byte[] class_file_bytes;
+ public final byte[] dex_file_bytes;
+
+ public CommonClassDefinition(Class<?> target, byte[] class_file_bytes, byte[] dex_file_bytes) {
+ this.target = target;
+ this.class_file_bytes = class_file_bytes;
+ this.dex_file_bytes = dex_file_bytes;
+ }
+ }
+
+ // A set of possible test configurations. Test should set this if they need to.
+ // This must be kept in sync with the defines in ti-agent/common_helper.cc
+ public static enum Config {
+ COMMON_REDEFINE(0),
+ COMMON_RETRANSFORM(1),
+ COMMON_TRANSFORM(2);
+
+ private final int val;
+ private Config(int val) {
+ this.val = val;
+ }
+ }
+
+ public static void setTestConfiguration(Config type) {
+ nativeSetTestConfiguration(type.val);
+ }
+
+ private static native void nativeSetTestConfiguration(int type);
+
+ // Transforms the class
+ public static native void doCommonClassRedefinition(Class<?> target,
+ byte[] classfile,
+ byte[] dexfile);
+
+ public static void doMultiClassRedefinition(CommonClassDefinition... defs) {
+ ArrayList<Class<?>> classes = new ArrayList<>();
+ ArrayList<byte[]> class_files = new ArrayList<>();
+ ArrayList<byte[]> dex_files = new ArrayList<>();
+
+ for (CommonClassDefinition d : defs) {
+ classes.add(d.target);
+ class_files.add(d.class_file_bytes);
+ dex_files.add(d.dex_file_bytes);
+ }
+ doCommonMultiClassRedefinition(classes.toArray(new Class<?>[0]),
+ class_files.toArray(new byte[0][]),
+ dex_files.toArray(new byte[0][]));
+ }
+
+ public static void addMultiTransformationResults(CommonClassDefinition... defs) {
+ for (CommonClassDefinition d : defs) {
+ addCommonTransformationResult(d.target.getCanonicalName(),
+ d.class_file_bytes,
+ d.dex_file_bytes);
+ }
+ }
+
+ public static native void doCommonMultiClassRedefinition(Class<?>[] targets,
+ byte[][] classfiles,
+ byte[][] dexfiles);
+ public static native void doCommonClassRetransformation(Class<?>... target);
+ public static native void setPopRetransformations(boolean pop);
+ public static native void popTransformationFor(String name);
+ public static native void enableCommonRetransformation(boolean enable);
+ public static native void addCommonTransformationResult(String target_name,
+ byte[] class_bytes,
+ byte[] dex_bytes);
+}
diff --git a/test/937-hello-retransform-package/src/Main.java b/test/937-hello-retransform-package/src/Main.java
index 866f75d..eef56c2 100644
--- a/test/937-hello-retransform-package/src/Main.java
+++ b/test/937-hello-retransform-package/src/Main.java
@@ -17,6 +17,8 @@
import java.util.Base64;
import testing.*;
+import art.Redefinition;
+
public class Main {
/**
@@ -53,22 +55,14 @@
"YgEAAAMgAAACAAAAGwIAAAAgAAABAAAAJgIAAAAQAAABAAAANAIAAA==");
public static void main(String[] args) {
- art.Main.bindAgentJNIForClass(Main.class);
doTest(new Transform());
}
public static void doTest(Transform t) {
t.sayHi();
- addCommonTransformationResult("testing/Transform", CLASS_BYTES, DEX_BYTES);
- enableCommonRetransformation(true);
- doCommonClassRetransformation(Transform.class);
+ Redefinition.addCommonTransformationResult("testing/Transform", CLASS_BYTES, DEX_BYTES);
+ Redefinition.enableCommonRetransformation(true);
+ Redefinition.doCommonClassRetransformation(Transform.class);
t.sayHi();
}
-
- // Transforms the class
- private static native void doCommonClassRetransformation(Class<?>... target);
- private static native void enableCommonRetransformation(boolean enable);
- private static native void addCommonTransformationResult(String target_name,
- byte[] class_bytes,
- byte[] dex_bytes);
}
diff --git a/test/937-hello-retransform-package/src/art/Redefinition.java b/test/937-hello-retransform-package/src/art/Redefinition.java
new file mode 100644
index 0000000..0350ab4
--- /dev/null
+++ b/test/937-hello-retransform-package/src/art/Redefinition.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package art;
+
+import java.util.ArrayList;
+// Common Redefinition functions. Placed here for use by CTS
+public class Redefinition {
+ // Bind native functions.
+ static {
+ Main.bindAgentJNIForClass(Redefinition.class);
+ }
+
+ public static final class CommonClassDefinition {
+ public final Class<?> target;
+ public final byte[] class_file_bytes;
+ public final byte[] dex_file_bytes;
+
+ public CommonClassDefinition(Class<?> target, byte[] class_file_bytes, byte[] dex_file_bytes) {
+ this.target = target;
+ this.class_file_bytes = class_file_bytes;
+ this.dex_file_bytes = dex_file_bytes;
+ }
+ }
+
+ // A set of possible test configurations. Test should set this if they need to.
+ // This must be kept in sync with the defines in ti-agent/common_helper.cc
+ public static enum Config {
+ COMMON_REDEFINE(0),
+ COMMON_RETRANSFORM(1),
+ COMMON_TRANSFORM(2);
+
+ private final int val;
+ private Config(int val) {
+ this.val = val;
+ }
+ }
+
+ public static void setTestConfiguration(Config type) {
+ nativeSetTestConfiguration(type.val);
+ }
+
+ private static native void nativeSetTestConfiguration(int type);
+
+ // Transforms the class
+ public static native void doCommonClassRedefinition(Class<?> target,
+ byte[] classfile,
+ byte[] dexfile);
+
+ public static void doMultiClassRedefinition(CommonClassDefinition... defs) {
+ ArrayList<Class<?>> classes = new ArrayList<>();
+ ArrayList<byte[]> class_files = new ArrayList<>();
+ ArrayList<byte[]> dex_files = new ArrayList<>();
+
+ for (CommonClassDefinition d : defs) {
+ classes.add(d.target);
+ class_files.add(d.class_file_bytes);
+ dex_files.add(d.dex_file_bytes);
+ }
+ doCommonMultiClassRedefinition(classes.toArray(new Class<?>[0]),
+ class_files.toArray(new byte[0][]),
+ dex_files.toArray(new byte[0][]));
+ }
+
+ public static void addMultiTransformationResults(CommonClassDefinition... defs) {
+ for (CommonClassDefinition d : defs) {
+ addCommonTransformationResult(d.target.getCanonicalName(),
+ d.class_file_bytes,
+ d.dex_file_bytes);
+ }
+ }
+
+ public static native void doCommonMultiClassRedefinition(Class<?>[] targets,
+ byte[][] classfiles,
+ byte[][] dexfiles);
+ public static native void doCommonClassRetransformation(Class<?>... target);
+ public static native void setPopRetransformations(boolean pop);
+ public static native void popTransformationFor(String name);
+ public static native void enableCommonRetransformation(boolean enable);
+ public static native void addCommonTransformationResult(String target_name,
+ byte[] class_bytes,
+ byte[] dex_bytes);
+}
diff --git a/test/938-load-transform-bcp/src/Main.java b/test/938-load-transform-bcp/src/Main.java
index 21b841f..e560942 100644
--- a/test/938-load-transform-bcp/src/Main.java
+++ b/test/938-load-transform-bcp/src/Main.java
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+import static art.Redefinition.*;
import java.lang.reflect.*;
import java.util.Base64;
@@ -114,11 +115,4 @@
e.printStackTrace();
}
}
-
- private static native void setPopRetransformations(boolean should_pop);
- // Transforms the class
- private static native void enableCommonRetransformation(boolean enable);
- private static native void addCommonTransformationResult(String target_name,
- byte[] class_bytes,
- byte[] dex_bytes);
}
diff --git a/test/938-load-transform-bcp/src/art/Redefinition.java b/test/938-load-transform-bcp/src/art/Redefinition.java
new file mode 100644
index 0000000..0350ab4
--- /dev/null
+++ b/test/938-load-transform-bcp/src/art/Redefinition.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package art;
+
+import java.util.ArrayList;
+// Common Redefinition functions. Placed here for use by CTS
+public class Redefinition {
+ // Bind native functions.
+ static {
+ Main.bindAgentJNIForClass(Redefinition.class);
+ }
+
+ public static final class CommonClassDefinition {
+ public final Class<?> target;
+ public final byte[] class_file_bytes;
+ public final byte[] dex_file_bytes;
+
+ public CommonClassDefinition(Class<?> target, byte[] class_file_bytes, byte[] dex_file_bytes) {
+ this.target = target;
+ this.class_file_bytes = class_file_bytes;
+ this.dex_file_bytes = dex_file_bytes;
+ }
+ }
+
+ // A set of possible test configurations. Test should set this if they need to.
+ // This must be kept in sync with the defines in ti-agent/common_helper.cc
+ public static enum Config {
+ COMMON_REDEFINE(0),
+ COMMON_RETRANSFORM(1),
+ COMMON_TRANSFORM(2);
+
+ private final int val;
+ private Config(int val) {
+ this.val = val;
+ }
+ }
+
+ public static void setTestConfiguration(Config type) {
+ nativeSetTestConfiguration(type.val);
+ }
+
+ private static native void nativeSetTestConfiguration(int type);
+
+ // Transforms the class
+ public static native void doCommonClassRedefinition(Class<?> target,
+ byte[] classfile,
+ byte[] dexfile);
+
+ public static void doMultiClassRedefinition(CommonClassDefinition... defs) {
+ ArrayList<Class<?>> classes = new ArrayList<>();
+ ArrayList<byte[]> class_files = new ArrayList<>();
+ ArrayList<byte[]> dex_files = new ArrayList<>();
+
+ for (CommonClassDefinition d : defs) {
+ classes.add(d.target);
+ class_files.add(d.class_file_bytes);
+ dex_files.add(d.dex_file_bytes);
+ }
+ doCommonMultiClassRedefinition(classes.toArray(new Class<?>[0]),
+ class_files.toArray(new byte[0][]),
+ dex_files.toArray(new byte[0][]));
+ }
+
+ public static void addMultiTransformationResults(CommonClassDefinition... defs) {
+ for (CommonClassDefinition d : defs) {
+ addCommonTransformationResult(d.target.getCanonicalName(),
+ d.class_file_bytes,
+ d.dex_file_bytes);
+ }
+ }
+
+ public static native void doCommonMultiClassRedefinition(Class<?>[] targets,
+ byte[][] classfiles,
+ byte[][] dexfiles);
+ public static native void doCommonClassRetransformation(Class<?>... target);
+ public static native void setPopRetransformations(boolean pop);
+ public static native void popTransformationFor(String name);
+ public static native void enableCommonRetransformation(boolean enable);
+ public static native void addCommonTransformationResult(String target_name,
+ byte[] class_bytes,
+ byte[] dex_bytes);
+}
diff --git a/test/939-hello-transformation-bcp/src/Main.java b/test/939-hello-transformation-bcp/src/Main.java
index 0e1f845..7bda667 100644
--- a/test/939-hello-transformation-bcp/src/Main.java
+++ b/test/939-hello-transformation-bcp/src/Main.java
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+import static art.Redefinition.doCommonClassRedefinition;
import java.util.Base64;
import java.util.OptionalLong;
public class Main {
@@ -110,7 +111,6 @@
"AABHBgAABCAAAAIAAACVBgAAACAAAAEAAACtBgAAABAAAAEAAAD4BgAA");
public static void main(String[] args) {
- art.Main.bindAgentJNIForClass(Main.class);
// OptionalLong is a class that is unlikely to be used by the time this test starts and is not
// likely to be changed in any meaningful way in the future.
OptionalLong ol = OptionalLong.of(0xDEADBEEF);
@@ -119,9 +119,4 @@
doCommonClassRedefinition(OptionalLong.class, CLASS_BYTES, DEX_BYTES);
System.out.println("ol.toString() -> '" + ol.toString() + "'");
}
-
- // Transforms the class
- private static native void doCommonClassRedefinition(Class<?> target,
- byte[] class_file,
- byte[] dex_file);
}
diff --git a/test/939-hello-transformation-bcp/src/art/Redefinition.java b/test/939-hello-transformation-bcp/src/art/Redefinition.java
new file mode 100644
index 0000000..0350ab4
--- /dev/null
+++ b/test/939-hello-transformation-bcp/src/art/Redefinition.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package art;
+
+import java.util.ArrayList;
+// Common Redefinition functions. Placed here for use by CTS
+public class Redefinition {
+ // Bind native functions.
+ static {
+ Main.bindAgentJNIForClass(Redefinition.class);
+ }
+
+ public static final class CommonClassDefinition {
+ public final Class<?> target;
+ public final byte[] class_file_bytes;
+ public final byte[] dex_file_bytes;
+
+ public CommonClassDefinition(Class<?> target, byte[] class_file_bytes, byte[] dex_file_bytes) {
+ this.target = target;
+ this.class_file_bytes = class_file_bytes;
+ this.dex_file_bytes = dex_file_bytes;
+ }
+ }
+
+ // A set of possible test configurations. Test should set this if they need to.
+ // This must be kept in sync with the defines in ti-agent/common_helper.cc
+ public static enum Config {
+ COMMON_REDEFINE(0),
+ COMMON_RETRANSFORM(1),
+ COMMON_TRANSFORM(2);
+
+ private final int val;
+ private Config(int val) {
+ this.val = val;
+ }
+ }
+
+ public static void setTestConfiguration(Config type) {
+ nativeSetTestConfiguration(type.val);
+ }
+
+ private static native void nativeSetTestConfiguration(int type);
+
+ // Transforms the class
+ public static native void doCommonClassRedefinition(Class<?> target,
+ byte[] classfile,
+ byte[] dexfile);
+
+ public static void doMultiClassRedefinition(CommonClassDefinition... defs) {
+ ArrayList<Class<?>> classes = new ArrayList<>();
+ ArrayList<byte[]> class_files = new ArrayList<>();
+ ArrayList<byte[]> dex_files = new ArrayList<>();
+
+ for (CommonClassDefinition d : defs) {
+ classes.add(d.target);
+ class_files.add(d.class_file_bytes);
+ dex_files.add(d.dex_file_bytes);
+ }
+ doCommonMultiClassRedefinition(classes.toArray(new Class<?>[0]),
+ class_files.toArray(new byte[0][]),
+ dex_files.toArray(new byte[0][]));
+ }
+
+ public static void addMultiTransformationResults(CommonClassDefinition... defs) {
+ for (CommonClassDefinition d : defs) {
+ addCommonTransformationResult(d.target.getCanonicalName(),
+ d.class_file_bytes,
+ d.dex_file_bytes);
+ }
+ }
+
+ public static native void doCommonMultiClassRedefinition(Class<?>[] targets,
+ byte[][] classfiles,
+ byte[][] dexfiles);
+ public static native void doCommonClassRetransformation(Class<?>... target);
+ public static native void setPopRetransformations(boolean pop);
+ public static native void popTransformationFor(String name);
+ public static native void enableCommonRetransformation(boolean enable);
+ public static native void addCommonTransformationResult(String target_name,
+ byte[] class_bytes,
+ byte[] dex_bytes);
+}
diff --git a/test/940-recursive-obsolete/src/Main.java b/test/940-recursive-obsolete/src/Main.java
index 724f82d..0b0211c 100644
--- a/test/940-recursive-obsolete/src/Main.java
+++ b/test/940-recursive-obsolete/src/Main.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,77 +14,8 @@
* limitations under the License.
*/
-import java.util.Base64;
-
public class Main {
-
- // class Transform {
- // public void sayHi(int recur, Runnable r) {
- // System.out.println("Hello" + recur + " - transformed");
- // if (recur == 1) {
- // r.run();
- // sayHi(recur - 1, r);
- // } else if (recur != 0) {
- // sayHi(recur - 1, r);
- // }
- // System.out.println("Goodbye" + recur + " - transformed");
- // }
- // }
- private static final byte[] CLASS_BYTES = Base64.getDecoder().decode(
- "yv66vgAAADQANwoADwAZCQAaABsHABwKAAMAGQgAHQoAAwAeCgADAB8IACAKAAMAIQoAIgAjCwAk" +
- "ACUKAA4AJggAJwcAKAcAKQEABjxpbml0PgEAAygpVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUB" +
- "AAVzYXlIaQEAGChJTGphdmEvbGFuZy9SdW5uYWJsZTspVgEADVN0YWNrTWFwVGFibGUBAApTb3Vy" +
- "Y2VGaWxlAQAOVHJhbnNmb3JtLmphdmEMABAAEQcAKgwAKwAsAQAXamF2YS9sYW5nL1N0cmluZ0J1" +
- "aWxkZXIBAAVIZWxsbwwALQAuDAAtAC8BAA4gLSB0cmFuc2Zvcm1lZAwAMAAxBwAyDAAzADQHADUM" +
- "ADYAEQwAFAAVAQAHR29vZGJ5ZQEACVRyYW5zZm9ybQEAEGphdmEvbGFuZy9PYmplY3QBABBqYXZh" +
- "L2xhbmcvU3lzdGVtAQADb3V0AQAVTGphdmEvaW8vUHJpbnRTdHJlYW07AQAGYXBwZW5kAQAtKExq" +
- "YXZhL2xhbmcvU3RyaW5nOylMamF2YS9sYW5nL1N0cmluZ0J1aWxkZXI7AQAcKEkpTGphdmEvbGFu" +
- "Zy9TdHJpbmdCdWlsZGVyOwEACHRvU3RyaW5nAQAUKClMamF2YS9sYW5nL1N0cmluZzsBABNqYXZh" +
- "L2lvL1ByaW50U3RyZWFtAQAHcHJpbnRsbgEAFShMamF2YS9sYW5nL1N0cmluZzspVgEAEmphdmEv" +
- "bGFuZy9SdW5uYWJsZQEAA3J1bgAgAA4ADwAAAAAAAgAAABAAEQABABIAAAAdAAEAAQAAAAUqtwAB" +
- "sQAAAAEAEwAAAAYAAQAAAAEAAQAUABUAAQASAAAAnQADAAMAAABfsgACuwADWbcABBIFtgAGG7YA" +
- "BxIItgAGtgAJtgAKGwSgABQsuQALAQAqGwRkLLYADKcADxuZAAsqGwRkLLYADLIAArsAA1m3AAQS" +
- "DbYABhu2AAcSCLYABrYACbYACrEAAAACABMAAAAiAAgAAAADAB4ABAAjAAUAKQAGADQABwA4AAgA" +
- "QAAKAF4ACwAWAAAABAACNAsAAQAXAAAAAgAY");
- private static final byte[] DEX_BYTES = Base64.getDecoder().decode(
- "ZGV4CjAzNQA3pkIgnymz2/eri+mp2dyZo3jolQmaRPKEBAAAcAAAAHhWNBIAAAAAAAAAAOQDAAAa" +
- "AAAAcAAAAAkAAADYAAAABgAAAPwAAAABAAAARAEAAAkAAABMAQAAAQAAAJQBAADQAgAAtAEAAJwC" +
- "AACsAgAAtAIAAL0CAADEAgAAxwIAAMoCAADOAgAA0gIAAN8CAAD2AgAACgMAACADAAA0AwAATwMA" +
- "AGMDAABzAwAAdgMAAHsDAAB/AwAAhwMAAJsDAACgAwAAqQMAAK4DAAC1AwAABAAAAAgAAAAJAAAA" +
- "CgAAAAsAAAAMAAAADQAAAA4AAAAQAAAABQAAAAUAAAAAAAAABgAAAAYAAACEAgAABwAAAAYAAACM" +
- "AgAAEAAAAAgAAAAAAAAAEQAAAAgAAACUAgAAEgAAAAgAAACMAgAABwACABUAAAABAAMAAQAAAAEA" +
- "BAAYAAAAAgAFABYAAAADAAMAAQAAAAQAAwAXAAAABgADAAEAAAAGAAEAEwAAAAYAAgATAAAABgAA" +
- "ABkAAAABAAAAAAAAAAMAAAAAAAAADwAAAAAAAADWAwAAAAAAAAEAAQABAAAAvwMAAAQAAABwEAMA" +
- "AAAOAAYAAwADAAAAxAMAAFQAAABiAAAAIgEGAHAQBQABABsCAwAAAG4gBwAhAAwBbiAGAEEADAEb" +
- "AgAAAABuIAcAIQAMAW4QCAABAAwBbiACABAAEhAzBCsAchAEAAUA2AAE/24wAQADBWIAAAAiAQYA" +
- "cBAFAAEAGwICAAAAbiAHACEADAFuIAYAQQAMARsCAAAAAG4gBwAhAAwBbhAIAAEADAFuIAIAEAAO" +
- "ADgE3//YAAT/bjABAAMFKNgBAAAAAAAAAAEAAAAFAAAAAgAAAAAABAAOIC0gdHJhbnNmb3JtZWQA" +
- "Bjxpbml0PgAHR29vZGJ5ZQAFSGVsbG8AAUkAAUwAAkxJAAJMTAALTFRyYW5zZm9ybTsAFUxqYXZh" +
- "L2lvL1ByaW50U3RyZWFtOwASTGphdmEvbGFuZy9PYmplY3Q7ABRMamF2YS9sYW5nL1J1bm5hYmxl" +
- "OwASTGphdmEvbGFuZy9TdHJpbmc7ABlMamF2YS9sYW5nL1N0cmluZ0J1aWxkZXI7ABJMamF2YS9s" +
- "YW5nL1N5c3RlbTsADlRyYW5zZm9ybS5qYXZhAAFWAANWSUwAAlZMAAZhcHBlbmQAEmVtaXR0ZXI6" +
- "IGphY2stNC4yNAADb3V0AAdwcmludGxuAANydW4ABXNheUhpAAh0b1N0cmluZwABAAcOAAMCAAAH" +
- "DgEgDzw8XQEgDxktAAAAAQEAgIAEtAMBAcwDDQAAAAAAAAABAAAAAAAAAAEAAAAaAAAAcAAAAAIA" +
- "AAAJAAAA2AAAAAMAAAAGAAAA/AAAAAQAAAABAAAARAEAAAUAAAAJAAAATAEAAAYAAAABAAAAlAEA" +
- "AAEgAAACAAAAtAEAAAEQAAADAAAAhAIAAAIgAAAaAAAAnAIAAAMgAAACAAAAvwMAAAAgAAABAAAA" +
- "1gMAAAAQAAABAAAA5AMAAA==");
-
- public static void main(String[] args) {
- art.Main.bindAgentJNIForClass(Main.class);
- doTest(new Transform());
+ public static void main(String[] args) throws Exception {
+ art.Test940.run();
}
-
- public static void doTest(Transform t) {
- t.sayHi(2, () -> { System.out.println("Not doing anything here"); });
- t.sayHi(2, () -> {
- System.out.println("transforming calling function");
- doCommonClassRedefinition(Transform.class, CLASS_BYTES, DEX_BYTES);
- });
- t.sayHi(2, () -> { System.out.println("Not doing anything here"); });
- }
-
- // Transforms the class
- private static native void doCommonClassRedefinition(Class<?> target,
- byte[] classfile,
- byte[] dexfile);
}
diff --git a/test/940-recursive-obsolete/src/Transform.java b/test/940-recursive-obsolete/src/Transform.java
deleted file mode 100644
index 97522cd..0000000
--- a/test/940-recursive-obsolete/src/Transform.java
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-class Transform {
- public void sayHi(int recur, Runnable r) {
- System.out.println("hello" + recur);
- if (recur == 1) {
- r.run();
- sayHi(recur - 1, r);
- } else if (recur != 0) {
- sayHi(recur - 1, r);
- }
- System.out.println("goodbye" + recur);
- }
-}
diff --git a/test/940-recursive-obsolete/src/art/Redefinition.java b/test/940-recursive-obsolete/src/art/Redefinition.java
new file mode 100644
index 0000000..0350ab4
--- /dev/null
+++ b/test/940-recursive-obsolete/src/art/Redefinition.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package art;
+
+import java.util.ArrayList;
+// Common Redefinition functions. Placed here for use by CTS
+public class Redefinition {
+ // Bind native functions.
+ static {
+ Main.bindAgentJNIForClass(Redefinition.class);
+ }
+
+ public static final class CommonClassDefinition {
+ public final Class<?> target;
+ public final byte[] class_file_bytes;
+ public final byte[] dex_file_bytes;
+
+ public CommonClassDefinition(Class<?> target, byte[] class_file_bytes, byte[] dex_file_bytes) {
+ this.target = target;
+ this.class_file_bytes = class_file_bytes;
+ this.dex_file_bytes = dex_file_bytes;
+ }
+ }
+
+ // A set of possible test configurations. Test should set this if they need to.
+ // This must be kept in sync with the defines in ti-agent/common_helper.cc
+ public static enum Config {
+ COMMON_REDEFINE(0),
+ COMMON_RETRANSFORM(1),
+ COMMON_TRANSFORM(2);
+
+ private final int val;
+ private Config(int val) {
+ this.val = val;
+ }
+ }
+
+ public static void setTestConfiguration(Config type) {
+ nativeSetTestConfiguration(type.val);
+ }
+
+ private static native void nativeSetTestConfiguration(int type);
+
+ // Transforms the class
+ public static native void doCommonClassRedefinition(Class<?> target,
+ byte[] classfile,
+ byte[] dexfile);
+
+ public static void doMultiClassRedefinition(CommonClassDefinition... defs) {
+ ArrayList<Class<?>> classes = new ArrayList<>();
+ ArrayList<byte[]> class_files = new ArrayList<>();
+ ArrayList<byte[]> dex_files = new ArrayList<>();
+
+ for (CommonClassDefinition d : defs) {
+ classes.add(d.target);
+ class_files.add(d.class_file_bytes);
+ dex_files.add(d.dex_file_bytes);
+ }
+ doCommonMultiClassRedefinition(classes.toArray(new Class<?>[0]),
+ class_files.toArray(new byte[0][]),
+ dex_files.toArray(new byte[0][]));
+ }
+
+ public static void addMultiTransformationResults(CommonClassDefinition... defs) {
+ for (CommonClassDefinition d : defs) {
+ addCommonTransformationResult(d.target.getCanonicalName(),
+ d.class_file_bytes,
+ d.dex_file_bytes);
+ }
+ }
+
+ public static native void doCommonMultiClassRedefinition(Class<?>[] targets,
+ byte[][] classfiles,
+ byte[][] dexfiles);
+ public static native void doCommonClassRetransformation(Class<?>... target);
+ public static native void setPopRetransformations(boolean pop);
+ public static native void popTransformationFor(String name);
+ public static native void enableCommonRetransformation(boolean enable);
+ public static native void addCommonTransformationResult(String target_name,
+ byte[] class_bytes,
+ byte[] dex_bytes);
+}
diff --git a/test/940-recursive-obsolete/src/art/Test940.java b/test/940-recursive-obsolete/src/art/Test940.java
new file mode 100644
index 0000000..d67d772
--- /dev/null
+++ b/test/940-recursive-obsolete/src/art/Test940.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package art;
+
+import java.util.Base64;
+
+public class Test940 {
+
+ static class Transform {
+ public void sayHi(int recur, Runnable r) {
+ System.out.println("hello" + recur);
+ if (recur == 1) {
+ r.run();
+ sayHi(recur - 1, r);
+ } else if (recur != 0) {
+ sayHi(recur - 1, r);
+ }
+ System.out.println("goodbye" + recur);
+ }
+ }
+
+
+ // static class Transform {
+ // public void sayHi(int recur, Runnable r) {
+ // System.out.println("Hello" + recur + " - transformed");
+ // if (recur == 1) {
+ // r.run();
+ // sayHi(recur - 1, r);
+ // } else if (recur != 0) {
+ // sayHi(recur - 1, r);
+ // }
+ // System.out.println("Goodbye" + recur + " - transformed");
+ // }
+ // }
+ private static final byte[] CLASS_BYTES = Base64.getDecoder().decode(
+ "yv66vgAAADQAOwoADwAZCQAaABsHABwKAAMAGQgAHQoAAwAeCgADAB8IACAKAAMAIQoAIgAjCwAk" +
+ "ACUKAA4AJggAJwcAKQcALAEABjxpbml0PgEAAygpVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUB" +
+ "AAVzYXlIaQEAGChJTGphdmEvbGFuZy9SdW5uYWJsZTspVgEADVN0YWNrTWFwVGFibGUBAApTb3Vy" +
+ "Y2VGaWxlAQAMVGVzdDk0MC5qYXZhDAAQABEHAC0MAC4ALwEAF2phdmEvbGFuZy9TdHJpbmdCdWls" +
+ "ZGVyAQAFSGVsbG8MADAAMQwAMAAyAQAOIC0gdHJhbnNmb3JtZWQMADMANAcANQwANgA3BwA4DAA5" +
+ "ABEMABQAFQEAB0dvb2RieWUHADoBABVhcnQvVGVzdDk0MCRUcmFuc2Zvcm0BAAlUcmFuc2Zvcm0B" +
+ "AAxJbm5lckNsYXNzZXMBABBqYXZhL2xhbmcvT2JqZWN0AQAQamF2YS9sYW5nL1N5c3RlbQEAA291" +
+ "dAEAFUxqYXZhL2lvL1ByaW50U3RyZWFtOwEABmFwcGVuZAEALShMamF2YS9sYW5nL1N0cmluZzsp" +
+ "TGphdmEvbGFuZy9TdHJpbmdCdWlsZGVyOwEAHChJKUxqYXZhL2xhbmcvU3RyaW5nQnVpbGRlcjsB" +
+ "AAh0b1N0cmluZwEAFCgpTGphdmEvbGFuZy9TdHJpbmc7AQATamF2YS9pby9QcmludFN0cmVhbQEA" +
+ "B3ByaW50bG4BABUoTGphdmEvbGFuZy9TdHJpbmc7KVYBABJqYXZhL2xhbmcvUnVubmFibGUBAANy" +
+ "dW4BAAthcnQvVGVzdDk0MAAgAA4ADwAAAAAAAgAAABAAEQABABIAAAAdAAEAAQAAAAUqtwABsQAA" +
+ "AAEAEwAAAAYAAQAAAAUAAQAUABUAAQASAAAAnQADAAMAAABfsgACuwADWbcABBIFtgAGG7YABxII" +
+ "tgAGtgAJtgAKGwSgABQsuQALAQAqGwRkLLYADKcADxuZAAsqGwRkLLYADLIAArsAA1m3AAQSDbYA" +
+ "Bhu2AAcSCLYABrYACbYACrEAAAACABMAAAAiAAgAAAAHAB4ACAAjAAkAKQAKADQACwA4AAwAQAAO" +
+ "AF4ADwAWAAAABAACNAsAAgAXAAAAAgAYACsAAAAKAAEADgAoACoACA==");
+ private static final byte[] DEX_BYTES = Base64.getDecoder().decode(
+ "ZGV4CjAzNQDQv3jgAAAAAAAAAAAAAAAAAAAAAAAAAAB8BQAAcAAAAHhWNBIAAAAAAAAAALgEAAAg" +
+ "AAAAcAAAAAwAAADwAAAABgAAACABAAABAAAAaAEAAAkAAABwAQAAAQAAALgBAACkAwAA2AEAANgB" +
+ "AADoAQAA8AEAAPkBAAAAAgAAAwIAAAYCAAAKAgAADgIAACcCAAA2AgAAWgIAAHoCAACRAgAApQIA" +
+ "ALsCAADPAgAA6gIAAP4CAAAMAwAAFwMAABoDAAAfAwAAIwMAADADAAA4AwAAPgMAAEMDAABMAwAA" +
+ "UQMAAFgDAABiAwAABAAAAAgAAAAJAAAACgAAAAsAAAAMAAAADQAAAA4AAAAPAAAAEAAAABEAAAAU" +
+ "AAAABQAAAAgAAAAAAAAABgAAAAkAAAB8AwAABwAAAAkAAAB0AwAAFAAAAAsAAAAAAAAAFQAAAAsA" +
+ "AABsAwAAFgAAAAsAAAB0AwAACgAFABoAAAABAAMAAQAAAAEABAAdAAAABQAFABsAAAAGAAMAAQAA" +
+ "AAcAAwAcAAAACQADAAEAAAAJAAEAGAAAAAkAAgAYAAAACQAAAB4AAAABAAAAAAAAAAYAAAAAAAAA" +
+ "EgAAAKgEAAB8BAAAAAAAAA4gLSB0cmFuc2Zvcm1lZAAGPGluaXQ+AAdHb29kYnllAAVIZWxsbwAB" +
+ "SQABTAACTEkAAkxMABdMYXJ0L1Rlc3Q5NDAkVHJhbnNmb3JtOwANTGFydC9UZXN0OTQwOwAiTGRh" +
+ "bHZpay9hbm5vdGF0aW9uL0VuY2xvc2luZ0NsYXNzOwAeTGRhbHZpay9hbm5vdGF0aW9uL0lubmVy" +
+ "Q2xhc3M7ABVMamF2YS9pby9QcmludFN0cmVhbTsAEkxqYXZhL2xhbmcvT2JqZWN0OwAUTGphdmEv" +
+ "bGFuZy9SdW5uYWJsZTsAEkxqYXZhL2xhbmcvU3RyaW5nOwAZTGphdmEvbGFuZy9TdHJpbmdCdWls" +
+ "ZGVyOwASTGphdmEvbGFuZy9TeXN0ZW07AAxUZXN0OTQwLmphdmEACVRyYW5zZm9ybQABVgADVklM" +
+ "AAJWTAALYWNjZXNzRmxhZ3MABmFwcGVuZAAEbmFtZQADb3V0AAdwcmludGxuAANydW4ABXNheUhp" +
+ "AAh0b1N0cmluZwAFdmFsdWUAAAAAAgAAAAAABwABAAAACAAAAAEAAAAAAAAABQAHDgAHAgAABw4B" +
+ "IA8BAw8BAw8BBRIBIA8BAQoBAg8AAAAAAQABAAEAAACEAwAABAAAAHAQAwAAAA4ABgADAAMAAACJ" +
+ "AwAAVQAAAGIAAAAiAQkAcBAFAAEAGwIDAAAAbiAHACEADAFuIAYAQQAMARsCAAAAAG4gBwAhAAwB" +
+ "bhAIAAEADAFuIAIAEAASEDMEKwByEAQABQDYAAT/bjABAAMFYgAAACIBCQBwEAUAAQAbAgIAAABu" +
+ "IAcAIQAMAW4gBgBBAAwBGwIAAAAAbiAHACEADAFuEAgAAQAMAW4gAgAQAA4AOATf/9gABP9uMAEA" +
+ "AwUpANj/AAAAAAEBAICABKgHAQHABwAAAgMBHxgCAgQCFwQIGRcTAAIAAACMBAAAkgQAAJwEAAAA" +
+ "AAAAAAAAAAAAAAAQAAAAAAAAAAEAAAAAAAAAAQAAACAAAABwAAAAAgAAAAwAAADwAAAAAwAAAAYA" +
+ "AAAgAQAABAAAAAEAAABoAQAABQAAAAkAAABwAQAABgAAAAEAAAC4AQAAAiAAACAAAADYAQAAARAA" +
+ "AAMAAABsAwAAAyAAAAIAAACEAwAAASAAAAIAAACoAwAAACAAAAEAAAB8BAAABCAAAAIAAACMBAAA" +
+ "AxAAAAEAAACcBAAABiAAAAEAAACoBAAAABAAAAEAAAC4BAAA");
+
+ public static void run() {
+ Redefinition.setTestConfiguration(Redefinition.Config.COMMON_REDEFINE);
+ doTest(new Transform());
+ }
+
+ public static void doTest(Transform t) {
+ t.sayHi(2, () -> { System.out.println("Not doing anything here"); });
+ t.sayHi(2, () -> {
+ System.out.println("transforming calling function");
+ Redefinition.doCommonClassRedefinition(Transform.class, CLASS_BYTES, DEX_BYTES);
+ });
+ t.sayHi(2, () -> { System.out.println("Not doing anything here"); });
+ }
+}
diff --git a/test/941-recurive-obsolete-jit/src/Main.java b/test/941-recurive-obsolete-jit/src/Main.java
index d88bb9b..1c391a4 100644
--- a/test/941-recurive-obsolete-jit/src/Main.java
+++ b/test/941-recurive-obsolete-jit/src/Main.java
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+import static art.Redefinition.doCommonClassRedefinition;
+
import java.util.Base64;
import java.util.function.Consumer;
import java.lang.reflect.Method;
@@ -148,9 +150,4 @@
private static native boolean isInterpretedFunction(Method m, boolean require_deoptimizable);
private static native void ensureJitCompiled(Class c, String name);
-
- // Transforms the class
- private static native void doCommonClassRedefinition(Class<?> target,
- byte[] classfile,
- byte[] dexfile);
}
diff --git a/test/941-recurive-obsolete-jit/src/art/Redefinition.java b/test/941-recurive-obsolete-jit/src/art/Redefinition.java
new file mode 100644
index 0000000..0350ab4
--- /dev/null
+++ b/test/941-recurive-obsolete-jit/src/art/Redefinition.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package art;
+
+import java.util.ArrayList;
+// Common Redefinition functions. Placed here for use by CTS
+public class Redefinition {
+ // Bind native functions.
+ static {
+ Main.bindAgentJNIForClass(Redefinition.class);
+ }
+
+ public static final class CommonClassDefinition {
+ public final Class<?> target;
+ public final byte[] class_file_bytes;
+ public final byte[] dex_file_bytes;
+
+ public CommonClassDefinition(Class<?> target, byte[] class_file_bytes, byte[] dex_file_bytes) {
+ this.target = target;
+ this.class_file_bytes = class_file_bytes;
+ this.dex_file_bytes = dex_file_bytes;
+ }
+ }
+
+ // A set of possible test configurations. Test should set this if they need to.
+ // This must be kept in sync with the defines in ti-agent/common_helper.cc
+ public static enum Config {
+ COMMON_REDEFINE(0),
+ COMMON_RETRANSFORM(1),
+ COMMON_TRANSFORM(2);
+
+ private final int val;
+ private Config(int val) {
+ this.val = val;
+ }
+ }
+
+ public static void setTestConfiguration(Config type) {
+ nativeSetTestConfiguration(type.val);
+ }
+
+ private static native void nativeSetTestConfiguration(int type);
+
+ // Transforms the class
+ public static native void doCommonClassRedefinition(Class<?> target,
+ byte[] classfile,
+ byte[] dexfile);
+
+ public static void doMultiClassRedefinition(CommonClassDefinition... defs) {
+ ArrayList<Class<?>> classes = new ArrayList<>();
+ ArrayList<byte[]> class_files = new ArrayList<>();
+ ArrayList<byte[]> dex_files = new ArrayList<>();
+
+ for (CommonClassDefinition d : defs) {
+ classes.add(d.target);
+ class_files.add(d.class_file_bytes);
+ dex_files.add(d.dex_file_bytes);
+ }
+ doCommonMultiClassRedefinition(classes.toArray(new Class<?>[0]),
+ class_files.toArray(new byte[0][]),
+ dex_files.toArray(new byte[0][]));
+ }
+
+ public static void addMultiTransformationResults(CommonClassDefinition... defs) {
+ for (CommonClassDefinition d : defs) {
+ addCommonTransformationResult(d.target.getCanonicalName(),
+ d.class_file_bytes,
+ d.dex_file_bytes);
+ }
+ }
+
+ public static native void doCommonMultiClassRedefinition(Class<?>[] targets,
+ byte[][] classfiles,
+ byte[][] dexfiles);
+ public static native void doCommonClassRetransformation(Class<?>... target);
+ public static native void setPopRetransformations(boolean pop);
+ public static native void popTransformationFor(String name);
+ public static native void enableCommonRetransformation(boolean enable);
+ public static native void addCommonTransformationResult(String target_name,
+ byte[] class_bytes,
+ byte[] dex_bytes);
+}
diff --git a/test/942-private-recursive/src/Main.java b/test/942-private-recursive/src/Main.java
index cac75c0..8a1f7c6 100644
--- a/test/942-private-recursive/src/Main.java
+++ b/test/942-private-recursive/src/Main.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,82 +14,8 @@
* limitations under the License.
*/
-import java.util.Base64;
-
public class Main {
-
- // class Transform {
- // public void sayHi(int recur, Runnable r) {
- // privateSayHi(recur, r);
- // }
- // private void privateSayHi(int recur, Runnable r) {
- // System.out.println("Hello" + recur + " - transformed");
- // if (recur == 1) {
- // r.run();
- // privateSayHi(recur - 1, r);
- // } else if (recur != 0) {
- // privateSayHi(recur - 1, r);
- // }
- // System.out.println("Goodbye" + recur + " - transformed");
- // }
- // }
- private static final byte[] CLASS_BYTES = Base64.getDecoder().decode(
- "yv66vgAAADQAOAoADwAaCgAOABsJABwAHQcAHgoABAAaCAAfCgAEACAKAAQAIQgAIgoABAAjCgAk" +
- "ACULACYAJwgAKAcAKQcAKgEABjxpbml0PgEAAygpVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUB" +
- "AAVzYXlIaQEAGChJTGphdmEvbGFuZy9SdW5uYWJsZTspVgEADHByaXZhdGVTYXlIaQEADVN0YWNr" +
- "TWFwVGFibGUBAApTb3VyY2VGaWxlAQAOVHJhbnNmb3JtLmphdmEMABAAEQwAFgAVBwArDAAsAC0B" +
- "ABdqYXZhL2xhbmcvU3RyaW5nQnVpbGRlcgEABUhlbGxvDAAuAC8MAC4AMAEADiAtIHRyYW5zZm9y" +
- "bWVkDAAxADIHADMMADQANQcANgwANwARAQAHR29vZGJ5ZQEACVRyYW5zZm9ybQEAEGphdmEvbGFu" +
- "Zy9PYmplY3QBABBqYXZhL2xhbmcvU3lzdGVtAQADb3V0AQAVTGphdmEvaW8vUHJpbnRTdHJlYW07" +
- "AQAGYXBwZW5kAQAtKExqYXZhL2xhbmcvU3RyaW5nOylMamF2YS9sYW5nL1N0cmluZ0J1aWxkZXI7" +
- "AQAcKEkpTGphdmEvbGFuZy9TdHJpbmdCdWlsZGVyOwEACHRvU3RyaW5nAQAUKClMamF2YS9sYW5n" +
- "L1N0cmluZzsBABNqYXZhL2lvL1ByaW50U3RyZWFtAQAHcHJpbnRsbgEAFShMamF2YS9sYW5nL1N0" +
- "cmluZzspVgEAEmphdmEvbGFuZy9SdW5uYWJsZQEAA3J1bgAgAA4ADwAAAAAAAwAAABAAEQABABIA" +
- "AAAdAAEAAQAAAAUqtwABsQAAAAEAEwAAAAYAAQAAAAEAAQAUABUAAQASAAAAIwADAAMAAAAHKhss" +
- "twACsQAAAAEAEwAAAAoAAgAAAAMABgAEAAIAFgAVAAEAEgAAAJ0AAwADAAAAX7IAA7sABFm3AAUS" +
- "BrYABxu2AAgSCbYAB7YACrYACxsEoAAULLkADAEAKhsEZCy3AAKnAA8bmQALKhsEZCy3AAKyAAO7" +
- "AARZtwAFEg22AAcbtgAIEgm2AAe2AAq2AAuxAAAAAgATAAAAIgAIAAAABgAeAAcAIwAIACkACQA0" +
- "AAoAOAALAEAADQBeAA4AFwAAAAQAAjQLAAEAGAAAAAIAGQ==");
- private static final byte[] DEX_BYTES = Base64.getDecoder().decode(
- "ZGV4CjAzNQBQqwVIiZvIuS8j1HDurKbXZEV62Mnug5PEBAAAcAAAAHhWNBIAAAAAAAAAACQEAAAb" +
- "AAAAcAAAAAkAAADcAAAABgAAAAABAAABAAAASAEAAAoAAABQAQAAAQAAAKABAAAEAwAAwAEAAMAC" +
- "AADQAgAA2AIAAOECAADoAgAA6wIAAO4CAADyAgAA9gIAAAMDAAAaAwAALgMAAEQDAABYAwAAcwMA" +
- "AIcDAACXAwAAmgMAAJ8DAACjAwAAqwMAAL8DAADEAwAAzQMAANsDAADgAwAA5wMAAAQAAAAIAAAA" +
- "CQAAAAoAAAALAAAADAAAAA0AAAAOAAAAEAAAAAUAAAAFAAAAAAAAAAYAAAAGAAAAqAIAAAcAAAAG" +
- "AAAAsAIAABAAAAAIAAAAAAAAABEAAAAIAAAAuAIAABIAAAAIAAAAsAIAAAcAAgAVAAAAAQADAAEA" +
- "AAABAAQAFwAAAAEABAAZAAAAAgAFABYAAAADAAMAAQAAAAQAAwAYAAAABgADAAEAAAAGAAEAEwAA" +
- "AAYAAgATAAAABgAAABoAAAABAAAAAAAAAAMAAAAAAAAADwAAAAAAAAAQBAAAAAAAAAEAAQABAAAA" +
- "8QMAAAQAAABwEAQAAAAOAAYAAwADAAAA9gMAAFQAAABiAAAAIgEGAHAQBgABABsCAwAAAG4gCAAh" +
- "AAwBbiAHAEEADAEbAgAAAABuIAgAIQAMAW4QCQABAAwBbiADABAAEhAzBCsAchAFAAUA2AAE/3Aw" +
- "AQADBWIAAAAiAQYAcBAGAAEAGwICAAAAbiAIACEADAFuIAcAQQAMARsCAAAAAG4gCAAhAAwBbhAJ" +
- "AAEADAFuIAMAEAAOADgE3//YAAT/cDABAAMFKNgDAAMAAwAAAAgEAAAEAAAAcDABABACDgABAAAA" +
- "AAAAAAEAAAAFAAAAAgAAAAAABAAOIC0gdHJhbnNmb3JtZWQABjxpbml0PgAHR29vZGJ5ZQAFSGVs" +
- "bG8AAUkAAUwAAkxJAAJMTAALTFRyYW5zZm9ybTsAFUxqYXZhL2lvL1ByaW50U3RyZWFtOwASTGph" +
- "dmEvbGFuZy9PYmplY3Q7ABRMamF2YS9sYW5nL1J1bm5hYmxlOwASTGphdmEvbGFuZy9TdHJpbmc7" +
- "ABlMamF2YS9sYW5nL1N0cmluZ0J1aWxkZXI7ABJMamF2YS9sYW5nL1N5c3RlbTsADlRyYW5zZm9y" +
- "bS5qYXZhAAFWAANWSUwAAlZMAAZhcHBlbmQAEmVtaXR0ZXI6IGphY2stNC4yNAADb3V0AAdwcmlu" +
- "dGxuAAxwcml2YXRlU2F5SGkAA3J1bgAFc2F5SGkACHRvU3RyaW5nAAEABw4ABgIAAAcOASAPPDxd" +
- "ASAPGS0AAwIAAAcOPAAAAAIBAICABMADAQLYAwIBkAUAAA0AAAAAAAAAAQAAAAAAAAABAAAAGwAA" +
- "AHAAAAACAAAACQAAANwAAAADAAAABgAAAAABAAAEAAAAAQAAAEgBAAAFAAAACgAAAFABAAAGAAAA" +
- "AQAAAKABAAABIAAAAwAAAMABAAABEAAAAwAAAKgCAAACIAAAGwAAAMACAAADIAAAAwAAAPEDAAAA" +
- "IAAAAQAAABAEAAAAEAAAAQAAACQEAAA=");
-
- public static void main(String[] args) {
- art.Main.bindAgentJNIForClass(Main.class);
- doTest(new Transform());
+ public static void main(String[] args) throws Exception {
+ art.Test942.run();
}
-
- public static void doTest(Transform t) {
- t.sayHi(2, () -> { System.out.println("Not doing anything here"); });
- t.sayHi(2, () -> {
- System.out.println("transforming calling function");
- doCommonClassRedefinition(Transform.class, CLASS_BYTES, DEX_BYTES);
- });
- t.sayHi(2, () -> { System.out.println("Not doing anything here"); });
- }
-
- // Transforms the class
- private static native void doCommonClassRedefinition(Class<?> target,
- byte[] classfile,
- byte[] dexfile);
}
diff --git a/test/942-private-recursive/src/Transform.java b/test/942-private-recursive/src/Transform.java
deleted file mode 100644
index 7714326..0000000
--- a/test/942-private-recursive/src/Transform.java
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-class Transform {
- private void privateSayHi(int recur, Runnable r) {
- System.out.println("hello" + recur);
- if (recur == 1) {
- r.run();
- privateSayHi(recur - 1, r);
- } else if (recur != 0) {
- privateSayHi(recur - 1, r);
- }
- System.out.println("goodbye" + recur);
- }
-
- public void sayHi(int recur, Runnable r) {
- privateSayHi(recur, r);
- }
-}
diff --git a/test/942-private-recursive/src/art/Redefinition.java b/test/942-private-recursive/src/art/Redefinition.java
new file mode 100644
index 0000000..0350ab4
--- /dev/null
+++ b/test/942-private-recursive/src/art/Redefinition.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package art;
+
+import java.util.ArrayList;
+// Common Redefinition functions. Placed here for use by CTS
+public class Redefinition {
+ // Bind native functions.
+ static {
+ Main.bindAgentJNIForClass(Redefinition.class);
+ }
+
+ public static final class CommonClassDefinition {
+ public final Class<?> target;
+ public final byte[] class_file_bytes;
+ public final byte[] dex_file_bytes;
+
+ public CommonClassDefinition(Class<?> target, byte[] class_file_bytes, byte[] dex_file_bytes) {
+ this.target = target;
+ this.class_file_bytes = class_file_bytes;
+ this.dex_file_bytes = dex_file_bytes;
+ }
+ }
+
+ // A set of possible test configurations. Test should set this if they need to.
+ // This must be kept in sync with the defines in ti-agent/common_helper.cc
+ public static enum Config {
+ COMMON_REDEFINE(0),
+ COMMON_RETRANSFORM(1),
+ COMMON_TRANSFORM(2);
+
+ private final int val;
+ private Config(int val) {
+ this.val = val;
+ }
+ }
+
+ public static void setTestConfiguration(Config type) {
+ nativeSetTestConfiguration(type.val);
+ }
+
+ private static native void nativeSetTestConfiguration(int type);
+
+ // Transforms the class
+ public static native void doCommonClassRedefinition(Class<?> target,
+ byte[] classfile,
+ byte[] dexfile);
+
+ public static void doMultiClassRedefinition(CommonClassDefinition... defs) {
+ ArrayList<Class<?>> classes = new ArrayList<>();
+ ArrayList<byte[]> class_files = new ArrayList<>();
+ ArrayList<byte[]> dex_files = new ArrayList<>();
+
+ for (CommonClassDefinition d : defs) {
+ classes.add(d.target);
+ class_files.add(d.class_file_bytes);
+ dex_files.add(d.dex_file_bytes);
+ }
+ doCommonMultiClassRedefinition(classes.toArray(new Class<?>[0]),
+ class_files.toArray(new byte[0][]),
+ dex_files.toArray(new byte[0][]));
+ }
+
+ public static void addMultiTransformationResults(CommonClassDefinition... defs) {
+ for (CommonClassDefinition d : defs) {
+ addCommonTransformationResult(d.target.getCanonicalName(),
+ d.class_file_bytes,
+ d.dex_file_bytes);
+ }
+ }
+
+ public static native void doCommonMultiClassRedefinition(Class<?>[] targets,
+ byte[][] classfiles,
+ byte[][] dexfiles);
+ public static native void doCommonClassRetransformation(Class<?>... target);
+ public static native void setPopRetransformations(boolean pop);
+ public static native void popTransformationFor(String name);
+ public static native void enableCommonRetransformation(boolean enable);
+ public static native void addCommonTransformationResult(String target_name,
+ byte[] class_bytes,
+ byte[] dex_bytes);
+}
diff --git a/test/942-private-recursive/src/art/Test942.java b/test/942-private-recursive/src/art/Test942.java
new file mode 100644
index 0000000..cccc2fd
--- /dev/null
+++ b/test/942-private-recursive/src/art/Test942.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package art;
+
+import java.util.Base64;
+
+public class Test942 {
+
+ static class Transform {
+ private void privateSayHi(int recur, Runnable r) {
+ System.out.println("hello" + recur);
+ if (recur == 1) {
+ r.run();
+ privateSayHi(recur - 1, r);
+ } else if (recur != 0) {
+ privateSayHi(recur - 1, r);
+ }
+ System.out.println("goodbye" + recur);
+ }
+
+ public void sayHi(int recur, Runnable r) {
+ privateSayHi(recur, r);
+ }
+ }
+
+
+ // static class Transform {
+ // public void sayHi(int recur, Runnable r) {
+ // privateSayHi(recur, r);
+ // }
+ // private void privateSayHi(int recur, Runnable r) {
+ // System.out.println("Hello" + recur + " - transformed");
+ // if (recur == 1) {
+ // r.run();
+ // privateSayHi(recur - 1, r);
+ // } else if (recur != 0) {
+ // privateSayHi(recur - 1, r);
+ // }
+ // System.out.println("Goodbye" + recur + " - transformed");
+ // }
+ // }
+ private static final byte[] CLASS_BYTES = Base64.getDecoder().decode(
+ "yv66vgAAADQAPAoADwAaCgAOABsJABwAHQcAHgoABAAaCAAfCgAEACAKAAQAIQgAIgoABAAjCgAk" +
+ "ACULACYAJwgAKAcAKgcALQEABjxpbml0PgEAAygpVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUB" +
+ "AAVzYXlIaQEAGChJTGphdmEvbGFuZy9SdW5uYWJsZTspVgEADHByaXZhdGVTYXlIaQEADVN0YWNr" +
+ "TWFwVGFibGUBAApTb3VyY2VGaWxlAQAMVGVzdDk0Mi5qYXZhDAAQABEMABYAFQcALgwALwAwAQAX" +
+ "amF2YS9sYW5nL1N0cmluZ0J1aWxkZXIBAAVIZWxsbwwAMQAyDAAxADMBAA4gLSB0cmFuc2Zvcm1l" +
+ "ZAwANAA1BwA2DAA3ADgHADkMADoAEQEAB0dvb2RieWUHADsBABVhcnQvVGVzdDk0MiRUcmFuc2Zv" +
+ "cm0BAAlUcmFuc2Zvcm0BAAxJbm5lckNsYXNzZXMBABBqYXZhL2xhbmcvT2JqZWN0AQAQamF2YS9s" +
+ "YW5nL1N5c3RlbQEAA291dAEAFUxqYXZhL2lvL1ByaW50U3RyZWFtOwEABmFwcGVuZAEALShMamF2" +
+ "YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9TdHJpbmdCdWlsZGVyOwEAHChJKUxqYXZhL2xhbmcv" +
+ "U3RyaW5nQnVpbGRlcjsBAAh0b1N0cmluZwEAFCgpTGphdmEvbGFuZy9TdHJpbmc7AQATamF2YS9p" +
+ "by9QcmludFN0cmVhbQEAB3ByaW50bG4BABUoTGphdmEvbGFuZy9TdHJpbmc7KVYBABJqYXZhL2xh" +
+ "bmcvUnVubmFibGUBAANydW4BAAthcnQvVGVzdDk0MgAgAA4ADwAAAAAAAwAAABAAEQABABIAAAAd" +
+ "AAEAAQAAAAUqtwABsQAAAAEAEwAAAAYAAQAAAAUAAQAUABUAAQASAAAAIwADAAMAAAAHKhsstwAC" +
+ "sQAAAAEAEwAAAAoAAgAAAAcABgAIAAIAFgAVAAEAEgAAAJ0AAwADAAAAX7IAA7sABFm3AAUSBrYA" +
+ "Bxu2AAgSCbYAB7YACrYACxsEoAAULLkADAEAKhsEZCy3AAKnAA8bmQALKhsEZCy3AAKyAAO7AARZ" +
+ "twAFEg22AAcbtgAIEgm2AAe2AAq2AAuxAAAAAgATAAAAIgAIAAAACgAeAAsAIwAMACkADQA0AA4A" +
+ "OAAPAEAAEQBeABIAFwAAAAQAAjQLAAIAGAAAAAIAGQAsAAAACgABAA4AKQArAAg=");
+ private static final byte[] DEX_BYTES = Base64.getDecoder().decode(
+ "ZGV4CjAzNQDiy6hGAAAAAAAAAAAAAAAAAAAAAAAAAAC4BQAAcAAAAHhWNBIAAAAAAAAAAPQEAAAh" +
+ "AAAAcAAAAAwAAAD0AAAABgAAACQBAAABAAAAbAEAAAoAAAB0AQAAAQAAAMQBAADUAwAA5AEAAOQB" +
+ "AAD0AQAA/AEAAAUCAAAMAgAADwIAABICAAAWAgAAGgIAADMCAABCAgAAZgIAAIYCAACdAgAAsQIA" +
+ "AMcCAADbAgAA9gIAAAoDAAAYAwAAIwMAACYDAAArAwAALwMAADwDAABEAwAASgMAAE8DAABYAwAA" +
+ "ZgMAAGsDAAByAwAAfAMAAAQAAAAIAAAACQAAAAoAAAALAAAADAAAAA0AAAAOAAAADwAAABAAAAAR" +
+ "AAAAFAAAAAUAAAAIAAAAAAAAAAYAAAAJAAAAlAMAAAcAAAAJAAAAjAMAABQAAAALAAAAAAAAABUA" +
+ "AAALAAAAhAMAABYAAAALAAAAjAMAAAoABQAaAAAAAQADAAEAAAABAAQAHAAAAAEABAAeAAAABQAF" +
+ "ABsAAAAGAAMAAQAAAAcAAwAdAAAACQADAAEAAAAJAAEAGAAAAAkAAgAYAAAACQAAAB8AAAABAAAA" +
+ "AAAAAAYAAAAAAAAAEgAAAOQEAAC0BAAAAAAAAA4gLSB0cmFuc2Zvcm1lZAAGPGluaXQ+AAdHb29k" +
+ "YnllAAVIZWxsbwABSQABTAACTEkAAkxMABdMYXJ0L1Rlc3Q5NDIkVHJhbnNmb3JtOwANTGFydC9U" +
+ "ZXN0OTQyOwAiTGRhbHZpay9hbm5vdGF0aW9uL0VuY2xvc2luZ0NsYXNzOwAeTGRhbHZpay9hbm5v" +
+ "dGF0aW9uL0lubmVyQ2xhc3M7ABVMamF2YS9pby9QcmludFN0cmVhbTsAEkxqYXZhL2xhbmcvT2Jq" +
+ "ZWN0OwAUTGphdmEvbGFuZy9SdW5uYWJsZTsAEkxqYXZhL2xhbmcvU3RyaW5nOwAZTGphdmEvbGFu" +
+ "Zy9TdHJpbmdCdWlsZGVyOwASTGphdmEvbGFuZy9TeXN0ZW07AAxUZXN0OTQyLmphdmEACVRyYW5z" +
+ "Zm9ybQABVgADVklMAAJWTAALYWNjZXNzRmxhZ3MABmFwcGVuZAAEbmFtZQADb3V0AAdwcmludGxu" +
+ "AAxwcml2YXRlU2F5SGkAA3J1bgAFc2F5SGkACHRvU3RyaW5nAAV2YWx1ZQAAAgAAAAAABwABAAAA" +
+ "CAAAAAEAAAAAAAAABQAHDgAKAgAABw4BIA8BAw8BAw8BBRIBIA8BAQoBAg8ABwIAAAcOAQMPAAAB" +
+ "AAEAAQAAAJwDAAAEAAAAcBAEAAAADgAGAAMAAwAAAKEDAABVAAAAYgAAACIBCQBwEAYAAQAbAgMA" +
+ "AABuIAgAIQAMAW4gBwBBAAwBGwIAAAAAbiAIACEADAFuEAkAAQAMAW4gAwAQABIQMwQrAHIQBQAF" +
+ "ANgABP9wMAEAAwViAAAAIgEJAHAQBgABABsCAgAAAG4gCAAhAAwBbiAHAEEADAEbAgAAAABuIAgA" +
+ "IQAMAW4QCQABAAwBbiADABAADgA4BN//2AAE/3AwAQADBSkA2P8AAAMAAwADAAAAvQMAAAQAAABw" +
+ "MAEAEAIOAAAAAgEAgIAEyAcBAuAHAgGcCQAAAgMBIBgCAgQCFwQIGRcTAAIAAADIBAAAzgQAANgE" +
+ "AAAAAAAAAAAAAAAAAAAQAAAAAAAAAAEAAAAAAAAAAQAAACEAAABwAAAAAgAAAAwAAAD0AAAAAwAA" +
+ "AAYAAAAkAQAABAAAAAEAAABsAQAABQAAAAoAAAB0AQAABgAAAAEAAADEAQAAAiAAACEAAADkAQAA" +
+ "ARAAAAMAAACEAwAAAyAAAAMAAACcAwAAASAAAAMAAADIAwAAACAAAAEAAAC0BAAABCAAAAIAAADI" +
+ "BAAAAxAAAAEAAADYBAAABiAAAAEAAADkBAAAABAAAAEAAAD0BAAA");
+
+ public static void run() {
+ Redefinition.setTestConfiguration(Redefinition.Config.COMMON_REDEFINE);
+ doTest(new Transform());
+ }
+
+ public static void doTest(Transform t) {
+ t.sayHi(2, () -> { System.out.println("Not doing anything here"); });
+ t.sayHi(2, () -> {
+ System.out.println("transforming calling function");
+ Redefinition.doCommonClassRedefinition(Transform.class, CLASS_BYTES, DEX_BYTES);
+ });
+ t.sayHi(2, () -> { System.out.println("Not doing anything here"); });
+ }
+}
diff --git a/test/943-private-recursive-jit/src/Main.java b/test/943-private-recursive-jit/src/Main.java
index f380c06..01760ad 100644
--- a/test/943-private-recursive-jit/src/Main.java
+++ b/test/943-private-recursive-jit/src/Main.java
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+import static art.Redefinition.doCommonClassRedefinition;
+
import java.util.Base64;
import java.util.function.Consumer;
import java.lang.reflect.Method;
@@ -164,9 +166,4 @@
private static native boolean isInterpretedFunction(Method m, boolean require_deoptimizable);
private static native void ensureJitCompiled(Class c, String name);
-
- // Transforms the class
- private static native void doCommonClassRedefinition(Class<?> target,
- byte[] classfile,
- byte[] dexfile);
}
diff --git a/test/943-private-recursive-jit/src/art/Redefinition.java b/test/943-private-recursive-jit/src/art/Redefinition.java
new file mode 100644
index 0000000..0350ab4
--- /dev/null
+++ b/test/943-private-recursive-jit/src/art/Redefinition.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package art;
+
+import java.util.ArrayList;
+// Common Redefinition functions. Placed here for use by CTS
+public class Redefinition {
+ // Bind native functions.
+ static {
+ Main.bindAgentJNIForClass(Redefinition.class);
+ }
+
+ public static final class CommonClassDefinition {
+ public final Class<?> target;
+ public final byte[] class_file_bytes;
+ public final byte[] dex_file_bytes;
+
+ public CommonClassDefinition(Class<?> target, byte[] class_file_bytes, byte[] dex_file_bytes) {
+ this.target = target;
+ this.class_file_bytes = class_file_bytes;
+ this.dex_file_bytes = dex_file_bytes;
+ }
+ }
+
+ // A set of possible test configurations. Test should set this if they need to.
+ // This must be kept in sync with the defines in ti-agent/common_helper.cc
+ public static enum Config {
+ COMMON_REDEFINE(0),
+ COMMON_RETRANSFORM(1),
+ COMMON_TRANSFORM(2);
+
+ private final int val;
+ private Config(int val) {
+ this.val = val;
+ }
+ }
+
+ public static void setTestConfiguration(Config type) {
+ nativeSetTestConfiguration(type.val);
+ }
+
+ private static native void nativeSetTestConfiguration(int type);
+
+ // Transforms the class
+ public static native void doCommonClassRedefinition(Class<?> target,
+ byte[] classfile,
+ byte[] dexfile);
+
+ public static void doMultiClassRedefinition(CommonClassDefinition... defs) {
+ ArrayList<Class<?>> classes = new ArrayList<>();
+ ArrayList<byte[]> class_files = new ArrayList<>();
+ ArrayList<byte[]> dex_files = new ArrayList<>();
+
+ for (CommonClassDefinition d : defs) {
+ classes.add(d.target);
+ class_files.add(d.class_file_bytes);
+ dex_files.add(d.dex_file_bytes);
+ }
+ doCommonMultiClassRedefinition(classes.toArray(new Class<?>[0]),
+ class_files.toArray(new byte[0][]),
+ dex_files.toArray(new byte[0][]));
+ }
+
+ public static void addMultiTransformationResults(CommonClassDefinition... defs) {
+ for (CommonClassDefinition d : defs) {
+ addCommonTransformationResult(d.target.getCanonicalName(),
+ d.class_file_bytes,
+ d.dex_file_bytes);
+ }
+ }
+
+ public static native void doCommonMultiClassRedefinition(Class<?>[] targets,
+ byte[][] classfiles,
+ byte[][] dexfiles);
+ public static native void doCommonClassRetransformation(Class<?>... target);
+ public static native void setPopRetransformations(boolean pop);
+ public static native void popTransformationFor(String name);
+ public static native void enableCommonRetransformation(boolean enable);
+ public static native void addCommonTransformationResult(String target_name,
+ byte[] class_bytes,
+ byte[] dex_bytes);
+}
diff --git a/test/944-transform-classloaders/classloader.cc b/test/944-transform-classloaders/classloader.cc
deleted file mode 100644
index 698e023..0000000
--- a/test/944-transform-classloaders/classloader.cc
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "android-base/macros.h"
-#include "jni.h"
-#include "jvmti.h"
-#include "mirror/class-inl.h"
-#include "scoped_local_ref.h"
-
-// Test infrastructure
-#include "test_env.h"
-
-namespace art {
-namespace Test944TransformClassloaders {
-
-extern "C" JNIEXPORT jlong JNICALL Java_Main_getDexFilePointer(JNIEnv* env, jclass, jclass klass) {
- if (Runtime::Current() == nullptr) {
- env->ThrowNew(env->FindClass("java/lang/Exception"),
- "We do not seem to be running in ART! Unable to get dex file.");
- return 0;
- }
- ScopedObjectAccess soa(env);
- // This sequence of casts must be the same as those done in
- // runtime/native/dalvik_system_DexFile.cc in order to ensure that we get the same results.
- return static_cast<jlong>(reinterpret_cast<uintptr_t>(
- &soa.Decode<mirror::Class>(klass)->GetDexFile()));
-}
-
-} // namespace Test944TransformClassloaders
-} // namespace art
diff --git a/test/944-transform-classloaders/src/CommonClassDefinition.java b/test/944-transform-classloaders/src/CommonClassDefinition.java
deleted file mode 100644
index 62602a0..0000000
--- a/test/944-transform-classloaders/src/CommonClassDefinition.java
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-class CommonClassDefinition {
- public final Class<?> target;
- public final byte[] class_file_bytes;
- public final byte[] dex_file_bytes;
-
- CommonClassDefinition(Class<?> target, byte[] class_file_bytes, byte[] dex_file_bytes) {
- this.target = target;
- this.class_file_bytes = class_file_bytes;
- this.dex_file_bytes = dex_file_bytes;
- }
-}
diff --git a/test/944-transform-classloaders/src/Main.java b/test/944-transform-classloaders/src/Main.java
index b558660..3d76d23 100644
--- a/test/944-transform-classloaders/src/Main.java
+++ b/test/944-transform-classloaders/src/Main.java
@@ -14,254 +14,8 @@
* limitations under the License.
*/
-import java.util.Arrays;
-import java.util.ArrayList;
-import java.util.Base64;
-import java.lang.reflect.*;
public class Main {
-
- /**
- * base64 encoded class/dex file for
- * class Transform {
- * public void sayHi() {
- * System.out.println("Goodbye");
- * }
- * }
- */
- private static CommonClassDefinition TRANSFORM_DEFINITION = new CommonClassDefinition(
- Transform.class,
- Base64.getDecoder().decode(
- "yv66vgAAADQAHAoABgAOCQAPABAIABEKABIAEwcAFAcAFQEABjxpbml0PgEAAygpVgEABENvZGUB" +
- "AA9MaW5lTnVtYmVyVGFibGUBAAVzYXlIaQEAClNvdXJjZUZpbGUBAA5UcmFuc2Zvcm0uamF2YQwA" +
- "BwAIBwAWDAAXABgBAAdHb29kYnllBwAZDAAaABsBAAlUcmFuc2Zvcm0BABBqYXZhL2xhbmcvT2Jq" +
- "ZWN0AQAQamF2YS9sYW5nL1N5c3RlbQEAA291dAEAFUxqYXZhL2lvL1ByaW50U3RyZWFtOwEAE2ph" +
- "dmEvaW8vUHJpbnRTdHJlYW0BAAdwcmludGxuAQAVKExqYXZhL2xhbmcvU3RyaW5nOylWACAABQAG" +
- "AAAAAAACAAAABwAIAAEACQAAAB0AAQABAAAABSq3AAGxAAAAAQAKAAAABgABAAAAEQABAAsACAAB" +
- "AAkAAAAlAAIAAQAAAAmyAAISA7YABLEAAAABAAoAAAAKAAIAAAATAAgAFAABAAwAAAACAA0="),
- Base64.getDecoder().decode(
- "ZGV4CjAzNQCLXSBQ5FiS3f16krSYZFF8xYZtFVp0GRXMAgAAcAAAAHhWNBIAAAAAAAAAACwCAAAO" +
- "AAAAcAAAAAYAAACoAAAAAgAAAMAAAAABAAAA2AAAAAQAAADgAAAAAQAAAAABAACsAQAAIAEAAGIB" +
- "AABqAQAAcwEAAIABAACXAQAAqwEAAL8BAADTAQAA4wEAAOYBAADqAQAA/gEAAAMCAAAMAgAAAgAA" +
- "AAMAAAAEAAAABQAAAAYAAAAIAAAACAAAAAUAAAAAAAAACQAAAAUAAABcAQAABAABAAsAAAAAAAAA" +
- "AAAAAAAAAAANAAAAAQABAAwAAAACAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAHAAAAAAAAAB4CAAAA" +
- "AAAAAQABAAEAAAATAgAABAAAAHAQAwAAAA4AAwABAAIAAAAYAgAACQAAAGIAAAAbAQEAAABuIAIA" +
- "EAAOAAAAAQAAAAMABjxpbml0PgAHR29vZGJ5ZQALTFRyYW5zZm9ybTsAFUxqYXZhL2lvL1ByaW50" +
- "U3RyZWFtOwASTGphdmEvbGFuZy9PYmplY3Q7ABJMamF2YS9sYW5nL1N0cmluZzsAEkxqYXZhL2xh" +
- "bmcvU3lzdGVtOwAOVHJhbnNmb3JtLmphdmEAAVYAAlZMABJlbWl0dGVyOiBqYWNrLTMuMzYAA291" +
- "dAAHcHJpbnRsbgAFc2F5SGkAEQAHDgATAAcOhQAAAAEBAICABKACAQG4Ag0AAAAAAAAAAQAAAAAA" +
- "AAABAAAADgAAAHAAAAACAAAABgAAAKgAAAADAAAAAgAAAMAAAAAEAAAAAQAAANgAAAAFAAAABAAA" +
- "AOAAAAAGAAAAAQAAAAABAAABIAAAAgAAACABAAABEAAAAQAAAFwBAAACIAAADgAAAGIBAAADIAAA" +
- "AgAAABMCAAAAIAAAAQAAAB4CAAAAEAAAAQAAACwCAAA="));
-
- /**
- * base64 encoded class/dex file for
- * class Transform2 {
- * public void sayHi() {
- * System.out.println("Goodbye2");
- * }
- * }
- */
- private static CommonClassDefinition TRANSFORM2_DEFINITION = new CommonClassDefinition(
- Transform2.class,
- Base64.getDecoder().decode(
- "yv66vgAAADQAHAoABgAOCQAPABAIABEKABIAEwcAFAcAFQEABjxpbml0PgEAAygpVgEABENvZGUB" +
- "AA9MaW5lTnVtYmVyVGFibGUBAAVzYXlIaQEAClNvdXJjZUZpbGUBAA9UcmFuc2Zvcm0yLmphdmEM" +
- "AAcACAcAFgwAFwAYAQAIR29vZGJ5ZTIHABkMABoAGwEAClRyYW5zZm9ybTIBABBqYXZhL2xhbmcv" +
- "T2JqZWN0AQAQamF2YS9sYW5nL1N5c3RlbQEAA291dAEAFUxqYXZhL2lvL1ByaW50U3RyZWFtOwEA" +
- "E2phdmEvaW8vUHJpbnRTdHJlYW0BAAdwcmludGxuAQAVKExqYXZhL2xhbmcvU3RyaW5nOylWACAA" +
- "BQAGAAAAAAACAAAABwAIAAEACQAAAB0AAQABAAAABSq3AAGxAAAAAQAKAAAABgABAAAAAQABAAsA" +
- "CAABAAkAAAAlAAIAAQAAAAmyAAISA7YABLEAAAABAAoAAAAKAAIAAAADAAgABAABAAwAAAACAA0="),
- Base64.getDecoder().decode(
- "ZGV4CjAzNQABX6vL8OT7aGLjbzFBEfCM9Aaz+zzGzVnQAgAAcAAAAHhWNBIAAAAAAAAAADACAAAO" +
- "AAAAcAAAAAYAAACoAAAAAgAAAMAAAAABAAAA2AAAAAQAAADgAAAAAQAAAAABAACwAQAAIAEAAGIB" +
- "AABqAQAAdAEAAIIBAACZAQAArQEAAMEBAADVAQAA5gEAAOkBAADtAQAAAQIAAAYCAAAPAgAAAgAA" +
- "AAMAAAAEAAAABQAAAAYAAAAIAAAACAAAAAUAAAAAAAAACQAAAAUAAABcAQAABAABAAsAAAAAAAAA" +
- "AAAAAAAAAAANAAAAAQABAAwAAAACAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAHAAAAAAAAACECAAAA" +
- "AAAAAQABAAEAAAAWAgAABAAAAHAQAwAAAA4AAwABAAIAAAAbAgAACQAAAGIAAAAbAQEAAABuIAIA" +
- "EAAOAAAAAQAAAAMABjxpbml0PgAIR29vZGJ5ZTIADExUcmFuc2Zvcm0yOwAVTGphdmEvaW8vUHJp" +
- "bnRTdHJlYW07ABJMamF2YS9sYW5nL09iamVjdDsAEkxqYXZhL2xhbmcvU3RyaW5nOwASTGphdmEv" +
- "bGFuZy9TeXN0ZW07AA9UcmFuc2Zvcm0yLmphdmEAAVYAAlZMABJlbWl0dGVyOiBqYWNrLTQuMjQA" +
- "A291dAAHcHJpbnRsbgAFc2F5SGkAAQAHDgADAAcOhwAAAAEBAICABKACAQG4AgANAAAAAAAAAAEA" +
- "AAAAAAAAAQAAAA4AAABwAAAAAgAAAAYAAACoAAAAAwAAAAIAAADAAAAABAAAAAEAAADYAAAABQAA" +
- "AAQAAADgAAAABgAAAAEAAAAAAQAAASAAAAIAAAAgAQAAARAAAAEAAABcAQAAAiAAAA4AAABiAQAA" +
- "AyAAAAIAAAAWAgAAACAAAAEAAAAhAgAAABAAAAEAAAAwAgAA"));
-
public static void main(String[] args) throws Exception {
- doTest();
- System.out.println("Passed");
+ art.Test944.run();
}
-
- private static void checkIsInstance(Class<?> klass, Object o) throws Exception {
- if (!klass.isInstance(o)) {
- throw new Exception(klass + " is not the class of " + o);
- }
- }
-
- private static boolean arrayContains(long[] arr, long value) {
- if (arr == null) {
- return false;
- }
- for (int i = 0; i < arr.length; i++) {
- if (arr[i] == value) {
- return true;
- }
- }
- return false;
- }
-
- /**
- * Checks that we can find the dex-file for the given class in its classloader.
- *
- * Throws if it fails.
- */
- private static void checkDexFileInClassLoader(Class<?> klass) throws Exception {
- // If all the android BCP classes were availible when compiling this test and access checks
- // weren't a thing this function would be written as follows:
- //
- // long dexFilePtr = getDexFilePointer(klass);
- // dalvik.system.BaseDexClassLoader loader =
- // (dalvik.system.BaseDexClassLoader)klass.getClassLoader();
- // dalvik.system.DexPathList pathListValue = loader.pathList;
- // dalvik.system.DexPathList.Element[] elementArrayValue = pathListValue.dexElements;
- // int array_length = elementArrayValue.length;
- // for (int i = 0; i < array_length; i++) {
- // dalvik.system.DexPathList.Element curElement = elementArrayValue[i];
- // dalvik.system.DexFile curDexFile = curElement.dexFile;
- // if (curDexFile == null) {
- // continue;
- // }
- // long[] curCookie = (long[])curDexFile.mCookie;
- // long[] curInternalCookie = (long[])curDexFile.mInternalCookie;
- // if (arrayContains(curCookie, dexFilePtr) || arrayContains(curInternalCookie, dexFilePtr)) {
- // return;
- // }
- // }
- // throw new Exception(
- // "Unable to find dex file pointer " + dexFilePtr + " in class loader for " + klass);
-
- // Get all the fields and classes we need by reflection.
- Class<?> baseDexClassLoaderClass = Class.forName("dalvik.system.BaseDexClassLoader");
- Field pathListField = baseDexClassLoaderClass.getDeclaredField("pathList");
-
- Class<?> dexPathListClass = Class.forName("dalvik.system.DexPathList");
- Field elementArrayField = dexPathListClass.getDeclaredField("dexElements");
-
- Class<?> dexPathListElementClass = Class.forName("dalvik.system.DexPathList$Element");
- Field dexFileField = dexPathListElementClass.getDeclaredField("dexFile");
-
- Class<?> dexFileClass = Class.forName("dalvik.system.DexFile");
- Field dexFileCookieField = dexFileClass.getDeclaredField("mCookie");
- Field dexFileInternalCookieField = dexFileClass.getDeclaredField("mInternalCookie");
-
- // Make all the fields accessible
- AccessibleObject.setAccessible(new AccessibleObject[] { pathListField,
- elementArrayField,
- dexFileField,
- dexFileCookieField,
- dexFileInternalCookieField }, true);
-
- long dexFilePtr = getDexFilePointer(klass);
-
- ClassLoader loader = klass.getClassLoader();
- checkIsInstance(baseDexClassLoaderClass, loader);
- // DexPathList pathListValue = ((BaseDexClassLoader) loader).pathList;
- Object pathListValue = pathListField.get(loader);
-
- checkIsInstance(dexPathListClass, pathListValue);
-
- // DexPathList.Element[] elementArrayValue = pathListValue.dexElements;
- Object elementArrayValue = elementArrayField.get(pathListValue);
- if (!elementArrayValue.getClass().isArray() ||
- elementArrayValue.getClass().getComponentType() != dexPathListElementClass) {
- throw new Exception("elementArrayValue is not an " + dexPathListElementClass + " array!");
- }
- // int array_length = elementArrayValue.length;
- int array_length = Array.getLength(elementArrayValue);
- for (int i = 0; i < array_length; i++) {
- // DexPathList.Element curElement = elementArrayValue[i];
- Object curElement = Array.get(elementArrayValue, i);
- checkIsInstance(dexPathListElementClass, curElement);
-
- // DexFile curDexFile = curElement.dexFile;
- Object curDexFile = dexFileField.get(curElement);
- if (curDexFile == null) {
- continue;
- }
- checkIsInstance(dexFileClass, curDexFile);
-
- // long[] curCookie = (long[])curDexFile.mCookie;
- long[] curCookie = (long[])dexFileCookieField.get(curDexFile);
- // long[] curInternalCookie = (long[])curDexFile.mInternalCookie;
- long[] curInternalCookie = (long[])dexFileInternalCookieField.get(curDexFile);
-
- if (arrayContains(curCookie, dexFilePtr) || arrayContains(curInternalCookie, dexFilePtr)) {
- return;
- }
- }
- throw new Exception(
- "Unable to find dex file pointer " + dexFilePtr + " in class loader for " + klass);
- }
-
- private static void doTest() throws Exception {
- art.Main.bindAgentJNIForClass(Main.class);
-
- Transform t = new Transform();
- Transform2 t2 = new Transform2();
-
- long initial_t1_dex = getDexFilePointer(Transform.class);
- long initial_t2_dex = getDexFilePointer(Transform2.class);
- if (initial_t2_dex != initial_t1_dex) {
- throw new Exception("The classes " + Transform.class + " and " + Transform2.class + " " +
- "have different initial dex files!");
- }
- checkDexFileInClassLoader(Transform.class);
- checkDexFileInClassLoader(Transform2.class);
-
- // Make sure they are loaded
- t.sayHi();
- t2.sayHi();
- // Redefine both of the classes.
- doMultiClassRedefinition(TRANSFORM_DEFINITION, TRANSFORM2_DEFINITION);
- // Make sure we actually transformed them!
- t.sayHi();
- t2.sayHi();
-
- long final_t1_dex = getDexFilePointer(Transform.class);
- long final_t2_dex = getDexFilePointer(Transform2.class);
- if (final_t2_dex == final_t1_dex) {
- throw new Exception("The classes " + Transform.class + " and " + Transform2.class + " " +
- "have the same initial dex files!");
- } else if (final_t1_dex == initial_t1_dex) {
- throw new Exception("The class " + Transform.class + " did not get a new dex file!");
- } else if (final_t2_dex == initial_t2_dex) {
- throw new Exception("The class " + Transform2.class + " did not get a new dex file!");
- }
- // Check to make sure the new dex files are in the class loader.
- checkDexFileInClassLoader(Transform.class);
- checkDexFileInClassLoader(Transform2.class);
- }
-
- private static void doMultiClassRedefinition(CommonClassDefinition... defs) {
- ArrayList<Class<?>> classes = new ArrayList<>();
- ArrayList<byte[]> class_files = new ArrayList<>();
- ArrayList<byte[]> dex_files = new ArrayList<>();
-
- for (CommonClassDefinition d : defs) {
- classes.add(d.target);
- class_files.add(d.class_file_bytes);
- dex_files.add(d.dex_file_bytes);
- }
- doCommonMultiClassRedefinition(classes.toArray(new Class<?>[0]),
- class_files.toArray(new byte[0][]),
- dex_files.toArray(new byte[0][]));
- }
-
- // Gets the 'long' (really a native pointer) that is stored in the ClassLoader representing the
- // DexFile a class is loaded from. This is converted from the DexFile* in the same way it is done
- // in runtime/native/dalvik_system_DexFile.cc
- private static native long getDexFilePointer(Class<?> target);
- // Transforms the classes
- private static native void doCommonMultiClassRedefinition(Class<?>[] targets,
- byte[][] classfiles,
- byte[][] dexfiles);
}
diff --git a/test/944-transform-classloaders/src/Transform.java b/test/944-transform-classloaders/src/Transform.java
deleted file mode 100644
index 8e8af35..0000000
--- a/test/944-transform-classloaders/src/Transform.java
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-class Transform {
- public void sayHi() {
- // Use lower 'h' to make sure the string will have a different string id
- // than the transformation (the transformation code is the same except
- // the actual printed String, which was making the test inacurately passing
- // in JIT mode when loading the string from the dex cache, as the string ids
- // of the two different strings were the same).
- // We know the string ids will be different because lexicographically:
- // "Goodbye" < "LTransform;" < "hello".
- System.out.println("hello");
- }
-}
diff --git a/test/944-transform-classloaders/src/art/Redefinition.java b/test/944-transform-classloaders/src/art/Redefinition.java
new file mode 100644
index 0000000..0350ab4
--- /dev/null
+++ b/test/944-transform-classloaders/src/art/Redefinition.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package art;
+
+import java.util.ArrayList;
+// Common Redefinition functions. Placed here for use by CTS
+public class Redefinition {
+ // Bind native functions.
+ static {
+ Main.bindAgentJNIForClass(Redefinition.class);
+ }
+
+ public static final class CommonClassDefinition {
+ public final Class<?> target;
+ public final byte[] class_file_bytes;
+ public final byte[] dex_file_bytes;
+
+ public CommonClassDefinition(Class<?> target, byte[] class_file_bytes, byte[] dex_file_bytes) {
+ this.target = target;
+ this.class_file_bytes = class_file_bytes;
+ this.dex_file_bytes = dex_file_bytes;
+ }
+ }
+
+ // A set of possible test configurations. Test should set this if they need to.
+ // This must be kept in sync with the defines in ti-agent/common_helper.cc
+ public static enum Config {
+ COMMON_REDEFINE(0),
+ COMMON_RETRANSFORM(1),
+ COMMON_TRANSFORM(2);
+
+ private final int val;
+ private Config(int val) {
+ this.val = val;
+ }
+ }
+
+ public static void setTestConfiguration(Config type) {
+ nativeSetTestConfiguration(type.val);
+ }
+
+ private static native void nativeSetTestConfiguration(int type);
+
+ // Transforms the class
+ public static native void doCommonClassRedefinition(Class<?> target,
+ byte[] classfile,
+ byte[] dexfile);
+
+ public static void doMultiClassRedefinition(CommonClassDefinition... defs) {
+ ArrayList<Class<?>> classes = new ArrayList<>();
+ ArrayList<byte[]> class_files = new ArrayList<>();
+ ArrayList<byte[]> dex_files = new ArrayList<>();
+
+ for (CommonClassDefinition d : defs) {
+ classes.add(d.target);
+ class_files.add(d.class_file_bytes);
+ dex_files.add(d.dex_file_bytes);
+ }
+ doCommonMultiClassRedefinition(classes.toArray(new Class<?>[0]),
+ class_files.toArray(new byte[0][]),
+ dex_files.toArray(new byte[0][]));
+ }
+
+ public static void addMultiTransformationResults(CommonClassDefinition... defs) {
+ for (CommonClassDefinition d : defs) {
+ addCommonTransformationResult(d.target.getCanonicalName(),
+ d.class_file_bytes,
+ d.dex_file_bytes);
+ }
+ }
+
+ public static native void doCommonMultiClassRedefinition(Class<?>[] targets,
+ byte[][] classfiles,
+ byte[][] dexfiles);
+ public static native void doCommonClassRetransformation(Class<?>... target);
+ public static native void setPopRetransformations(boolean pop);
+ public static native void popTransformationFor(String name);
+ public static native void enableCommonRetransformation(boolean enable);
+ public static native void addCommonTransformationResult(String target_name,
+ byte[] class_bytes,
+ byte[] dex_bytes);
+}
diff --git a/test/944-transform-classloaders/src/art/Test944.java b/test/944-transform-classloaders/src/art/Test944.java
new file mode 100644
index 0000000..fe1c024
--- /dev/null
+++ b/test/944-transform-classloaders/src/art/Test944.java
@@ -0,0 +1,297 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package art;
+
+import static art.Redefinition.CommonClassDefinition;
+
+import java.util.Arrays;
+import java.util.ArrayList;
+import java.util.Base64;
+import java.lang.reflect.*;
+public class Test944 {
+
+ static class Transform {
+ public void sayHi() {
+ System.out.println("hello");
+ }
+ }
+
+ static class Transform2 {
+ public void sayHi() {
+ System.out.println("hello2");
+ }
+ }
+
+ /**
+ * base64 encoded class/dex file for
+ * static class Transform {
+ * public void sayHi() {
+ * System.out.println("Goodbye");
+ * }
+ * }
+ */
+ private static CommonClassDefinition TRANSFORM_DEFINITION = new CommonClassDefinition(
+ Transform.class,
+ Base64.getDecoder().decode(
+ "yv66vgAAADQAIAoABgAOCQAPABAIABEKABIAEwcAFQcAGAEABjxpbml0PgEAAygpVgEABENvZGUB" +
+ "AA9MaW5lTnVtYmVyVGFibGUBAAVzYXlIaQEAClNvdXJjZUZpbGUBAAxUZXN0OTQ0LmphdmEMAAcA" +
+ "CAcAGQwAGgAbAQAHR29vZGJ5ZQcAHAwAHQAeBwAfAQAVYXJ0L1Rlc3Q5NDQkVHJhbnNmb3JtAQAJ" +
+ "VHJhbnNmb3JtAQAMSW5uZXJDbGFzc2VzAQAQamF2YS9sYW5nL09iamVjdAEAEGphdmEvbGFuZy9T" +
+ "eXN0ZW0BAANvdXQBABVMamF2YS9pby9QcmludFN0cmVhbTsBABNqYXZhL2lvL1ByaW50U3RyZWFt" +
+ "AQAHcHJpbnRsbgEAFShMamF2YS9sYW5nL1N0cmluZzspVgEAC2FydC9UZXN0OTQ0ACAABQAGAAAA" +
+ "AAACAAAABwAIAAEACQAAAB0AAQABAAAABSq3AAGxAAAAAQAKAAAABgABAAAACgABAAsACAABAAkA" +
+ "AAAlAAIAAQAAAAmyAAISA7YABLEAAAABAAoAAAAKAAIAAAAMAAgADQACAAwAAAACAA0AFwAAAAoA" +
+ "AQAFABQAFgAI"),
+ Base64.getDecoder().decode(
+ "ZGV4CjAzNQCFgsuWAAAAAAAAAAAAAAAAAAAAAAAAAAC4AwAAcAAAAHhWNBIAAAAAAAAAAPQCAAAU" +
+ "AAAAcAAAAAkAAADAAAAAAgAAAOQAAAABAAAA/AAAAAQAAAAEAQAAAQAAACQBAAB0AgAARAEAAEQB" +
+ "AABMAQAAVQEAAG4BAAB9AQAAoQEAAMEBAADYAQAA7AEAAAACAAAUAgAAIgIAAC0CAAAwAgAANAIA" +
+ "AEECAABHAgAATAIAAFUCAABcAgAAAgAAAAMAAAAEAAAABQAAAAYAAAAHAAAACAAAAAkAAAAMAAAA" +
+ "DAAAAAgAAAAAAAAADQAAAAgAAABkAgAABwAEABAAAAAAAAAAAAAAAAAAAAASAAAABAABABEAAAAF" +
+ "AAAAAAAAAAAAAAAAAAAABQAAAAAAAAAKAAAA5AIAALgCAAAAAAAABjxpbml0PgAHR29vZGJ5ZQAX" +
+ "TGFydC9UZXN0OTQ0JFRyYW5zZm9ybTsADUxhcnQvVGVzdDk0NDsAIkxkYWx2aWsvYW5ub3RhdGlv" +
+ "bi9FbmNsb3NpbmdDbGFzczsAHkxkYWx2aWsvYW5ub3RhdGlvbi9Jbm5lckNsYXNzOwAVTGphdmEv" +
+ "aW8vUHJpbnRTdHJlYW07ABJMamF2YS9sYW5nL09iamVjdDsAEkxqYXZhL2xhbmcvU3RyaW5nOwAS" +
+ "TGphdmEvbGFuZy9TeXN0ZW07AAxUZXN0OTQ0LmphdmEACVRyYW5zZm9ybQABVgACVkwAC2FjY2Vz" +
+ "c0ZsYWdzAARuYW1lAANvdXQAB3ByaW50bG4ABXNheUhpAAV2YWx1ZQAAAQAAAAYAAAAKAAcOAAwA" +
+ "Bw4BCA8AAAAAAQABAAEAAABsAgAABAAAAHAQAwAAAA4AAwABAAIAAABxAgAACQAAAGIAAAAbAQEA" +
+ "AABuIAIAEAAOAAAAAAABAQCAgAT8BAEBlAUAAAICARMYAQIDAg4ECA8XCwACAAAAyAIAAM4CAADY" +
+ "AgAAAAAAAAAAAAAAAAAAEAAAAAAAAAABAAAAAAAAAAEAAAAUAAAAcAAAAAIAAAAJAAAAwAAAAAMA" +
+ "AAACAAAA5AAAAAQAAAABAAAA/AAAAAUAAAAEAAAABAEAAAYAAAABAAAAJAEAAAIgAAAUAAAARAEA" +
+ "AAEQAAABAAAAZAIAAAMgAAACAAAAbAIAAAEgAAACAAAAfAIAAAAgAAABAAAAuAIAAAQgAAACAAAA" +
+ "yAIAAAMQAAABAAAA2AIAAAYgAAABAAAA5AIAAAAQAAABAAAA9AIAAA=="));
+
+ /**
+ * base64 encoded class/dex file for
+ * static class Transform2 {
+ * public void sayHi() {
+ * System.out.println("Goodbye2");
+ * }
+ * }
+ */
+ private static CommonClassDefinition TRANSFORM2_DEFINITION = new CommonClassDefinition(
+ Transform2.class,
+ Base64.getDecoder().decode(
+ "yv66vgAAADQAIAoABgAOCQAPABAIABEKABIAEwcAFQcAGAEABjxpbml0PgEAAygpVgEABENvZGUB" +
+ "AA9MaW5lTnVtYmVyVGFibGUBAAVzYXlIaQEAClNvdXJjZUZpbGUBAAxUZXN0OTQ0LmphdmEMAAcA" +
+ "CAcAGQwAGgAbAQAIR29vZGJ5ZTIHABwMAB0AHgcAHwEAFmFydC9UZXN0OTQ0JFRyYW5zZm9ybTIB" +
+ "AApUcmFuc2Zvcm0yAQAMSW5uZXJDbGFzc2VzAQAQamF2YS9sYW5nL09iamVjdAEAEGphdmEvbGFu" +
+ "Zy9TeXN0ZW0BAANvdXQBABVMamF2YS9pby9QcmludFN0cmVhbTsBABNqYXZhL2lvL1ByaW50U3Ry" +
+ "ZWFtAQAHcHJpbnRsbgEAFShMamF2YS9sYW5nL1N0cmluZzspVgEAC2FydC9UZXN0OTQ0ACAABQAG" +
+ "AAAAAAACAAAABwAIAAEACQAAAB0AAQABAAAABSq3AAGxAAAAAQAKAAAABgABAAAABQABAAsACAAB" +
+ "AAkAAAAlAAIAAQAAAAmyAAISA7YABLEAAAABAAoAAAAKAAIAAAAHAAgACAACAAwAAAACAA0AFwAA" +
+ "AAoAAQAFABQAFgAI"),
+ Base64.getDecoder().decode(
+ "ZGV4CjAzNQAUg8BCAAAAAAAAAAAAAAAAAAAAAAAAAAC8AwAAcAAAAHhWNBIAAAAAAAAAAPgCAAAU" +
+ "AAAAcAAAAAkAAADAAAAAAgAAAOQAAAABAAAA/AAAAAQAAAAEAQAAAQAAACQBAAB4AgAARAEAAEQB" +
+ "AABMAQAAVgEAAHABAAB/AQAAowEAAMMBAADaAQAA7gEAAAICAAAWAgAAJAIAADACAAAzAgAANwIA" +
+ "AEQCAABKAgAATwIAAFgCAABfAgAAAgAAAAMAAAAEAAAABQAAAAYAAAAHAAAACAAAAAkAAAAMAAAA" +
+ "DAAAAAgAAAAAAAAADQAAAAgAAABoAgAABwAEABAAAAAAAAAAAAAAAAAAAAASAAAABAABABEAAAAF" +
+ "AAAAAAAAAAAAAAAAAAAABQAAAAAAAAAKAAAA6AIAALwCAAAAAAAABjxpbml0PgAIR29vZGJ5ZTIA" +
+ "GExhcnQvVGVzdDk0NCRUcmFuc2Zvcm0yOwANTGFydC9UZXN0OTQ0OwAiTGRhbHZpay9hbm5vdGF0" +
+ "aW9uL0VuY2xvc2luZ0NsYXNzOwAeTGRhbHZpay9hbm5vdGF0aW9uL0lubmVyQ2xhc3M7ABVMamF2" +
+ "YS9pby9QcmludFN0cmVhbTsAEkxqYXZhL2xhbmcvT2JqZWN0OwASTGphdmEvbGFuZy9TdHJpbmc7" +
+ "ABJMamF2YS9sYW5nL1N5c3RlbTsADFRlc3Q5NDQuamF2YQAKVHJhbnNmb3JtMgABVgACVkwAC2Fj" +
+ "Y2Vzc0ZsYWdzAARuYW1lAANvdXQAB3ByaW50bG4ABXNheUhpAAV2YWx1ZQAAAAEAAAAGAAAABQAH" +
+ "DgAHAAcOAQgPAAAAAAEAAQABAAAAcAIAAAQAAABwEAMAAAAOAAMAAQACAAAAdQIAAAkAAABiAAAA" +
+ "GwEBAAAAbiACABAADgAAAAAAAQEAgIAEgAUBAZgFAAACAgETGAECAwIOBAgPFwsAAgAAAMwCAADS" +
+ "AgAA3AIAAAAAAAAAAAAAAAAAABAAAAAAAAAAAQAAAAAAAAABAAAAFAAAAHAAAAACAAAACQAAAMAA" +
+ "AAADAAAAAgAAAOQAAAAEAAAAAQAAAPwAAAAFAAAABAAAAAQBAAAGAAAAAQAAACQBAAACIAAAFAAA" +
+ "AEQBAAABEAAAAQAAAGgCAAADIAAAAgAAAHACAAABIAAAAgAAAIACAAAAIAAAAQAAALwCAAAEIAAA" +
+ "AgAAAMwCAAADEAAAAQAAANwCAAAGIAAAAQAAAOgCAAAAEAAAAQAAAPgCAAA="));
+
+ public static void run() throws Exception {
+ Redefinition.setTestConfiguration(Redefinition.Config.COMMON_REDEFINE);
+ doTest();
+ System.out.println("Passed");
+ }
+
+ private static void checkIsInstance(Class<?> klass, Object o) throws Exception {
+ if (!klass.isInstance(o)) {
+ throw new Exception(klass + " is not the class of " + o);
+ }
+ }
+
+ private static boolean arrayContains(long[] arr, long value) {
+ if (arr == null) {
+ return false;
+ }
+ for (int i = 0; i < arr.length; i++) {
+ if (arr[i] == value) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Checks that we can find the dex-file for the given class in its classloader.
+ *
+ * Throws if it fails.
+ */
+ private static void checkDexFileInClassLoader(Class<?> klass) throws Exception {
+ // If all the android BCP classes were availible when compiling this test and access checks
+ // weren't a thing this function would be written as follows:
+ //
+ // long dexFilePtr = getDexFilePointer(klass);
+ // dalvik.system.BaseDexClassLoader loader =
+ // (dalvik.system.BaseDexClassLoader)klass.getClassLoader();
+ // dalvik.system.DexPathList pathListValue = loader.pathList;
+ // dalvik.system.DexPathList.Element[] elementArrayValue = pathListValue.dexElements;
+ // int array_length = elementArrayValue.length;
+ // for (int i = 0; i < array_length; i++) {
+ // dalvik.system.DexPathList.Element curElement = elementArrayValue[i];
+ // dalvik.system.DexFile curDexFile = curElement.dexFile;
+ // if (curDexFile == null) {
+ // continue;
+ // }
+ // long[] curCookie = (long[])curDexFile.mCookie;
+ // long[] curInternalCookie = (long[])curDexFile.mInternalCookie;
+ // if (arrayContains(curCookie, dexFilePtr) || arrayContains(curInternalCookie, dexFilePtr)) {
+ // return;
+ // }
+ // }
+ // throw new Exception(
+ // "Unable to find dex file pointer " + dexFilePtr + " in class loader for " + klass);
+
+ // Get all the fields and classes we need by reflection.
+ Class<?> baseDexClassLoaderClass = Class.forName("dalvik.system.BaseDexClassLoader");
+ Field pathListField = baseDexClassLoaderClass.getDeclaredField("pathList");
+
+ Class<?> dexPathListClass = Class.forName("dalvik.system.DexPathList");
+ Field elementArrayField = dexPathListClass.getDeclaredField("dexElements");
+
+ Class<?> dexPathListElementClass = Class.forName("dalvik.system.DexPathList$Element");
+ Field dexFileField = dexPathListElementClass.getDeclaredField("dexFile");
+
+ Class<?> dexFileClass = Class.forName("dalvik.system.DexFile");
+ Field dexFileCookieField = dexFileClass.getDeclaredField("mCookie");
+ Field dexFileInternalCookieField = dexFileClass.getDeclaredField("mInternalCookie");
+
+ // Make all the fields accessible
+ AccessibleObject.setAccessible(new AccessibleObject[] { pathListField,
+ elementArrayField,
+ dexFileField,
+ dexFileCookieField,
+ dexFileInternalCookieField }, true);
+
+ long dexFilePtr = getDexFilePointer(klass);
+
+ ClassLoader loader = klass.getClassLoader();
+ checkIsInstance(baseDexClassLoaderClass, loader);
+ // DexPathList pathListValue = ((BaseDexClassLoader) loader).pathList;
+ Object pathListValue = pathListField.get(loader);
+
+ checkIsInstance(dexPathListClass, pathListValue);
+
+ // DexPathList.Element[] elementArrayValue = pathListValue.dexElements;
+ Object elementArrayValue = elementArrayField.get(pathListValue);
+ if (!elementArrayValue.getClass().isArray() ||
+ elementArrayValue.getClass().getComponentType() != dexPathListElementClass) {
+ throw new Exception("elementArrayValue is not an " + dexPathListElementClass + " array!");
+ }
+ // int array_length = elementArrayValue.length;
+ int array_length = Array.getLength(elementArrayValue);
+ for (int i = 0; i < array_length; i++) {
+ // DexPathList.Element curElement = elementArrayValue[i];
+ Object curElement = Array.get(elementArrayValue, i);
+ checkIsInstance(dexPathListElementClass, curElement);
+
+ // DexFile curDexFile = curElement.dexFile;
+ Object curDexFile = dexFileField.get(curElement);
+ if (curDexFile == null) {
+ continue;
+ }
+ checkIsInstance(dexFileClass, curDexFile);
+
+ // long[] curCookie = (long[])curDexFile.mCookie;
+ long[] curCookie = (long[])dexFileCookieField.get(curDexFile);
+ // long[] curInternalCookie = (long[])curDexFile.mInternalCookie;
+ long[] curInternalCookie = (long[])dexFileInternalCookieField.get(curDexFile);
+
+ if (arrayContains(curCookie, dexFilePtr) || arrayContains(curInternalCookie, dexFilePtr)) {
+ return;
+ }
+ }
+ throw new Exception(
+ "Unable to find dex file pointer " + dexFilePtr + " in class loader for " + klass);
+ }
+
+ private static void doTest() throws Exception {
+ Transform t = new Transform();
+ Transform2 t2 = new Transform2();
+
+ long initial_t1_dex = getDexFilePointer(Transform.class);
+ long initial_t2_dex = getDexFilePointer(Transform2.class);
+ if (initial_t2_dex != initial_t1_dex) {
+ throw new Exception("The classes " + Transform.class + " and " + Transform2.class + " " +
+ "have different initial dex files!");
+ }
+ checkDexFileInClassLoader(Transform.class);
+ checkDexFileInClassLoader(Transform2.class);
+
+ // Make sure they are loaded
+ t.sayHi();
+ t2.sayHi();
+ // Redefine both of the classes.
+ Redefinition.doMultiClassRedefinition(TRANSFORM_DEFINITION, TRANSFORM2_DEFINITION);
+ // Make sure we actually transformed them!
+ t.sayHi();
+ t2.sayHi();
+
+ long final_t1_dex = getDexFilePointer(Transform.class);
+ long final_t2_dex = getDexFilePointer(Transform2.class);
+ if (final_t2_dex == final_t1_dex) {
+ throw new Exception("The classes " + Transform.class + " and " + Transform2.class + " " +
+ "have the same initial dex files!");
+ } else if (final_t1_dex == initial_t1_dex) {
+ throw new Exception("The class " + Transform.class + " did not get a new dex file!");
+ } else if (final_t2_dex == initial_t2_dex) {
+ throw new Exception("The class " + Transform2.class + " did not get a new dex file!");
+ }
+ // Check to make sure the new dex files are in the class loader.
+ checkDexFileInClassLoader(Transform.class);
+ checkDexFileInClassLoader(Transform2.class);
+ }
+
+ // Gets the 'long' (really a native pointer) that is stored in the ClassLoader representing the
+ // DexFile a class is loaded from. This is plucked out of the internal DexCache object associated
+ // with the class.
+ private static long getDexFilePointer(Class<?> target) throws Exception {
+ // If all the android BCP classes were available when compiling this test and access checks
+ // weren't a thing this function would be written as follows:
+ //
+ // java.lang.DexCache dexCacheObject = target.dexCache;
+ // if (dexCacheObject == null) {
+ // return 0;
+ // }
+ // return dexCacheObject.dexFile;
+ Field dexCacheField = Class.class.getDeclaredField("dexCache");
+
+ Class<?> dexCacheClass = Class.forName("java.lang.DexCache");
+ Field dexFileField = dexCacheClass.getDeclaredField("dexFile");
+
+ AccessibleObject.setAccessible(new AccessibleObject[] { dexCacheField, dexFileField }, true);
+
+ Object dexCacheObject = dexCacheField.get(target);
+ if (dexCacheObject == null) {
+ return 0;
+ }
+ checkIsInstance(dexCacheClass, dexCacheObject);
+ return dexFileField.getLong(dexCacheObject);
+ }
+}
diff --git a/test/945-obsolete-native/obsolete_native.cc b/test/945-obsolete-native/obsolete_native.cc
index ee653a4..e3090f5 100644
--- a/test/945-obsolete-native/obsolete_native.cc
+++ b/test/945-obsolete-native/obsolete_native.cc
@@ -19,31 +19,20 @@
#include <stdio.h>
#include "android-base/stringprintf.h"
-
-#include "android-base/stringprintf.h"
-#include "base/logging.h"
-#include "base/macros.h"
#include "jni.h"
#include "jvmti.h"
-#include "scoped_local_ref.h"
// Test infrastructure
#include "jni_binder.h"
#include "test_env.h"
+#include "scoped_local_ref.h"
namespace art {
namespace Test945ObsoleteNative {
-extern "C" JNIEXPORT void JNICALL Java_Main_bindTest945ObsoleteNative(
- JNIEnv* env, jclass klass ATTRIBUTE_UNUSED) {
- BindFunctions(jvmti_env, env, "Transform");
-}
-
-extern "C" JNIEXPORT void JNICALL Java_Transform_doExecute(JNIEnv* env,
- jclass klass ATTRIBUTE_UNUSED,
- jobject runnable) {
+extern "C" JNIEXPORT void JNICALL Java_art_Test945_00024Transform_doExecute(
+ JNIEnv* env, jclass klass ATTRIBUTE_UNUSED, jobject runnable) {
jclass runnable_klass = env->FindClass("java/lang/Runnable");
- DCHECK(runnable_klass != nullptr);
jmethodID run_method = env->GetMethodID(runnable_klass, "run", "()V");
env->CallVoidMethod(runnable, run_method);
}
diff --git a/test/945-obsolete-native/src/Main.java b/test/945-obsolete-native/src/Main.java
index a7901cd..c94bc22 100644
--- a/test/945-obsolete-native/src/Main.java
+++ b/test/945-obsolete-native/src/Main.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,65 +14,8 @@
* limitations under the License.
*/
-import java.util.Base64;
-
public class Main {
- // class Transform {
- // public void sayHi(Runnable r) {
- // System.out.println("Hello - Transformed");
- // doExecute(r);
- // System.out.println("Goodbye - Transformed");
- // }
- //
- // private static native void doExecute(Runnable r);
- // }
- private static final byte[] CLASS_BYTES = Base64.getDecoder().decode(
- "yv66vgAAADQAIgoACAASCQATABQIABUKABYAFwoABwAYCAAZBwAaBwAbAQAGPGluaXQ+AQADKClW" +
- "AQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEABXNheUhpAQAXKExqYXZhL2xhbmcvUnVubmFibGU7" +
- "KVYBAAlkb0V4ZWN1dGUBAApTb3VyY2VGaWxlAQAOVHJhbnNmb3JtLmphdmEMAAkACgcAHAwAHQAe" +
- "AQATSGVsbG8gLSBUcmFuc2Zvcm1lZAcAHwwAIAAhDAAPAA4BABVHb29kYnllIC0gVHJhbnNmb3Jt" +
- "ZWQBAAlUcmFuc2Zvcm0BABBqYXZhL2xhbmcvT2JqZWN0AQAQamF2YS9sYW5nL1N5c3RlbQEAA291" +
- "dAEAFUxqYXZhL2lvL1ByaW50U3RyZWFtOwEAE2phdmEvaW8vUHJpbnRTdHJlYW0BAAdwcmludGxu" +
- "AQAVKExqYXZhL2xhbmcvU3RyaW5nOylWACAABwAIAAAAAAADAAAACQAKAAEACwAAAB0AAQABAAAA" +
- "BSq3AAGxAAAAAQAMAAAABgABAAAAEQABAA0ADgABAAsAAAA5AAIAAgAAABWyAAISA7YABCu4AAWy" +
- "AAISBrYABLEAAAABAAwAAAASAAQAAAATAAgAFAAMABUAFAAWAQoADwAOAAAAAQAQAAAAAgAR");
- private static final byte[] DEX_BYTES = Base64.getDecoder().decode(
- "ZGV4CjAzNQB1fZcJR/opPuXacK8mIla5shH0LSg72qJYAwAAcAAAAHhWNBIAAAAAAAAAALgCAAAR" +
- "AAAAcAAAAAcAAAC0AAAAAwAAANAAAAABAAAA9AAAAAUAAAD8AAAAAQAAACQBAAAUAgAARAEAAKIB" +
- "AACqAQAAwQEAANYBAADjAQAA+gEAAA4CAAAkAgAAOAIAAEwCAABcAgAAXwIAAGMCAABuAgAAggIA" +
- "AIcCAACQAgAAAwAAAAQAAAAFAAAABgAAAAcAAAAIAAAACgAAAAoAAAAGAAAAAAAAAAsAAAAGAAAA" +
- "lAEAAAsAAAAGAAAAnAEAAAUAAQAOAAAAAAAAAAAAAAAAAAEADAAAAAAAAQAQAAAAAQACAA8AAAAC" +
- "AAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAJAAAAAAAAAKUCAAAAAAAAAQABAAEAAACXAgAABAAAAHAQ" +
- "BAAAAA4ABAACAAIAAACcAgAAFAAAAGIAAAAbAQIAAABuIAMAEABxEAEAAwBiAAAAGwEBAAAAbiAD" +
- "ABAADgABAAAAAwAAAAEAAAAEAAY8aW5pdD4AFUdvb2RieWUgLSBUcmFuc2Zvcm1lZAATSGVsbG8g" +
- "LSBUcmFuc2Zvcm1lZAALTFRyYW5zZm9ybTsAFUxqYXZhL2lvL1ByaW50U3RyZWFtOwASTGphdmEv" +
- "bGFuZy9PYmplY3Q7ABRMamF2YS9sYW5nL1J1bm5hYmxlOwASTGphdmEvbGFuZy9TdHJpbmc7ABJM" +
- "amF2YS9sYW5nL1N5c3RlbTsADlRyYW5zZm9ybS5qYXZhAAFWAAJWTAAJZG9FeGVjdXRlABJlbWl0" +
- "dGVyOiBqYWNrLTQuMjUAA291dAAHcHJpbnRsbgAFc2F5SGkAEQAHDgATAQAHDoc8hwAAAAIBAICA" +
- "BMQCAYoCAAIB3AIADQAAAAAAAAABAAAAAAAAAAEAAAARAAAAcAAAAAIAAAAHAAAAtAAAAAMAAAAD" +
- "AAAA0AAAAAQAAAABAAAA9AAAAAUAAAAFAAAA/AAAAAYAAAABAAAAJAEAAAEgAAACAAAARAEAAAEQ" +
- "AAACAAAAlAEAAAIgAAARAAAAogEAAAMgAAACAAAAlwIAAAAgAAABAAAApQIAAAAQAAABAAAAuAIA" +
- "AA==");
-
- public static void main(String[] args) {
- art.Main.bindAgentJNIForClass(Main.class);
- bindTest945ObsoleteNative();
- doTest(new Transform());
+ public static void main(String[] args) throws Exception {
+ art.Test945.run();
}
-
- public static void doTest(Transform t) {
- t.sayHi(() -> { System.out.println("Not doing anything here"); });
- t.sayHi(() -> {
- System.out.println("transforming calling function");
- doCommonClassRedefinition(Transform.class, CLASS_BYTES, DEX_BYTES);
- });
- t.sayHi(() -> { System.out.println("Not doing anything here"); });
- }
-
- // Transforms the class
- private static native void doCommonClassRedefinition(Class<?> target,
- byte[] classfile,
- byte[] dexfile);
-
- private static native void bindTest945ObsoleteNative();
}
diff --git a/test/945-obsolete-native/src/Transform.java b/test/945-obsolete-native/src/Transform.java
deleted file mode 100644
index 2b7cc1b..0000000
--- a/test/945-obsolete-native/src/Transform.java
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-class Transform {
- public void sayHi(Runnable r) {
- System.out.println("hello");
- doExecute(r);
- System.out.println("goodbye");
- }
-
- private static native void doExecute(Runnable r);
-}
diff --git a/test/945-obsolete-native/src/art/Redefinition.java b/test/945-obsolete-native/src/art/Redefinition.java
new file mode 100644
index 0000000..0350ab4
--- /dev/null
+++ b/test/945-obsolete-native/src/art/Redefinition.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package art;
+
+import java.util.ArrayList;
+// Common Redefinition functions. Placed here for use by CTS
+public class Redefinition {
+ // Bind native functions.
+ static {
+ Main.bindAgentJNIForClass(Redefinition.class);
+ }
+
+ public static final class CommonClassDefinition {
+ public final Class<?> target;
+ public final byte[] class_file_bytes;
+ public final byte[] dex_file_bytes;
+
+ public CommonClassDefinition(Class<?> target, byte[] class_file_bytes, byte[] dex_file_bytes) {
+ this.target = target;
+ this.class_file_bytes = class_file_bytes;
+ this.dex_file_bytes = dex_file_bytes;
+ }
+ }
+
+ // A set of possible test configurations. Test should set this if they need to.
+ // This must be kept in sync with the defines in ti-agent/common_helper.cc
+ public static enum Config {
+ COMMON_REDEFINE(0),
+ COMMON_RETRANSFORM(1),
+ COMMON_TRANSFORM(2);
+
+ private final int val;
+ private Config(int val) {
+ this.val = val;
+ }
+ }
+
+ public static void setTestConfiguration(Config type) {
+ nativeSetTestConfiguration(type.val);
+ }
+
+ private static native void nativeSetTestConfiguration(int type);
+
+ // Transforms the class
+ public static native void doCommonClassRedefinition(Class<?> target,
+ byte[] classfile,
+ byte[] dexfile);
+
+ public static void doMultiClassRedefinition(CommonClassDefinition... defs) {
+ ArrayList<Class<?>> classes = new ArrayList<>();
+ ArrayList<byte[]> class_files = new ArrayList<>();
+ ArrayList<byte[]> dex_files = new ArrayList<>();
+
+ for (CommonClassDefinition d : defs) {
+ classes.add(d.target);
+ class_files.add(d.class_file_bytes);
+ dex_files.add(d.dex_file_bytes);
+ }
+ doCommonMultiClassRedefinition(classes.toArray(new Class<?>[0]),
+ class_files.toArray(new byte[0][]),
+ dex_files.toArray(new byte[0][]));
+ }
+
+ public static void addMultiTransformationResults(CommonClassDefinition... defs) {
+ for (CommonClassDefinition d : defs) {
+ addCommonTransformationResult(d.target.getCanonicalName(),
+ d.class_file_bytes,
+ d.dex_file_bytes);
+ }
+ }
+
+ public static native void doCommonMultiClassRedefinition(Class<?>[] targets,
+ byte[][] classfiles,
+ byte[][] dexfiles);
+ public static native void doCommonClassRetransformation(Class<?>... target);
+ public static native void setPopRetransformations(boolean pop);
+ public static native void popTransformationFor(String name);
+ public static native void enableCommonRetransformation(boolean enable);
+ public static native void addCommonTransformationResult(String target_name,
+ byte[] class_bytes,
+ byte[] dex_bytes);
+}
diff --git a/test/945-obsolete-native/src/art/Test945.java b/test/945-obsolete-native/src/art/Test945.java
new file mode 100644
index 0000000..6cf31f6
--- /dev/null
+++ b/test/945-obsolete-native/src/art/Test945.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package art;
+
+import java.util.Base64;
+
+public class Test945 {
+
+ static class Transform {
+ static {
+ art.Main.bindAgentJNIForClass(Transform.class);
+ }
+
+ public void sayHi(Runnable r) {
+ System.out.println("hello");
+ doExecute(r);
+ System.out.println("goodbye");
+ }
+
+ private static native void doExecute(Runnable r);
+ }
+
+ // static class Transform {
+ // static { }
+ // public void sayHi(Runnable r) {
+ // System.out.println("Hello - Transformed");
+ // doExecute(r);
+ // System.out.println("Goodbye - Transformed");
+ // }
+ //
+ // private static native void doExecute(Runnable r);
+ // }
+ private static final byte[] CLASS_BYTES = Base64.getDecoder().decode(
+ "yv66vgAAADQAJwoACAATCQAUABUIABYKABcAGAoABwAZCAAaBwAcBwAfAQAGPGluaXQ+AQADKClW" +
+ "AQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEABXNheUhpAQAXKExqYXZhL2xhbmcvUnVubmFibGU7" +
+ "KVYBAAlkb0V4ZWN1dGUBAAg8Y2xpbml0PgEAClNvdXJjZUZpbGUBAAxUZXN0OTQ1LmphdmEMAAkA" +
+ "CgcAIAwAIQAiAQATSGVsbG8gLSBUcmFuc2Zvcm1lZAcAIwwAJAAlDAAPAA4BABVHb29kYnllIC0g" +
+ "VHJhbnNmb3JtZWQHACYBABVhcnQvVGVzdDk0NSRUcmFuc2Zvcm0BAAlUcmFuc2Zvcm0BAAxJbm5l" +
+ "ckNsYXNzZXMBABBqYXZhL2xhbmcvT2JqZWN0AQAQamF2YS9sYW5nL1N5c3RlbQEAA291dAEAFUxq" +
+ "YXZhL2lvL1ByaW50U3RyZWFtOwEAE2phdmEvaW8vUHJpbnRTdHJlYW0BAAdwcmludGxuAQAVKExq" +
+ "YXZhL2xhbmcvU3RyaW5nOylWAQALYXJ0L1Rlc3Q5NDUAIAAHAAgAAAAAAAQAAAAJAAoAAQALAAAA" +
+ "HQABAAEAAAAFKrcAAbEAAAABAAwAAAAGAAEAAAAFAAEADQAOAAEACwAAADkAAgACAAAAFbIAAhID" +
+ "tgAEK7gABbIAAhIGtgAEsQAAAAEADAAAABIABAAAAAgACAAJAAwACgAUAAsBCgAPAA4AAAAIABAA" +
+ "CgABAAsAAAAZAAAAAAAAAAGxAAAAAQAMAAAABgABAAAABgACABEAAAACABIAHgAAAAoAAQAHABsA" +
+ "HQAI");
+ private static final byte[] DEX_BYTES = Base64.getDecoder().decode(
+ "ZGV4CjAzNQAFqcJFAAAAAAAAAAAAAAAAAAAAAAAAAAB8BAAAcAAAAHhWNBIAAAAAAAAAALgDAAAY" +
+ "AAAAcAAAAAoAAADQAAAAAwAAAPgAAAABAAAAHAEAAAYAAAAkAQAAAQAAAFQBAAAIAwAAdAEAAHQB" +
+ "AAB+AQAAhgEAAJ0BAACyAQAAywEAANoBAAD+AQAAHgIAADUCAABJAgAAXwIAAHMCAACHAgAAlQIA" +
+ "AKACAACjAgAApwIAALQCAAC/AgAAxQIAAMoCAADTAgAA2gIAAAQAAAAFAAAABgAAAAcAAAAIAAAA" +
+ "CQAAAAoAAAALAAAADAAAAA8AAAAPAAAACQAAAAAAAAAQAAAACQAAAOQCAAAQAAAACQAAAOwCAAAI" +
+ "AAQAFAAAAAAAAAAAAAAAAAAAAAEAAAAAAAEAEgAAAAAAAQAWAAAABAACABUAAAAFAAAAAQAAAAAA" +
+ "AAAAAAAABQAAAAAAAAANAAAAqAMAAHQDAAAAAAAACDxjbGluaXQ+AAY8aW5pdD4AFUdvb2RieWUg" +
+ "LSBUcmFuc2Zvcm1lZAATSGVsbG8gLSBUcmFuc2Zvcm1lZAAXTGFydC9UZXN0OTQ1JFRyYW5zZm9y" +
+ "bTsADUxhcnQvVGVzdDk0NTsAIkxkYWx2aWsvYW5ub3RhdGlvbi9FbmNsb3NpbmdDbGFzczsAHkxk" +
+ "YWx2aWsvYW5ub3RhdGlvbi9Jbm5lckNsYXNzOwAVTGphdmEvaW8vUHJpbnRTdHJlYW07ABJMamF2" +
+ "YS9sYW5nL09iamVjdDsAFExqYXZhL2xhbmcvUnVubmFibGU7ABJMamF2YS9sYW5nL1N0cmluZzsA" +
+ "EkxqYXZhL2xhbmcvU3lzdGVtOwAMVGVzdDk0NS5qYXZhAAlUcmFuc2Zvcm0AAVYAAlZMAAthY2Nl" +
+ "c3NGbGFncwAJZG9FeGVjdXRlAARuYW1lAANvdXQAB3ByaW50bG4ABXNheUhpAAV2YWx1ZQAAAAAB" +
+ "AAAABgAAAAEAAAAHAAAABQAHDgAFAAcOAAgBAAcOAQgPAQMPAQgPAAAAAAAAAAAAAAAA9AIAAAEA" +
+ "AAAOAAAAAQABAAEAAAD5AgAABAAAAHAQBQAAAA4ABAACAAIAAAD+AgAAFAAAAGIAAAAbAQMAAABu" +
+ "IAQAEABxEAIAAwBiAAAAGwECAAAAbiAEABAADgAAAAMBAIiABJAGAYCABKQGAYoCAAMBvAYCAgEX" +
+ "GAECAwIRBAgTFw4AAgAAAIwDAACSAwAAnAMAAAAAAAAAAAAAAAAAABAAAAAAAAAAAQAAAAAAAAAB" +
+ "AAAAGAAAAHAAAAACAAAACgAAANAAAAADAAAAAwAAAPgAAAAEAAAAAQAAABwBAAAFAAAABgAAACQB" +
+ "AAAGAAAAAQAAAFQBAAACIAAAGAAAAHQBAAABEAAAAgAAAOQCAAADIAAAAwAAAPQCAAABIAAAAwAA" +
+ "ABADAAAAIAAAAQAAAHQDAAAEIAAAAgAAAIwDAAADEAAAAQAAAJwDAAAGIAAAAQAAAKgDAAAAEAAA" +
+ "AQAAALgDAAA=");
+
+ public static void run() {
+ Redefinition.setTestConfiguration(Redefinition.Config.COMMON_REDEFINE);
+ doTest(new Transform());
+ }
+
+ public static void doTest(Transform t) {
+ t.sayHi(() -> { System.out.println("Not doing anything here"); });
+ t.sayHi(() -> {
+ System.out.println("transforming calling function");
+ Redefinition.doCommonClassRedefinition(Transform.class, CLASS_BYTES, DEX_BYTES);
+ });
+ t.sayHi(() -> { System.out.println("Not doing anything here"); });
+ }
+}
diff --git a/test/946-obsolete-throw/expected.txt b/test/946-obsolete-throw/expected.txt
index 71d5182..edf796e 100644
--- a/test/946-obsolete-throw/expected.txt
+++ b/test/946-obsolete-throw/expected.txt
@@ -5,10 +5,11 @@
transforming calling function
Received error : java.lang.Error: Throwing exception into an obsolete method!
java.lang.Error: Throwing exception into an obsolete method!
- at Main$DoRedefinitionClass.run(Main.java:65)
- at Transform.sayHi(Transform.java:27)
- at Main.doTest(Main.java:72)
- at Main.main(Main.java:57)
+ at art.Test946$DoRedefinitionClass.run(Test946.java:81)
+ at art.Test946$Transform.sayHi(Test946.java:26)
+ at art.Test946.doTest(Test946.java:88)
+ at art.Test946.run(Test946.java:73)
+ at Main.main(Main.java:19)
Hello - Transformed
Not doing anything here
Goodbye - Transformed
diff --git a/test/946-obsolete-throw/src/Main.java b/test/946-obsolete-throw/src/Main.java
index 077ad72..0b1f78d 100644
--- a/test/946-obsolete-throw/src/Main.java
+++ b/test/946-obsolete-throw/src/Main.java
@@ -14,71 +14,8 @@
* limitations under the License.
*/
-import java.util.Base64;
-
public class Main {
- // class Transform {
- // public void sayHi(Runnable r) {
- // System.out.println("Hello - Transformed");
- // r.run();
- // System.out.println("Goodbye - Transformed");
- // }
- // }
- private static final byte[] CLASS_BYTES = Base64.getDecoder().decode(
- "yv66vgAAADQAJAoACAARCQASABMIABQKABUAFgsAFwAYCAAZBwAaBwAbAQAGPGluaXQ+AQADKClW" +
- "AQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEABXNheUhpAQAXKExqYXZhL2xhbmcvUnVubmFibGU7" +
- "KVYBAApTb3VyY2VGaWxlAQAOVHJhbnNmb3JtLmphdmEMAAkACgcAHAwAHQAeAQATSGVsbG8gLSBU" +
- "cmFuc2Zvcm1lZAcAHwwAIAAhBwAiDAAjAAoBABVHb29kYnllIC0gVHJhbnNmb3JtZWQBAAlUcmFu" +
- "c2Zvcm0BABBqYXZhL2xhbmcvT2JqZWN0AQAQamF2YS9sYW5nL1N5c3RlbQEAA291dAEAFUxqYXZh" +
- "L2lvL1ByaW50U3RyZWFtOwEAE2phdmEvaW8vUHJpbnRTdHJlYW0BAAdwcmludGxuAQAVKExqYXZh" +
- "L2xhbmcvU3RyaW5nOylWAQASamF2YS9sYW5nL1J1bm5hYmxlAQADcnVuACAABwAIAAAAAAACAAAA" +
- "CQAKAAEACwAAAB0AAQABAAAABSq3AAGxAAAAAQAMAAAABgABAAAAAQABAA0ADgABAAsAAAA7AAIA" +
- "AgAAABeyAAISA7YABCu5AAUBALIAAhIGtgAEsQAAAAEADAAAABIABAAAAAMACAAEAA4ABQAWAAYA" +
- "AQAPAAAAAgAQ");
- private static final byte[] DEX_BYTES = Base64.getDecoder().decode(
- "ZGV4CjAzNQAYeAMMXgYWxoeSHAS9EWKCCtVRSAGpqZVQAwAAcAAAAHhWNBIAAAAAAAAAALACAAAR" +
- "AAAAcAAAAAcAAAC0AAAAAwAAANAAAAABAAAA9AAAAAUAAAD8AAAAAQAAACQBAAAMAgAARAEAAKIB" +
- "AACqAQAAwQEAANYBAADjAQAA+gEAAA4CAAAkAgAAOAIAAEwCAABcAgAAXwIAAGMCAAB3AgAAfAIA" +
- "AIUCAACKAgAAAwAAAAQAAAAFAAAABgAAAAcAAAAIAAAACgAAAAoAAAAGAAAAAAAAAAsAAAAGAAAA" +
- "lAEAAAsAAAAGAAAAnAEAAAUAAQANAAAAAAAAAAAAAAAAAAEAEAAAAAEAAgAOAAAAAgAAAAAAAAAD" +
- "AAAADwAAAAAAAAAAAAAAAgAAAAAAAAAJAAAAAAAAAJ8CAAAAAAAAAQABAAEAAACRAgAABAAAAHAQ" +
- "AwAAAA4ABAACAAIAAACWAgAAFAAAAGIAAAAbAQIAAABuIAIAEAByEAQAAwBiAAAAGwEBAAAAbiAC" +
- "ABAADgABAAAAAwAAAAEAAAAEAAY8aW5pdD4AFUdvb2RieWUgLSBUcmFuc2Zvcm1lZAATSGVsbG8g" +
- "LSBUcmFuc2Zvcm1lZAALTFRyYW5zZm9ybTsAFUxqYXZhL2lvL1ByaW50U3RyZWFtOwASTGphdmEv" +
- "bGFuZy9PYmplY3Q7ABRMamF2YS9sYW5nL1J1bm5hYmxlOwASTGphdmEvbGFuZy9TdHJpbmc7ABJM" +
- "amF2YS9sYW5nL1N5c3RlbTsADlRyYW5zZm9ybS5qYXZhAAFWAAJWTAASZW1pdHRlcjogamFjay00" +
- "LjEzAANvdXQAB3ByaW50bG4AA3J1bgAFc2F5SGkAAQAHDgADAQAHDoc8hwAAAAEBAICABMQCAQHc" +
- "AgAAAA0AAAAAAAAAAQAAAAAAAAABAAAAEQAAAHAAAAACAAAABwAAALQAAAADAAAAAwAAANAAAAAE" +
- "AAAAAQAAAPQAAAAFAAAABQAAAPwAAAAGAAAAAQAAACQBAAABIAAAAgAAAEQBAAABEAAAAgAAAJQB" +
- "AAACIAAAEQAAAKIBAAADIAAAAgAAAJECAAAAIAAAAQAAAJ8CAAAAEAAAAQAAALACAAA=");
-
- public static void main(String[] args) {
- art.Main.bindAgentJNIForClass(Main.class);
- doTest(new Transform());
+ public static void main(String[] args) throws Exception {
+ art.Test946.run();
}
-
- static class DoRedefinitionClass implements Runnable {
- @Override
- public void run() {
- System.out.println("transforming calling function");
- doCommonClassRedefinition(Transform.class, CLASS_BYTES, DEX_BYTES);
- throw new Error("Throwing exception into an obsolete method!");
- }
- }
-
- public static void doTest(Transform t) {
- t.sayHi(() -> { System.out.println("Not doing anything here"); });
- try {
- t.sayHi(new DoRedefinitionClass());
- } catch (Throwable e) {
- System.out.println("Received error : " + e);
- e.printStackTrace(System.out);
- }
- t.sayHi(() -> { System.out.println("Not doing anything here"); });
- }
-
- // Transforms the class
- private static native void doCommonClassRedefinition(Class<?> target,
- byte[] classfile,
- byte[] dexfile);
}
diff --git a/test/946-obsolete-throw/src/Transform.java b/test/946-obsolete-throw/src/Transform.java
deleted file mode 100644
index 4f43086..0000000
--- a/test/946-obsolete-throw/src/Transform.java
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-class Transform {
- public void sayHi(Runnable r) {
- // Use lower 'h' to make sure the string will have a different string id
- // than the transformation (the transformation code is the same except
- // the actual printed String, which was making the test inacurately passing
- // in JIT mode when loading the string from the dex cache, as the string ids
- // of the two different strings were the same).
- // We know the string ids will be different because lexicographically:
- // "Hello" < "LTransform;" < "hello".
- System.out.println("hello");
- r.run();
- System.out.println("goodbye");
- }
-}
diff --git a/test/946-obsolete-throw/src/art/Redefinition.java b/test/946-obsolete-throw/src/art/Redefinition.java
new file mode 100644
index 0000000..0350ab4
--- /dev/null
+++ b/test/946-obsolete-throw/src/art/Redefinition.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package art;
+
+import java.util.ArrayList;
+// Common Redefinition functions. Placed here for use by CTS
+public class Redefinition {
+ // Bind native functions.
+ static {
+ Main.bindAgentJNIForClass(Redefinition.class);
+ }
+
+ public static final class CommonClassDefinition {
+ public final Class<?> target;
+ public final byte[] class_file_bytes;
+ public final byte[] dex_file_bytes;
+
+ public CommonClassDefinition(Class<?> target, byte[] class_file_bytes, byte[] dex_file_bytes) {
+ this.target = target;
+ this.class_file_bytes = class_file_bytes;
+ this.dex_file_bytes = dex_file_bytes;
+ }
+ }
+
+ // A set of possible test configurations. Test should set this if they need to.
+ // This must be kept in sync with the defines in ti-agent/common_helper.cc
+ public static enum Config {
+ COMMON_REDEFINE(0),
+ COMMON_RETRANSFORM(1),
+ COMMON_TRANSFORM(2);
+
+ private final int val;
+ private Config(int val) {
+ this.val = val;
+ }
+ }
+
+ public static void setTestConfiguration(Config type) {
+ nativeSetTestConfiguration(type.val);
+ }
+
+ private static native void nativeSetTestConfiguration(int type);
+
+ // Transforms the class
+ public static native void doCommonClassRedefinition(Class<?> target,
+ byte[] classfile,
+ byte[] dexfile);
+
+ public static void doMultiClassRedefinition(CommonClassDefinition... defs) {
+ ArrayList<Class<?>> classes = new ArrayList<>();
+ ArrayList<byte[]> class_files = new ArrayList<>();
+ ArrayList<byte[]> dex_files = new ArrayList<>();
+
+ for (CommonClassDefinition d : defs) {
+ classes.add(d.target);
+ class_files.add(d.class_file_bytes);
+ dex_files.add(d.dex_file_bytes);
+ }
+ doCommonMultiClassRedefinition(classes.toArray(new Class<?>[0]),
+ class_files.toArray(new byte[0][]),
+ dex_files.toArray(new byte[0][]));
+ }
+
+ public static void addMultiTransformationResults(CommonClassDefinition... defs) {
+ for (CommonClassDefinition d : defs) {
+ addCommonTransformationResult(d.target.getCanonicalName(),
+ d.class_file_bytes,
+ d.dex_file_bytes);
+ }
+ }
+
+ public static native void doCommonMultiClassRedefinition(Class<?>[] targets,
+ byte[][] classfiles,
+ byte[][] dexfiles);
+ public static native void doCommonClassRetransformation(Class<?>... target);
+ public static native void setPopRetransformations(boolean pop);
+ public static native void popTransformationFor(String name);
+ public static native void enableCommonRetransformation(boolean enable);
+ public static native void addCommonTransformationResult(String target_name,
+ byte[] class_bytes,
+ byte[] dex_bytes);
+}
diff --git a/test/946-obsolete-throw/src/art/Test946.java b/test/946-obsolete-throw/src/art/Test946.java
new file mode 100644
index 0000000..9f0e57c
--- /dev/null
+++ b/test/946-obsolete-throw/src/art/Test946.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package art;
+
+import java.util.Base64;
+
+public class Test946 {
+
+ static class Transform {
+ public void sayHi(Runnable r) {
+ System.out.println("hello");
+ r.run();
+ System.out.println("goodbye");
+ }
+ }
+
+ // static class Transform {
+ // public void sayHi(Runnable r) {
+ // System.out.println("Hello - Transformed");
+ // r.run();
+ // System.out.println("Goodbye - Transformed");
+ // }
+ // }
+ private static final byte[] CLASS_BYTES = Base64.getDecoder().decode(
+ "yv66vgAAADQAKAoACAARCQASABMIABQKABUAFgsAFwAYCAAZBwAbBwAeAQAGPGluaXQ+AQADKClW" +
+ "AQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEABXNheUhpAQAXKExqYXZhL2xhbmcvUnVubmFibGU7" +
+ "KVYBAApTb3VyY2VGaWxlAQAMVGVzdDk0Ni5qYXZhDAAJAAoHAB8MACAAIQEAE0hlbGxvIC0gVHJh" +
+ "bnNmb3JtZWQHACIMACMAJAcAJQwAJgAKAQAVR29vZGJ5ZSAtIFRyYW5zZm9ybWVkBwAnAQAVYXJ0" +
+ "L1Rlc3Q5NDYkVHJhbnNmb3JtAQAJVHJhbnNmb3JtAQAMSW5uZXJDbGFzc2VzAQAQamF2YS9sYW5n" +
+ "L09iamVjdAEAEGphdmEvbGFuZy9TeXN0ZW0BAANvdXQBABVMamF2YS9pby9QcmludFN0cmVhbTsB" +
+ "ABNqYXZhL2lvL1ByaW50U3RyZWFtAQAHcHJpbnRsbgEAFShMamF2YS9sYW5nL1N0cmluZzspVgEA" +
+ "EmphdmEvbGFuZy9SdW5uYWJsZQEAA3J1bgEAC2FydC9UZXN0OTQ2ACAABwAIAAAAAAACAAAACQAK" +
+ "AAEACwAAAB0AAQABAAAABSq3AAGxAAAAAQAMAAAABgABAAAABQABAA0ADgABAAsAAAA7AAIAAgAA" +
+ "ABeyAAISA7YABCu5AAUBALIAAhIGtgAEsQAAAAEADAAAABIABAAAAAcACAAIAA4ACQAWAAoAAgAP" +
+ "AAAAAgAQAB0AAAAKAAEABwAaABwACA==");
+ private static final byte[] DEX_BYTES = Base64.getDecoder().decode(
+ "ZGV4CjAzNQB0mzt6AAAAAAAAAAAAAAAAAAAAAAAAAAA8BAAAcAAAAHhWNBIAAAAAAAAAAHgDAAAX" +
+ "AAAAcAAAAAoAAADMAAAAAwAAAPQAAAABAAAAGAEAAAUAAAAgAQAAAQAAAEgBAADUAgAAaAEAAGgB" +
+ "AABwAQAAhwEAAJwBAAC1AQAAxAEAAOgBAAAIAgAAHwIAADMCAABJAgAAXQIAAHECAAB/AgAAigIA" +
+ "AI0CAACRAgAAngIAAKQCAACpAgAAsgIAALcCAAC+AgAAAwAAAAQAAAAFAAAABgAAAAcAAAAIAAAA" +
+ "CQAAAAoAAAALAAAADgAAAA4AAAAJAAAAAAAAAA8AAAAJAAAAyAIAAA8AAAAJAAAA0AIAAAgABAAS" +
+ "AAAAAAAAAAAAAAAAAAEAFQAAAAQAAgATAAAABQAAAAAAAAAGAAAAFAAAAAAAAAAAAAAABQAAAAAA" +
+ "AAAMAAAAaAMAADwDAAAAAAAABjxpbml0PgAVR29vZGJ5ZSAtIFRyYW5zZm9ybWVkABNIZWxsbyAt" +
+ "IFRyYW5zZm9ybWVkABdMYXJ0L1Rlc3Q5NDYkVHJhbnNmb3JtOwANTGFydC9UZXN0OTQ2OwAiTGRh" +
+ "bHZpay9hbm5vdGF0aW9uL0VuY2xvc2luZ0NsYXNzOwAeTGRhbHZpay9hbm5vdGF0aW9uL0lubmVy" +
+ "Q2xhc3M7ABVMamF2YS9pby9QcmludFN0cmVhbTsAEkxqYXZhL2xhbmcvT2JqZWN0OwAUTGphdmEv" +
+ "bGFuZy9SdW5uYWJsZTsAEkxqYXZhL2xhbmcvU3RyaW5nOwASTGphdmEvbGFuZy9TeXN0ZW07AAxU" +
+ "ZXN0OTQ2LmphdmEACVRyYW5zZm9ybQABVgACVkwAC2FjY2Vzc0ZsYWdzAARuYW1lAANvdXQAB3By" +
+ "aW50bG4AA3J1bgAFc2F5SGkABXZhbHVlAAAAAAEAAAAGAAAAAQAAAAcAAAAFAAcOAAcBAAcOAQgP" +
+ "AQMPAQgPAAEAAQABAAAA2AIAAAQAAABwEAMAAAAOAAQAAgACAAAA3QIAABQAAABiAAAAGwECAAAA" +
+ "biACABAAchAEAAMAYgAAABsBAQAAAG4gAgAQAA4AAAABAQCAgATsBQEBhAYAAAICARYYAQIDAhAE" +
+ "CBEXDQACAAAATAMAAFIDAABcAwAAAAAAAAAAAAAAAAAAEAAAAAAAAAABAAAAAAAAAAEAAAAXAAAA" +
+ "cAAAAAIAAAAKAAAAzAAAAAMAAAADAAAA9AAAAAQAAAABAAAAGAEAAAUAAAAFAAAAIAEAAAYAAAAB" +
+ "AAAASAEAAAIgAAAXAAAAaAEAAAEQAAACAAAAyAIAAAMgAAACAAAA2AIAAAEgAAACAAAA7AIAAAAg" +
+ "AAABAAAAPAMAAAQgAAACAAAATAMAAAMQAAABAAAAXAMAAAYgAAABAAAAaAMAAAAQAAABAAAAeAMA" +
+ "AA==");
+
+ public static void run() {
+ doTest(new Transform());
+ }
+
+ static class DoRedefinitionClass implements Runnable {
+ @Override
+ public void run() {
+ System.out.println("transforming calling function");
+ Redefinition.doCommonClassRedefinition(Transform.class, CLASS_BYTES, DEX_BYTES);
+ throw new Error("Throwing exception into an obsolete method!");
+ }
+ }
+
+ public static void doTest(Transform t) {
+ t.sayHi(() -> { System.out.println("Not doing anything here"); });
+ try {
+ t.sayHi(new DoRedefinitionClass());
+ } catch (Throwable e) {
+ System.out.println("Received error : " + e);
+ e.printStackTrace(System.out);
+ }
+ t.sayHi(() -> { System.out.println("Not doing anything here"); });
+ }
+}
diff --git a/test/947-reflect-method/src/Main.java b/test/947-reflect-method/src/Main.java
index da746ac..bc3f4b2 100644
--- a/test/947-reflect-method/src/Main.java
+++ b/test/947-reflect-method/src/Main.java
@@ -14,60 +14,8 @@
* limitations under the License.
*/
-import java.util.Base64;
-import java.lang.reflect.Method;
-
public class Main {
-
- /**
- * base64 encoded class/dex file for
- * class Transform {
- * public void sayHi() {
- * System.out.println("Goodbye");
- * }
- * }
- */
- private static final byte[] CLASS_BYTES = Base64.getDecoder().decode(
- "yv66vgAAADQAHAoABgAOCQAPABAIABEKABIAEwcAFAcAFQEABjxpbml0PgEAAygpVgEABENvZGUB" +
- "AA9MaW5lTnVtYmVyVGFibGUBAAVzYXlIaQEAClNvdXJjZUZpbGUBAA5UcmFuc2Zvcm0uamF2YQwA" +
- "BwAIBwAWDAAXABgBAAdHb29kYnllBwAZDAAaABsBAAlUcmFuc2Zvcm0BABBqYXZhL2xhbmcvT2Jq" +
- "ZWN0AQAQamF2YS9sYW5nL1N5c3RlbQEAA291dAEAFUxqYXZhL2lvL1ByaW50U3RyZWFtOwEAE2ph" +
- "dmEvaW8vUHJpbnRTdHJlYW0BAAdwcmludGxuAQAVKExqYXZhL2xhbmcvU3RyaW5nOylWACAABQAG" +
- "AAAAAAACAAAABwAIAAEACQAAAB0AAQABAAAABSq3AAGxAAAAAQAKAAAABgABAAAAEQABAAsACAAB" +
- "AAkAAAAlAAIAAQAAAAmyAAISA7YABLEAAAABAAoAAAAKAAIAAAATAAgAFAABAAwAAAACAA0=");
- private static final byte[] DEX_BYTES = Base64.getDecoder().decode(
- "ZGV4CjAzNQCLXSBQ5FiS3f16krSYZFF8xYZtFVp0GRXMAgAAcAAAAHhWNBIAAAAAAAAAACwCAAAO" +
- "AAAAcAAAAAYAAACoAAAAAgAAAMAAAAABAAAA2AAAAAQAAADgAAAAAQAAAAABAACsAQAAIAEAAGIB" +
- "AABqAQAAcwEAAIABAACXAQAAqwEAAL8BAADTAQAA4wEAAOYBAADqAQAA/gEAAAMCAAAMAgAAAgAA" +
- "AAMAAAAEAAAABQAAAAYAAAAIAAAACAAAAAUAAAAAAAAACQAAAAUAAABcAQAABAABAAsAAAAAAAAA" +
- "AAAAAAAAAAANAAAAAQABAAwAAAACAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAHAAAAAAAAAB4CAAAA" +
- "AAAAAQABAAEAAAATAgAABAAAAHAQAwAAAA4AAwABAAIAAAAYAgAACQAAAGIAAAAbAQEAAABuIAIA" +
- "EAAOAAAAAQAAAAMABjxpbml0PgAHR29vZGJ5ZQALTFRyYW5zZm9ybTsAFUxqYXZhL2lvL1ByaW50" +
- "U3RyZWFtOwASTGphdmEvbGFuZy9PYmplY3Q7ABJMamF2YS9sYW5nL1N0cmluZzsAEkxqYXZhL2xh" +
- "bmcvU3lzdGVtOwAOVHJhbnNmb3JtLmphdmEAAVYAAlZMABJlbWl0dGVyOiBqYWNrLTMuMzYAA291" +
- "dAAHcHJpbnRsbgAFc2F5SGkAEQAHDgATAAcOhQAAAAEBAICABKACAQG4Ag0AAAAAAAAAAQAAAAAA" +
- "AAABAAAADgAAAHAAAAACAAAABgAAAKgAAAADAAAAAgAAAMAAAAAEAAAAAQAAANgAAAAFAAAABAAA" +
- "AOAAAAAGAAAAAQAAAAABAAABIAAAAgAAACABAAABEAAAAQAAAFwBAAACIAAADgAAAGIBAAADIAAA" +
- "AgAAABMCAAAAIAAAAQAAAB4CAAAAEAAAAQAAACwCAAA=");
-
- public static void main(String[] args) {
- art.Main.bindAgentJNIForClass(Main.class);
- doTest(new Transform());
+ public static void main(String[] args) throws Exception {
+ art.Test947.run();
}
-
- public static void doTest(Transform t) {
- try {
- Method say_hi_method = t.getClass().getDeclaredMethod("sayHi");
- say_hi_method.invoke(t);
- doCommonClassRedefinition(Transform.class, CLASS_BYTES, DEX_BYTES);
- say_hi_method.invoke(t);
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
-
- // Transforms the class
- private static native void doCommonClassRedefinition(Class<?> target,
- byte[] class_file,
- byte[] dex_file);
}
diff --git a/test/947-reflect-method/src/Transform.java b/test/947-reflect-method/src/Transform.java
deleted file mode 100644
index b8fe34a..0000000
--- a/test/947-reflect-method/src/Transform.java
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-class Transform {
- public void sayHi() {
- // Use lower 'h' to make sure the string will have a different string id
- // than the transformation (the transformation code is the same except
- // the actual printed String, which was making the test inacurately passing
- // in JIT mode when loading the string from the dex cache, as the string ids
- // of the two different strings were the same).
- // We know the string ids will be different because lexicographically:
- // "Goodbye" < "LTransform;" < "hello".
- System.out.println("hello");
- }
-}
diff --git a/test/947-reflect-method/src/art/Redefinition.java b/test/947-reflect-method/src/art/Redefinition.java
new file mode 100644
index 0000000..0350ab4
--- /dev/null
+++ b/test/947-reflect-method/src/art/Redefinition.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package art;
+
+import java.util.ArrayList;
+// Common Redefinition functions. Placed here for use by CTS
+public class Redefinition {
+ // Bind native functions.
+ static {
+ Main.bindAgentJNIForClass(Redefinition.class);
+ }
+
+ public static final class CommonClassDefinition {
+ public final Class<?> target;
+ public final byte[] class_file_bytes;
+ public final byte[] dex_file_bytes;
+
+ public CommonClassDefinition(Class<?> target, byte[] class_file_bytes, byte[] dex_file_bytes) {
+ this.target = target;
+ this.class_file_bytes = class_file_bytes;
+ this.dex_file_bytes = dex_file_bytes;
+ }
+ }
+
+ // A set of possible test configurations. Test should set this if they need to.
+ // This must be kept in sync with the defines in ti-agent/common_helper.cc
+ public static enum Config {
+ COMMON_REDEFINE(0),
+ COMMON_RETRANSFORM(1),
+ COMMON_TRANSFORM(2);
+
+ private final int val;
+ private Config(int val) {
+ this.val = val;
+ }
+ }
+
+ public static void setTestConfiguration(Config type) {
+ nativeSetTestConfiguration(type.val);
+ }
+
+ private static native void nativeSetTestConfiguration(int type);
+
+ // Transforms the class
+ public static native void doCommonClassRedefinition(Class<?> target,
+ byte[] classfile,
+ byte[] dexfile);
+
+ public static void doMultiClassRedefinition(CommonClassDefinition... defs) {
+ ArrayList<Class<?>> classes = new ArrayList<>();
+ ArrayList<byte[]> class_files = new ArrayList<>();
+ ArrayList<byte[]> dex_files = new ArrayList<>();
+
+ for (CommonClassDefinition d : defs) {
+ classes.add(d.target);
+ class_files.add(d.class_file_bytes);
+ dex_files.add(d.dex_file_bytes);
+ }
+ doCommonMultiClassRedefinition(classes.toArray(new Class<?>[0]),
+ class_files.toArray(new byte[0][]),
+ dex_files.toArray(new byte[0][]));
+ }
+
+ public static void addMultiTransformationResults(CommonClassDefinition... defs) {
+ for (CommonClassDefinition d : defs) {
+ addCommonTransformationResult(d.target.getCanonicalName(),
+ d.class_file_bytes,
+ d.dex_file_bytes);
+ }
+ }
+
+ public static native void doCommonMultiClassRedefinition(Class<?>[] targets,
+ byte[][] classfiles,
+ byte[][] dexfiles);
+ public static native void doCommonClassRetransformation(Class<?>... target);
+ public static native void setPopRetransformations(boolean pop);
+ public static native void popTransformationFor(String name);
+ public static native void enableCommonRetransformation(boolean enable);
+ public static native void addCommonTransformationResult(String target_name,
+ byte[] class_bytes,
+ byte[] dex_bytes);
+}
diff --git a/test/947-reflect-method/src/art/Test947.java b/test/947-reflect-method/src/art/Test947.java
new file mode 100644
index 0000000..8cb515e
--- /dev/null
+++ b/test/947-reflect-method/src/art/Test947.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package art;
+
+import java.util.Base64;
+import java.lang.reflect.Method;
+
+public class Test947 {
+
+ static class Transform {
+ public void sayHi() {
+ System.out.println("hello");
+ }
+ }
+
+
+ /**
+ * base64 encoded class/dex file for
+ * static class Transform {
+ * public void sayHi() {
+ * System.out.println("Goodbye");
+ * }
+ * }
+ */
+ private static final byte[] CLASS_BYTES = Base64.getDecoder().decode(
+ "yv66vgAAADQAIAoABgAOCQAPABAIABEKABIAEwcAFQcAGAEABjxpbml0PgEAAygpVgEABENvZGUB" +
+ "AA9MaW5lTnVtYmVyVGFibGUBAAVzYXlIaQEAClNvdXJjZUZpbGUBAAxUZXN0OTQ3LmphdmEMAAcA" +
+ "CAcAGQwAGgAbAQAHR29vZGJ5ZQcAHAwAHQAeBwAfAQAVYXJ0L1Rlc3Q5NDckVHJhbnNmb3JtAQAJ" +
+ "VHJhbnNmb3JtAQAMSW5uZXJDbGFzc2VzAQAQamF2YS9sYW5nL09iamVjdAEAEGphdmEvbGFuZy9T" +
+ "eXN0ZW0BAANvdXQBABVMamF2YS9pby9QcmludFN0cmVhbTsBABNqYXZhL2lvL1ByaW50U3RyZWFt" +
+ "AQAHcHJpbnRsbgEAFShMamF2YS9sYW5nL1N0cmluZzspVgEAC2FydC9UZXN0OTQ3ACAABQAGAAAA" +
+ "AAACAAAABwAIAAEACQAAAB0AAQABAAAABSq3AAGxAAAAAQAKAAAABgABAAAABQABAAsACAABAAkA" +
+ "AAAlAAIAAQAAAAmyAAISA7YABLEAAAABAAoAAAAKAAIAAAAHAAgACAACAAwAAAACAA0AFwAAAAoA" +
+ "AQAFABQAFgAI");
+ private static final byte[] DEX_BYTES = Base64.getDecoder().decode(
+ "ZGV4CjAzNQCEgoKcAAAAAAAAAAAAAAAAAAAAAAAAAAC4AwAAcAAAAHhWNBIAAAAAAAAAAPQCAAAU" +
+ "AAAAcAAAAAkAAADAAAAAAgAAAOQAAAABAAAA/AAAAAQAAAAEAQAAAQAAACQBAAB0AgAARAEAAEQB" +
+ "AABMAQAAVQEAAG4BAAB9AQAAoQEAAMEBAADYAQAA7AEAAAACAAAUAgAAIgIAAC0CAAAwAgAANAIA" +
+ "AEECAABHAgAATAIAAFUCAABcAgAAAgAAAAMAAAAEAAAABQAAAAYAAAAHAAAACAAAAAkAAAAMAAAA" +
+ "DAAAAAgAAAAAAAAADQAAAAgAAABkAgAABwAEABAAAAAAAAAAAAAAAAAAAAASAAAABAABABEAAAAF" +
+ "AAAAAAAAAAAAAAAAAAAABQAAAAAAAAAKAAAA5AIAALgCAAAAAAAABjxpbml0PgAHR29vZGJ5ZQAX" +
+ "TGFydC9UZXN0OTQ3JFRyYW5zZm9ybTsADUxhcnQvVGVzdDk0NzsAIkxkYWx2aWsvYW5ub3RhdGlv" +
+ "bi9FbmNsb3NpbmdDbGFzczsAHkxkYWx2aWsvYW5ub3RhdGlvbi9Jbm5lckNsYXNzOwAVTGphdmEv" +
+ "aW8vUHJpbnRTdHJlYW07ABJMamF2YS9sYW5nL09iamVjdDsAEkxqYXZhL2xhbmcvU3RyaW5nOwAS" +
+ "TGphdmEvbGFuZy9TeXN0ZW07AAxUZXN0OTQ3LmphdmEACVRyYW5zZm9ybQABVgACVkwAC2FjY2Vz" +
+ "c0ZsYWdzAARuYW1lAANvdXQAB3ByaW50bG4ABXNheUhpAAV2YWx1ZQAAAQAAAAYAAAAFAAcOAAcA" +
+ "Bw4BCA8AAAAAAQABAAEAAABsAgAABAAAAHAQAwAAAA4AAwABAAIAAABxAgAACQAAAGIAAAAbAQEA" +
+ "AABuIAIAEAAOAAAAAAABAQCAgAT8BAEBlAUAAAICARMYAQIDAg4ECA8XCwACAAAAyAIAAM4CAADY" +
+ "AgAAAAAAAAAAAAAAAAAAEAAAAAAAAAABAAAAAAAAAAEAAAAUAAAAcAAAAAIAAAAJAAAAwAAAAAMA" +
+ "AAACAAAA5AAAAAQAAAABAAAA/AAAAAUAAAAEAAAABAEAAAYAAAABAAAAJAEAAAIgAAAUAAAARAEA" +
+ "AAEQAAABAAAAZAIAAAMgAAACAAAAbAIAAAEgAAACAAAAfAIAAAAgAAABAAAAuAIAAAQgAAACAAAA" +
+ "yAIAAAMQAAABAAAA2AIAAAYgAAABAAAA5AIAAAAQAAABAAAA9AIAAA==");
+
+ public static void run() {
+ doTest(new Transform());
+ }
+
+ public static void doTest(Transform t) {
+ try {
+ Method say_hi_method = t.getClass().getDeclaredMethod("sayHi");
+ say_hi_method.invoke(t);
+ Redefinition.doCommonClassRedefinition(Transform.class, CLASS_BYTES, DEX_BYTES);
+ say_hi_method.invoke(t);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+}
diff --git a/test/948-change-annotations/src/Main.java b/test/948-change-annotations/src/Main.java
index a290396..5d3406d 100644
--- a/test/948-change-annotations/src/Main.java
+++ b/test/948-change-annotations/src/Main.java
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+import art.Redefinition;
import java.util.Arrays;
import java.util.Base64;
import java.util.Comparator;
@@ -85,7 +86,9 @@
}
// Transforms the class
- public static native void doCommonClassRedefinition(Class<?> target,
- byte[] class_file,
- byte[] dex_file);
+ public static void doCommonClassRedefinition(Class<?> target,
+ byte[] class_file,
+ byte[] dex_file) {
+ Redefinition.doCommonClassRedefinition(target, class_file, dex_file);
+ }
}
diff --git a/test/948-change-annotations/src/art/Redefinition.java b/test/948-change-annotations/src/art/Redefinition.java
new file mode 100644
index 0000000..0350ab4
--- /dev/null
+++ b/test/948-change-annotations/src/art/Redefinition.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package art;
+
+import java.util.ArrayList;
+// Common Redefinition functions. Placed here for use by CTS
+public class Redefinition {
+ // Bind native functions.
+ static {
+ Main.bindAgentJNIForClass(Redefinition.class);
+ }
+
+ public static final class CommonClassDefinition {
+ public final Class<?> target;
+ public final byte[] class_file_bytes;
+ public final byte[] dex_file_bytes;
+
+ public CommonClassDefinition(Class<?> target, byte[] class_file_bytes, byte[] dex_file_bytes) {
+ this.target = target;
+ this.class_file_bytes = class_file_bytes;
+ this.dex_file_bytes = dex_file_bytes;
+ }
+ }
+
+ // A set of possible test configurations. Test should set this if they need to.
+ // This must be kept in sync with the defines in ti-agent/common_helper.cc
+ public static enum Config {
+ COMMON_REDEFINE(0),
+ COMMON_RETRANSFORM(1),
+ COMMON_TRANSFORM(2);
+
+ private final int val;
+ private Config(int val) {
+ this.val = val;
+ }
+ }
+
+ public static void setTestConfiguration(Config type) {
+ nativeSetTestConfiguration(type.val);
+ }
+
+ private static native void nativeSetTestConfiguration(int type);
+
+ // Transforms the class
+ public static native void doCommonClassRedefinition(Class<?> target,
+ byte[] classfile,
+ byte[] dexfile);
+
+ public static void doMultiClassRedefinition(CommonClassDefinition... defs) {
+ ArrayList<Class<?>> classes = new ArrayList<>();
+ ArrayList<byte[]> class_files = new ArrayList<>();
+ ArrayList<byte[]> dex_files = new ArrayList<>();
+
+ for (CommonClassDefinition d : defs) {
+ classes.add(d.target);
+ class_files.add(d.class_file_bytes);
+ dex_files.add(d.dex_file_bytes);
+ }
+ doCommonMultiClassRedefinition(classes.toArray(new Class<?>[0]),
+ class_files.toArray(new byte[0][]),
+ dex_files.toArray(new byte[0][]));
+ }
+
+ public static void addMultiTransformationResults(CommonClassDefinition... defs) {
+ for (CommonClassDefinition d : defs) {
+ addCommonTransformationResult(d.target.getCanonicalName(),
+ d.class_file_bytes,
+ d.dex_file_bytes);
+ }
+ }
+
+ public static native void doCommonMultiClassRedefinition(Class<?>[] targets,
+ byte[][] classfiles,
+ byte[][] dexfiles);
+ public static native void doCommonClassRetransformation(Class<?>... target);
+ public static native void setPopRetransformations(boolean pop);
+ public static native void popTransformationFor(String name);
+ public static native void enableCommonRetransformation(boolean enable);
+ public static native void addCommonTransformationResult(String target_name,
+ byte[] class_bytes,
+ byte[] dex_bytes);
+}
diff --git a/test/949-in-memory-transform/src/Main.java b/test/949-in-memory-transform/src/Main.java
index 1a6b224..b49a93f 100644
--- a/test/949-in-memory-transform/src/Main.java
+++ b/test/949-in-memory-transform/src/Main.java
@@ -14,112 +14,8 @@
* limitations under the License.
*/
-import java.util.Base64;
-import java.lang.reflect.*;
-import java.nio.ByteBuffer;
-
public class Main {
- /**
- * base64 encoded class/dex file for
- * public class Transform {
- * public void sayHi() {
- * System.out.println("hello");
- * }
- * }
- */
- private static final byte[] INITIAL_CLASS_BYTES = Base64.getDecoder().decode(
- "yv66vgAAADQAHAoABgAOCQAPABAIABEKABIAEwcAFAcAFQEABjxpbml0PgEAAygpVgEABENvZGUB" +
- "AA9MaW5lTnVtYmVyVGFibGUBAAVzYXlIaQEAClNvdXJjZUZpbGUBAA5UcmFuc2Zvcm0uamF2YQwA" +
- "BwAIBwAWDAAXABgBAAVoZWxsbwcAGQwAGgAbAQAJVHJhbnNmb3JtAQAQamF2YS9sYW5nL09iamVj" +
- "dAEAEGphdmEvbGFuZy9TeXN0ZW0BAANvdXQBABVMamF2YS9pby9QcmludFN0cmVhbTsBABNqYXZh" +
- "L2lvL1ByaW50U3RyZWFtAQAHcHJpbnRsbgEAFShMamF2YS9sYW5nL1N0cmluZzspVgAhAAUABgAA" +
- "AAAAAgABAAcACAABAAkAAAAdAAEAAQAAAAUqtwABsQAAAAEACgAAAAYAAQAAABEAAQALAAgAAQAJ" +
- "AAAAJQACAAEAAAAJsgACEgO2AASxAAAAAQAKAAAACgACAAAAGgAIABsAAQAMAAAAAgAN");
- private static final byte[] INITIAL_DEX_BYTES = Base64.getDecoder().decode(
- "ZGV4CjAzNQAJX3mZphwHJCT1qdTz/GS+jXOR+O/9e3fMAgAAcAAAAHhWNBIAAAAAAAAAACwCAAAO" +
- "AAAAcAAAAAYAAACoAAAAAgAAAMAAAAABAAAA2AAAAAQAAADgAAAAAQAAAAABAACsAQAAIAEAAGIB" +
- "AABqAQAAdwEAAI4BAACiAQAAtgEAAMoBAADaAQAA3QEAAOEBAAD1AQAA/AEAAAECAAAKAgAAAQAA" +
- "AAIAAAADAAAABAAAAAUAAAAHAAAABwAAAAUAAAAAAAAACAAAAAUAAABcAQAABAABAAsAAAAAAAAA" +
- "AAAAAAAAAAANAAAAAQABAAwAAAACAAAAAAAAAAAAAAABAAAAAgAAAAAAAAAGAAAAAAAAABwCAAAA" +
- "AAAAAQABAAEAAAARAgAABAAAAHAQAwAAAA4AAwABAAIAAAAWAgAACQAAAGIAAAAbAQoAAABuIAIA" +
- "EAAOAAAAAQAAAAMABjxpbml0PgALTFRyYW5zZm9ybTsAFUxqYXZhL2lvL1ByaW50U3RyZWFtOwAS" +
- "TGphdmEvbGFuZy9PYmplY3Q7ABJMamF2YS9sYW5nL1N0cmluZzsAEkxqYXZhL2xhbmcvU3lzdGVt" +
- "OwAOVHJhbnNmb3JtLmphdmEAAVYAAlZMABJlbWl0dGVyOiBqYWNrLTQuMjUABWhlbGxvAANvdXQA" +
- "B3ByaW50bG4ABXNheUhpABEABw4AGgAHDocAAAABAQCBgASgAgEBuAIAAA0AAAAAAAAAAQAAAAAA" +
- "AAABAAAADgAAAHAAAAACAAAABgAAAKgAAAADAAAAAgAAAMAAAAAEAAAAAQAAANgAAAAFAAAABAAA" +
- "AOAAAAAGAAAAAQAAAAABAAABIAAAAgAAACABAAABEAAAAQAAAFwBAAACIAAADgAAAGIBAAADIAAA" +
- "AgAAABECAAAAIAAAAQAAABwCAAAAEAAAAQAAACwCAAA=");
-
-
- /**
- * base64 encoded class/dex file for
- * public class Transform {
- * public void sayHi() {
- * System.out.println("Goodbye");
- * }
- * }
- */
- private static final byte[] TRANSFORMED_CLASS_BYTES = Base64.getDecoder().decode(
- "yv66vgAAADQAHAoABgAOCQAPABAIABEKABIAEwcAFAcAFQEABjxpbml0PgEAAygpVgEABENvZGUB" +
- "AA9MaW5lTnVtYmVyVGFibGUBAAVzYXlIaQEAClNvdXJjZUZpbGUBAA5UcmFuc2Zvcm0uamF2YQwA" +
- "BwAIBwAWDAAXABgBAAdHb29kYnllBwAZDAAaABsBAAlUcmFuc2Zvcm0BABBqYXZhL2xhbmcvT2Jq" +
- "ZWN0AQAQamF2YS9sYW5nL1N5c3RlbQEAA291dAEAFUxqYXZhL2lvL1ByaW50U3RyZWFtOwEAE2ph" +
- "dmEvaW8vUHJpbnRTdHJlYW0BAAdwcmludGxuAQAVKExqYXZhL2xhbmcvU3RyaW5nOylWACEABQAG" +
- "AAAAAAACAAEABwAIAAEACQAAAB0AAQABAAAABSq3AAGxAAAAAQAKAAAABgABAAAAEQABAAsACAAB" +
- "AAkAAAAlAAIAAQAAAAmyAAISA7YABLEAAAABAAoAAAAKAAIAAAAaAAgAGwABAAwAAAACAA0=");
- private static final byte[] TRANSFORMED_DEX_BYTES = Base64.getDecoder().decode(
- "ZGV4CjAzNQAPXh6T3l1FObhHsKf1U2vi+0GmAvElxBLMAgAAcAAAAHhWNBIAAAAAAAAAACwCAAAO" +
- "AAAAcAAAAAYAAACoAAAAAgAAAMAAAAABAAAA2AAAAAQAAADgAAAAAQAAAAABAACsAQAAIAEAAGIB" +
- "AABqAQAAcwEAAIABAACXAQAAqwEAAL8BAADTAQAA4wEAAOYBAADqAQAA/gEAAAMCAAAMAgAAAgAA" +
- "AAMAAAAEAAAABQAAAAYAAAAIAAAACAAAAAUAAAAAAAAACQAAAAUAAABcAQAABAABAAsAAAAAAAAA" +
- "AAAAAAAAAAANAAAAAQABAAwAAAACAAAAAAAAAAAAAAABAAAAAgAAAAAAAAAHAAAAAAAAAB4CAAAA" +
- "AAAAAQABAAEAAAATAgAABAAAAHAQAwAAAA4AAwABAAIAAAAYAgAACQAAAGIAAAAbAQEAAABuIAIA" +
- "EAAOAAAAAQAAAAMABjxpbml0PgAHR29vZGJ5ZQALTFRyYW5zZm9ybTsAFUxqYXZhL2lvL1ByaW50" +
- "U3RyZWFtOwASTGphdmEvbGFuZy9PYmplY3Q7ABJMamF2YS9sYW5nL1N0cmluZzsAEkxqYXZhL2xh" +
- "bmcvU3lzdGVtOwAOVHJhbnNmb3JtLmphdmEAAVYAAlZMABJlbWl0dGVyOiBqYWNrLTQuMjUAA291" +
- "dAAHcHJpbnRsbgAFc2F5SGkAEQAHDgAaAAcOhwAAAAEBAIGABKACAQG4Ag0AAAAAAAAAAQAAAAAA" +
- "AAABAAAADgAAAHAAAAACAAAABgAAAKgAAAADAAAAAgAAAMAAAAAEAAAAAQAAANgAAAAFAAAABAAA" +
- "AOAAAAAGAAAAAQAAAAABAAABIAAAAgAAACABAAABEAAAAQAAAFwBAAACIAAADgAAAGIBAAADIAAA" +
- "AgAAABMCAAAAIAAAAQAAAB4CAAAAEAAAAQAAACwCAAA=");
-
public static void main(String[] args) throws Exception {
- art.Main.bindAgentJNIForClass(Main.class);
- ClassLoader loader;
- try {
- // Art uses this classloader to do in-memory dex files. There is no support for defineClass
- loader = (ClassLoader)Class.forName("dalvik.system.InMemoryDexClassLoader")
- .getConstructor(ByteBuffer.class, ClassLoader.class)
- .newInstance(ByteBuffer.wrap(INITIAL_DEX_BYTES),
- ClassLoader.getSystemClassLoader());
- } catch (ClassNotFoundException e) {
- // Seem to be on RI. Just make a new ClassLoader that calls defineClass.
- loader = new ClassLoader() {
- public Class<?> findClass(String name) throws ClassNotFoundException {
- if (name.equals("Transform")) {
- return defineClass(name, INITIAL_CLASS_BYTES, 0, INITIAL_CLASS_BYTES.length);
- } else {
- throw new ClassNotFoundException("Couldn't find class: " + name);
- }
- }
- };
- }
- doTest(loader);
+ art.Test949.run();
}
-
- public static void doTest(ClassLoader loader) throws Exception {
- // Get the class
- Class<?> transform_class = loader.loadClass("Transform");
- Method say_hi_method = transform_class.getMethod("sayHi");
- Object t = transform_class.newInstance();
-
- // Run the actual test.
- say_hi_method.invoke(t);
- doCommonClassRedefinition(transform_class, TRANSFORMED_CLASS_BYTES, TRANSFORMED_DEX_BYTES);
- say_hi_method.invoke(t);
- }
-
- // Transforms the class
- private static native void doCommonClassRedefinition(Class<?> target,
- byte[] class_file,
- byte[] dex_file);
}
diff --git a/test/949-in-memory-transform/src/art/Redefinition.java b/test/949-in-memory-transform/src/art/Redefinition.java
new file mode 100644
index 0000000..0350ab4
--- /dev/null
+++ b/test/949-in-memory-transform/src/art/Redefinition.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package art;
+
+import java.util.ArrayList;
+// Common Redefinition functions. Placed here for use by CTS
+public class Redefinition {
+ // Bind native functions.
+ static {
+ Main.bindAgentJNIForClass(Redefinition.class);
+ }
+
+ public static final class CommonClassDefinition {
+ public final Class<?> target;
+ public final byte[] class_file_bytes;
+ public final byte[] dex_file_bytes;
+
+ public CommonClassDefinition(Class<?> target, byte[] class_file_bytes, byte[] dex_file_bytes) {
+ this.target = target;
+ this.class_file_bytes = class_file_bytes;
+ this.dex_file_bytes = dex_file_bytes;
+ }
+ }
+
+ // A set of possible test configurations. Test should set this if they need to.
+ // This must be kept in sync with the defines in ti-agent/common_helper.cc
+ public static enum Config {
+ COMMON_REDEFINE(0),
+ COMMON_RETRANSFORM(1),
+ COMMON_TRANSFORM(2);
+
+ private final int val;
+ private Config(int val) {
+ this.val = val;
+ }
+ }
+
+ public static void setTestConfiguration(Config type) {
+ nativeSetTestConfiguration(type.val);
+ }
+
+ private static native void nativeSetTestConfiguration(int type);
+
+ // Transforms the class
+ public static native void doCommonClassRedefinition(Class<?> target,
+ byte[] classfile,
+ byte[] dexfile);
+
+ public static void doMultiClassRedefinition(CommonClassDefinition... defs) {
+ ArrayList<Class<?>> classes = new ArrayList<>();
+ ArrayList<byte[]> class_files = new ArrayList<>();
+ ArrayList<byte[]> dex_files = new ArrayList<>();
+
+ for (CommonClassDefinition d : defs) {
+ classes.add(d.target);
+ class_files.add(d.class_file_bytes);
+ dex_files.add(d.dex_file_bytes);
+ }
+ doCommonMultiClassRedefinition(classes.toArray(new Class<?>[0]),
+ class_files.toArray(new byte[0][]),
+ dex_files.toArray(new byte[0][]));
+ }
+
+ public static void addMultiTransformationResults(CommonClassDefinition... defs) {
+ for (CommonClassDefinition d : defs) {
+ addCommonTransformationResult(d.target.getCanonicalName(),
+ d.class_file_bytes,
+ d.dex_file_bytes);
+ }
+ }
+
+ public static native void doCommonMultiClassRedefinition(Class<?>[] targets,
+ byte[][] classfiles,
+ byte[][] dexfiles);
+ public static native void doCommonClassRetransformation(Class<?>... target);
+ public static native void setPopRetransformations(boolean pop);
+ public static native void popTransformationFor(String name);
+ public static native void enableCommonRetransformation(boolean enable);
+ public static native void addCommonTransformationResult(String target_name,
+ byte[] class_bytes,
+ byte[] dex_bytes);
+}
diff --git a/test/949-in-memory-transform/src/art/Test949.java b/test/949-in-memory-transform/src/art/Test949.java
new file mode 100644
index 0000000..cd733b9
--- /dev/null
+++ b/test/949-in-memory-transform/src/art/Test949.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package art;
+
+import static art.Redefinition.doCommonClassRedefinition;
+
+import java.util.Base64;
+import java.lang.reflect.*;
+import java.nio.ByteBuffer;
+
+public class Test949 {
+ /**
+ * base64 encoded class/dex file for
+ * public class Transform {
+ * public void sayHi() {
+ * System.out.println("hello");
+ * }
+ * }
+ */
+ private static final byte[] INITIAL_CLASS_BYTES = Base64.getDecoder().decode(
+ "yv66vgAAADQAHAoABgAOCQAPABAIABEKABIAEwcAFAcAFQEABjxpbml0PgEAAygpVgEABENvZGUB" +
+ "AA9MaW5lTnVtYmVyVGFibGUBAAVzYXlIaQEAClNvdXJjZUZpbGUBAA5UcmFuc2Zvcm0uamF2YQwA" +
+ "BwAIBwAWDAAXABgBAAVoZWxsbwcAGQwAGgAbAQAJVHJhbnNmb3JtAQAQamF2YS9sYW5nL09iamVj" +
+ "dAEAEGphdmEvbGFuZy9TeXN0ZW0BAANvdXQBABVMamF2YS9pby9QcmludFN0cmVhbTsBABNqYXZh" +
+ "L2lvL1ByaW50U3RyZWFtAQAHcHJpbnRsbgEAFShMamF2YS9sYW5nL1N0cmluZzspVgAhAAUABgAA" +
+ "AAAAAgABAAcACAABAAkAAAAdAAEAAQAAAAUqtwABsQAAAAEACgAAAAYAAQAAABEAAQALAAgAAQAJ" +
+ "AAAAJQACAAEAAAAJsgACEgO2AASxAAAAAQAKAAAACgACAAAAGgAIABsAAQAMAAAAAgAN");
+ private static final byte[] INITIAL_DEX_BYTES = Base64.getDecoder().decode(
+ "ZGV4CjAzNQAJX3mZphwHJCT1qdTz/GS+jXOR+O/9e3fMAgAAcAAAAHhWNBIAAAAAAAAAACwCAAAO" +
+ "AAAAcAAAAAYAAACoAAAAAgAAAMAAAAABAAAA2AAAAAQAAADgAAAAAQAAAAABAACsAQAAIAEAAGIB" +
+ "AABqAQAAdwEAAI4BAACiAQAAtgEAAMoBAADaAQAA3QEAAOEBAAD1AQAA/AEAAAECAAAKAgAAAQAA" +
+ "AAIAAAADAAAABAAAAAUAAAAHAAAABwAAAAUAAAAAAAAACAAAAAUAAABcAQAABAABAAsAAAAAAAAA" +
+ "AAAAAAAAAAANAAAAAQABAAwAAAACAAAAAAAAAAAAAAABAAAAAgAAAAAAAAAGAAAAAAAAABwCAAAA" +
+ "AAAAAQABAAEAAAARAgAABAAAAHAQAwAAAA4AAwABAAIAAAAWAgAACQAAAGIAAAAbAQoAAABuIAIA" +
+ "EAAOAAAAAQAAAAMABjxpbml0PgALTFRyYW5zZm9ybTsAFUxqYXZhL2lvL1ByaW50U3RyZWFtOwAS" +
+ "TGphdmEvbGFuZy9PYmplY3Q7ABJMamF2YS9sYW5nL1N0cmluZzsAEkxqYXZhL2xhbmcvU3lzdGVt" +
+ "OwAOVHJhbnNmb3JtLmphdmEAAVYAAlZMABJlbWl0dGVyOiBqYWNrLTQuMjUABWhlbGxvAANvdXQA" +
+ "B3ByaW50bG4ABXNheUhpABEABw4AGgAHDocAAAABAQCBgASgAgEBuAIAAA0AAAAAAAAAAQAAAAAA" +
+ "AAABAAAADgAAAHAAAAACAAAABgAAAKgAAAADAAAAAgAAAMAAAAAEAAAAAQAAANgAAAAFAAAABAAA" +
+ "AOAAAAAGAAAAAQAAAAABAAABIAAAAgAAACABAAABEAAAAQAAAFwBAAACIAAADgAAAGIBAAADIAAA" +
+ "AgAAABECAAAAIAAAAQAAABwCAAAAEAAAAQAAACwCAAA=");
+
+
+ /**
+ * base64 encoded class/dex file for
+ * public class Transform {
+ * public void sayHi() {
+ * System.out.println("Goodbye");
+ * }
+ * }
+ */
+ private static final byte[] TRANSFORMED_CLASS_BYTES = Base64.getDecoder().decode(
+ "yv66vgAAADQAHAoABgAOCQAPABAIABEKABIAEwcAFAcAFQEABjxpbml0PgEAAygpVgEABENvZGUB" +
+ "AA9MaW5lTnVtYmVyVGFibGUBAAVzYXlIaQEAClNvdXJjZUZpbGUBAA5UcmFuc2Zvcm0uamF2YQwA" +
+ "BwAIBwAWDAAXABgBAAdHb29kYnllBwAZDAAaABsBAAlUcmFuc2Zvcm0BABBqYXZhL2xhbmcvT2Jq" +
+ "ZWN0AQAQamF2YS9sYW5nL1N5c3RlbQEAA291dAEAFUxqYXZhL2lvL1ByaW50U3RyZWFtOwEAE2ph" +
+ "dmEvaW8vUHJpbnRTdHJlYW0BAAdwcmludGxuAQAVKExqYXZhL2xhbmcvU3RyaW5nOylWACEABQAG" +
+ "AAAAAAACAAEABwAIAAEACQAAAB0AAQABAAAABSq3AAGxAAAAAQAKAAAABgABAAAAEQABAAsACAAB" +
+ "AAkAAAAlAAIAAQAAAAmyAAISA7YABLEAAAABAAoAAAAKAAIAAAAaAAgAGwABAAwAAAACAA0=");
+ private static final byte[] TRANSFORMED_DEX_BYTES = Base64.getDecoder().decode(
+ "ZGV4CjAzNQAPXh6T3l1FObhHsKf1U2vi+0GmAvElxBLMAgAAcAAAAHhWNBIAAAAAAAAAACwCAAAO" +
+ "AAAAcAAAAAYAAACoAAAAAgAAAMAAAAABAAAA2AAAAAQAAADgAAAAAQAAAAABAACsAQAAIAEAAGIB" +
+ "AABqAQAAcwEAAIABAACXAQAAqwEAAL8BAADTAQAA4wEAAOYBAADqAQAA/gEAAAMCAAAMAgAAAgAA" +
+ "AAMAAAAEAAAABQAAAAYAAAAIAAAACAAAAAUAAAAAAAAACQAAAAUAAABcAQAABAABAAsAAAAAAAAA" +
+ "AAAAAAAAAAANAAAAAQABAAwAAAACAAAAAAAAAAAAAAABAAAAAgAAAAAAAAAHAAAAAAAAAB4CAAAA" +
+ "AAAAAQABAAEAAAATAgAABAAAAHAQAwAAAA4AAwABAAIAAAAYAgAACQAAAGIAAAAbAQEAAABuIAIA" +
+ "EAAOAAAAAQAAAAMABjxpbml0PgAHR29vZGJ5ZQALTFRyYW5zZm9ybTsAFUxqYXZhL2lvL1ByaW50" +
+ "U3RyZWFtOwASTGphdmEvbGFuZy9PYmplY3Q7ABJMamF2YS9sYW5nL1N0cmluZzsAEkxqYXZhL2xh" +
+ "bmcvU3lzdGVtOwAOVHJhbnNmb3JtLmphdmEAAVYAAlZMABJlbWl0dGVyOiBqYWNrLTQuMjUAA291" +
+ "dAAHcHJpbnRsbgAFc2F5SGkAEQAHDgAaAAcOhwAAAAEBAIGABKACAQG4Ag0AAAAAAAAAAQAAAAAA" +
+ "AAABAAAADgAAAHAAAAACAAAABgAAAKgAAAADAAAAAgAAAMAAAAAEAAAAAQAAANgAAAAFAAAABAAA" +
+ "AOAAAAAGAAAAAQAAAAABAAABIAAAAgAAACABAAABEAAAAQAAAFwBAAACIAAADgAAAGIBAAADIAAA" +
+ "AgAAABMCAAAAIAAAAQAAAB4CAAAAEAAAAQAAACwCAAA=");
+
+ public static void run() throws Exception {
+ ClassLoader loader;
+ try {
+ // Art uses this classloader to do in-memory dex files. There is no support for defineClass
+ loader = (ClassLoader)Class.forName("dalvik.system.InMemoryDexClassLoader")
+ .getConstructor(ByteBuffer.class, ClassLoader.class)
+ .newInstance(ByteBuffer.wrap(INITIAL_DEX_BYTES),
+ ClassLoader.getSystemClassLoader());
+ } catch (ClassNotFoundException e) {
+ // Seem to be on RI. Just make a new ClassLoader that calls defineClass.
+ loader = new ClassLoader() {
+ public Class<?> findClass(String name) throws ClassNotFoundException {
+ if (name.equals("Transform")) {
+ return defineClass(name, INITIAL_CLASS_BYTES, 0, INITIAL_CLASS_BYTES.length);
+ } else {
+ throw new ClassNotFoundException("Couldn't find class: " + name);
+ }
+ }
+ };
+ }
+ doTest(loader);
+ }
+
+ public static void doTest(ClassLoader loader) throws Exception {
+ // Get the class
+ Class<?> transform_class = loader.loadClass("Transform");
+ Method say_hi_method = transform_class.getMethod("sayHi");
+ Object t = transform_class.newInstance();
+
+ // Run the actual test.
+ say_hi_method.invoke(t);
+ doCommonClassRedefinition(transform_class, TRANSFORMED_CLASS_BYTES, TRANSFORMED_DEX_BYTES);
+ say_hi_method.invoke(t);
+ }
+}
diff --git a/test/950-redefine-intrinsic/src/Main.java b/test/950-redefine-intrinsic/src/Main.java
index 2578d6e..369a8f4 100644
--- a/test/950-redefine-intrinsic/src/Main.java
+++ b/test/950-redefine-intrinsic/src/Main.java
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+import static art.Redefinition.doCommonClassRedefinition;
import java.util.Base64;
import java.util.Random;
import java.util.function.*;
@@ -464,9 +465,4 @@
}
System.out.println("Finished!");
}
-
- // Transforms the class
- private static native void doCommonClassRedefinition(Class<?> target,
- byte[] class_file,
- byte[] dex_file);
}
diff --git a/test/950-redefine-intrinsic/src/art/Redefinition.java b/test/950-redefine-intrinsic/src/art/Redefinition.java
new file mode 100644
index 0000000..0350ab4
--- /dev/null
+++ b/test/950-redefine-intrinsic/src/art/Redefinition.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package art;
+
+import java.util.ArrayList;
+// Common Redefinition functions. Placed here for use by CTS
+public class Redefinition {
+ // Bind native functions.
+ static {
+ Main.bindAgentJNIForClass(Redefinition.class);
+ }
+
+ public static final class CommonClassDefinition {
+ public final Class<?> target;
+ public final byte[] class_file_bytes;
+ public final byte[] dex_file_bytes;
+
+ public CommonClassDefinition(Class<?> target, byte[] class_file_bytes, byte[] dex_file_bytes) {
+ this.target = target;
+ this.class_file_bytes = class_file_bytes;
+ this.dex_file_bytes = dex_file_bytes;
+ }
+ }
+
+ // A set of possible test configurations. Test should set this if they need to.
+ // This must be kept in sync with the defines in ti-agent/common_helper.cc
+ public static enum Config {
+ COMMON_REDEFINE(0),
+ COMMON_RETRANSFORM(1),
+ COMMON_TRANSFORM(2);
+
+ private final int val;
+ private Config(int val) {
+ this.val = val;
+ }
+ }
+
+ public static void setTestConfiguration(Config type) {
+ nativeSetTestConfiguration(type.val);
+ }
+
+ private static native void nativeSetTestConfiguration(int type);
+
+ // Transforms the class
+ public static native void doCommonClassRedefinition(Class<?> target,
+ byte[] classfile,
+ byte[] dexfile);
+
+ public static void doMultiClassRedefinition(CommonClassDefinition... defs) {
+ ArrayList<Class<?>> classes = new ArrayList<>();
+ ArrayList<byte[]> class_files = new ArrayList<>();
+ ArrayList<byte[]> dex_files = new ArrayList<>();
+
+ for (CommonClassDefinition d : defs) {
+ classes.add(d.target);
+ class_files.add(d.class_file_bytes);
+ dex_files.add(d.dex_file_bytes);
+ }
+ doCommonMultiClassRedefinition(classes.toArray(new Class<?>[0]),
+ class_files.toArray(new byte[0][]),
+ dex_files.toArray(new byte[0][]));
+ }
+
+ public static void addMultiTransformationResults(CommonClassDefinition... defs) {
+ for (CommonClassDefinition d : defs) {
+ addCommonTransformationResult(d.target.getCanonicalName(),
+ d.class_file_bytes,
+ d.dex_file_bytes);
+ }
+ }
+
+ public static native void doCommonMultiClassRedefinition(Class<?>[] targets,
+ byte[][] classfiles,
+ byte[][] dexfiles);
+ public static native void doCommonClassRetransformation(Class<?>... target);
+ public static native void setPopRetransformations(boolean pop);
+ public static native void popTransformationFor(String name);
+ public static native void enableCommonRetransformation(boolean enable);
+ public static native void addCommonTransformationResult(String target_name,
+ byte[] class_bytes,
+ byte[] dex_bytes);
+}
diff --git a/test/951-threaded-obsolete/src/Main.java b/test/951-threaded-obsolete/src/Main.java
index a82090e..d245aa9 100644
--- a/test/951-threaded-obsolete/src/Main.java
+++ b/test/951-threaded-obsolete/src/Main.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,84 +14,8 @@
* limitations under the License.
*/
-import java.util.Base64;
-import java.util.concurrent.Semaphore;
-
public class Main {
- // class Transform {
- // public void sayHi(Runnable r) {
- // System.out.println("Hello - Transformed");
- // r.run();
- // System.out.println("Goodbye - Transformed");
- // }
- // }
- private static final byte[] CLASS_BYTES = Base64.getDecoder().decode(
- "yv66vgAAADQAJAoACAARCQASABMIABQKABUAFgsAFwAYCAAZBwAaBwAbAQAGPGluaXQ+AQADKClW" +
- "AQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEABXNheUhpAQAXKExqYXZhL2xhbmcvUnVubmFibGU7" +
- "KVYBAApTb3VyY2VGaWxlAQAOVHJhbnNmb3JtLmphdmEMAAkACgcAHAwAHQAeAQATSGVsbG8gLSBU" +
- "cmFuc2Zvcm1lZAcAHwwAIAAhBwAiDAAjAAoBABVHb29kYnllIC0gVHJhbnNmb3JtZWQBAAlUcmFu" +
- "c2Zvcm0BABBqYXZhL2xhbmcvT2JqZWN0AQAQamF2YS9sYW5nL1N5c3RlbQEAA291dAEAFUxqYXZh" +
- "L2lvL1ByaW50U3RyZWFtOwEAE2phdmEvaW8vUHJpbnRTdHJlYW0BAAdwcmludGxuAQAVKExqYXZh" +
- "L2xhbmcvU3RyaW5nOylWAQASamF2YS9sYW5nL1J1bm5hYmxlAQADcnVuACAABwAIAAAAAAACAAAA" +
- "CQAKAAEACwAAAB0AAQABAAAABSq3AAGxAAAAAQAMAAAABgABAAAAAQABAA0ADgABAAsAAAA7AAIA" +
- "AgAAABeyAAISA7YABCu5AAUBALIAAhIGtgAEsQAAAAEADAAAABIABAAAAAMACAAEAA4ABQAWAAYA" +
- "AQAPAAAAAgAQ");
- private static final byte[] DEX_BYTES = Base64.getDecoder().decode(
- "ZGV4CjAzNQAYeAMMXgYWxoeSHAS9EWKCCtVRSAGpqZVQAwAAcAAAAHhWNBIAAAAAAAAAALACAAAR" +
- "AAAAcAAAAAcAAAC0AAAAAwAAANAAAAABAAAA9AAAAAUAAAD8AAAAAQAAACQBAAAMAgAARAEAAKIB" +
- "AACqAQAAwQEAANYBAADjAQAA+gEAAA4CAAAkAgAAOAIAAEwCAABcAgAAXwIAAGMCAAB3AgAAfAIA" +
- "AIUCAACKAgAAAwAAAAQAAAAFAAAABgAAAAcAAAAIAAAACgAAAAoAAAAGAAAAAAAAAAsAAAAGAAAA" +
- "lAEAAAsAAAAGAAAAnAEAAAUAAQANAAAAAAAAAAAAAAAAAAEAEAAAAAEAAgAOAAAAAgAAAAAAAAAD" +
- "AAAADwAAAAAAAAAAAAAAAgAAAAAAAAAJAAAAAAAAAJ8CAAAAAAAAAQABAAEAAACRAgAABAAAAHAQ" +
- "AwAAAA4ABAACAAIAAACWAgAAFAAAAGIAAAAbAQIAAABuIAIAEAByEAQAAwBiAAAAGwEBAAAAbiAC" +
- "ABAADgABAAAAAwAAAAEAAAAEAAY8aW5pdD4AFUdvb2RieWUgLSBUcmFuc2Zvcm1lZAATSGVsbG8g" +
- "LSBUcmFuc2Zvcm1lZAALTFRyYW5zZm9ybTsAFUxqYXZhL2lvL1ByaW50U3RyZWFtOwASTGphdmEv" +
- "bGFuZy9PYmplY3Q7ABRMamF2YS9sYW5nL1J1bm5hYmxlOwASTGphdmEvbGFuZy9TdHJpbmc7ABJM" +
- "amF2YS9sYW5nL1N5c3RlbTsADlRyYW5zZm9ybS5qYXZhAAFWAAJWTAASZW1pdHRlcjogamFjay00" +
- "LjEzAANvdXQAB3ByaW50bG4AA3J1bgAFc2F5SGkAAQAHDgADAQAHDoc8hwAAAAEBAICABMQCAQHc" +
- "AgAAAA0AAAAAAAAAAQAAAAAAAAABAAAAEQAAAHAAAAACAAAABwAAALQAAAADAAAAAwAAANAAAAAE" +
- "AAAAAQAAAPQAAAAFAAAABQAAAPwAAAAGAAAAAQAAACQBAAABIAAAAgAAAEQBAAABEAAAAgAAAJQB" +
- "AAACIAAAEQAAAKIBAAADIAAAAgAAAJECAAAAIAAAAQAAAJ8CAAAAEAAAAQAAALACAAA=");
-
- public static void main(String[] args) {
- art.Main.bindAgentJNIForClass(Main.class);
- // Semaphores to let each thread know where the other is. We could use barriers but semaphores
- // mean we don't need to have the worker thread be waiting around.
- final Semaphore sem_redefine_start = new Semaphore(0);
- final Semaphore sem_redefine_end = new Semaphore(0);
- // Create a thread to do the actual redefinition. We will just communicate through an
- // atomic-integer.
- new Thread(() -> {
- try {
- // Wait for the other thread to ask for redefinition.
- sem_redefine_start.acquire();
- // Do the redefinition.
- doCommonClassRedefinition(Transform.class, CLASS_BYTES, DEX_BYTES);
- // Allow the other thread to wake up if it is waiting.
- sem_redefine_end.release();
- } catch (InterruptedException e) {
- throw new Error("unable to do redefinition", e);
- }
- }).start();
-
- Transform t = new Transform();
- t.sayHi(() -> { System.out.println("Not doing anything here"); });
- t.sayHi(() -> {
- try {
- System.out.println("transforming calling function");
- // Wake up the waiting thread.
- sem_redefine_start.release();
- // Wait for the other thread to finish with redefinition.
- sem_redefine_end.acquire();
- } catch (InterruptedException e) {
- throw new Error("unable to do redefinition", e);
- }
- });
- t.sayHi(() -> { System.out.println("Not doing anything here"); });
+ public static void main(String[] args) throws Exception {
+ art.Test951.run();
}
-
- // Transforms the class
- private static native void doCommonClassRedefinition(Class<?> target,
- byte[] classfile,
- byte[] dexfile);
}
diff --git a/test/951-threaded-obsolete/src/Transform.java b/test/951-threaded-obsolete/src/Transform.java
deleted file mode 100644
index 8cda6cd..0000000
--- a/test/951-threaded-obsolete/src/Transform.java
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-class Transform {
- public void sayHi(Runnable r) {
- // Use lower 'h' to make sure the string will have a different string id
- // than the transformation (the transformation code is the same except
- // the actual printed String, which was making the test inacurately passing
- // in JIT mode when loading the string from the dex cache, as the string ids
- // of the two different strings were the same).
- // We know the string ids will be different because lexicographically:
- // "Hello" < "LTransform;" < "hello".
- System.out.println("hello");
- r.run();
- System.out.println("goodbye");
- }
-}
diff --git a/test/951-threaded-obsolete/src/art/Redefinition.java b/test/951-threaded-obsolete/src/art/Redefinition.java
new file mode 100644
index 0000000..0350ab4
--- /dev/null
+++ b/test/951-threaded-obsolete/src/art/Redefinition.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package art;
+
+import java.util.ArrayList;
+// Common Redefinition functions. Placed here for use by CTS
+public class Redefinition {
+ // Bind native functions.
+ static {
+ Main.bindAgentJNIForClass(Redefinition.class);
+ }
+
+ public static final class CommonClassDefinition {
+ public final Class<?> target;
+ public final byte[] class_file_bytes;
+ public final byte[] dex_file_bytes;
+
+ public CommonClassDefinition(Class<?> target, byte[] class_file_bytes, byte[] dex_file_bytes) {
+ this.target = target;
+ this.class_file_bytes = class_file_bytes;
+ this.dex_file_bytes = dex_file_bytes;
+ }
+ }
+
+ // A set of possible test configurations. Test should set this if they need to.
+ // This must be kept in sync with the defines in ti-agent/common_helper.cc
+ public static enum Config {
+ COMMON_REDEFINE(0),
+ COMMON_RETRANSFORM(1),
+ COMMON_TRANSFORM(2);
+
+ private final int val;
+ private Config(int val) {
+ this.val = val;
+ }
+ }
+
+ public static void setTestConfiguration(Config type) {
+ nativeSetTestConfiguration(type.val);
+ }
+
+ private static native void nativeSetTestConfiguration(int type);
+
+ // Transforms the class
+ public static native void doCommonClassRedefinition(Class<?> target,
+ byte[] classfile,
+ byte[] dexfile);
+
+ public static void doMultiClassRedefinition(CommonClassDefinition... defs) {
+ ArrayList<Class<?>> classes = new ArrayList<>();
+ ArrayList<byte[]> class_files = new ArrayList<>();
+ ArrayList<byte[]> dex_files = new ArrayList<>();
+
+ for (CommonClassDefinition d : defs) {
+ classes.add(d.target);
+ class_files.add(d.class_file_bytes);
+ dex_files.add(d.dex_file_bytes);
+ }
+ doCommonMultiClassRedefinition(classes.toArray(new Class<?>[0]),
+ class_files.toArray(new byte[0][]),
+ dex_files.toArray(new byte[0][]));
+ }
+
+ public static void addMultiTransformationResults(CommonClassDefinition... defs) {
+ for (CommonClassDefinition d : defs) {
+ addCommonTransformationResult(d.target.getCanonicalName(),
+ d.class_file_bytes,
+ d.dex_file_bytes);
+ }
+ }
+
+ public static native void doCommonMultiClassRedefinition(Class<?>[] targets,
+ byte[][] classfiles,
+ byte[][] dexfiles);
+ public static native void doCommonClassRetransformation(Class<?>... target);
+ public static native void setPopRetransformations(boolean pop);
+ public static native void popTransformationFor(String name);
+ public static native void enableCommonRetransformation(boolean enable);
+ public static native void addCommonTransformationResult(String target_name,
+ byte[] class_bytes,
+ byte[] dex_bytes);
+}
diff --git a/test/951-threaded-obsolete/src/art/Test951.java b/test/951-threaded-obsolete/src/art/Test951.java
new file mode 100644
index 0000000..3628f4f
--- /dev/null
+++ b/test/951-threaded-obsolete/src/art/Test951.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package art;
+
+import java.util.Base64;
+import java.util.concurrent.Semaphore;
+
+public class Test951 {
+
+ static class Transform {
+ public void sayHi(Runnable r) {
+ System.out.println("hello");
+ r.run();
+ System.out.println("goodbye");
+ }
+ }
+
+ // static class Transform {
+ // public void sayHi(Runnable r) {
+ // System.out.println("Hello - Transformed");
+ // r.run();
+ // System.out.println("Goodbye - Transformed");
+ // }
+ // }
+ private static final byte[] CLASS_BYTES = Base64.getDecoder().decode(
+ "yv66vgAAADQAKAoACAARCQASABMIABQKABUAFgsAFwAYCAAZBwAbBwAeAQAGPGluaXQ+AQADKClW" +
+ "AQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEABXNheUhpAQAXKExqYXZhL2xhbmcvUnVubmFibGU7" +
+ "KVYBAApTb3VyY2VGaWxlAQAMVGVzdDk1MS5qYXZhDAAJAAoHAB8MACAAIQEAE0hlbGxvIC0gVHJh" +
+ "bnNmb3JtZWQHACIMACMAJAcAJQwAJgAKAQAVR29vZGJ5ZSAtIFRyYW5zZm9ybWVkBwAnAQAVYXJ0" +
+ "L1Rlc3Q5NTEkVHJhbnNmb3JtAQAJVHJhbnNmb3JtAQAMSW5uZXJDbGFzc2VzAQAQamF2YS9sYW5n" +
+ "L09iamVjdAEAEGphdmEvbGFuZy9TeXN0ZW0BAANvdXQBABVMamF2YS9pby9QcmludFN0cmVhbTsB" +
+ "ABNqYXZhL2lvL1ByaW50U3RyZWFtAQAHcHJpbnRsbgEAFShMamF2YS9sYW5nL1N0cmluZzspVgEA" +
+ "EmphdmEvbGFuZy9SdW5uYWJsZQEAA3J1bgEAC2FydC9UZXN0OTUxACAABwAIAAAAAAACAAAACQAK" +
+ "AAEACwAAAB0AAQABAAAABSq3AAGxAAAAAQAMAAAABgABAAAABQABAA0ADgABAAsAAAA7AAIAAgAA" +
+ "ABeyAAISA7YABCu5AAUBALIAAhIGtgAEsQAAAAEADAAAABIABAAAAAcACAAIAA4ACQAWAAoAAgAP" +
+ "AAAAAgAQAB0AAAAKAAEABwAaABwACA==");
+ private static final byte[] DEX_BYTES = Base64.getDecoder().decode(
+ "ZGV4CjAzNQBom/JeAAAAAAAAAAAAAAAAAAAAAAAAAAA8BAAAcAAAAHhWNBIAAAAAAAAAAHgDAAAX" +
+ "AAAAcAAAAAoAAADMAAAAAwAAAPQAAAABAAAAGAEAAAUAAAAgAQAAAQAAAEgBAADUAgAAaAEAAGgB" +
+ "AABwAQAAhwEAAJwBAAC1AQAAxAEAAOgBAAAIAgAAHwIAADMCAABJAgAAXQIAAHECAAB/AgAAigIA" +
+ "AI0CAACRAgAAngIAAKQCAACpAgAAsgIAALcCAAC+AgAAAwAAAAQAAAAFAAAABgAAAAcAAAAIAAAA" +
+ "CQAAAAoAAAALAAAADgAAAA4AAAAJAAAAAAAAAA8AAAAJAAAAyAIAAA8AAAAJAAAA0AIAAAgABAAS" +
+ "AAAAAAAAAAAAAAAAAAEAFQAAAAQAAgATAAAABQAAAAAAAAAGAAAAFAAAAAAAAAAAAAAABQAAAAAA" +
+ "AAAMAAAAaAMAADwDAAAAAAAABjxpbml0PgAVR29vZGJ5ZSAtIFRyYW5zZm9ybWVkABNIZWxsbyAt" +
+ "IFRyYW5zZm9ybWVkABdMYXJ0L1Rlc3Q5NTEkVHJhbnNmb3JtOwANTGFydC9UZXN0OTUxOwAiTGRh" +
+ "bHZpay9hbm5vdGF0aW9uL0VuY2xvc2luZ0NsYXNzOwAeTGRhbHZpay9hbm5vdGF0aW9uL0lubmVy" +
+ "Q2xhc3M7ABVMamF2YS9pby9QcmludFN0cmVhbTsAEkxqYXZhL2xhbmcvT2JqZWN0OwAUTGphdmEv" +
+ "bGFuZy9SdW5uYWJsZTsAEkxqYXZhL2xhbmcvU3RyaW5nOwASTGphdmEvbGFuZy9TeXN0ZW07AAxU" +
+ "ZXN0OTUxLmphdmEACVRyYW5zZm9ybQABVgACVkwAC2FjY2Vzc0ZsYWdzAARuYW1lAANvdXQAB3By" +
+ "aW50bG4AA3J1bgAFc2F5SGkABXZhbHVlAAAAAAEAAAAGAAAAAQAAAAcAAAAFAAcOAAcBAAcOAQgP" +
+ "AQMPAQgPAAEAAQABAAAA2AIAAAQAAABwEAMAAAAOAAQAAgACAAAA3QIAABQAAABiAAAAGwECAAAA" +
+ "biACABAAchAEAAMAYgAAABsBAQAAAG4gAgAQAA4AAAABAQCAgATsBQEBhAYAAAICARYYAQIDAhAE" +
+ "CBEXDQACAAAATAMAAFIDAABcAwAAAAAAAAAAAAAAAAAAEAAAAAAAAAABAAAAAAAAAAEAAAAXAAAA" +
+ "cAAAAAIAAAAKAAAAzAAAAAMAAAADAAAA9AAAAAQAAAABAAAAGAEAAAUAAAAFAAAAIAEAAAYAAAAB" +
+ "AAAASAEAAAIgAAAXAAAAaAEAAAEQAAACAAAAyAIAAAMgAAACAAAA2AIAAAEgAAACAAAA7AIAAAAg" +
+ "AAABAAAAPAMAAAQgAAACAAAATAMAAAMQAAABAAAAXAMAAAYgAAABAAAAaAMAAAAQAAABAAAAeAMA" +
+ "AA==");
+
+ public static void run() {
+ // Semaphores to let each thread know where the other is. We could use barriers but semaphores
+ // mean we don't need to have the worker thread be waiting around.
+ final Semaphore sem_redefine_start = new Semaphore(0);
+ final Semaphore sem_redefine_end = new Semaphore(0);
+ // Create a thread to do the actual redefinition. We will just communicate through an
+ // atomic-integer.
+ new Thread(() -> {
+ try {
+ // Wait for the other thread to ask for redefinition.
+ sem_redefine_start.acquire();
+ // Do the redefinition.
+ Redefinition.doCommonClassRedefinition(Transform.class, CLASS_BYTES, DEX_BYTES);
+ // Allow the other thread to wake up if it is waiting.
+ sem_redefine_end.release();
+ } catch (InterruptedException e) {
+ throw new Error("unable to do redefinition", e);
+ }
+ }).start();
+
+ Transform t = new Transform();
+ t.sayHi(() -> { System.out.println("Not doing anything here"); });
+ t.sayHi(() -> {
+ try {
+ System.out.println("transforming calling function");
+ // Wake up the waiting thread.
+ sem_redefine_start.release();
+ // Wait for the other thread to finish with redefinition.
+ sem_redefine_end.acquire();
+ } catch (InterruptedException e) {
+ throw new Error("unable to do redefinition", e);
+ }
+ });
+ t.sayHi(() -> { System.out.println("Not doing anything here"); });
+ }
+}
diff --git a/test/959-invoke-polymorphic-accessors/src/Main.java b/test/959-invoke-polymorphic-accessors/src/Main.java
index b7ecf8e..59db807 100644
--- a/test/959-invoke-polymorphic-accessors/src/Main.java
+++ b/test/959-invoke-polymorphic-accessors/src/Main.java
@@ -794,6 +794,7 @@
ValueHolder valueHolder = new ValueHolder();
MethodHandles.Lookup lookup = MethodHandles.lookup();
MethodHandle h0 = lookup.findSetter(ValueHolder.class, "m_f", float.class);
+ MethodHandle s0 = lookup.findSetter(ValueHolder.class, "m_s", short.class);
h0.invoke(valueHolder, 0.22f);
h0.invoke(valueHolder, new Float(1.11f));
Number floatNumber = getFloatAsNumber();
@@ -807,6 +808,11 @@
unreachable();
} catch (NullPointerException e) {}
+ // Test that type conversion checks work on small field types.
+ short temp = (short)s0.invoke(valueHolder, new Byte((byte)45));
+ assertTrue(temp == 0);
+ assertTrue(valueHolder.m_s == 45);
+
h0.invoke(valueHolder, (byte)1);
h0.invoke(valueHolder, (short)2);
h0.invoke(valueHolder, 3);
@@ -848,6 +854,7 @@
private static void testStaticSetter() throws Throwable {
MethodHandles.Lookup lookup = MethodHandles.lookup();
+ MethodHandle s0 = lookup.findStaticSetter(ValueHolder.class, "s_s", short.class);
MethodHandle h0 = lookup.findStaticSetter(ValueHolder.class, "s_f", float.class);
h0.invoke(0.22f);
h0.invoke(new Float(1.11f));
@@ -860,6 +867,11 @@
unreachable();
} catch (NullPointerException e) {}
+ // Test that type conversion checks work on small field types.
+ short temp = (short)s0.invoke(new Byte((byte)45));
+ assertTrue(temp == 0);
+ assertTrue(ValueHolder.s_s == 45);
+
h0.invoke((byte)1);
h0.invoke((short)2);
h0.invoke(3);
diff --git a/test/980-redefine-object/check b/test/980-redefine-object/check
index 987066f..07b21b3 100755
--- a/test/980-redefine-object/check
+++ b/test/980-redefine-object/check
@@ -17,4 +17,4 @@
# The number of paused background threads (and therefore InterruptedExceptions)
# can change so we will just delete their lines from the log.
-sed "/Object allocated of type 'Ljava\/lang\/InterruptedException;'/d" "$2" | diff --strip-trailing-cr -q "$1" - >/dev/null
+sed "/Object allocated of type 'java\.lang\.InterruptedException'/d" "$2" | diff --strip-trailing-cr -q "$1" - >/dev/null
diff --git a/test/980-redefine-object/expected.txt b/test/980-redefine-object/expected.txt
index 6e9bce0..4c294bc 100644
--- a/test/980-redefine-object/expected.txt
+++ b/test/980-redefine-object/expected.txt
@@ -2,51 +2,31 @@
Allocating an j.l.Object before redefining Object class
Allocating a Transform before redefining Object class
Redefining the Object class to add a hook into the <init> method
-Object allocated of type 'Ljava/lang/StringBuilder;'
-Object allocated of type 'Ljava/nio/HeapCharBuffer;'
Allocating an j.l.Object after redefining Object class
-Object allocated of type 'Ljava/lang/Object;'
-Object allocated of type 'Ljava/lang/StringBuilder;'
-Object allocated of type 'Ljava/nio/HeapCharBuffer;'
+Object allocated of type 'java.lang.Object'
Allocating a Transform after redefining Object class
-Object allocated of type 'LTransform;'
-Object allocated of type 'Ljava/lang/StringBuilder;'
-Object allocated of type 'Ljava/nio/HeapCharBuffer;'
+Object allocated of type 'Transform'
Allocating an int[] after redefining Object class
-Object allocated of type 'Ljava/lang/StringBuilder;'
-Object allocated of type 'Ljava/nio/HeapCharBuffer;'
Allocating an array list
-Object allocated of type 'Ljava/util/ArrayList;'
-Object allocated of type 'Ljava/lang/StringBuilder;'
-Object allocated of type 'Ljava/nio/HeapCharBuffer;'
+Object allocated of type 'java.util.ArrayList'
Adding a bunch of stuff to the array list
-Object allocated of type 'Ljava/lang/Object;'
-Object allocated of type 'Ljava/lang/Object;'
-Object allocated of type 'LTransform;'
-Object allocated of type 'Ljava/lang/StringBuilder;'
-Object allocated of type 'Ljava/nio/HeapCharBuffer;'
+Object allocated of type 'java.lang.Object'
+Object allocated of type 'java.lang.Object'
+Object allocated of type 'Transform'
Allocating a linked list
-Object allocated of type 'Ljava/util/LinkedList;'
-Object allocated of type 'Ljava/lang/StringBuilder;'
-Object allocated of type 'Ljava/nio/HeapCharBuffer;'
+Object allocated of type 'java.util.LinkedList'
Adding a bunch of stuff to the linked list
-Object allocated of type 'Ljava/lang/Object;'
-Object allocated of type 'Ljava/util/LinkedList$Node;'
-Object allocated of type 'Ljava/lang/Object;'
-Object allocated of type 'Ljava/util/LinkedList$Node;'
-Object allocated of type 'Ljava/util/LinkedList$Node;'
-Object allocated of type 'Ljava/util/LinkedList$Node;'
-Object allocated of type 'Ljava/util/LinkedList$Node;'
-Object allocated of type 'Ljava/util/LinkedList$Node;'
-Object allocated of type 'LTransform;'
-Object allocated of type 'Ljava/util/LinkedList$Node;'
-Object allocated of type 'Ljava/lang/StringBuilder;'
-Object allocated of type 'Ljava/nio/HeapCharBuffer;'
+Object allocated of type 'java.lang.Object'
+Object allocated of type 'java.util.LinkedList$Node'
+Object allocated of type 'java.lang.Object'
+Object allocated of type 'java.util.LinkedList$Node'
+Object allocated of type 'java.util.LinkedList$Node'
+Object allocated of type 'java.util.LinkedList$Node'
+Object allocated of type 'java.util.LinkedList$Node'
+Object allocated of type 'java.util.LinkedList$Node'
+Object allocated of type 'Transform'
+Object allocated of type 'java.util.LinkedList$Node'
Throwing from down 4 stack frames
-Object allocated of type 'Ljava/lang/Exception;'
-Object allocated of type 'Ljava/lang/StringBuilder;'
-Object allocated of type 'Ljava/nio/HeapCharBuffer;'
+Object allocated of type 'java.lang.Exception'
Exception caught.
-Object allocated of type 'Ljava/lang/StringBuilder;'
-Object allocated of type 'Ljava/nio/HeapCharBuffer;'
Finishing test!
diff --git a/test/980-redefine-object/redefine_object.cc b/test/980-redefine-object/redefine_object.cc
deleted file mode 100644
index 1faf1a1..0000000
--- a/test/980-redefine-object/redefine_object.cc
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <inttypes.h>
-#include <iostream>
-
-#include "android-base/stringprintf.h"
-#include "base/logging.h"
-#include "base/macros.h"
-#include "jni.h"
-#include "jvmti.h"
-#include "scoped_utf_chars.h"
-
-// Test infrastructure
-#include "jni_binder.h"
-#include "jvmti_helper.h"
-#include "test_env.h"
-
-namespace art {
-namespace Test980RedefineObjects {
-
-extern "C" JNIEXPORT void JNICALL Java_Main_bindFunctionsForClass(
- JNIEnv* env, jclass Main_klass ATTRIBUTE_UNUSED, jclass target) {
- BindFunctionsOnClass(jvmti_env, env, target);
-}
-
-extern "C" JNIEXPORT void JNICALL Java_art_test_TestWatcher_NotifyConstructed(
- JNIEnv* env, jclass TestWatcherClass ATTRIBUTE_UNUSED, jobject constructed) {
- char* sig = nullptr;
- char* generic_sig = nullptr;
- if (JvmtiErrorToException(env,
- jvmti_env,
- jvmti_env->GetClassSignature(env->GetObjectClass(constructed),
- &sig,
- &generic_sig))) {
- // Exception.
- return;
- }
- std::cout << "Object allocated of type '" << sig << "'" << std::endl;
- jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(sig));
- jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(generic_sig));
-}
-
-} // namespace Test980RedefineObjects
-} // namespace art
diff --git a/test/980-redefine-object/src-ex/TestWatcher.java b/test/980-redefine-object/src-ex/TestWatcher.java
index d15e688..c38e07b 100644
--- a/test/980-redefine-object/src-ex/TestWatcher.java
+++ b/test/980-redefine-object/src-ex/TestWatcher.java
@@ -16,10 +16,60 @@
package art.test;
+import java.util.concurrent.locks.ReentrantLock;
+
public class TestWatcher {
- // NB This function is native since it is called in the Object.<init> method and so cannot cause
- // any java allocations at all. The normal System.out.print* functions will cause allocations to
- // occur so we cannot use them. This means the easiest way to report the object as being created
- // is to go into native code and do it there.
- public static native void NotifyConstructed(Object o);
+ // Lock to synchronize access to the static state of this class.
+ private static final ReentrantLock lock = new ReentrantLock();
+ private static volatile boolean criticalFailure = false;
+ private static boolean reportingEnabled = true;
+ private static boolean doingReport = false;
+
+ private static void MonitorEnter() {
+ lock.lock();
+ }
+
+ private static void MonitorExit() {
+ // Need to do this manually since we need to notify critical failure but would deadlock if
+ // waited for the unlock.
+ if (!lock.isHeldByCurrentThread()) {
+ NotifyCriticalFailure();
+ throw new IllegalMonitorStateException("Locking error!");
+ } else {
+ lock.unlock();
+ }
+ }
+
+ // Stops reporting. Must be paired with an EnableReporting call.
+ public static void DisableReporting() {
+ MonitorEnter();
+ reportingEnabled = false;
+ }
+
+ // Stops reporting. Must be paired with a DisableReporting call.
+ public static void EnableReporting() {
+ reportingEnabled = true;
+ MonitorExit();
+ }
+
+ public static void NotifyCriticalFailure() {
+ criticalFailure = true;
+ }
+
+ public static void NotifyConstructed(Object o) {
+ if (criticalFailure) {
+ // Something went very wrong. We are probably trying to report it so don't get in the way.
+ return;
+ }
+ MonitorEnter();
+ // We could enter an infinite loop if println allocates (which it does) so we disable
+ // reporting while we are doing a report. Since we are synchronized we won't miss any
+ // allocations.
+ if (reportingEnabled && !doingReport) {
+ doingReport = true;
+ System.out.println("Object allocated of type '" + o.getClass().getName() + "'");
+ doingReport = false;
+ }
+ MonitorExit();
+ }
}
diff --git a/test/980-redefine-object/src/Main.java b/test/980-redefine-object/src/Main.java
index a50215e..63c0cab 100644
--- a/test/980-redefine-object/src/Main.java
+++ b/test/980-redefine-object/src/Main.java
@@ -14,6 +14,9 @@
* limitations under the License.
*/
+import static art.Redefinition.doCommonClassRedefinition;
+
+import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Base64;
import java.util.LinkedList;
@@ -287,6 +290,31 @@
private static final String LISTENER_LOCATION =
System.getenv("DEX_LOCATION") + "/980-redefine-object-ex.jar";
+ private static Method doEnableReporting;
+ private static Method doDisableReporting;
+
+ private static void DisableReporting() {
+ if (doDisableReporting == null) {
+ return;
+ }
+ try {
+ doDisableReporting.invoke(null);
+ } catch (Exception e) {
+ throw new Error("Unable to disable reporting!");
+ }
+ }
+
+ private static void EnableReporting() {
+ if (doEnableReporting == null) {
+ return;
+ }
+ try {
+ doEnableReporting.invoke(null);
+ } catch (Exception e) {
+ throw new Error("Unable to enable reporting!");
+ }
+ }
+
public static void main(String[] args) {
art.Main.bindAgentJNIForClass(Main.class);
doTest();
@@ -298,8 +326,8 @@
addToBootClassLoader(LISTENER_LOCATION);
// Load TestWatcher from the bootclassloader and make sure it is initialized.
Class<?> testwatcher_class = Class.forName("art.test.TestWatcher", true, null);
- // Bind the native functions of testwatcher_class.
- bindFunctionsForClass(testwatcher_class);
+ doEnableReporting = testwatcher_class.getDeclaredMethod("EnableReporting");
+ doDisableReporting = testwatcher_class.getDeclaredMethod("DisableReporting");
} catch (Exception e) {
throw new Error("Exception while making testwatcher", e);
}
@@ -308,9 +336,9 @@
// NB This function will cause 2 objects of type "Ljava/nio/HeapCharBuffer;" and
// "Ljava/nio/HeapCharBuffer;" to be allocated each time it is called.
private static void safePrintln(Object o) {
- System.out.flush();
- System.out.print("\t" + o + "\n");
- System.out.flush();
+ DisableReporting();
+ System.out.println("\t" + o);
+ EnableReporting();
}
private static void throwFrom(int depth) throws Exception {
@@ -381,11 +409,4 @@
}
private static native void addToBootClassLoader(String s);
-
- private static native void bindFunctionsForClass(Class<?> target);
-
- // Transforms the class
- private static native void doCommonClassRedefinition(Class<?> target,
- byte[] class_file,
- byte[] dex_file);
}
diff --git a/test/980-redefine-object/src/art/Redefinition.java b/test/980-redefine-object/src/art/Redefinition.java
new file mode 100644
index 0000000..0350ab4
--- /dev/null
+++ b/test/980-redefine-object/src/art/Redefinition.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package art;
+
+import java.util.ArrayList;
+// Common Redefinition functions. Placed here for use by CTS
+public class Redefinition {
+ // Bind native functions.
+ static {
+ Main.bindAgentJNIForClass(Redefinition.class);
+ }
+
+ public static final class CommonClassDefinition {
+ public final Class<?> target;
+ public final byte[] class_file_bytes;
+ public final byte[] dex_file_bytes;
+
+ public CommonClassDefinition(Class<?> target, byte[] class_file_bytes, byte[] dex_file_bytes) {
+ this.target = target;
+ this.class_file_bytes = class_file_bytes;
+ this.dex_file_bytes = dex_file_bytes;
+ }
+ }
+
+ // A set of possible test configurations. Test should set this if they need to.
+ // This must be kept in sync with the defines in ti-agent/common_helper.cc
+ public static enum Config {
+ COMMON_REDEFINE(0),
+ COMMON_RETRANSFORM(1),
+ COMMON_TRANSFORM(2);
+
+ private final int val;
+ private Config(int val) {
+ this.val = val;
+ }
+ }
+
+ public static void setTestConfiguration(Config type) {
+ nativeSetTestConfiguration(type.val);
+ }
+
+ private static native void nativeSetTestConfiguration(int type);
+
+ // Transforms the class
+ public static native void doCommonClassRedefinition(Class<?> target,
+ byte[] classfile,
+ byte[] dexfile);
+
+ public static void doMultiClassRedefinition(CommonClassDefinition... defs) {
+ ArrayList<Class<?>> classes = new ArrayList<>();
+ ArrayList<byte[]> class_files = new ArrayList<>();
+ ArrayList<byte[]> dex_files = new ArrayList<>();
+
+ for (CommonClassDefinition d : defs) {
+ classes.add(d.target);
+ class_files.add(d.class_file_bytes);
+ dex_files.add(d.dex_file_bytes);
+ }
+ doCommonMultiClassRedefinition(classes.toArray(new Class<?>[0]),
+ class_files.toArray(new byte[0][]),
+ dex_files.toArray(new byte[0][]));
+ }
+
+ public static void addMultiTransformationResults(CommonClassDefinition... defs) {
+ for (CommonClassDefinition d : defs) {
+ addCommonTransformationResult(d.target.getCanonicalName(),
+ d.class_file_bytes,
+ d.dex_file_bytes);
+ }
+ }
+
+ public static native void doCommonMultiClassRedefinition(Class<?>[] targets,
+ byte[][] classfiles,
+ byte[][] dexfiles);
+ public static native void doCommonClassRetransformation(Class<?>... target);
+ public static native void setPopRetransformations(boolean pop);
+ public static native void popTransformationFor(String name);
+ public static native void enableCommonRetransformation(boolean enable);
+ public static native void addCommonTransformationResult(String target_name,
+ byte[] class_bytes,
+ byte[] dex_bytes);
+}
diff --git a/test/981-dedup-original-dex/src/Main.java b/test/981-dedup-original-dex/src/Main.java
index 288f7ce..f90c15c 100644
--- a/test/981-dedup-original-dex/src/Main.java
+++ b/test/981-dedup-original-dex/src/Main.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,190 +14,8 @@
* limitations under the License.
*/
-import java.lang.reflect.Field;
-import java.util.Base64;
-import java.nio.ByteBuffer;
-
-import dalvik.system.ClassExt;
-import dalvik.system.InMemoryDexClassLoader;
-
public class Main {
-
- /**
- * base64 encoded class/dex file for
- * class Transform {
- * public void sayHi() {
- * System.out.println("Goodbye");
- * }
- * }
- */
- private static final byte[] DEX_BYTES_1 = Base64.getDecoder().decode(
- "ZGV4CjAzNQCLXSBQ5FiS3f16krSYZFF8xYZtFVp0GRXMAgAAcAAAAHhWNBIAAAAAAAAAACwCAAAO" +
- "AAAAcAAAAAYAAACoAAAAAgAAAMAAAAABAAAA2AAAAAQAAADgAAAAAQAAAAABAACsAQAAIAEAAGIB" +
- "AABqAQAAcwEAAIABAACXAQAAqwEAAL8BAADTAQAA4wEAAOYBAADqAQAA/gEAAAMCAAAMAgAAAgAA" +
- "AAMAAAAEAAAABQAAAAYAAAAIAAAACAAAAAUAAAAAAAAACQAAAAUAAABcAQAABAABAAsAAAAAAAAA" +
- "AAAAAAAAAAANAAAAAQABAAwAAAACAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAHAAAAAAAAAB4CAAAA" +
- "AAAAAQABAAEAAAATAgAABAAAAHAQAwAAAA4AAwABAAIAAAAYAgAACQAAAGIAAAAbAQEAAABuIAIA" +
- "EAAOAAAAAQAAAAMABjxpbml0PgAHR29vZGJ5ZQALTFRyYW5zZm9ybTsAFUxqYXZhL2lvL1ByaW50" +
- "U3RyZWFtOwASTGphdmEvbGFuZy9PYmplY3Q7ABJMamF2YS9sYW5nL1N0cmluZzsAEkxqYXZhL2xh" +
- "bmcvU3lzdGVtOwAOVHJhbnNmb3JtLmphdmEAAVYAAlZMABJlbWl0dGVyOiBqYWNrLTMuMzYAA291" +
- "dAAHcHJpbnRsbgAFc2F5SGkAEQAHDgATAAcOhQAAAAEBAICABKACAQG4Ag0AAAAAAAAAAQAAAAAA" +
- "AAABAAAADgAAAHAAAAACAAAABgAAAKgAAAADAAAAAgAAAMAAAAAEAAAAAQAAANgAAAAFAAAABAAA" +
- "AOAAAAAGAAAAAQAAAAABAAABIAAAAgAAACABAAABEAAAAQAAAFwBAAACIAAADgAAAGIBAAADIAAA" +
- "AgAAABMCAAAAIAAAAQAAAB4CAAAAEAAAAQAAACwCAAA=");
-
- /**
- * base64 encoded class/dex file for
- * class Transform2 {
- * public void sayHi() {
- * System.out.println("Goodbye2");
- * }
- * }
- */
- private static final byte[] DEX_BYTES_2 = Base64.getDecoder().decode(
- "ZGV4CjAzNQAjXDED2iflQ3NXbPtBRVjQVMqoDU9nDz/QAgAAcAAAAHhWNBIAAAAAAAAAADACAAAO" +
- "AAAAcAAAAAYAAACoAAAAAgAAAMAAAAABAAAA2AAAAAQAAADgAAAAAQAAAAABAACwAQAAIAEAAGIB" +
- "AABqAQAAdAEAAIIBAACZAQAArQEAAMEBAADVAQAA5gEAAOkBAADtAQAAAQIAAAYCAAAPAgAAAgAA" +
- "AAMAAAAEAAAABQAAAAYAAAAIAAAACAAAAAUAAAAAAAAACQAAAAUAAABcAQAABAABAAsAAAAAAAAA" +
- "AAAAAAAAAAANAAAAAQABAAwAAAACAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAHAAAAAAAAACECAAAA" +
- "AAAAAQABAAEAAAAWAgAABAAAAHAQAwAAAA4AAwABAAIAAAAbAgAACQAAAGIAAAAbAQEAAABuIAIA" +
- "EAAOAAAAAQAAAAMABjxpbml0PgAIR29vZGJ5ZTIADExUcmFuc2Zvcm0yOwAVTGphdmEvaW8vUHJp" +
- "bnRTdHJlYW07ABJMamF2YS9sYW5nL09iamVjdDsAEkxqYXZhL2xhbmcvU3RyaW5nOwASTGphdmEv" +
- "bGFuZy9TeXN0ZW07AA9UcmFuc2Zvcm0yLmphdmEAAVYAAlZMABJlbWl0dGVyOiBqYWNrLTQuMzAA" +
- "A291dAAHcHJpbnRsbgAFc2F5SGkAAQAHDgADAAcOhwAAAAEBAICABKACAQG4AgANAAAAAAAAAAEA" +
- "AAAAAAAAAQAAAA4AAABwAAAAAgAAAAYAAACoAAAAAwAAAAIAAADAAAAABAAAAAEAAADYAAAABQAA" +
- "AAQAAADgAAAABgAAAAEAAAAAAQAAASAAAAIAAAAgAQAAARAAAAEAAABcAQAAAiAAAA4AAABiAQAA" +
- "AyAAAAIAAAAWAgAAACAAAAEAAAAhAgAAABAAAAEAAAAwAgAA");
-
-
- /**
- * base64 encoded class/dex file for
- * class Transform3 {
- * public void sayHi() {
- * System.out.println("hello3");
- * }
- * }
- */
- private static final byte[] DEX_BYTES_3_INITIAL = Base64.getDecoder().decode(
- "ZGV4CjAzNQC2W2fBsAeLNAwWYlG8FVigzfsV7nBWITzQAgAAcAAAAHhWNBIAAAAAAAAAADACAAAO" +
- "AAAAcAAAAAYAAACoAAAAAgAAAMAAAAABAAAA2AAAAAQAAADgAAAAAQAAAAABAACwAQAAIAEAAGIB" +
- "AABqAQAAeAEAAI8BAACjAQAAtwEAAMsBAADcAQAA3wEAAOMBAAD3AQAA/wEAAAQCAAANAgAAAQAA" +
- "AAIAAAADAAAABAAAAAUAAAAHAAAABwAAAAUAAAAAAAAACAAAAAUAAABcAQAABAABAAsAAAAAAAAA" +
- "AAAAAAAAAAANAAAAAQABAAwAAAACAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAGAAAAAAAAAB8CAAAA" +
- "AAAAAQABAAEAAAAUAgAABAAAAHAQAwAAAA4AAwABAAIAAAAZAgAACQAAAGIAAAAbAQoAAABuIAIA" +
- "EAAOAAAAAQAAAAMABjxpbml0PgAMTFRyYW5zZm9ybTM7ABVMamF2YS9pby9QcmludFN0cmVhbTsA" +
- "EkxqYXZhL2xhbmcvT2JqZWN0OwASTGphdmEvbGFuZy9TdHJpbmc7ABJMamF2YS9sYW5nL1N5c3Rl" +
- "bTsAD1RyYW5zZm9ybTMuamF2YQABVgACVkwAEmVtaXR0ZXI6IGphY2stNC4zMAAGaGVsbG8zAANv" +
- "dXQAB3ByaW50bG4ABXNheUhpAAIABw4ABAAHDocAAAABAQCAgASgAgEBuAIAAAANAAAAAAAAAAEA" +
- "AAAAAAAAAQAAAA4AAABwAAAAAgAAAAYAAACoAAAAAwAAAAIAAADAAAAABAAAAAEAAADYAAAABQAA" +
- "AAQAAADgAAAABgAAAAEAAAAAAQAAASAAAAIAAAAgAQAAARAAAAEAAABcAQAAAiAAAA4AAABiAQAA" +
- "AyAAAAIAAAAUAgAAACAAAAEAAAAfAgAAABAAAAEAAAAwAgAA");
-
- /**
- * base64 encoded class/dex file for
- * class Transform3 {
- * public void sayHi() {
- * System.out.println("Goodbye3");
- * }
- * }
- */
- private static final byte[] DEX_BYTES_3_FINAL = Base64.getDecoder().decode(
- "ZGV4CjAzNQBAXE5GthgMydaFBuinf+ZBfXcBYIw2UlXQAgAAcAAAAHhWNBIAAAAAAAAAADACAAAO" +
- "AAAAcAAAAAYAAACoAAAAAgAAAMAAAAABAAAA2AAAAAQAAADgAAAAAQAAAAABAACwAQAAIAEAAGIB" +
- "AABqAQAAdAEAAIIBAACZAQAArQEAAMEBAADVAQAA5gEAAOkBAADtAQAAAQIAAAYCAAAPAgAAAgAA" +
- "AAMAAAAEAAAABQAAAAYAAAAIAAAACAAAAAUAAAAAAAAACQAAAAUAAABcAQAABAABAAsAAAAAAAAA" +
- "AAAAAAAAAAANAAAAAQABAAwAAAACAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAHAAAAAAAAACECAAAA" +
- "AAAAAQABAAEAAAAWAgAABAAAAHAQAwAAAA4AAwABAAIAAAAbAgAACQAAAGIAAAAbAQEAAABuIAIA" +
- "EAAOAAAAAQAAAAMABjxpbml0PgAIR29vZGJ5ZTMADExUcmFuc2Zvcm0zOwAVTGphdmEvaW8vUHJp" +
- "bnRTdHJlYW07ABJMamF2YS9sYW5nL09iamVjdDsAEkxqYXZhL2xhbmcvU3RyaW5nOwASTGphdmEv" +
- "bGFuZy9TeXN0ZW07AA9UcmFuc2Zvcm0zLmphdmEAAVYAAlZMABJlbWl0dGVyOiBqYWNrLTQuMzAA" +
- "A291dAAHcHJpbnRsbgAFc2F5SGkAAgAHDgAEAAcOhwAAAAEBAICABKACAQG4AgANAAAAAAAAAAEA" +
- "AAAAAAAAAQAAAA4AAABwAAAAAgAAAAYAAACoAAAAAwAAAAIAAADAAAAABAAAAAEAAADYAAAABQAA" +
- "AAQAAADgAAAABgAAAAEAAAAAAQAAASAAAAIAAAAgAQAAARAAAAEAAABcAQAAAiAAAA4AAABiAQAA" +
- "AyAAAAIAAAAWAgAAACAAAAEAAAAhAgAAABAAAAEAAAAwAgAA");
-
- public static void main(String[] args) {
- art.Main.bindAgentJNIForClass(Main.class);
- try {
- doTest();
- } catch (Exception e) {
- e.printStackTrace();
- }
+ public static void main(String[] args) throws Exception {
+ art.Test981.run();
}
-
- private static void assertSame(Object a, Object b) throws Exception {
- if (a != b) {
- throw new AssertionError("'" + (a != null ? a.toString() : "null") + "' is not the same as " +
- "'" + (b != null ? b.toString() : "null") + "'");
- }
- }
-
- private static Object getObjectField(Object o, String name) throws Exception {
- return getObjectField(o, o.getClass(), name);
- }
-
- private static Object getObjectField(Object o, Class<?> type, String name) throws Exception {
- Field f = type.getDeclaredField(name);
- f.setAccessible(true);
- return f.get(o);
- }
-
- private static Object getOriginalDexFile(Class<?> k) throws Exception {
- ClassExt ext_data_object = (ClassExt) getObjectField(k, "extData");
- if (ext_data_object == null) {
- return null;
- }
-
- return getObjectField(ext_data_object, "originalDexFile");
- }
-
- public static void doTest() throws Exception {
- // Make sure both of these are loaded prior to transformations being added so they have the same
- // original dex files.
- Transform t1 = new Transform();
- Transform2 t2 = new Transform2();
-
- assertSame(null, getOriginalDexFile(t1.getClass()));
- assertSame(null, getOriginalDexFile(t2.getClass()));
- assertSame(null, getOriginalDexFile(Main.class));
-
- addCommonTransformationResult("Transform", new byte[0], DEX_BYTES_1);
- addCommonTransformationResult("Transform2", new byte[0], DEX_BYTES_2);
- enableCommonRetransformation(true);
- doCommonClassRetransformation(Transform.class, Transform2.class);
-
- assertSame(getOriginalDexFile(t1.getClass()), getOriginalDexFile(t2.getClass()));
- assertSame(null, getOriginalDexFile(Main.class));
- // Make sure that the original dex file is a DexCache object.
- assertSame(getOriginalDexFile(t1.getClass()).getClass(), Class.forName("java.lang.DexCache"));
-
- // Check that we end up with a byte[] if we do a direct RedefineClasses
- enableCommonRetransformation(false);
- doCommonClassRedefinition(Transform.class, new byte[0], DEX_BYTES_1);
- assertSame((new byte[0]).getClass(), getOriginalDexFile(t1.getClass()).getClass());
-
- // Check we don't have anything if we don't have any originalDexFile if the onload
- // transformation doesn't do anything.
- enableCommonRetransformation(true);
- Class<?> transform3Class = new InMemoryDexClassLoader(
- ByteBuffer.wrap(DEX_BYTES_3_INITIAL), Main.class.getClassLoader()).loadClass("Transform3");
- assertSame(null, getOriginalDexFile(transform3Class));
-
- // Check that we end up with a java.lang.Long pointer if we do an 'on-load' redefinition.
- addCommonTransformationResult("Transform3", new byte[0], DEX_BYTES_3_FINAL);
- enableCommonRetransformation(true);
- Class<?> transform3ClassTransformed = new InMemoryDexClassLoader(
- ByteBuffer.wrap(DEX_BYTES_3_INITIAL), Main.class.getClassLoader()).loadClass("Transform3");
- assertSame(Long.class, getOriginalDexFile(transform3ClassTransformed).getClass());
- }
-
- // Transforms the class
- private static native void doCommonClassRetransformation(Class<?>... target);
- private static native void doCommonClassRedefinition(Class<?> target,
- byte[] class_file,
- byte[] dex_file);
- private static native void enableCommonRetransformation(boolean enable);
- private static native void addCommonTransformationResult(String target_name,
- byte[] class_bytes,
- byte[] dex_bytes);
}
diff --git a/test/981-dedup-original-dex/src/Transform.java b/test/981-dedup-original-dex/src/Transform.java
deleted file mode 100644
index 3c97907..0000000
--- a/test/981-dedup-original-dex/src/Transform.java
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-class Transform {
- public void sayHi() {
- System.out.println("hello");
- }
-}
diff --git a/test/981-dedup-original-dex/src/Transform2.java b/test/981-dedup-original-dex/src/Transform2.java
deleted file mode 100644
index eb22842..0000000
--- a/test/981-dedup-original-dex/src/Transform2.java
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-class Transform2 {
- public void sayHi() {
- System.out.println("hello2");
- }
-}
diff --git a/test/981-dedup-original-dex/src/art/Redefinition.java b/test/981-dedup-original-dex/src/art/Redefinition.java
new file mode 100644
index 0000000..0350ab4
--- /dev/null
+++ b/test/981-dedup-original-dex/src/art/Redefinition.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package art;
+
+import java.util.ArrayList;
+// Common Redefinition functions. Placed here for use by CTS
+public class Redefinition {
+ // Bind native functions.
+ static {
+ Main.bindAgentJNIForClass(Redefinition.class);
+ }
+
+ public static final class CommonClassDefinition {
+ public final Class<?> target;
+ public final byte[] class_file_bytes;
+ public final byte[] dex_file_bytes;
+
+ public CommonClassDefinition(Class<?> target, byte[] class_file_bytes, byte[] dex_file_bytes) {
+ this.target = target;
+ this.class_file_bytes = class_file_bytes;
+ this.dex_file_bytes = dex_file_bytes;
+ }
+ }
+
+ // A set of possible test configurations. Test should set this if they need to.
+ // This must be kept in sync with the defines in ti-agent/common_helper.cc
+ public static enum Config {
+ COMMON_REDEFINE(0),
+ COMMON_RETRANSFORM(1),
+ COMMON_TRANSFORM(2);
+
+ private final int val;
+ private Config(int val) {
+ this.val = val;
+ }
+ }
+
+ public static void setTestConfiguration(Config type) {
+ nativeSetTestConfiguration(type.val);
+ }
+
+ private static native void nativeSetTestConfiguration(int type);
+
+ // Transforms the class
+ public static native void doCommonClassRedefinition(Class<?> target,
+ byte[] classfile,
+ byte[] dexfile);
+
+ public static void doMultiClassRedefinition(CommonClassDefinition... defs) {
+ ArrayList<Class<?>> classes = new ArrayList<>();
+ ArrayList<byte[]> class_files = new ArrayList<>();
+ ArrayList<byte[]> dex_files = new ArrayList<>();
+
+ for (CommonClassDefinition d : defs) {
+ classes.add(d.target);
+ class_files.add(d.class_file_bytes);
+ dex_files.add(d.dex_file_bytes);
+ }
+ doCommonMultiClassRedefinition(classes.toArray(new Class<?>[0]),
+ class_files.toArray(new byte[0][]),
+ dex_files.toArray(new byte[0][]));
+ }
+
+ public static void addMultiTransformationResults(CommonClassDefinition... defs) {
+ for (CommonClassDefinition d : defs) {
+ addCommonTransformationResult(d.target.getCanonicalName(),
+ d.class_file_bytes,
+ d.dex_file_bytes);
+ }
+ }
+
+ public static native void doCommonMultiClassRedefinition(Class<?>[] targets,
+ byte[][] classfiles,
+ byte[][] dexfiles);
+ public static native void doCommonClassRetransformation(Class<?>... target);
+ public static native void setPopRetransformations(boolean pop);
+ public static native void popTransformationFor(String name);
+ public static native void enableCommonRetransformation(boolean enable);
+ public static native void addCommonTransformationResult(String target_name,
+ byte[] class_bytes,
+ byte[] dex_bytes);
+}
diff --git a/test/981-dedup-original-dex/src/art/Test981.java b/test/981-dedup-original-dex/src/art/Test981.java
new file mode 100644
index 0000000..3a97268
--- /dev/null
+++ b/test/981-dedup-original-dex/src/art/Test981.java
@@ -0,0 +1,210 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package art;
+
+import java.lang.reflect.Field;
+import java.util.Base64;
+import java.nio.ByteBuffer;
+
+import dalvik.system.ClassExt;
+import dalvik.system.InMemoryDexClassLoader;
+
+public class Test981 {
+
+ static class Transform {
+ public void sayHi() {
+ System.out.println("hello");
+ }
+ }
+
+ static class Transform2 {
+ public void sayHi() {
+ System.out.println("hello2");
+ }
+ }
+
+ /**
+ * base64 encoded class/dex file for
+ * static class Transform {
+ * public void sayHi() {
+ * System.out.println("Goodbye");
+ * }
+ * }
+ */
+ private static final byte[] DEX_BYTES_1 = Base64.getDecoder().decode(
+ "ZGV4CjAzNQB+giqQAAAAAAAAAAAAAAAAAAAAAAAAAAC4AwAAcAAAAHhWNBIAAAAAAAAAAPQCAAAU" +
+ "AAAAcAAAAAkAAADAAAAAAgAAAOQAAAABAAAA/AAAAAQAAAAEAQAAAQAAACQBAAB0AgAARAEAAEQB" +
+ "AABMAQAAVQEAAG4BAAB9AQAAoQEAAMEBAADYAQAA7AEAAAACAAAUAgAAIgIAAC0CAAAwAgAANAIA" +
+ "AEECAABHAgAATAIAAFUCAABcAgAAAgAAAAMAAAAEAAAABQAAAAYAAAAHAAAACAAAAAkAAAAMAAAA" +
+ "DAAAAAgAAAAAAAAADQAAAAgAAABkAgAABwAEABAAAAAAAAAAAAAAAAAAAAASAAAABAABABEAAAAF" +
+ "AAAAAAAAAAAAAAAAAAAABQAAAAAAAAAKAAAA5AIAALgCAAAAAAAABjxpbml0PgAHR29vZGJ5ZQAX" +
+ "TGFydC9UZXN0OTgxJFRyYW5zZm9ybTsADUxhcnQvVGVzdDk4MTsAIkxkYWx2aWsvYW5ub3RhdGlv" +
+ "bi9FbmNsb3NpbmdDbGFzczsAHkxkYWx2aWsvYW5ub3RhdGlvbi9Jbm5lckNsYXNzOwAVTGphdmEv" +
+ "aW8vUHJpbnRTdHJlYW07ABJMamF2YS9sYW5nL09iamVjdDsAEkxqYXZhL2xhbmcvU3RyaW5nOwAS" +
+ "TGphdmEvbGFuZy9TeXN0ZW07AAxUZXN0OTgxLmphdmEACVRyYW5zZm9ybQABVgACVkwAC2FjY2Vz" +
+ "c0ZsYWdzAARuYW1lAANvdXQAB3ByaW50bG4ABXNheUhpAAV2YWx1ZQAAAQAAAAYAAAAFAAcOAAcA" +
+ "Bw4BCA8AAAAAAQABAAEAAABsAgAABAAAAHAQAwAAAA4AAwABAAIAAABxAgAACQAAAGIAAAAbAQEA" +
+ "AABuIAIAEAAOAAAAAAABAQCAgAT8BAEBlAUAAAICARMYAQIDAg4ECA8XCwACAAAAyAIAAM4CAADY" +
+ "AgAAAAAAAAAAAAAAAAAAEAAAAAAAAAABAAAAAAAAAAEAAAAUAAAAcAAAAAIAAAAJAAAAwAAAAAMA" +
+ "AAACAAAA5AAAAAQAAAABAAAA/AAAAAUAAAAEAAAABAEAAAYAAAABAAAAJAEAAAIgAAAUAAAARAEA" +
+ "AAEQAAABAAAAZAIAAAMgAAACAAAAbAIAAAEgAAACAAAAfAIAAAAgAAABAAAAuAIAAAQgAAACAAAA" +
+ "yAIAAAMQAAABAAAA2AIAAAYgAAABAAAA5AIAAAAQAAABAAAA9AIAAA==");
+
+ /**
+ * base64 encoded class/dex file for
+ * static class Transform2 {
+ * public void sayHi() {
+ * System.out.println("Goodbye2");
+ * }
+ * }
+ */
+ private static final byte[] DEX_BYTES_2 = Base64.getDecoder().decode(
+ "ZGV4CjAzNQAhg+RVAAAAAAAAAAAAAAAAAAAAAAAAAAC8AwAAcAAAAHhWNBIAAAAAAAAAAPgCAAAU" +
+ "AAAAcAAAAAkAAADAAAAAAgAAAOQAAAABAAAA/AAAAAQAAAAEAQAAAQAAACQBAAB4AgAARAEAAEQB" +
+ "AABMAQAAVgEAAHABAAB/AQAAowEAAMMBAADaAQAA7gEAAAICAAAWAgAAJAIAADACAAAzAgAANwIA" +
+ "AEQCAABKAgAATwIAAFgCAABfAgAAAgAAAAMAAAAEAAAABQAAAAYAAAAHAAAACAAAAAkAAAAMAAAA" +
+ "DAAAAAgAAAAAAAAADQAAAAgAAABoAgAABwAEABAAAAAAAAAAAAAAAAAAAAASAAAABAABABEAAAAF" +
+ "AAAAAAAAAAAAAAAAAAAABQAAAAAAAAAKAAAA6AIAALwCAAAAAAAABjxpbml0PgAIR29vZGJ5ZTIA" +
+ "GExhcnQvVGVzdDk4MSRUcmFuc2Zvcm0yOwANTGFydC9UZXN0OTgxOwAiTGRhbHZpay9hbm5vdGF0" +
+ "aW9uL0VuY2xvc2luZ0NsYXNzOwAeTGRhbHZpay9hbm5vdGF0aW9uL0lubmVyQ2xhc3M7ABVMamF2" +
+ "YS9pby9QcmludFN0cmVhbTsAEkxqYXZhL2xhbmcvT2JqZWN0OwASTGphdmEvbGFuZy9TdHJpbmc7" +
+ "ABJMamF2YS9sYW5nL1N5c3RlbTsADFRlc3Q5ODEuamF2YQAKVHJhbnNmb3JtMgABVgACVkwAC2Fj" +
+ "Y2Vzc0ZsYWdzAARuYW1lAANvdXQAB3ByaW50bG4ABXNheUhpAAV2YWx1ZQAAAAEAAAAGAAAACgAH" +
+ "DgAMAAcOAQgPAAAAAAEAAQABAAAAcAIAAAQAAABwEAMAAAAOAAMAAQACAAAAdQIAAAkAAABiAAAA" +
+ "GwEBAAAAbiACABAADgAAAAAAAQEAgIAEgAUBAZgFAAACAgETGAECAwIOBAgPFwsAAgAAAMwCAADS" +
+ "AgAA3AIAAAAAAAAAAAAAAAAAABAAAAAAAAAAAQAAAAAAAAABAAAAFAAAAHAAAAACAAAACQAAAMAA" +
+ "AAADAAAAAgAAAOQAAAAEAAAAAQAAAPwAAAAFAAAABAAAAAQBAAAGAAAAAQAAACQBAAACIAAAFAAA" +
+ "AEQBAAABEAAAAQAAAGgCAAADIAAAAgAAAHACAAABIAAAAgAAAIACAAAAIAAAAQAAALwCAAAEIAAA" +
+ "AgAAAMwCAAADEAAAAQAAANwCAAAGIAAAAQAAAOgCAAAAEAAAAQAAAPgCAAA=");
+
+ /**
+ * base64 encoded class/dex file for
+ * class Transform3 {
+ * public void sayHi() {
+ * System.out.println("hello3");
+ * }
+ * }
+ */
+ private static final byte[] DEX_BYTES_3_INITIAL = Base64.getDecoder().decode(
+ "ZGV4CjAzNQC2W2fBsAeLNAwWYlG8FVigzfsV7nBWITzQAgAAcAAAAHhWNBIAAAAAAAAAADACAAAO" +
+ "AAAAcAAAAAYAAACoAAAAAgAAAMAAAAABAAAA2AAAAAQAAADgAAAAAQAAAAABAACwAQAAIAEAAGIB" +
+ "AABqAQAAeAEAAI8BAACjAQAAtwEAAMsBAADcAQAA3wEAAOMBAAD3AQAA/wEAAAQCAAANAgAAAQAA" +
+ "AAIAAAADAAAABAAAAAUAAAAHAAAABwAAAAUAAAAAAAAACAAAAAUAAABcAQAABAABAAsAAAAAAAAA" +
+ "AAAAAAAAAAANAAAAAQABAAwAAAACAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAGAAAAAAAAAB8CAAAA" +
+ "AAAAAQABAAEAAAAUAgAABAAAAHAQAwAAAA4AAwABAAIAAAAZAgAACQAAAGIAAAAbAQoAAABuIAIA" +
+ "EAAOAAAAAQAAAAMABjxpbml0PgAMTFRyYW5zZm9ybTM7ABVMamF2YS9pby9QcmludFN0cmVhbTsA" +
+ "EkxqYXZhL2xhbmcvT2JqZWN0OwASTGphdmEvbGFuZy9TdHJpbmc7ABJMamF2YS9sYW5nL1N5c3Rl" +
+ "bTsAD1RyYW5zZm9ybTMuamF2YQABVgACVkwAEmVtaXR0ZXI6IGphY2stNC4zMAAGaGVsbG8zAANv" +
+ "dXQAB3ByaW50bG4ABXNheUhpAAIABw4ABAAHDocAAAABAQCAgASgAgEBuAIAAAANAAAAAAAAAAEA" +
+ "AAAAAAAAAQAAAA4AAABwAAAAAgAAAAYAAACoAAAAAwAAAAIAAADAAAAABAAAAAEAAADYAAAABQAA" +
+ "AAQAAADgAAAABgAAAAEAAAAAAQAAASAAAAIAAAAgAQAAARAAAAEAAABcAQAAAiAAAA4AAABiAQAA" +
+ "AyAAAAIAAAAUAgAAACAAAAEAAAAfAgAAABAAAAEAAAAwAgAA");
+
+ /**
+ * base64 encoded class/dex file for
+ * class Transform3 {
+ * public void sayHi() {
+ * System.out.println("Goodbye3");
+ * }
+ * }
+ */
+ private static final byte[] DEX_BYTES_3_FINAL = Base64.getDecoder().decode(
+ "ZGV4CjAzNQBAXE5GthgMydaFBuinf+ZBfXcBYIw2UlXQAgAAcAAAAHhWNBIAAAAAAAAAADACAAAO" +
+ "AAAAcAAAAAYAAACoAAAAAgAAAMAAAAABAAAA2AAAAAQAAADgAAAAAQAAAAABAACwAQAAIAEAAGIB" +
+ "AABqAQAAdAEAAIIBAACZAQAArQEAAMEBAADVAQAA5gEAAOkBAADtAQAAAQIAAAYCAAAPAgAAAgAA" +
+ "AAMAAAAEAAAABQAAAAYAAAAIAAAACAAAAAUAAAAAAAAACQAAAAUAAABcAQAABAABAAsAAAAAAAAA" +
+ "AAAAAAAAAAANAAAAAQABAAwAAAACAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAHAAAAAAAAACECAAAA" +
+ "AAAAAQABAAEAAAAWAgAABAAAAHAQAwAAAA4AAwABAAIAAAAbAgAACQAAAGIAAAAbAQEAAABuIAIA" +
+ "EAAOAAAAAQAAAAMABjxpbml0PgAIR29vZGJ5ZTMADExUcmFuc2Zvcm0zOwAVTGphdmEvaW8vUHJp" +
+ "bnRTdHJlYW07ABJMamF2YS9sYW5nL09iamVjdDsAEkxqYXZhL2xhbmcvU3RyaW5nOwASTGphdmEv" +
+ "bGFuZy9TeXN0ZW07AA9UcmFuc2Zvcm0zLmphdmEAAVYAAlZMABJlbWl0dGVyOiBqYWNrLTQuMzAA" +
+ "A291dAAHcHJpbnRsbgAFc2F5SGkAAgAHDgAEAAcOhwAAAAEBAICABKACAQG4AgANAAAAAAAAAAEA" +
+ "AAAAAAAAAQAAAA4AAABwAAAAAgAAAAYAAACoAAAAAwAAAAIAAADAAAAABAAAAAEAAADYAAAABQAA" +
+ "AAQAAADgAAAABgAAAAEAAAAAAQAAASAAAAIAAAAgAQAAARAAAAEAAABcAQAAAiAAAA4AAABiAQAA" +
+ "AyAAAAIAAAAWAgAAACAAAAEAAAAhAgAAABAAAAEAAAAwAgAA");
+
+ public static void run() throws Exception {
+ Redefinition.setTestConfiguration(Redefinition.Config.COMMON_RETRANSFORM);
+ doTest();
+ }
+
+ private static void assertSame(Object a, Object b) throws Exception {
+ if (a != b) {
+ throw new AssertionError("'" + (a != null ? a.toString() : "null") + "' is not the same as " +
+ "'" + (b != null ? b.toString() : "null") + "'");
+ }
+ }
+
+ private static Object getObjectField(Object o, String name) throws Exception {
+ return getObjectField(o, o.getClass(), name);
+ }
+
+ private static Object getObjectField(Object o, Class<?> type, String name) throws Exception {
+ Field f = type.getDeclaredField(name);
+ f.setAccessible(true);
+ return f.get(o);
+ }
+
+ private static Object getOriginalDexFile(Class<?> k) throws Exception {
+ ClassExt ext_data_object = (ClassExt) getObjectField(k, "extData");
+ if (ext_data_object == null) {
+ return null;
+ }
+
+ return getObjectField(ext_data_object, "originalDexFile");
+ }
+
+ public static void doTest() throws Exception {
+ // Make sure both of these are loaded prior to transformations being added so they have the same
+ // original dex files.
+ Transform t1 = new Transform();
+ Transform2 t2 = new Transform2();
+
+ assertSame(null, getOriginalDexFile(t1.getClass()));
+ assertSame(null, getOriginalDexFile(t2.getClass()));
+ assertSame(null, getOriginalDexFile(Test981.class));
+
+ Redefinition.addCommonTransformationResult("art/Test981$Transform", new byte[0], DEX_BYTES_1);
+ Redefinition.addCommonTransformationResult("art/Test981$Transform2", new byte[0], DEX_BYTES_2);
+ Redefinition.enableCommonRetransformation(true);
+ Redefinition.doCommonClassRetransformation(Transform.class, Transform2.class);
+
+ assertSame(getOriginalDexFile(t1.getClass()), getOriginalDexFile(t2.getClass()));
+ assertSame(null, getOriginalDexFile(Test981.class));
+ // Make sure that the original dex file is a DexCache object.
+ assertSame(getOriginalDexFile(t1.getClass()).getClass(), Class.forName("java.lang.DexCache"));
+
+ // Check that we end up with a byte[] if we do a direct RedefineClasses
+ Redefinition.enableCommonRetransformation(false);
+ Redefinition.doCommonClassRedefinition(Transform.class, new byte[0], DEX_BYTES_1);
+ assertSame((new byte[0]).getClass(), getOriginalDexFile(t1.getClass()).getClass());
+
+ // Check we don't have anything if we don't have any originalDexFile if the onload
+ // transformation doesn't do anything.
+ Redefinition.enableCommonRetransformation(true);
+ Class<?> transform3Class = new InMemoryDexClassLoader(
+ ByteBuffer.wrap(DEX_BYTES_3_INITIAL), Test981.class.getClassLoader()).loadClass("Transform3");
+ assertSame(null, getOriginalDexFile(transform3Class));
+
+ // Check that we end up with a java.lang.Long pointer if we do an 'on-load' redefinition.
+ Redefinition.addCommonTransformationResult("Transform3", new byte[0], DEX_BYTES_3_FINAL);
+ Redefinition.enableCommonRetransformation(true);
+ Class<?> transform3ClassTransformed = new InMemoryDexClassLoader(
+ ByteBuffer.wrap(DEX_BYTES_3_INITIAL), Test981.class.getClassLoader()).loadClass("Transform3");
+ assertSame(Long.class, getOriginalDexFile(transform3ClassTransformed).getClass());
+ }
+}
diff --git a/test/982-ok-no-retransform/src/Main.java b/test/982-ok-no-retransform/src/Main.java
index 33e50d7..bd73e81 100644
--- a/test/982-ok-no-retransform/src/Main.java
+++ b/test/982-ok-no-retransform/src/Main.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,22 +14,8 @@
* limitations under the License.
*/
-import java.util.Base64;
public class Main {
-
- public static void main(String[] args) {
- art.Main.bindAgentJNIForClass(Main.class);
- doTest(new Transform());
+ public static void main(String[] args) throws Exception {
+ art.Test982.run();
}
-
- public static void doTest(Transform t) {
- t.sayHi();
- enableCommonRetransformation(true);
- doCommonClassRetransformation(Transform.class);
- t.sayHi();
- }
-
- // Transforms the class
- private static native void doCommonClassRetransformation(Class<?>... target);
- private static native void enableCommonRetransformation(boolean enable);
}
diff --git a/test/982-ok-no-retransform/src/Transform.java b/test/982-ok-no-retransform/src/Transform.java
deleted file mode 100644
index 8e8af35..0000000
--- a/test/982-ok-no-retransform/src/Transform.java
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-class Transform {
- public void sayHi() {
- // Use lower 'h' to make sure the string will have a different string id
- // than the transformation (the transformation code is the same except
- // the actual printed String, which was making the test inacurately passing
- // in JIT mode when loading the string from the dex cache, as the string ids
- // of the two different strings were the same).
- // We know the string ids will be different because lexicographically:
- // "Goodbye" < "LTransform;" < "hello".
- System.out.println("hello");
- }
-}
diff --git a/test/982-ok-no-retransform/src/art/Redefinition.java b/test/982-ok-no-retransform/src/art/Redefinition.java
new file mode 100644
index 0000000..0350ab4
--- /dev/null
+++ b/test/982-ok-no-retransform/src/art/Redefinition.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package art;
+
+import java.util.ArrayList;
+// Common Redefinition functions. Placed here for use by CTS
+public class Redefinition {
+ // Bind native functions.
+ static {
+ Main.bindAgentJNIForClass(Redefinition.class);
+ }
+
+ public static final class CommonClassDefinition {
+ public final Class<?> target;
+ public final byte[] class_file_bytes;
+ public final byte[] dex_file_bytes;
+
+ public CommonClassDefinition(Class<?> target, byte[] class_file_bytes, byte[] dex_file_bytes) {
+ this.target = target;
+ this.class_file_bytes = class_file_bytes;
+ this.dex_file_bytes = dex_file_bytes;
+ }
+ }
+
+ // A set of possible test configurations. Test should set this if they need to.
+ // This must be kept in sync with the defines in ti-agent/common_helper.cc
+ public static enum Config {
+ COMMON_REDEFINE(0),
+ COMMON_RETRANSFORM(1),
+ COMMON_TRANSFORM(2);
+
+ private final int val;
+ private Config(int val) {
+ this.val = val;
+ }
+ }
+
+ public static void setTestConfiguration(Config type) {
+ nativeSetTestConfiguration(type.val);
+ }
+
+ private static native void nativeSetTestConfiguration(int type);
+
+ // Transforms the class
+ public static native void doCommonClassRedefinition(Class<?> target,
+ byte[] classfile,
+ byte[] dexfile);
+
+ public static void doMultiClassRedefinition(CommonClassDefinition... defs) {
+ ArrayList<Class<?>> classes = new ArrayList<>();
+ ArrayList<byte[]> class_files = new ArrayList<>();
+ ArrayList<byte[]> dex_files = new ArrayList<>();
+
+ for (CommonClassDefinition d : defs) {
+ classes.add(d.target);
+ class_files.add(d.class_file_bytes);
+ dex_files.add(d.dex_file_bytes);
+ }
+ doCommonMultiClassRedefinition(classes.toArray(new Class<?>[0]),
+ class_files.toArray(new byte[0][]),
+ dex_files.toArray(new byte[0][]));
+ }
+
+ public static void addMultiTransformationResults(CommonClassDefinition... defs) {
+ for (CommonClassDefinition d : defs) {
+ addCommonTransformationResult(d.target.getCanonicalName(),
+ d.class_file_bytes,
+ d.dex_file_bytes);
+ }
+ }
+
+ public static native void doCommonMultiClassRedefinition(Class<?>[] targets,
+ byte[][] classfiles,
+ byte[][] dexfiles);
+ public static native void doCommonClassRetransformation(Class<?>... target);
+ public static native void setPopRetransformations(boolean pop);
+ public static native void popTransformationFor(String name);
+ public static native void enableCommonRetransformation(boolean enable);
+ public static native void addCommonTransformationResult(String target_name,
+ byte[] class_bytes,
+ byte[] dex_bytes);
+}
diff --git a/test/982-ok-no-retransform/src/art/Test982.java b/test/982-ok-no-retransform/src/art/Test982.java
new file mode 100644
index 0000000..080d47f
--- /dev/null
+++ b/test/982-ok-no-retransform/src/art/Test982.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package art;
+
+import java.util.Base64;
+public class Test982 {
+
+ static class Transform {
+ public void sayHi() {
+ System.out.println("hello");
+ }
+ }
+
+ public static void run() {
+ Redefinition.setTestConfiguration(Redefinition.Config.COMMON_RETRANSFORM);
+ doTest(new Transform());
+ }
+
+ public static void doTest(Transform t) {
+ t.sayHi();
+ Redefinition.enableCommonRetransformation(true);
+ Redefinition.doCommonClassRetransformation(Transform.class);
+ t.sayHi();
+ }
+}
diff --git a/test/983-source-transform-verify/expected.txt b/test/983-source-transform-verify/expected.txt
index 0a94212..abcdf3a 100644
--- a/test/983-source-transform-verify/expected.txt
+++ b/test/983-source-transform-verify/expected.txt
@@ -1,2 +1,2 @@
-Dex file hook for Transform
+Dex file hook for art/Test983$Transform
Dex file hook for java/lang/Object
diff --git a/test/983-source-transform-verify/src/Main.java b/test/983-source-transform-verify/src/Main.java
index ad081a2..e1d20f6 100644
--- a/test/983-source-transform-verify/src/Main.java
+++ b/test/983-source-transform-verify/src/Main.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,23 +14,8 @@
* limitations under the License.
*/
-import java.util.Base64;
public class Main {
-
- public static void main(String[] args) {
- art.Main.bindAgentJNIForClass(Main.class);
- doTest();
+ public static void main(String[] args) throws Exception {
+ art.Test983.run();
}
-
- public static void doTest() {
- Transform abc = new Transform();
- enableCommonRetransformation(true);
- doCommonClassRetransformation(Transform.class);
- doCommonClassRetransformation(Object.class);
- enableCommonRetransformation(false);
- }
-
- // Transforms the class
- private static native void doCommonClassRetransformation(Class<?>... target);
- private static native void enableCommonRetransformation(boolean enable);
}
diff --git a/test/983-source-transform-verify/src/Transform.java b/test/983-source-transform-verify/src/Transform.java
deleted file mode 100644
index 8e8af35..0000000
--- a/test/983-source-transform-verify/src/Transform.java
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-class Transform {
- public void sayHi() {
- // Use lower 'h' to make sure the string will have a different string id
- // than the transformation (the transformation code is the same except
- // the actual printed String, which was making the test inacurately passing
- // in JIT mode when loading the string from the dex cache, as the string ids
- // of the two different strings were the same).
- // We know the string ids will be different because lexicographically:
- // "Goodbye" < "LTransform;" < "hello".
- System.out.println("hello");
- }
-}
diff --git a/test/983-source-transform-verify/src/art/Redefinition.java b/test/983-source-transform-verify/src/art/Redefinition.java
new file mode 100644
index 0000000..0350ab4
--- /dev/null
+++ b/test/983-source-transform-verify/src/art/Redefinition.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package art;
+
+import java.util.ArrayList;
+// Common Redefinition functions. Placed here for use by CTS
+public class Redefinition {
+ // Bind native functions.
+ static {
+ Main.bindAgentJNIForClass(Redefinition.class);
+ }
+
+ public static final class CommonClassDefinition {
+ public final Class<?> target;
+ public final byte[] class_file_bytes;
+ public final byte[] dex_file_bytes;
+
+ public CommonClassDefinition(Class<?> target, byte[] class_file_bytes, byte[] dex_file_bytes) {
+ this.target = target;
+ this.class_file_bytes = class_file_bytes;
+ this.dex_file_bytes = dex_file_bytes;
+ }
+ }
+
+ // A set of possible test configurations. Test should set this if they need to.
+ // This must be kept in sync with the defines in ti-agent/common_helper.cc
+ public static enum Config {
+ COMMON_REDEFINE(0),
+ COMMON_RETRANSFORM(1),
+ COMMON_TRANSFORM(2);
+
+ private final int val;
+ private Config(int val) {
+ this.val = val;
+ }
+ }
+
+ public static void setTestConfiguration(Config type) {
+ nativeSetTestConfiguration(type.val);
+ }
+
+ private static native void nativeSetTestConfiguration(int type);
+
+ // Transforms the class
+ public static native void doCommonClassRedefinition(Class<?> target,
+ byte[] classfile,
+ byte[] dexfile);
+
+ public static void doMultiClassRedefinition(CommonClassDefinition... defs) {
+ ArrayList<Class<?>> classes = new ArrayList<>();
+ ArrayList<byte[]> class_files = new ArrayList<>();
+ ArrayList<byte[]> dex_files = new ArrayList<>();
+
+ for (CommonClassDefinition d : defs) {
+ classes.add(d.target);
+ class_files.add(d.class_file_bytes);
+ dex_files.add(d.dex_file_bytes);
+ }
+ doCommonMultiClassRedefinition(classes.toArray(new Class<?>[0]),
+ class_files.toArray(new byte[0][]),
+ dex_files.toArray(new byte[0][]));
+ }
+
+ public static void addMultiTransformationResults(CommonClassDefinition... defs) {
+ for (CommonClassDefinition d : defs) {
+ addCommonTransformationResult(d.target.getCanonicalName(),
+ d.class_file_bytes,
+ d.dex_file_bytes);
+ }
+ }
+
+ public static native void doCommonMultiClassRedefinition(Class<?>[] targets,
+ byte[][] classfiles,
+ byte[][] dexfiles);
+ public static native void doCommonClassRetransformation(Class<?>... target);
+ public static native void setPopRetransformations(boolean pop);
+ public static native void popTransformationFor(String name);
+ public static native void enableCommonRetransformation(boolean enable);
+ public static native void addCommonTransformationResult(String target_name,
+ byte[] class_bytes,
+ byte[] dex_bytes);
+}
diff --git a/test/983-source-transform-verify/src/art/Test983.java b/test/983-source-transform-verify/src/art/Test983.java
new file mode 100644
index 0000000..b81e7f4
--- /dev/null
+++ b/test/983-source-transform-verify/src/art/Test983.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package art;
+
+import java.util.Base64;
+public class Test983 {
+ static class Transform {
+ public void sayHi() {
+ System.out.println("hello");
+ }
+ }
+
+ public static void run() {
+ doTest();
+ }
+
+ public static void doTest() {
+ Transform abc = new Transform();
+ Redefinition.enableCommonRetransformation(true);
+ Redefinition.doCommonClassRetransformation(Transform.class);
+ Redefinition.doCommonClassRetransformation(Object.class);
+ Redefinition.enableCommonRetransformation(false);
+ }
+}
diff --git a/test/984-obsolete-invoke/obsolete_invoke.cc b/test/984-obsolete-invoke/obsolete_invoke.cc
index 27e36ba..ab2499a 100644
--- a/test/984-obsolete-invoke/obsolete_invoke.cc
+++ b/test/984-obsolete-invoke/obsolete_invoke.cc
@@ -17,20 +17,20 @@
#include "android-base/macros.h"
#include "jni.h"
#include "jvmti.h"
-#include "mirror/class-inl.h"
-#include "scoped_local_ref.h"
// Test infrastructure
#include "test_env.h"
#include "jvmti_helper.h"
+#include "scoped_local_ref.h"
namespace art {
namespace Test984ObsoleteInvoke {
static constexpr size_t kNumFrames = 30;
-extern "C" JNIEXPORT jobject JNICALL Java_Main_getFirstObsoleteMethod984(JNIEnv* env, jclass) {
+extern "C" JNIEXPORT jobject JNICALL Java_art_Test984_getFirstObsoleteMethod984(JNIEnv* env,
+ jclass) {
jthread cur;
jint frame_count;
jvmtiFrameInfo frames[kNumFrames];
diff --git a/test/984-obsolete-invoke/src/Main.java b/test/984-obsolete-invoke/src/Main.java
index 418d64d..04a368dc 100644
--- a/test/984-obsolete-invoke/src/Main.java
+++ b/test/984-obsolete-invoke/src/Main.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,96 +14,8 @@
* limitations under the License.
*/
-import java.lang.reflect.Method;
-import java.util.Base64;
-
public class Main {
- // class Transform {
- // public static void sayHi(Runnable r) {
- // System.out.println("Hello - Transformed");
- // r.run();
- // System.out.println("Goodbye - Transformed");
- // }
- // }
- private static final byte[] CLASS_BYTES = Base64.getDecoder().decode(
- "yv66vgAAADQAJAoACAARCQASABMIABQKABUAFgsAFwAYCAAZBwAaBwAbAQAGPGluaXQ+AQADKClW" +
- "AQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEABXNheUhpAQAXKExqYXZhL2xhbmcvUnVubmFibGU7" +
- "KVYBAApTb3VyY2VGaWxlAQAOVHJhbnNmb3JtLmphdmEMAAkACgcAHAwAHQAeAQATSGVsbG8gLSBU" +
- "cmFuc2Zvcm1lZAcAHwwAIAAhBwAiDAAjAAoBABVHb29kYnllIC0gVHJhbnNmb3JtZWQBAAlUcmFu" +
- "c2Zvcm0BABBqYXZhL2xhbmcvT2JqZWN0AQAQamF2YS9sYW5nL1N5c3RlbQEAA291dAEAFUxqYXZh" +
- "L2lvL1ByaW50U3RyZWFtOwEAE2phdmEvaW8vUHJpbnRTdHJlYW0BAAdwcmludGxuAQAVKExqYXZh" +
- "L2xhbmcvU3RyaW5nOylWAQASamF2YS9sYW5nL1J1bm5hYmxlAQADcnVuACAABwAIAAAAAAACAAAA" +
- "CQAKAAEACwAAAB0AAQABAAAABSq3AAGxAAAAAQAMAAAABgABAAAAAQAJAA0ADgABAAsAAAA7AAIA" +
- "AQAAABeyAAISA7YABCq5AAUBALIAAhIGtgAEsQAAAAEADAAAABIABAAAAAMACAAEAA4ABQAWAAYA" +
- "AQAPAAAAAgAQ");
- private static final byte[] DEX_BYTES = Base64.getDecoder().decode(
- "ZGV4CjAzNQCMekj2NPwzrEp/v+2yzzSg8xZvBtU1bC1QAwAAcAAAAHhWNBIAAAAAAAAAALACAAAR" +
- "AAAAcAAAAAcAAAC0AAAAAwAAANAAAAABAAAA9AAAAAUAAAD8AAAAAQAAACQBAAAMAgAARAEAAKIB" +
- "AACqAQAAwQEAANYBAADjAQAA+gEAAA4CAAAkAgAAOAIAAEwCAABcAgAAXwIAAGMCAAB3AgAAfAIA" +
- "AIUCAACKAgAAAwAAAAQAAAAFAAAABgAAAAcAAAAIAAAACgAAAAoAAAAGAAAAAAAAAAsAAAAGAAAA" +
- "lAEAAAsAAAAGAAAAnAEAAAUAAQANAAAAAAAAAAAAAAAAAAEAEAAAAAEAAgAOAAAAAgAAAAAAAAAD" +
- "AAAADwAAAAAAAAAAAAAAAgAAAAAAAAAJAAAAAAAAAJ8CAAAAAAAAAQABAAEAAACRAgAABAAAAHAQ" +
- "AwAAAA4AAwABAAIAAACWAgAAFAAAAGIAAAAbAQIAAABuIAIAEAByEAQAAgBiAAAAGwEBAAAAbiAC" +
- "ABAADgABAAAAAwAAAAEAAAAEAAY8aW5pdD4AFUdvb2RieWUgLSBUcmFuc2Zvcm1lZAATSGVsbG8g" +
- "LSBUcmFuc2Zvcm1lZAALTFRyYW5zZm9ybTsAFUxqYXZhL2lvL1ByaW50U3RyZWFtOwASTGphdmEv" +
- "bGFuZy9PYmplY3Q7ABRMamF2YS9sYW5nL1J1bm5hYmxlOwASTGphdmEvbGFuZy9TdHJpbmc7ABJM" +
- "amF2YS9sYW5nL1N5c3RlbTsADlRyYW5zZm9ybS5qYXZhAAFWAAJWTAASZW1pdHRlcjogamFjay00" +
- "LjMxAANvdXQAB3ByaW50bG4AA3J1bgAFc2F5SGkAAQAHDgADAQAHDoc8hwAAAAIAAICABMQCAQnc" +
- "AgAAAA0AAAAAAAAAAQAAAAAAAAABAAAAEQAAAHAAAAACAAAABwAAALQAAAADAAAAAwAAANAAAAAE" +
- "AAAAAQAAAPQAAAAFAAAABQAAAPwAAAAGAAAAAQAAACQBAAABIAAAAgAAAEQBAAABEAAAAgAAAJQB" +
- "AAACIAAAEQAAAKIBAAADIAAAAgAAAJECAAAAIAAAAQAAAJ8CAAAAEAAAAQAAALACAAA=");
-
- public static void main(String[] args) {
- art.Main.bindAgentJNIForClass(Main.class);
- doTest();
+ public static void main(String[] args) throws Exception {
+ art.Test984.run();
}
-
- // The Method that holds an obsolete method pointer. We will fill it in by getting a jmethodID
- // from a stack with an obsolete method in it. There should be no other ways to obtain an obsolete
- // jmethodID in ART without unsafe casts.
- public static Method obsolete_method = null;
-
- public static void doTest() {
- // Capture the obsolete method.
- //
- // NB The obsolete method must be direct so that we will not look in the receiver type to get
- // the actual method.
- Transform.sayHi(() -> {
- System.out.println("transforming calling function");
- doCommonClassRedefinition(Transform.class, CLASS_BYTES, DEX_BYTES);
- System.out.println("Retrieving obsolete method from current stack");
- // This should get the obsolete sayHi method (as the only obsolete method on the current
- // threads stack).
- Main.obsolete_method = getFirstObsoleteMethod984();
- });
-
- // Prove we did actually redefine something.
- System.out.println("Invoking redefined version of method.");
- Transform.sayHi(() -> { System.out.println("Not doing anything here"); });
-
- System.out.println("invoking obsolete method");
- try {
- obsolete_method.invoke(null, (Runnable)() -> {
- throw new Error("Unexpected code running from invoke of obsolete method!");
- });
- throw new Error("Running obsolete method did not throw exception");
- } catch (Throwable e) {
- if (e instanceof InternalError || e.getCause() instanceof InternalError) {
- System.out.println("Caught expected error from attempting to invoke an obsolete method.");
- } else {
- System.out.println("Unexpected error type for calling obsolete method! Expected either "
- + "an InternalError or something that is caused by an InternalError.");
- throw new Error("Unexpected error caught: ", e);
- }
- }
- }
-
- // Transforms the class
- private static native void doCommonClassRedefinition(Class<?> target,
- byte[] classfile,
- byte[] dexfile);
-
- // Gets the first obsolete method on the current threads stack (NB only looks through the first 30
- // stack frames).
- private static native Method getFirstObsoleteMethod984();
}
diff --git a/test/984-obsolete-invoke/src/Transform.java b/test/984-obsolete-invoke/src/Transform.java
deleted file mode 100644
index 536de84..0000000
--- a/test/984-obsolete-invoke/src/Transform.java
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-class Transform {
- // This method must be 'static' so that when we try to invoke it through a j.l.r.Method we will
- // simply use the jmethodID directly and not do any lookup in any receiver object.
- public static void sayHi(Runnable r) {
- System.out.println("hello");
- r.run();
- System.out.println("goodbye");
- }
-}
diff --git a/test/984-obsolete-invoke/src/art/Redefinition.java b/test/984-obsolete-invoke/src/art/Redefinition.java
new file mode 100644
index 0000000..0350ab4
--- /dev/null
+++ b/test/984-obsolete-invoke/src/art/Redefinition.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package art;
+
+import java.util.ArrayList;
+// Common Redefinition functions. Placed here for use by CTS
+public class Redefinition {
+ // Bind native functions.
+ static {
+ Main.bindAgentJNIForClass(Redefinition.class);
+ }
+
+ public static final class CommonClassDefinition {
+ public final Class<?> target;
+ public final byte[] class_file_bytes;
+ public final byte[] dex_file_bytes;
+
+ public CommonClassDefinition(Class<?> target, byte[] class_file_bytes, byte[] dex_file_bytes) {
+ this.target = target;
+ this.class_file_bytes = class_file_bytes;
+ this.dex_file_bytes = dex_file_bytes;
+ }
+ }
+
+ // A set of possible test configurations. Test should set this if they need to.
+ // This must be kept in sync with the defines in ti-agent/common_helper.cc
+ public static enum Config {
+ COMMON_REDEFINE(0),
+ COMMON_RETRANSFORM(1),
+ COMMON_TRANSFORM(2);
+
+ private final int val;
+ private Config(int val) {
+ this.val = val;
+ }
+ }
+
+ public static void setTestConfiguration(Config type) {
+ nativeSetTestConfiguration(type.val);
+ }
+
+ private static native void nativeSetTestConfiguration(int type);
+
+ // Transforms the class
+ public static native void doCommonClassRedefinition(Class<?> target,
+ byte[] classfile,
+ byte[] dexfile);
+
+ public static void doMultiClassRedefinition(CommonClassDefinition... defs) {
+ ArrayList<Class<?>> classes = new ArrayList<>();
+ ArrayList<byte[]> class_files = new ArrayList<>();
+ ArrayList<byte[]> dex_files = new ArrayList<>();
+
+ for (CommonClassDefinition d : defs) {
+ classes.add(d.target);
+ class_files.add(d.class_file_bytes);
+ dex_files.add(d.dex_file_bytes);
+ }
+ doCommonMultiClassRedefinition(classes.toArray(new Class<?>[0]),
+ class_files.toArray(new byte[0][]),
+ dex_files.toArray(new byte[0][]));
+ }
+
+ public static void addMultiTransformationResults(CommonClassDefinition... defs) {
+ for (CommonClassDefinition d : defs) {
+ addCommonTransformationResult(d.target.getCanonicalName(),
+ d.class_file_bytes,
+ d.dex_file_bytes);
+ }
+ }
+
+ public static native void doCommonMultiClassRedefinition(Class<?>[] targets,
+ byte[][] classfiles,
+ byte[][] dexfiles);
+ public static native void doCommonClassRetransformation(Class<?>... target);
+ public static native void setPopRetransformations(boolean pop);
+ public static native void popTransformationFor(String name);
+ public static native void enableCommonRetransformation(boolean enable);
+ public static native void addCommonTransformationResult(String target_name,
+ byte[] class_bytes,
+ byte[] dex_bytes);
+}
diff --git a/test/984-obsolete-invoke/src/art/Test984.java b/test/984-obsolete-invoke/src/art/Test984.java
new file mode 100644
index 0000000..3fe66f6
--- /dev/null
+++ b/test/984-obsolete-invoke/src/art/Test984.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package art;
+
+import java.lang.reflect.Method;
+import java.util.Base64;
+
+public class Test984 {
+
+ static class Transform {
+ // This method must be 'static' so that when we try to invoke it through a j.l.r.Method we will
+ // simply use the jmethodID directly and not do any lookup in any receiver object.
+ public static void sayHi(Runnable r) {
+ System.out.println("hello");
+ r.run();
+ System.out.println("goodbye");
+ }
+ }
+ // static class Transform {
+ // public static void sayHi(Runnable r) {
+ // System.out.println("Hello - Transformed");
+ // r.run();
+ // System.out.println("Goodbye - Transformed");
+ // }
+ // }
+ private static final byte[] CLASS_BYTES = Base64.getDecoder().decode(
+ "yv66vgAAADQAKAoACAARCQASABMIABQKABUAFgsAFwAYCAAZBwAbBwAeAQAGPGluaXQ+AQADKClW" +
+ "AQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEABXNheUhpAQAXKExqYXZhL2xhbmcvUnVubmFibGU7" +
+ "KVYBAApTb3VyY2VGaWxlAQAMVGVzdDk4NC5qYXZhDAAJAAoHAB8MACAAIQEAE0hlbGxvIC0gVHJh" +
+ "bnNmb3JtZWQHACIMACMAJAcAJQwAJgAKAQAVR29vZGJ5ZSAtIFRyYW5zZm9ybWVkBwAnAQAVYXJ0" +
+ "L1Rlc3Q5ODQkVHJhbnNmb3JtAQAJVHJhbnNmb3JtAQAMSW5uZXJDbGFzc2VzAQAQamF2YS9sYW5n" +
+ "L09iamVjdAEAEGphdmEvbGFuZy9TeXN0ZW0BAANvdXQBABVMamF2YS9pby9QcmludFN0cmVhbTsB" +
+ "ABNqYXZhL2lvL1ByaW50U3RyZWFtAQAHcHJpbnRsbgEAFShMamF2YS9sYW5nL1N0cmluZzspVgEA" +
+ "EmphdmEvbGFuZy9SdW5uYWJsZQEAA3J1bgEAC2FydC9UZXN0OTg0ACAABwAIAAAAAAACAAAACQAK" +
+ "AAEACwAAAB0AAQABAAAABSq3AAGxAAAAAQAMAAAABgABAAAABQAJAA0ADgABAAsAAAA7AAIAAQAA" +
+ "ABeyAAISA7YABCq5AAUBALIAAhIGtgAEsQAAAAEADAAAABIABAAAAAcACAAIAA4ACQAWAAoAAgAP" +
+ "AAAAAgAQAB0AAAAKAAEABwAaABwACA==");
+ private static final byte[] DEX_BYTES = Base64.getDecoder().decode(
+ "ZGV4CjAzNQB/mxSMAAAAAAAAAAAAAAAAAAAAAAAAAAA8BAAAcAAAAHhWNBIAAAAAAAAAAHgDAAAX" +
+ "AAAAcAAAAAoAAADMAAAAAwAAAPQAAAABAAAAGAEAAAUAAAAgAQAAAQAAAEgBAADUAgAAaAEAAGgB" +
+ "AABwAQAAhwEAAJwBAAC1AQAAxAEAAOgBAAAIAgAAHwIAADMCAABJAgAAXQIAAHECAAB/AgAAigIA" +
+ "AI0CAACRAgAAngIAAKQCAACpAgAAsgIAALcCAAC+AgAAAwAAAAQAAAAFAAAABgAAAAcAAAAIAAAA" +
+ "CQAAAAoAAAALAAAADgAAAA4AAAAJAAAAAAAAAA8AAAAJAAAAyAIAAA8AAAAJAAAA0AIAAAgABAAS" +
+ "AAAAAAAAAAAAAAAAAAEAFQAAAAQAAgATAAAABQAAAAAAAAAGAAAAFAAAAAAAAAAAAAAABQAAAAAA" +
+ "AAAMAAAAaAMAADwDAAAAAAAABjxpbml0PgAVR29vZGJ5ZSAtIFRyYW5zZm9ybWVkABNIZWxsbyAt" +
+ "IFRyYW5zZm9ybWVkABdMYXJ0L1Rlc3Q5ODQkVHJhbnNmb3JtOwANTGFydC9UZXN0OTg0OwAiTGRh" +
+ "bHZpay9hbm5vdGF0aW9uL0VuY2xvc2luZ0NsYXNzOwAeTGRhbHZpay9hbm5vdGF0aW9uL0lubmVy" +
+ "Q2xhc3M7ABVMamF2YS9pby9QcmludFN0cmVhbTsAEkxqYXZhL2xhbmcvT2JqZWN0OwAUTGphdmEv" +
+ "bGFuZy9SdW5uYWJsZTsAEkxqYXZhL2xhbmcvU3RyaW5nOwASTGphdmEvbGFuZy9TeXN0ZW07AAxU" +
+ "ZXN0OTg0LmphdmEACVRyYW5zZm9ybQABVgACVkwAC2FjY2Vzc0ZsYWdzAARuYW1lAANvdXQAB3By" +
+ "aW50bG4AA3J1bgAFc2F5SGkABXZhbHVlAAAAAAEAAAAGAAAAAQAAAAcAAAAFAAcOAAcBAAcOAQgP" +
+ "AQMPAQgPAAEAAQABAAAA2AIAAAQAAABwEAMAAAAOAAMAAQACAAAA3QIAABQAAABiAAAAGwECAAAA" +
+ "biACABAAchAEAAIAYgAAABsBAQAAAG4gAgAQAA4AAAACAACAgATsBQEJhAYAAAICARYYAQIDAhAE" +
+ "CBEXDQACAAAATAMAAFIDAABcAwAAAAAAAAAAAAAAAAAAEAAAAAAAAAABAAAAAAAAAAEAAAAXAAAA" +
+ "cAAAAAIAAAAKAAAAzAAAAAMAAAADAAAA9AAAAAQAAAABAAAAGAEAAAUAAAAFAAAAIAEAAAYAAAAB" +
+ "AAAASAEAAAIgAAAXAAAAaAEAAAEQAAACAAAAyAIAAAMgAAACAAAA2AIAAAEgAAACAAAA7AIAAAAg" +
+ "AAABAAAAPAMAAAQgAAACAAAATAMAAAMQAAABAAAAXAMAAAYgAAABAAAAaAMAAAAQAAABAAAAeAMA" +
+ "AA==");
+
+ public static void run() {
+ art.Main.bindAgentJNIForClass(Test984.class);
+ doTest();
+ }
+
+ // The Method that holds an obsolete method pointer. We will fill it in by getting a jmethodID
+ // from a stack with an obsolete method in it. There should be no other ways to obtain an obsolete
+ // jmethodID in ART without unsafe casts.
+ public static Method obsolete_method = null;
+
+ public static void doTest() {
+ // Capture the obsolete method.
+ //
+ // NB The obsolete method must be direct so that we will not look in the receiver type to get
+ // the actual method.
+ Transform.sayHi(() -> {
+ System.out.println("transforming calling function");
+ Redefinition.doCommonClassRedefinition(Transform.class, CLASS_BYTES, DEX_BYTES);
+ System.out.println("Retrieving obsolete method from current stack");
+ // This should get the obsolete sayHi method (as the only obsolete method on the current
+ // threads stack).
+ Test984.obsolete_method = getFirstObsoleteMethod984();
+ });
+
+ // Prove we did actually redefine something.
+ System.out.println("Invoking redefined version of method.");
+ Transform.sayHi(() -> { System.out.println("Not doing anything here"); });
+
+ System.out.println("invoking obsolete method");
+ try {
+ obsolete_method.invoke(null, (Runnable)() -> {
+ throw new Error("Unexpected code running from invoke of obsolete method!");
+ });
+ throw new Error("Running obsolete method did not throw exception");
+ } catch (Throwable e) {
+ if (e instanceof InternalError || e.getCause() instanceof InternalError) {
+ System.out.println("Caught expected error from attempting to invoke an obsolete method.");
+ } else {
+ System.out.println("Unexpected error type for calling obsolete method! Expected either "
+ + "an InternalError or something that is caused by an InternalError.");
+ throw new Error("Unexpected error caught: ", e);
+ }
+ }
+ }
+
+ // Gets the first obsolete method on the current threads stack (NB only looks through the first 30
+ // stack frames).
+ private static native Method getFirstObsoleteMethod984();
+}
diff --git a/test/985-re-obsolete/expected.txt b/test/985-re-obsolete/expected.txt
new file mode 100644
index 0000000..5159a00
--- /dev/null
+++ b/test/985-re-obsolete/expected.txt
@@ -0,0 +1,35 @@
+Pre Start private method call
+hello - private
+Post Start private method call
+Not doing anything here
+Pre Finish private method call
+goodbye - private
+Post Finish private method call
+Pre Start private method call
+hello - private
+Post Start private method call
+transforming calling function
+Pre Finish private method call
+Goodbye - private - Transformed
+Post Finish private method call
+Pre Start private method call - Transformed
+Hello - private - Transformed
+Post Start private method call - Transformed
+Not doing anything here
+Pre Finish private method call - Transformed
+Goodbye - private - Transformed
+Post Finish private method call - Transformed
+Pre Start private method call - Transformed
+Hello - private - Transformed
+Post Start private method call - Transformed
+transforming calling function
+Pre Finish private method call - Transformed
+second - Goodbye - private - Transformed
+Post Finish private method call - Transformed
+second - Pre Start private method call - Transformed
+second - Hello - private - Transformed
+second - Post Start private method call - Transformed
+Not doing anything here
+second - Pre Finish private method call - Transformed
+second - Goodbye - private - Transformed
+second - Post Finish private method call - Transformed
diff --git a/test/985-re-obsolete/info.txt b/test/985-re-obsolete/info.txt
new file mode 100644
index 0000000..c8eafdc
--- /dev/null
+++ b/test/985-re-obsolete/info.txt
@@ -0,0 +1,4 @@
+Tests basic obsolete method support
+
+Regression test for b/37475600 which was caused by incorrectly checking for
+differences in the obsolete methods map.
diff --git a/test/985-re-obsolete/run b/test/985-re-obsolete/run
new file mode 100755
index 0000000..e92b873
--- /dev/null
+++ b/test/985-re-obsolete/run
@@ -0,0 +1,17 @@
+#!/bin/bash
+#
+# Copyright 2017 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+./default-run "$@" --jvmti
diff --git a/test/944-transform-classloaders/src/Transform2.java b/test/985-re-obsolete/src/Main.java
similarity index 77%
rename from test/944-transform-classloaders/src/Transform2.java
rename to test/985-re-obsolete/src/Main.java
index eb22842..d78d591 100644
--- a/test/944-transform-classloaders/src/Transform2.java
+++ b/test/985-re-obsolete/src/Main.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-class Transform2 {
- public void sayHi() {
- System.out.println("hello2");
+public class Main {
+ public static void main(String[] args) throws Exception {
+ art.Test985.run();
}
}
diff --git a/test/985-re-obsolete/src/art/Main.java b/test/985-re-obsolete/src/art/Main.java
new file mode 100644
index 0000000..8b01920
--- /dev/null
+++ b/test/985-re-obsolete/src/art/Main.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package art;
+
+// Binder class so the agent's C code has something that can be bound and exposed to tests.
+// In a package to separate cleanly and work around CTS reference issues (though this class
+// should be replaced in the CTS version).
+public class Main {
+ // Load the given class with the given classloader, and bind all native methods to corresponding
+ // C methods in the agent. Will abort if any of the steps fail.
+ public static native void bindAgentJNI(String className, ClassLoader classLoader);
+ // Same as above, giving the class directly.
+ public static native void bindAgentJNIForClass(Class<?> klass);
+}
diff --git a/test/985-re-obsolete/src/art/Redefinition.java b/test/985-re-obsolete/src/art/Redefinition.java
new file mode 100644
index 0000000..0350ab4
--- /dev/null
+++ b/test/985-re-obsolete/src/art/Redefinition.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package art;
+
+import java.util.ArrayList;
+// Common Redefinition functions. Placed here for use by CTS
+public class Redefinition {
+ // Bind native functions.
+ static {
+ Main.bindAgentJNIForClass(Redefinition.class);
+ }
+
+ public static final class CommonClassDefinition {
+ public final Class<?> target;
+ public final byte[] class_file_bytes;
+ public final byte[] dex_file_bytes;
+
+ public CommonClassDefinition(Class<?> target, byte[] class_file_bytes, byte[] dex_file_bytes) {
+ this.target = target;
+ this.class_file_bytes = class_file_bytes;
+ this.dex_file_bytes = dex_file_bytes;
+ }
+ }
+
+ // A set of possible test configurations. Test should set this if they need to.
+ // This must be kept in sync with the defines in ti-agent/common_helper.cc
+ public static enum Config {
+ COMMON_REDEFINE(0),
+ COMMON_RETRANSFORM(1),
+ COMMON_TRANSFORM(2);
+
+ private final int val;
+ private Config(int val) {
+ this.val = val;
+ }
+ }
+
+ public static void setTestConfiguration(Config type) {
+ nativeSetTestConfiguration(type.val);
+ }
+
+ private static native void nativeSetTestConfiguration(int type);
+
+ // Transforms the class
+ public static native void doCommonClassRedefinition(Class<?> target,
+ byte[] classfile,
+ byte[] dexfile);
+
+ public static void doMultiClassRedefinition(CommonClassDefinition... defs) {
+ ArrayList<Class<?>> classes = new ArrayList<>();
+ ArrayList<byte[]> class_files = new ArrayList<>();
+ ArrayList<byte[]> dex_files = new ArrayList<>();
+
+ for (CommonClassDefinition d : defs) {
+ classes.add(d.target);
+ class_files.add(d.class_file_bytes);
+ dex_files.add(d.dex_file_bytes);
+ }
+ doCommonMultiClassRedefinition(classes.toArray(new Class<?>[0]),
+ class_files.toArray(new byte[0][]),
+ dex_files.toArray(new byte[0][]));
+ }
+
+ public static void addMultiTransformationResults(CommonClassDefinition... defs) {
+ for (CommonClassDefinition d : defs) {
+ addCommonTransformationResult(d.target.getCanonicalName(),
+ d.class_file_bytes,
+ d.dex_file_bytes);
+ }
+ }
+
+ public static native void doCommonMultiClassRedefinition(Class<?>[] targets,
+ byte[][] classfiles,
+ byte[][] dexfiles);
+ public static native void doCommonClassRetransformation(Class<?>... target);
+ public static native void setPopRetransformations(boolean pop);
+ public static native void popTransformationFor(String name);
+ public static native void enableCommonRetransformation(boolean enable);
+ public static native void addCommonTransformationResult(String target_name,
+ byte[] class_bytes,
+ byte[] dex_bytes);
+}
diff --git a/test/985-re-obsolete/src/art/Test985.java b/test/985-re-obsolete/src/art/Test985.java
new file mode 100644
index 0000000..405abd5
--- /dev/null
+++ b/test/985-re-obsolete/src/art/Test985.java
@@ -0,0 +1,197 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package art;
+
+import java.util.Base64;
+
+public class Test985 {
+
+ static class Transform {
+ private void Start() {
+ System.out.println("hello - private");
+ }
+
+ private void Finish() {
+ System.out.println("goodbye - private");
+ }
+
+ public void sayHi(Runnable r) {
+ System.out.println("Pre Start private method call");
+ Start();
+ System.out.println("Post Start private method call");
+ r.run();
+ System.out.println("Pre Finish private method call");
+ Finish();
+ System.out.println("Post Finish private method call");
+ }
+ }
+
+ // static class Transform {
+ // private void Start() {
+ // System.out.println("Hello - private - Transformed");
+ // }
+ //
+ // private void Finish() {
+ // System.out.println("Goodbye - private - Transformed");
+ // }
+ //
+ // public void sayHi(Runnable r) {
+ // System.out.println("Pre Start private method call - Transformed");
+ // Start();
+ // System.out.println("Post Start private method call - Transformed");
+ // r.run();
+ // System.out.println("Pre Finish private method call - Transformed");
+ // Finish();
+ // System.out.println("Post Finish private method call - Transformed");
+ // }
+ // }
+ private static final byte[] CLASS_BYTES_1 = Base64.getDecoder().decode(
+ "yv66vgAAADQANgoADgAZCQAaABsIABwKAB0AHggAHwgAIAoADQAhCAAiCwAjACQIACUKAA0AJggA" +
+ "JwcAKQcALAEABjxpbml0PgEAAygpVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUBAAVTdGFydAEA" +
+ "BkZpbmlzaAEABXNheUhpAQAXKExqYXZhL2xhbmcvUnVubmFibGU7KVYBAApTb3VyY2VGaWxlAQAM" +
+ "VGVzdDk4NS5qYXZhDAAPABAHAC0MAC4ALwEAHUhlbGxvIC0gcHJpdmF0ZSAtIFRyYW5zZm9ybWVk" +
+ "BwAwDAAxADIBAB9Hb29kYnllIC0gcHJpdmF0ZSAtIFRyYW5zZm9ybWVkAQArUHJlIFN0YXJ0IHBy" +
+ "aXZhdGUgbWV0aG9kIGNhbGwgLSBUcmFuc2Zvcm1lZAwAEwAQAQAsUG9zdCBTdGFydCBwcml2YXRl" +
+ "IG1ldGhvZCBjYWxsIC0gVHJhbnNmb3JtZWQHADMMADQAEAEALFByZSBGaW5pc2ggcHJpdmF0ZSBt" +
+ "ZXRob2QgY2FsbCAtIFRyYW5zZm9ybWVkDAAUABABAC1Qb3N0IEZpbmlzaCBwcml2YXRlIG1ldGhv" +
+ "ZCBjYWxsIC0gVHJhbnNmb3JtZWQHADUBABVhcnQvVGVzdDk4NSRUcmFuc2Zvcm0BAAlUcmFuc2Zv" +
+ "cm0BAAxJbm5lckNsYXNzZXMBABBqYXZhL2xhbmcvT2JqZWN0AQAQamF2YS9sYW5nL1N5c3RlbQEA" +
+ "A291dAEAFUxqYXZhL2lvL1ByaW50U3RyZWFtOwEAE2phdmEvaW8vUHJpbnRTdHJlYW0BAAdwcmlu" +
+ "dGxuAQAVKExqYXZhL2xhbmcvU3RyaW5nOylWAQASamF2YS9sYW5nL1J1bm5hYmxlAQADcnVuAQAL" +
+ "YXJ0L1Rlc3Q5ODUAIAANAA4AAAAAAAQAAAAPABAAAQARAAAAHQABAAEAAAAFKrcAAbEAAAABABIA" +
+ "AAAGAAEAAAAEAAIAEwAQAAEAEQAAACUAAgABAAAACbIAAhIDtgAEsQAAAAEAEgAAAAoAAgAAAAYA" +
+ "CAAHAAIAFAAQAAEAEQAAACUAAgABAAAACbIAAhIFtgAEsQAAAAEAEgAAAAoAAgAAAAkACAAKAAEA" +
+ "FQAWAAEAEQAAAGMAAgACAAAAL7IAAhIGtgAEKrcAB7IAAhIItgAEK7kACQEAsgACEgq2AAQqtwAL" +
+ "sgACEgy2AASxAAAAAQASAAAAIgAIAAAADAAIAA0ADAAOABQADwAaABAAIgARACYAEgAuABMAAgAX" +
+ "AAAAAgAYACsAAAAKAAEADQAoACoACA==");
+ private static final byte[] DEX_BYTES_1 = Base64.getDecoder().decode(
+ "ZGV4CjAzNQAh+CJbAAAAAAAAAAAAAAAAAAAAAAAAAADUBQAAcAAAAHhWNBIAAAAAAAAAABAFAAAd" +
+ "AAAAcAAAAAoAAADkAAAAAwAAAAwBAAABAAAAMAEAAAcAAAA4AQAAAQAAAHABAABEBAAAkAEAAJAB" +
+ "AACYAQAAoAEAAMEBAADgAQAA+QEAAAgCAAAsAgAATAIAAGMCAAB3AgAAjQIAAKECAAC1AgAA5AIA" +
+ "ABIDAABAAwAAbQMAAHQDAACCAwAAjQMAAJADAACUAwAAoQMAAKcDAACsAwAAtQMAALoDAADBAwAA" +
+ "BAAAAAUAAAAGAAAABwAAAAgAAAAJAAAACgAAAAsAAAAMAAAAFAAAABQAAAAJAAAAAAAAABUAAAAJ" +
+ "AAAA0AMAABUAAAAJAAAAyAMAAAgABAAYAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAARAAAAAAABABsA" +
+ "AAAEAAIAGQAAAAUAAAAAAAAABgAAABoAAAAAAAAAAAAAAAUAAAAAAAAAEgAAAAAFAADMBAAAAAAA" +
+ "AAY8aW5pdD4ABkZpbmlzaAAfR29vZGJ5ZSAtIHByaXZhdGUgLSBUcmFuc2Zvcm1lZAAdSGVsbG8g" +
+ "LSBwcml2YXRlIC0gVHJhbnNmb3JtZWQAF0xhcnQvVGVzdDk4NSRUcmFuc2Zvcm07AA1MYXJ0L1Rl" +
+ "c3Q5ODU7ACJMZGFsdmlrL2Fubm90YXRpb24vRW5jbG9zaW5nQ2xhc3M7AB5MZGFsdmlrL2Fubm90" +
+ "YXRpb24vSW5uZXJDbGFzczsAFUxqYXZhL2lvL1ByaW50U3RyZWFtOwASTGphdmEvbGFuZy9PYmpl" +
+ "Y3Q7ABRMamF2YS9sYW5nL1J1bm5hYmxlOwASTGphdmEvbGFuZy9TdHJpbmc7ABJMamF2YS9sYW5n" +
+ "L1N5c3RlbTsALVBvc3QgRmluaXNoIHByaXZhdGUgbWV0aG9kIGNhbGwgLSBUcmFuc2Zvcm1lZAAs" +
+ "UG9zdCBTdGFydCBwcml2YXRlIG1ldGhvZCBjYWxsIC0gVHJhbnNmb3JtZWQALFByZSBGaW5pc2gg" +
+ "cHJpdmF0ZSBtZXRob2QgY2FsbCAtIFRyYW5zZm9ybWVkACtQcmUgU3RhcnQgcHJpdmF0ZSBtZXRo" +
+ "b2QgY2FsbCAtIFRyYW5zZm9ybWVkAAVTdGFydAAMVGVzdDk4NS5qYXZhAAlUcmFuc2Zvcm0AAVYA" +
+ "AlZMAAthY2Nlc3NGbGFncwAEbmFtZQADb3V0AAdwcmludGxuAANydW4ABXNheUhpAAV2YWx1ZQAB" +
+ "AAAABwAAAAEAAAAGAAAABAAHDgAJAAcOAQgPAAYABw4BCA8ADAEABw4BCA8BAw8BCA8BAw8BCA8B" +
+ "Aw8BCA8AAQABAAEAAADYAwAABAAAAHAQBQAAAA4AAwABAAIAAADdAwAACQAAAGIAAAAbAQIAAABu" +
+ "IAQAEAAOAAAAAwABAAIAAADlAwAACQAAAGIAAAAbAQMAAABuIAQAEAAOAAAABAACAAIAAADtAwAA" +
+ "KgAAAGIAAAAbARAAAABuIAQAEABwEAIAAgBiAAAAGwEOAAAAbiAEABAAchAGAAMAYgAAABsBDwAA" +
+ "AG4gBAAQAHAQAQACAGIAAAAbAQ0AAABuIAQAEAAOAAAAAwEAgIAEiAgBAqAIAQLECAMB6AgAAAIC" +
+ "ARwYAQIDAhYECBcXEwACAAAA5AQAAOoEAAD0BAAAAAAAAAAAAAAAAAAAEAAAAAAAAAABAAAAAAAA" +
+ "AAEAAAAdAAAAcAAAAAIAAAAKAAAA5AAAAAMAAAADAAAADAEAAAQAAAABAAAAMAEAAAUAAAAHAAAA" +
+ "OAEAAAYAAAABAAAAcAEAAAIgAAAdAAAAkAEAAAEQAAACAAAAyAMAAAMgAAAEAAAA2AMAAAEgAAAE" +
+ "AAAACAQAAAAgAAABAAAAzAQAAAQgAAACAAAA5AQAAAMQAAABAAAA9AQAAAYgAAABAAAAAAUAAAAQ" +
+ "AAABAAAAEAUAAA==");
+
+ // static class Transform {
+ // private void Start() {
+ // System.out.println("second - Hello - private - Transformed");
+ // }
+ //
+ // private void Finish() {
+ // System.out.println("second - Goodbye - private - Transformed");
+ // }
+ //
+ // public void sayHi(Runnable r) {
+ // System.out.println("second - Pre Start private method call - Transformed");
+ // Start();
+ // System.out.println("second - Post Start private method call - Transformed");
+ // r.run();
+ // System.out.println("second - Pre Finish private method call - Transformed");
+ // Finish();
+ // System.out.println("second - Post Finish private method call - Transformed");
+ // }
+ // }
+ private static final byte[] CLASS_BYTES_2 = Base64.getDecoder().decode(
+ "yv66vgAAADQANgoADgAZCQAaABsIABwKAB0AHggAHwgAIAoADQAhCAAiCwAjACQIACUKAA0AJggA" +
+ "JwcAKQcALAEABjxpbml0PgEAAygpVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUBAAVTdGFydAEA" +
+ "BkZpbmlzaAEABXNheUhpAQAXKExqYXZhL2xhbmcvUnVubmFibGU7KVYBAApTb3VyY2VGaWxlAQAM" +
+ "VGVzdDk4NS5qYXZhDAAPABAHAC0MAC4ALwEAJnNlY29uZCAtIEhlbGxvIC0gcHJpdmF0ZSAtIFRy" +
+ "YW5zZm9ybWVkBwAwDAAxADIBAChzZWNvbmQgLSBHb29kYnllIC0gcHJpdmF0ZSAtIFRyYW5zZm9y" +
+ "bWVkAQA0c2Vjb25kIC0gUHJlIFN0YXJ0IHByaXZhdGUgbWV0aG9kIGNhbGwgLSBUcmFuc2Zvcm1l" +
+ "ZAwAEwAQAQA1c2Vjb25kIC0gUG9zdCBTdGFydCBwcml2YXRlIG1ldGhvZCBjYWxsIC0gVHJhbnNm" +
+ "b3JtZWQHADMMADQAEAEANXNlY29uZCAtIFByZSBGaW5pc2ggcHJpdmF0ZSBtZXRob2QgY2FsbCAt" +
+ "IFRyYW5zZm9ybWVkDAAUABABADZzZWNvbmQgLSBQb3N0IEZpbmlzaCBwcml2YXRlIG1ldGhvZCBj" +
+ "YWxsIC0gVHJhbnNmb3JtZWQHADUBABVhcnQvVGVzdDk4NSRUcmFuc2Zvcm0BAAlUcmFuc2Zvcm0B" +
+ "AAxJbm5lckNsYXNzZXMBABBqYXZhL2xhbmcvT2JqZWN0AQAQamF2YS9sYW5nL1N5c3RlbQEAA291" +
+ "dAEAFUxqYXZhL2lvL1ByaW50U3RyZWFtOwEAE2phdmEvaW8vUHJpbnRTdHJlYW0BAAdwcmludGxu" +
+ "AQAVKExqYXZhL2xhbmcvU3RyaW5nOylWAQASamF2YS9sYW5nL1J1bm5hYmxlAQADcnVuAQALYXJ0" +
+ "L1Rlc3Q5ODUAIAANAA4AAAAAAAQAAAAPABAAAQARAAAAHQABAAEAAAAFKrcAAbEAAAABABIAAAAG" +
+ "AAEAAAAEAAIAEwAQAAEAEQAAACUAAgABAAAACbIAAhIDtgAEsQAAAAEAEgAAAAoAAgAAAAYACAAH" +
+ "AAIAFAAQAAEAEQAAACUAAgABAAAACbIAAhIFtgAEsQAAAAEAEgAAAAoAAgAAAAkACAAKAAEAFQAW" +
+ "AAEAEQAAAGMAAgACAAAAL7IAAhIGtgAEKrcAB7IAAhIItgAEK7kACQEAsgACEgq2AAQqtwALsgAC" +
+ "Egy2AASxAAAAAQASAAAAIgAIAAAADAAIAA0ADAAOABQADwAaABAAIgARACYAEgAuABMAAgAXAAAA" +
+ "AgAYACsAAAAKAAEADQAoACoACA==");
+ private static final byte[] DEX_BYTES_2 = Base64.getDecoder().decode(
+ "ZGV4CjAzNQBw/x+UAAAAAAAAAAAAAAAAAAAAAAAAAAAMBgAAcAAAAHhWNBIAAAAAAAAAAEgFAAAd" +
+ "AAAAcAAAAAoAAADkAAAAAwAAAAwBAAABAAAAMAEAAAcAAAA4AQAAAQAAAHABAAB8BAAAkAEAAJAB" +
+ "AACYAQAAoAEAALkBAADIAQAA7AEAAAwCAAAjAgAANwIAAE0CAABhAgAAdQIAAHwCAACKAgAAlQIA" +
+ "AJgCAACcAgAAqQIAAK8CAAC0AgAAvQIAAMICAADJAgAA8wIAABsDAABTAwAAigMAAMEDAAD3AwAA" +
+ "AgAAAAMAAAAEAAAABQAAAAYAAAAHAAAACAAAAAkAAAAKAAAADgAAAA4AAAAJAAAAAAAAAA8AAAAJ" +
+ "AAAACAQAAA8AAAAJAAAAAAQAAAgABAASAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAALAAAAAAABABUA" +
+ "AAAEAAIAEwAAAAUAAAAAAAAABgAAABQAAAAAAAAAAAAAAAUAAAAAAAAADAAAADgFAAAEBQAAAAAA" +
+ "AAY8aW5pdD4ABkZpbmlzaAAXTGFydC9UZXN0OTg1JFRyYW5zZm9ybTsADUxhcnQvVGVzdDk4NTsA" +
+ "IkxkYWx2aWsvYW5ub3RhdGlvbi9FbmNsb3NpbmdDbGFzczsAHkxkYWx2aWsvYW5ub3RhdGlvbi9J" +
+ "bm5lckNsYXNzOwAVTGphdmEvaW8vUHJpbnRTdHJlYW07ABJMamF2YS9sYW5nL09iamVjdDsAFExq" +
+ "YXZhL2xhbmcvUnVubmFibGU7ABJMamF2YS9sYW5nL1N0cmluZzsAEkxqYXZhL2xhbmcvU3lzdGVt" +
+ "OwAFU3RhcnQADFRlc3Q5ODUuamF2YQAJVHJhbnNmb3JtAAFWAAJWTAALYWNjZXNzRmxhZ3MABG5h" +
+ "bWUAA291dAAHcHJpbnRsbgADcnVuAAVzYXlIaQAoc2Vjb25kIC0gR29vZGJ5ZSAtIHByaXZhdGUg" +
+ "LSBUcmFuc2Zvcm1lZAAmc2Vjb25kIC0gSGVsbG8gLSBwcml2YXRlIC0gVHJhbnNmb3JtZWQANnNl" +
+ "Y29uZCAtIFBvc3QgRmluaXNoIHByaXZhdGUgbWV0aG9kIGNhbGwgLSBUcmFuc2Zvcm1lZAA1c2Vj" +
+ "b25kIC0gUG9zdCBTdGFydCBwcml2YXRlIG1ldGhvZCBjYWxsIC0gVHJhbnNmb3JtZWQANXNlY29u" +
+ "ZCAtIFByZSBGaW5pc2ggcHJpdmF0ZSBtZXRob2QgY2FsbCAtIFRyYW5zZm9ybWVkADRzZWNvbmQg" +
+ "LSBQcmUgU3RhcnQgcHJpdmF0ZSBtZXRob2QgY2FsbCAtIFRyYW5zZm9ybWVkAAV2YWx1ZQAAAAEA" +
+ "AAAHAAAAAQAAAAYAAAAEAAcOAAkABw4BCA8ABgAHDgEIDwAMAQAHDgEIDwEDDwEIDwEDDwEIDwED" +
+ "DwEIDwABAAEAAQAAABAEAAAEAAAAcBAFAAAADgADAAEAAgAAABUEAAAJAAAAYgAAABsBFgAAAG4g" +
+ "BAAQAA4AAAADAAEAAgAAAB0EAAAJAAAAYgAAABsBFwAAAG4gBAAQAA4AAAAEAAIAAgAAACUEAAAq" +
+ "AAAAYgAAABsBGwAAAG4gBAAQAHAQAgACAGIAAAAbARkAAABuIAQAEAByEAYAAwBiAAAAGwEaAAAA" +
+ "biAEABAAcBABAAIAYgAAABsBGAAAAG4gBAAQAA4AAAADAQCAgATACAEC2AgBAvwIAwGgCQAAAgIB" +
+ "HBgBAgMCEAQIERcNAAIAAAAcBQAAIgUAACwFAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAEAAAAAAAAA" +
+ "AQAAAB0AAABwAAAAAgAAAAoAAADkAAAAAwAAAAMAAAAMAQAABAAAAAEAAAAwAQAABQAAAAcAAAA4" +
+ "AQAABgAAAAEAAABwAQAAAiAAAB0AAACQAQAAARAAAAIAAAAABAAAAyAAAAQAAAAQBAAAASAAAAQA" +
+ "AABABAAAACAAAAEAAAAEBQAABCAAAAIAAAAcBQAAAxAAAAEAAAAsBQAABiAAAAEAAAA4BQAAABAA" +
+ "AAEAAABIBQAA");
+
+ public static void run() {
+ Redefinition.setTestConfiguration(Redefinition.Config.COMMON_REDEFINE);
+ doTest(new Transform());
+ }
+
+ public static void doTest(Transform t) {
+ t.sayHi(() -> { System.out.println("Not doing anything here"); });
+ t.sayHi(() -> {
+ System.out.println("transforming calling function");
+ Redefinition.doCommonClassRedefinition(Transform.class, CLASS_BYTES_1, DEX_BYTES_1);
+ });
+ t.sayHi(() -> { System.out.println("Not doing anything here"); });
+ t.sayHi(() -> {
+ System.out.println("transforming calling function");
+ Redefinition.doCommonClassRedefinition(Transform.class, CLASS_BYTES_2, DEX_BYTES_2);
+ });
+ t.sayHi(() -> { System.out.println("Not doing anything here"); });
+ }
+}
diff --git a/test/Android.bp b/test/Android.bp
index 9a8e174..c5d96da 100644
--- a/test/Android.bp
+++ b/test/Android.bp
@@ -250,6 +250,7 @@
"ti-agent/jni_binder.cc",
"ti-agent/jvmti_helper.cc",
"ti-agent/test_env.cc",
+ "ti-agent/common_helper.cc",
// This is the list of non-special OnLoad things and excludes BCI and anything that depends
// on ART internals.
"903-hello-tagging/tagging.cc",
@@ -260,6 +261,7 @@
"908-gc-start-finish/gc_callbacks.cc",
"910-methods/methods.cc",
"911-get-stack-trace/stack_trace.cc",
+ "913-heaps/heaps.cc",
"918-fields/fields.cc",
"920-objects/objects.cc",
"922-properties/properties.cc",
@@ -271,6 +273,8 @@
"929-search/search.cc",
"931-agent-thread/agent_thread.cc",
"933-misc-events/misc_events.cc",
+ "945-obsolete-native/obsolete_native.cc",
+ "984-obsolete-invoke/obsolete_invoke.cc",
],
shared_libs: [
"libbase",
@@ -286,20 +290,14 @@
// This is to get the IsInterpreted native method.
"common/stack_inspect.cc",
"common/runtime_state.cc",
+ "ti-agent/common_load.cc",
// This includes the remaining test functions. We should try to refactor things to
// make this list smaller.
- "ti-agent/common_helper.cc",
- "ti-agent/common_load.cc",
"901-hello-ti-agent/basics.cc",
"909-attach-agent/attach.cc",
"912-classes/classes.cc",
- "913-heaps/heaps.cc",
"936-search-onload/search_onload.cc",
- "944-transform-classloaders/classloader.cc",
- "945-obsolete-native/obsolete_native.cc",
- "980-redefine-object/redefine_object.cc",
"983-source-transform-verify/source_transform.cc",
- "984-obsolete-invoke/obsolete_invoke.cc",
],
}
@@ -318,6 +316,33 @@
shared_libs: ["libartd"],
}
+art_cc_defaults {
+ name: "libtistress-defaults",
+ defaults: ["libartagent-defaults"],
+ srcs: [
+ "ti-stress/stress.cc",
+ ],
+ shared_libs: [
+ "libbase",
+ ],
+ header_libs: ["libopenjdkjvmti_headers"],
+}
+
+art_cc_test_library {
+ name: "libtistress",
+ defaults: [ "libtistress-defaults"],
+ shared_libs: ["libart"],
+}
+
+art_cc_test_library {
+ name: "libtistressd",
+ defaults: [
+ "libtistress-defaults",
+ "art_debug_defaults",
+ ],
+ shared_libs: ["libartd"],
+}
+
art_cc_test_library {
name: "libctstiagent",
defaults: ["libtiagent-base-defaults"],
diff --git a/test/Android.run-test-jvmti-java-library.mk b/test/Android.run-test-jvmti-java-library.mk
index b6da92b..dcb238c 100644
--- a/test/Android.run-test-jvmti-java-library.mk
+++ b/test/Android.run-test-jvmti-java-library.mk
@@ -18,13 +18,17 @@
include $(CLEAR_VARS)
-# Main shim classes. We use one that exposes the tagging common functionality.
-LOCAL_MAIN_SHIM := 903-hello-tagging/src/art/Main.java
-LOCAL_SRC_FILES := $(LOCAL_MAIN_SHIM)
+# shim classes. We use one that exposes the common functionality.
+LOCAL_SHIM_CLASSES := \
+ 902-hello-transformation/src/art/Redefinition.java \
+ 903-hello-tagging/src/art/Main.java \
+
+LOCAL_SRC_FILES := $(LOCAL_SHIM_CLASSES)
# Actual test classes.
LOCAL_SRC_FILES += \
901-hello-ti-agent/src/art/Test901.java \
+ 902-hello-transformation/src/art/Test902.java \
903-hello-tagging/src/art/Test903.java \
904-object-allocation/src/art/Test904.java \
905-object-free/src/art/Test905.java \
@@ -42,19 +46,36 @@
911-get-stack-trace/src/art/SameThread.java \
911-get-stack-trace/src/art/ThreadListTraces.java \
913-heaps/src/art/Test913.java \
+ 914-hello-obsolescence/src/art/Test914.java \
+ 915-obsolete-2/src/art/Test915.java \
+ 917-fields-transformation/src/art/Test917.java \
918-fields/src/art/Test918.java \
+ 919-obsolete-fields/src/art/Test919.java \
920-objects/src/art/Test920.java \
922-properties/src/art/Test922.java \
923-monitors/src/art/Test923.java \
924-threads/src/art/Test924.java \
925-threadgroups/src/art/Test925.java \
+ 926-multi-obsolescence/src/art/Test926.java \
927-timers/src/art/Test927.java \
928-jni-table/src/art/Test928.java \
+ 930-hello-retransform/src/art/Test930.java \
931-agent-thread/src/art/Test931.java \
+ 932-transform-saves/src/art/Test932.java \
933-misc-events/src/art/Test933.java \
+ 940-recursive-obsolete/src/art/Test940.java \
+ 942-private-recursive/src/art/Test942.java \
+ 944-transform-classloaders/src/art/Test944.java \
+ 945-obsolete-native/src/art/Test945.java \
+ 947-reflect-method/src/art/Test947.java \
+ 951-threaded-obsolete/src/art/Test951.java \
+ 981-dedup-original-dex/src/art/Test981.java \
+ 982-ok-no-retransform/src/art/Test982.java \
+ 984-obsolete-invoke/src/art/Test984.java \
JVMTI_RUN_TEST_GENERATED_NUMBERS := \
901 \
+ 902 \
903 \
904 \
905 \
@@ -64,16 +85,32 @@
910 \
911 \
913 \
+ 914 \
+ 915 \
+ 917 \
918 \
+ 919 \
920 \
922 \
923 \
924 \
925 \
+ 926 \
927 \
928 \
+ 930 \
931 \
+ 932 \
933 \
+ 940 \
+ 942 \
+ 944 \
+ 945 \
+ 947 \
+ 951 \
+ 981 \
+ 982 \
+ 984 \
# Try to enforce that the directories correspond to the Java files we pull in.
JVMTI_RUN_TEST_DIR_CHECK := $(sort $(foreach DIR,$(JVMTI_RUN_TEST_GENERATED_NUMBERS), \
diff --git a/test/Android.run-test.mk b/test/Android.run-test.mk
index ece5762..4415b2c 100644
--- a/test/Android.run-test.mk
+++ b/test/Android.run-test.mk
@@ -114,6 +114,14 @@
TEST_ART_TARGET_SYNC_DEPS += $(OUT_DIR)/$(ART_TEST_LIST_device_$(TARGET_2ND_ARCH)_libtiagentd)
endif
+# Also need libtistress.
+TEST_ART_TARGET_SYNC_DEPS += $(OUT_DIR)/$(ART_TEST_LIST_device_$(TARGET_ARCH)_libtistress)
+TEST_ART_TARGET_SYNC_DEPS += $(OUT_DIR)/$(ART_TEST_LIST_device_$(TARGET_ARCH)_libtistressd)
+ifdef TARGET_2ND_ARCH
+TEST_ART_TARGET_SYNC_DEPS += $(OUT_DIR)/$(ART_TEST_LIST_device_$(TARGET_2ND_ARCH)_libtistress)
+TEST_ART_TARGET_SYNC_DEPS += $(OUT_DIR)/$(ART_TEST_LIST_device_$(TARGET_2ND_ARCH)_libtistressd)
+endif
+
# Also need libarttest.
TEST_ART_TARGET_SYNC_DEPS += $(OUT_DIR)/$(ART_TEST_LIST_device_$(TARGET_ARCH)_libarttest)
TEST_ART_TARGET_SYNC_DEPS += $(OUT_DIR)/$(ART_TEST_LIST_device_$(TARGET_ARCH)_libarttestd)
@@ -145,6 +153,8 @@
$(HOST_OUT_EXECUTABLES)/hprof-conv \
$(OUT_DIR)/$(ART_TEST_LIST_host_$(ART_HOST_ARCH)_libtiagent) \
$(OUT_DIR)/$(ART_TEST_LIST_host_$(ART_HOST_ARCH)_libtiagentd) \
+ $(OUT_DIR)/$(ART_TEST_LIST_host_$(ART_HOST_ARCH)_libtistress) \
+ $(OUT_DIR)/$(ART_TEST_LIST_host_$(ART_HOST_ARCH)_libtistressd) \
$(OUT_DIR)/$(ART_TEST_LIST_host_$(ART_HOST_ARCH)_libartagent) \
$(OUT_DIR)/$(ART_TEST_LIST_host_$(ART_HOST_ARCH)_libartagentd) \
$(OUT_DIR)/$(ART_TEST_LIST_host_$(ART_HOST_ARCH)_libarttest) \
@@ -160,6 +170,8 @@
ART_TEST_HOST_RUN_TEST_DEPENDENCIES += \
$(OUT_DIR)/$(ART_TEST_LIST_host_$(2ND_ART_HOST_ARCH)_libtiagent) \
$(OUT_DIR)/$(ART_TEST_LIST_host_$(2ND_ART_HOST_ARCH)_libtiagentd) \
+ $(OUT_DIR)/$(ART_TEST_LIST_host_$(2ND_ART_HOST_ARCH)_libtistress) \
+ $(OUT_DIR)/$(ART_TEST_LIST_host_$(2ND_ART_HOST_ARCH)_libtistressd) \
$(OUT_DIR)/$(ART_TEST_LIST_host_$(2ND_ART_HOST_ARCH)_libartagent) \
$(OUT_DIR)/$(ART_TEST_LIST_host_$(2ND_ART_HOST_ARCH)_libartagentd) \
$(OUT_DIR)/$(ART_TEST_LIST_host_$(2ND_ART_HOST_ARCH)_libarttest) \
diff --git a/test/etc/default-build b/test/etc/default-build
index d74b24d..744c38b 100755
--- a/test/etc/default-build
+++ b/test/etc/default-build
@@ -91,7 +91,7 @@
JAVAC_EXPERIMENTAL_ARGS["lambdas"]="-source 1.8 -target 1.8"
JAVAC_EXPERIMENTAL_ARGS["method-handles"]="-source 1.8 -target 1.8"
# We need to leave javac at default 1.7 so that dx will continue to work
-JAVAC_EXPERIMENTAL_ARGS[${DEFAULT_EXPERIMENT}]="-source 1.7 -target 1.7"
+JAVAC_EXPERIMENTAL_ARGS[${DEFAULT_EXPERIMENT}]="-source 1.8 -target 1.8"
JAVAC_EXPERIMENTAL_ARGS["agents"]="-source 1.8 -target 1.8"
while true; do
diff --git a/test/etc/run-test-jar b/test/etc/run-test-jar
index f1b6132..56cfd24 100755
--- a/test/etc/run-test-jar
+++ b/test/etc/run-test-jar
@@ -62,6 +62,7 @@
TEST_VDEX="n"
TEST_IS_NDEBUG="n"
APP_IMAGE="y"
+JVMTI_STRESS="n"
VDEX_FILTER=""
PROFILE="n"
RANDOM_PROFILE="n"
@@ -145,6 +146,11 @@
elif [ "x$1" = "x--prebuild" ]; then
PREBUILD="y"
shift
+ elif [ "x$1" = "x--jvmti-stress" ]; then
+ # APP_IMAGE doesn't really work with jvmti-torture
+ APP_IMAGE="n"
+ JVMTI_STRESS="y"
+ shift
elif [ "x$1" = "x--no-app-image" ]; then
APP_IMAGE="n"
shift
@@ -365,6 +371,28 @@
fi
fi
+if [[ "$JVMTI_STRESS" = "y" ]]; then
+ if [[ "$USE_JVM" = "n" ]]; then
+ plugin=libopenjdkjvmtid.so
+ agent=libtistressd.so
+ if [[ "$TEST_IS_NDEBUG" = "y" ]]; then
+ agent=libtistress.so
+ plugin=libopenjdkjvmti.so
+ fi
+
+ file_1=$(mktemp --tmpdir=${DEX_LOCATION})
+ file_2=$(mktemp --tmpdir=${DEX_LOCATION})
+ # TODO Remove need for DEXTER_BINARY!
+ FLAGS="${FLAGS} -agentpath:${agent}=${DEXTER_BINARY},${file_1},${file_2}"
+ if [ "$IS_JVMTI_TEST" = "n" ]; then
+ FLAGS="${FLAGS} -Xplugin:${plugin}"
+ FLAGS="${FLAGS} -Xcompiler-option --debuggable"
+ # Always make the compilation be debuggable.
+ COMPILE_FLAGS="${COMPILE_FLAGS} --debuggable"
+ fi
+ fi
+fi
+
if [ "$USE_JVM" = "y" ]; then
export LD_LIBRARY_PATH=${ANDROID_HOST_OUT}/lib64
# Xmx is necessary since we don't pass down the ART flags to JVM.
diff --git a/test/knownfailures.json b/test/knownfailures.json
index 7891d4c..e7343a0 100644
--- a/test/knownfailures.json
+++ b/test/knownfailures.json
@@ -366,5 +366,248 @@
"634-vdex-duplicate"],
"description": ["Profile driven dexlayout does not work with vdex or dex verifier."],
"variant": "speed-profile"
+ },
+ {
+ "tests": [
+ "004-checker-UnsafeTest18",
+ "127-checker-secondarydex",
+ "441-checker-inliner",
+ "442-checker-constant-folding",
+ "444-checker-nce",
+ "445-checker-licm",
+ "446-checker-inliner2",
+ "447-checker-inliner3",
+ "449-checker-bce",
+ "450-checker-types",
+ "455-checker-gvn",
+ "458-checker-instruct-simplification",
+ "462-checker-inlining-dex-files",
+ "463-checker-boolean-simplifier",
+ "464-checker-inline-sharpen-calls",
+ "465-checker-clinit-gvn",
+ "468-checker-bool-simplif-regression",
+ "473-checker-inliner-constants",
+ "474-checker-boolean-input",
+ "476-checker-ctor-memory-barrier",
+ "477-checker-bound-type",
+ "478-checker-clinit-check-pruning",
+ "478-checker-inline-noreturn",
+ "478-checker-inliner-nested-loop",
+ "480-checker-dead-blocks",
+ "482-checker-loop-back-edge-use",
+ "484-checker-register-hints",
+ "485-checker-dce-loop-update",
+ "485-checker-dce-switch",
+ "486-checker-must-do-null-check",
+ "487-checker-inline-calls",
+ "488-checker-inline-recursive-calls",
+ "490-checker-inline",
+ "492-checker-inline-invoke-interface",
+ "493-checker-inline-invoke-interface",
+ "494-checker-instanceof-tests",
+ "495-checker-checkcast-tests",
+ "496-checker-inlining-class-loader",
+ "508-checker-disassembly",
+ "510-checker-try-catch",
+ "517-checker-builder-fallthrough",
+ "521-checker-array-set-null",
+ "522-checker-regression-monitor-exit",
+ "523-checker-can-throw-regression",
+ "525-checker-arrays-fields1",
+ "525-checker-arrays-fields2",
+ "526-checker-caller-callee-regs",
+ "527-checker-array-access-split",
+ "529-checker-unresolved",
+ "530-checker-loops1",
+ "530-checker-loops2",
+ "530-checker-loops3",
+ "530-checker-loops4",
+ "530-checker-loops5",
+ "530-checker-lse",
+ "530-checker-lse2",
+ "530-checker-regression-reftyp-final",
+ "532-checker-nonnull-arrayset",
+ "534-checker-bce-deoptimization",
+ "536-checker-intrinsic-optimization",
+ "536-checker-needs-access-check",
+ "537-checker-arraycopy",
+ "537-checker-debuggable",
+ "537-checker-inline-and-unverified",
+ "537-checker-jump-over-jump",
+ "538-checker-embed-constants",
+ "540-checker-rtp-bug",
+ "543-checker-dce-trycatch",
+ "548-checker-inlining-and-dce",
+ "549-checker-types-merge",
+ "550-checker-multiply-accumulate",
+ "550-checker-regression-wide-store",
+ "551-checker-clinit",
+ "551-checker-shifter-operand",
+ "552-checker-primitive-typeprop",
+ "552-checker-sharpening",
+ "554-checker-rtp-checkcast",
+ "557-checker-instruct-simplifier-ror",
+ "557-checker-ref-equivalent",
+ "559-checker-irreducible-loop",
+ "559-checker-rtp-ifnotnull",
+ "562-checker-no-intermediate",
+ "563-checker-fakestring",
+ "563-checker-invoke-super",
+ "564-checker-bitcount",
+ "564-checker-inline-loop",
+ "564-checker-irreducible-loop",
+ "564-checker-negbitwise",
+ "565-checker-condition-liveness",
+ "565-checker-doublenegbitwise",
+ "565-checker-irreducible-loop",
+ "565-checker-rotate",
+ "566-checker-codegen-select",
+ "566-checker-signum",
+ "567-checker-compare",
+ "568-checker-onebit",
+ "569-checker-pattern-replacement",
+ "570-checker-osr",
+ "570-checker-select",
+ "572-checker-array-get-regression",
+ "573-checker-checkcast-regression",
+ "575-checker-isnan",
+ "575-checker-string-init-alias",
+ "577-checker-fp2int",
+ "580-checker-round",
+ "580-checker-string-fact-intrinsics",
+ "582-checker-bce-length",
+ "583-checker-zero",
+ "584-checker-div-bool",
+ "586-checker-null-array-get",
+ "588-checker-irreducib-lifetime-hole",
+ "590-checker-arr-set-null-regression",
+ "591-checker-regression-dead-loop",
+ "592-checker-regression-bool-input",
+ "593-checker-boolean-2-integral-conv",
+ "593-checker-long-2-float-regression",
+ "593-checker-shift-and-simplifier",
+ "594-checker-array-alias",
+ "594-checker-irreducible-linorder",
+ "596-checker-dead-phi",
+ "598-checker-irreducible-dominance",
+ "599-checker-irreducible-loop",
+ "603-checker-instanceof",
+ "608-checker-unresolved-lse",
+ "609-checker-inline-interface",
+ "609-checker-x86-bounds-check",
+ "611-checker-simplify-if",
+ "614-checker-dump-constant-location",
+ "615-checker-arm64-store-zero",
+ "618-checker-induction",
+ "619-checker-current-method",
+ "620-checker-bce-intrinsics",
+ "622-checker-bce-regressions",
+ "623-checker-loop-regressions",
+ "624-checker-stringops",
+ "625-checker-licm-regressions",
+ "626-checker-arm64-scratch-register",
+ "627-checker-unroll",
+ "631-checker-fp-abs",
+ "631-checker-get-class",
+ "632-checker-char-at-bounds",
+ "633-checker-rtp-getclass",
+ "635-checker-arm64-volatile-load-cc",
+ "637-checker-throw-inline",
+ "638-checker-inline-caches",
+ "639-checker-code-sinking",
+ "640-checker-boolean-simd",
+ "640-checker-byte-simd",
+ "640-checker-char-simd",
+ "640-checker-double-simd",
+ "640-checker-float-simd",
+ "640-checker-integer-valueof",
+ "640-checker-int-simd",
+ "640-checker-long-simd",
+ "640-checker-short-simd",
+ "641-checker-arraycopy",
+ "643-checker-bogus-ic",
+ "644-checker-deopt",
+ "645-checker-abs-simd",
+ "706-checker-scheduler"],
+ "description": ["Checker tests are not compatible with jvmti."],
+ "variant": "jvmti-stress"
+ },
+ {
+ "tests": [
+ "961-default-iface-resolution-gen",
+ "964-default-iface-init-gen"
+ ],
+ "description": ["Tests that just take too long with jvmti-stress"],
+ "variant": "jvmti-stress"
+ },
+ {
+ "tests": [
+ "950-redefine-intrinsic",
+ "951-threaded-obsolete",
+ "952-invoke-custom",
+ "953-invoke-polymorphic-compiler",
+ "954-invoke-polymorphic-verifier",
+ "955-methodhandles-smali",
+ "956-methodhandles",
+ "957-methodhandle-transforms",
+ "958-methodhandle-stackframe",
+ "959-invoke-polymorphic-accessors"
+ ],
+ "description": [
+ "Tests that use dex version 38 which is not yet supported by",
+ "dexter/slicer."
+ ],
+ "bug": "b/37272822",
+ "variant": "jvmti-stress"
+ },
+ {
+ "tests": [
+ "137-cfi",
+ "595-profile-saving",
+ "900-hello-plugin",
+ "909-attach-agent",
+ "981-dedup-original-dex"
+ ],
+ "description": ["Tests that require exact knowledge of the number of plugins and agents."],
+ "variant": "jvmti-stress"
+ },
+ {
+ "tests": [
+ "097-duplicate-method",
+ "138-duplicate-classes-check2",
+ "804-class-extends-itself",
+ "921-hello-failure"
+ ],
+ "description": [
+ "Tests that use illegal dex files or otherwise break dexter assumptions"
+ ],
+ "variant": "jvmti-stress"
+ },
+ {
+ "tests": [
+ "018-stack-overflow",
+ "068-classloader",
+ "086-null-super",
+ "087-gc-after-link",
+ "626-const-class-linking",
+ "629-vdex-speed",
+ "944-transform-classloaders"
+ ],
+ "description": [
+ "Tests that use custom class loaders or other features not supported ",
+ "by our JVMTI implementation"
+ ],
+ "variant": "jvmti-stress"
+ },
+ {
+ "tests": [
+ "031-class-attributes",
+ "911-get-stack-trace"
+ ],
+ "description": [
+ "Tests that use annotations and debug data that is not kept around by dexter."
+ ],
+ "bug": "b/37239009",
+ "variant": "jvmti-stress"
}
]
diff --git a/test/run-test b/test/run-test
index e46099d..f60f766 100755
--- a/test/run-test
+++ b/test/run-test
@@ -137,6 +137,7 @@
basic_verify="false"
gc_verify="false"
gc_stress="false"
+jvmti_stress="false"
strace="false"
always_clean="no"
never_clean="no"
@@ -233,6 +234,9 @@
basic_verify="true"
gc_stress="true"
shift
+ elif [ "x$1" = "x--jvmti-stress" ]; then
+ jvmti_stress="true"
+ shift
elif [ "x$1" = "x--suspend-timeout" ]; then
shift
suspend_timeout="$1"
@@ -443,6 +447,9 @@
if [ "$gc_stress" = "true" ]; then
run_args="${run_args} --gc-stress --runtime-option -Xgc:gcstress --runtime-option -Xms2m --runtime-option -Xmx16m"
fi
+if [ "$jvmti_stress" = "true" ]; then
+ run_args="${run_args} --no-app-image --jvmti-stress"
+fi
if [ "$trace" = "true" ]; then
run_args="${run_args} --runtime-option -Xmethod-trace --runtime-option -Xmethod-trace-file-size:2000000"
if [ "$trace_stream" = "true" ]; then
@@ -651,6 +658,7 @@
echo " --stream Run method tracing in streaming mode (requires --trace)"
echo " --gcstress Run with gc stress testing"
echo " --gcverify Run with gc verification"
+ echo " --jvmti-stress Run with jvmti stress testing"
echo " --always-clean Delete the test files even if the test fails."
echo " --never-clean Keep the test files even if the test succeeds."
echo " --android-root [path] The path on target for the android root. (/system by default)."
diff --git a/test/testrunner/env.py b/test/testrunner/env.py
index f5e2a61..7d9297f 100644
--- a/test/testrunner/env.py
+++ b/test/testrunner/env.py
@@ -202,6 +202,9 @@
# Note: ART_2ND_PHONY_TEST_TARGET_SUFFIX is 2ND_ART_PHONY_TEST_TARGET_SUFFIX in .mk files
# Note: ART_2ND_PHONY_TEST_HOST_SUFFIX is 2ND_ART_PHONY_HOST_TARGET_SUFFIX in .mk files
# Python does not let us have variable names starting with a digit, so it has differ.
+
+ART_TEST_RUN_TEST_JVMTI_STRESS = _getEnvBoolean('ART_TEST_RUN_TEST_JVMTI_STRESS', ART_TEST_FULL)
+
if TARGET_2ND_ARCH:
if "64" in TARGET_ARCH:
ART_PHONY_TEST_TARGET_SUFFIX = "64"
diff --git a/test/testrunner/target_config.py b/test/testrunner/target_config.py
index 8e29b8e..6e47c5e 100644
--- a/test/testrunner/target_config.py
+++ b/test/testrunner/target_config.py
@@ -26,7 +26,7 @@
'make' : 'test-art-host-gtest',
'run-test' : [],
'env' : {
- 'ART_USE_READ_BARRIER' : 'false'
+ 'ART_USE_READ_BARRIER' : 'true'
}
},
@@ -45,19 +45,19 @@
'art-interpreter' : {
'run-test' : ['--interpreter'],
'env' : {
- 'ART_USE_READ_BARRIER' : 'false'
+ 'ART_USE_READ_BARRIER' : 'true'
}
},
'art-interpreter-access-checks' : {
'run-test' : ['--interp-ac'],
'env' : {
- 'ART_USE_READ_BARRIER' : 'false'
+ 'ART_USE_READ_BARRIER' : 'true'
}
},
'art-jit' : {
'run-test' : ['--jit'],
'env' : {
- 'ART_USE_READ_BARRIER' : 'false'
+ 'ART_USE_READ_BARRIER' : 'true'
}
},
'art-gcstress-gcverify': {
@@ -167,51 +167,51 @@
'art-tracing' : {
'run-test' : ['--trace'],
'env' : {
- 'ART_USE_READ_BARRIER' : 'false'
+ 'ART_USE_READ_BARRIER' : 'true'
}
},
'art-interpreter-tracing' : {
'run-test' : ['--interpreter',
'--trace'],
'env' : {
- 'ART_USE_READ_BARRIER' : 'false',
+ 'ART_USE_READ_BARRIER' : 'true',
}
},
'art-forcecopy' : {
'run-test' : ['--forcecopy'],
'env' : {
- 'ART_USE_READ_BARRIER' : 'false',
+ 'ART_USE_READ_BARRIER' : 'true',
}
},
'art-no-prebuild' : {
'run-test' : ['--no-prebuild'],
'env' : {
- 'ART_USE_READ_BARRIER' : 'false',
+ 'ART_USE_READ_BARRIER' : 'true',
}
},
'art-no-image' : {
'run-test' : ['--no-image'],
'env' : {
- 'ART_USE_READ_BARRIER' : 'false',
+ 'ART_USE_READ_BARRIER' : 'true',
}
},
'art-interpreter-no-image' : {
'run-test' : ['--interpreter',
'--no-image'],
'env' : {
- 'ART_USE_READ_BARRIER' : 'false',
+ 'ART_USE_READ_BARRIER' : 'true',
}
},
'art-relocate-no-patchoat' : {
'run-test' : ['--relocate-npatchoat'],
'env' : {
- 'ART_USE_READ_BARRIER' : 'false',
+ 'ART_USE_READ_BARRIER' : 'true',
}
},
'art-no-dex2oat' : {
'run-test' : ['--no-dex2oat'],
'env' : {
- 'ART_USE_READ_BARRIER' : 'false',
+ 'ART_USE_READ_BARRIER' : 'true',
}
},
'art-heap-poisoning' : {
@@ -222,6 +222,18 @@
'ART_HEAP_POISONING' : 'true'
}
},
+ 'art-preopt' : {
+ # This test configuration is intended to be representative of the case
+ # of preopted apps, which are precompiled compiled pic against an
+ # unrelocated image, then used with a relocated image.
+ 'run-test' : ['--pictest',
+ '--prebuild',
+ '--relocate',
+ '--jit'],
+ 'env' : {
+ 'ART_USE_READ_BARRIER' : 'true'
+ }
+ },
# ART gtest configurations
# (calls make 'target' which builds and then runs the gtests).
diff --git a/test/testrunner/testrunner.py b/test/testrunner/testrunner.py
index 5d3687e..8072631 100755
--- a/test/testrunner/testrunner.py
+++ b/test/testrunner/testrunner.py
@@ -73,6 +73,7 @@
DEBUGGABLE_TYPES = set()
ADDRESS_SIZES = set()
OPTIMIZING_COMPILER_TYPES = set()
+JVMTI_TYPES = set()
ADDRESS_SIZES_TARGET = {'host': set(), 'target': set()}
# timeout for individual tests.
# TODO: make it adjustable per tests and for buildbots
@@ -146,6 +147,7 @@
VARIANT_TYPE_DICT['relocate'] = {'relocate-npatchoat', 'relocate', 'no-relocate'}
VARIANT_TYPE_DICT['jni'] = {'jni', 'forcecopy', 'checkjni'}
VARIANT_TYPE_DICT['address_sizes'] = {'64', '32'}
+ VARIANT_TYPE_DICT['jvmti'] = {'no-jvmti', 'jvmti-stress'}
VARIANT_TYPE_DICT['compiler'] = {'interp-ac', 'interpreter', 'jit', 'optimizing',
'regalloc_gc', 'speed-profile'}
@@ -195,6 +197,10 @@
if env.ART_TEST_SPEED_PROFILE:
COMPILER_TYPES.add('speed-profile')
+ # By default only run without jvmti
+ if not JVMTI_TYPES:
+ JVMTI_TYPES.add('no-jvmti')
+
# By default we run all 'compiler' variants.
if not COMPILER_TYPES:
COMPILER_TYPES.add('optimizing')
@@ -310,6 +316,7 @@
total_test_count *= len(PICTEST_TYPES)
total_test_count *= len(DEBUGGABLE_TYPES)
total_test_count *= len(COMPILER_TYPES)
+ total_test_count *= len(JVMTI_TYPES)
target_address_combinations = 0
for target in TARGET_TYPES:
for address_size in ADDRESS_SIZES_TARGET[target]:
@@ -336,10 +343,10 @@
config = itertools.product(tests, TARGET_TYPES, RUN_TYPES, PREBUILD_TYPES,
COMPILER_TYPES, RELOCATE_TYPES, TRACE_TYPES,
GC_TYPES, JNI_TYPES, IMAGE_TYPES, PICTEST_TYPES,
- DEBUGGABLE_TYPES)
+ DEBUGGABLE_TYPES, JVMTI_TYPES)
for test, target, run, prebuild, compiler, relocate, trace, gc, \
- jni, image, pictest, debuggable in config:
+ jni, image, pictest, debuggable, jvmti in config:
for address_size in ADDRESS_SIZES_TARGET[target]:
if stop_testrunner:
# When ART_TEST_KEEP_GOING is set to false, then as soon as a test
@@ -361,11 +368,12 @@
test_name += image + '-'
test_name += pictest + '-'
test_name += debuggable + '-'
+ test_name += jvmti + '-'
test_name += test
test_name += address_size
variant_set = {target, run, prebuild, compiler, relocate, trace, gc, jni,
- image, pictest, debuggable, address_size}
+ image, pictest, debuggable, jvmti, address_size}
options_test = options_all
@@ -428,6 +436,9 @@
if debuggable == 'debuggable':
options_test += ' --debuggable'
+ if jvmti == 'jvmti-stress':
+ options_test += ' --jvmti-stress'
+
if address_size == '64':
options_test += ' --64'
@@ -762,6 +773,7 @@
regex += '(' + '|'.join(VARIANT_TYPE_DICT['image']) + ')-'
regex += '(' + '|'.join(VARIANT_TYPE_DICT['pictest']) + ')-'
regex += '(' + '|'.join(VARIANT_TYPE_DICT['debuggable']) + ')-'
+ regex += '(' + '|'.join(VARIANT_TYPE_DICT['jvmti']) + ')-'
regex += '(' + '|'.join(RUN_TEST_SET) + ')'
regex += '(' + '|'.join(VARIANT_TYPE_DICT['address_sizes']) + ')$'
match = re.match(regex, test_name)
@@ -777,8 +789,9 @@
IMAGE_TYPES.add(match.group(9))
PICTEST_TYPES.add(match.group(10))
DEBUGGABLE_TYPES.add(match.group(11))
- ADDRESS_SIZES.add(match.group(13))
- return {match.group(12)}
+ JVMTI_TYPES.add(match.group(12))
+ ADDRESS_SIZES.add(match.group(14))
+ return {match.group(13)}
raise ValueError(test_name + " is not a valid test")
@@ -918,6 +931,10 @@
GC_TYPES.add('cms')
if options['multipicimage']:
IMAGE_TYPES.add('multipicimage')
+ if options['jvmti_stress']:
+ JVMTI_TYPES.add('jvmti-stress')
+ if options['no_jvmti']:
+ JVMTI_TYPES.add('no-jvmti')
if options['verbose']:
verbose = True
if options['n_thread']:
diff --git a/test/ti-agent/common_helper.cc b/test/ti-agent/common_helper.cc
index ab5dbcc..bfd4d25 100644
--- a/test/ti-agent/common_helper.cc
+++ b/test/ti-agent/common_helper.cc
@@ -17,18 +17,15 @@
#include "common_helper.h"
#include <dlfcn.h>
+#include <map>
#include <stdio.h>
#include <sstream>
#include <deque>
+#include <vector>
#include "android-base/stringprintf.h"
-#include "art_method.h"
#include "jni.h"
-#include "jni_internal.h"
#include "jvmti.h"
-#include "scoped_thread_state_change-inl.h"
-#include "stack.h"
-#include "utils.h"
#include "jni_binder.h"
#include "jvmti_helper.h"
@@ -37,6 +34,10 @@
namespace art {
+static void SetupCommonRetransform();
+static void SetupCommonRedefine();
+static void SetupCommonTransform();
+
template <bool is_redefine>
static void throwCommonRedefinitionError(jvmtiEnv* jvmti,
JNIEnv* env,
@@ -108,18 +109,15 @@
// Magic JNI export that classes can use for redefining classes.
// To use classes should declare this as a native function with signature (Ljava/lang/Class;[B[B)V
-extern "C" JNIEXPORT void JNICALL Java_Main_doCommonClassRedefinition(JNIEnv* env,
- jclass,
- jclass target,
- jbyteArray class_file_bytes,
- jbyteArray dex_file_bytes) {
+extern "C" JNIEXPORT void JNICALL Java_art_Redefinition_doCommonClassRedefinition(
+ JNIEnv* env, jclass, jclass target, jbyteArray class_file_bytes, jbyteArray dex_file_bytes) {
DoClassRedefine(jvmti_env, env, target, class_file_bytes, dex_file_bytes);
}
// Magic JNI export that classes can use for redefining classes.
// To use classes should declare this as a native function with signature
// ([Ljava/lang/Class;[[B[[B)V
-extern "C" JNIEXPORT void JNICALL Java_Main_doCommonMultiClassRedefinition(
+extern "C" JNIEXPORT void JNICALL Java_art_Redefinition_doCommonMultiClassRedefinition(
JNIEnv* env,
jclass,
jobjectArray targets,
@@ -155,11 +153,7 @@
printf("Unable to get jvmti env!\n");
return 1;
}
- jvmtiCapabilities caps;
- jvmti_env->GetPotentialCapabilities(&caps);
- caps.can_retransform_classes = 0;
- caps.can_retransform_any_class = 0;
- jvmti_env->AddCapabilities(&caps);
+ SetupCommonRedefine();
return 0;
}
@@ -183,11 +177,8 @@
std::map<std::string, std::deque<CommonTransformationResult>> gTransformations;
bool gPopTransformations = true;
-extern "C" JNIEXPORT void JNICALL Java_Main_addCommonTransformationResult(JNIEnv* env,
- jclass,
- jstring class_name,
- jbyteArray class_array,
- jbyteArray dex_array) {
+extern "C" JNIEXPORT void JNICALL Java_art_Redefinition_addCommonTransformationResult(
+ JNIEnv* env, jclass, jstring class_name, jbyteArray class_array, jbyteArray dex_array) {
const char* name_chrs = env->GetStringUTFChars(class_name, nullptr);
std::string name_str(name_chrs);
env->ReleaseStringUTFChars(class_name, name_chrs);
@@ -244,15 +235,15 @@
}
}
-extern "C" JNIEXPORT void Java_Main_setPopRetransformations(JNIEnv*,
- jclass,
- jboolean enable) {
+extern "C" JNIEXPORT void Java_art_Redefinition_setPopRetransformations(JNIEnv*,
+ jclass,
+ jboolean enable) {
gPopTransformations = enable;
}
-extern "C" JNIEXPORT void Java_Main_popTransformationFor(JNIEnv* env,
- jclass,
- jstring class_name) {
+extern "C" JNIEXPORT void Java_art_Redefinition_popTransformationFor(JNIEnv* env,
+ jclass,
+ jstring class_name) {
const char* name_chrs = env->GetStringUTFChars(class_name, nullptr);
std::string name_str(name_chrs);
env->ReleaseStringUTFChars(class_name, name_chrs);
@@ -267,9 +258,9 @@
}
}
-extern "C" JNIEXPORT void Java_Main_enableCommonRetransformation(JNIEnv* env,
- jclass,
- jboolean enable) {
+extern "C" JNIEXPORT void Java_art_Redefinition_enableCommonRetransformation(JNIEnv* env,
+ jclass,
+ jboolean enable) {
jvmtiError res = jvmti_env->SetEventNotificationMode(enable ? JVMTI_ENABLE : JVMTI_DISABLE,
JVMTI_EVENT_CLASS_FILE_LOAD_HOOK,
nullptr);
@@ -298,9 +289,8 @@
}
}
-extern "C" JNIEXPORT void JNICALL Java_Main_doCommonClassRetransformation(JNIEnv* env,
- jclass,
- jobjectArray targets) {
+extern "C" JNIEXPORT void JNICALL Java_art_Redefinition_doCommonClassRetransformation(
+ JNIEnv* env, jclass, jobjectArray targets) {
jvmtiCapabilities caps;
jvmtiError caps_err = jvmti_env->GetCapabilities(&caps);
if (caps_err != JVMTI_ERROR_NONE) {
@@ -338,14 +328,7 @@
printf("Unable to get jvmti env!\n");
return 1;
}
- SetAllCapabilities(jvmti_env);
- jvmtiEventCallbacks cb;
- memset(&cb, 0, sizeof(cb));
- cb.ClassFileLoadHook = CommonClassFileLoadHookRetransformable;
- if (jvmti_env->SetEventCallbacks(&cb, sizeof(cb)) != JVMTI_ERROR_NONE) {
- printf("Unable to set class file load hook cb!\n");
- return 1;
- }
+ SetupCommonRetransform();
return 0;
}
@@ -353,8 +336,6 @@
namespace common_transform {
-using art::common_retransform::CommonClassFileLoadHookRetransformable;
-
// Get all capabilities except those related to retransformation.
jint OnLoad(JavaVM* vm,
char* options ATTRIBUTE_UNUSED,
@@ -363,6 +344,35 @@
printf("Unable to get jvmti env!\n");
return 1;
}
+ SetupCommonTransform();
+ return 0;
+}
+
+} // namespace common_transform
+
+#define CONFIGURATION_COMMON_REDEFINE 0
+#define CONFIGURATION_COMMON_RETRANSFORM 1
+#define CONFIGURATION_COMMON_TRANSFORM 2
+
+static void SetupCommonRedefine() {
+ jvmtiCapabilities caps;
+ jvmti_env->GetPotentialCapabilities(&caps);
+ caps.can_retransform_classes = 0;
+ caps.can_retransform_any_class = 0;
+ jvmti_env->AddCapabilities(&caps);
+}
+
+static void SetupCommonRetransform() {
+ SetAllCapabilities(jvmti_env);
+ jvmtiEventCallbacks cb;
+ memset(&cb, 0, sizeof(cb));
+ cb.ClassFileLoadHook = common_retransform::CommonClassFileLoadHookRetransformable;
+ jvmtiError res = jvmti_env->SetEventCallbacks(&cb, sizeof(cb));
+ CHECK_EQ(res, JVMTI_ERROR_NONE);
+ common_retransform::gTransformations.clear();
+}
+
+static void SetupCommonTransform() {
// Don't set the retransform caps
jvmtiCapabilities caps;
jvmti_env->GetPotentialCapabilities(&caps);
@@ -373,14 +383,31 @@
// Use the same callback as the retransform test.
jvmtiEventCallbacks cb;
memset(&cb, 0, sizeof(cb));
- cb.ClassFileLoadHook = CommonClassFileLoadHookRetransformable;
- if (jvmti_env->SetEventCallbacks(&cb, sizeof(cb)) != JVMTI_ERROR_NONE) {
- printf("Unable to set class file load hook cb!\n");
- return 1;
- }
- return 0;
+ cb.ClassFileLoadHook = common_retransform::CommonClassFileLoadHookRetransformable;
+ jvmtiError res = jvmti_env->SetEventCallbacks(&cb, sizeof(cb));
+ CHECK_EQ(res, JVMTI_ERROR_NONE);
+ common_retransform::gTransformations.clear();
}
-} // namespace common_transform
-
+extern "C" JNIEXPORT void JNICALL Java_art_Redefinition_nativeSetTestConfiguration(JNIEnv*,
+ jclass,
+ jint type) {
+ switch (type) {
+ case CONFIGURATION_COMMON_REDEFINE: {
+ SetupCommonRedefine();
+ return;
+ }
+ case CONFIGURATION_COMMON_RETRANSFORM: {
+ SetupCommonRetransform();
+ return;
+ }
+ case CONFIGURATION_COMMON_TRANSFORM: {
+ SetupCommonTransform();
+ return;
+ }
+ default: {
+ LOG(FATAL) << "Unknown test configuration: " << type;
+ }
+ }
+}
} // namespace art
diff --git a/test/ti-agent/common_load.cc b/test/ti-agent/common_load.cc
index 9e7b75d..3455409 100644
--- a/test/ti-agent/common_load.cc
+++ b/test/ti-agent/common_load.cc
@@ -60,31 +60,17 @@
// MinimalOnLoad.
static AgentLib agents[] = {
{ "901-hello-ti-agent", Test901HelloTi::OnLoad, nullptr },
- { "902-hello-transformation", common_redefine::OnLoad, nullptr },
{ "909-attach-agent", nullptr, Test909AttachAgent::OnAttach },
- { "914-hello-obsolescence", common_redefine::OnLoad, nullptr },
- { "915-obsolete-2", common_redefine::OnLoad, nullptr },
{ "916-obsolete-jit", common_redefine::OnLoad, nullptr },
- { "917-fields-transformation", common_redefine::OnLoad, nullptr },
- { "919-obsolete-fields", common_redefine::OnLoad, nullptr },
{ "921-hello-failure", common_retransform::OnLoad, nullptr },
- { "926-multi-obsolescence", common_redefine::OnLoad, nullptr },
- { "930-hello-retransform", common_retransform::OnLoad, nullptr },
- { "932-transform-saves", common_retransform::OnLoad, nullptr },
{ "934-load-transform", common_retransform::OnLoad, nullptr },
{ "935-non-retransformable", common_transform::OnLoad, nullptr },
{ "936-search-onload", Test936SearchOnload::OnLoad, nullptr },
{ "937-hello-retransform-package", common_retransform::OnLoad, nullptr },
{ "938-load-transform-bcp", common_retransform::OnLoad, nullptr },
{ "939-hello-transformation-bcp", common_redefine::OnLoad, nullptr },
- { "940-recursive-obsolete", common_redefine::OnLoad, nullptr },
{ "941-recursive-obsolete-jit", common_redefine::OnLoad, nullptr },
- { "942-private-recursive", common_redefine::OnLoad, nullptr },
{ "943-private-recursive-jit", common_redefine::OnLoad, nullptr },
- { "944-transform-classloaders", common_redefine::OnLoad, nullptr },
- { "945-obsolete-native", common_redefine::OnLoad, nullptr },
- { "981-dedup-original-dex", common_retransform::OnLoad, nullptr },
- { "982-ok-no-retransform", common_retransform::OnLoad, nullptr },
{ "983-source-transform-verify", Test983SourceTransformVerify::OnLoad, nullptr },
};
diff --git a/test/ti-agent/scoped_local_ref.h b/test/ti-agent/scoped_local_ref.h
index daa1583..ba9725f 100644
--- a/test/ti-agent/scoped_local_ref.h
+++ b/test/ti-agent/scoped_local_ref.h
@@ -44,7 +44,7 @@
}
}
- T release() __attribute__((warn_unused_result)) {
+ T release() WARN_UNUSED {
T localRef = mLocalRef;
mLocalRef = nullptr;
return localRef;
diff --git a/test/ti-stress/stress.cc b/test/ti-stress/stress.cc
new file mode 100644
index 0000000..fa49a35
--- /dev/null
+++ b/test/ti-stress/stress.cc
@@ -0,0 +1,210 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <jni.h>
+#include <stdio.h>
+#include <iostream>
+#include <fstream>
+#include <stdio.h>
+#include <sstream>
+
+#include "jvmti.h"
+#include "exec_utils.h"
+#include "utils.h"
+
+namespace art {
+
+// Should we do a 'full_rewrite' with this test?
+static constexpr bool kDoFullRewrite = true;
+
+struct StressData {
+ std::string dexter_cmd;
+ std::string out_temp_dex;
+ std::string in_temp_dex;
+ bool vm_class_loader_initialized;
+};
+
+static void WriteToFile(const std::string& fname, jint data_len, const unsigned char* data) {
+ std::ofstream file(fname, std::ios::binary | std::ios::out | std::ios::trunc);
+ file.write(reinterpret_cast<const char*>(data), data_len);
+ file.flush();
+}
+
+static bool ReadIntoBuffer(const std::string& fname, /*out*/std::vector<unsigned char>* data) {
+ std::ifstream file(fname, std::ios::binary | std::ios::in);
+ file.seekg(0, std::ios::end);
+ size_t len = file.tellg();
+ data->resize(len);
+ file.seekg(0);
+ file.read(reinterpret_cast<char*>(data->data()), len);
+ return len != 0;
+}
+
+// TODO rewrite later.
+static bool DoExtractClassFromData(StressData* data,
+ const std::string& class_name,
+ jint in_len,
+ const unsigned char* in_data,
+ /*out*/std::vector<unsigned char>* dex) {
+ // Write the dex file into a temporary file.
+ WriteToFile(data->in_temp_dex, in_len, in_data);
+ // Clear out file so even if something suppresses the exit value we will still detect dexter
+ // failure.
+ WriteToFile(data->out_temp_dex, 0, nullptr);
+ // Have dexter do the extraction.
+ std::vector<std::string> args;
+ args.push_back(data->dexter_cmd);
+ if (kDoFullRewrite) {
+ args.push_back("-x");
+ args.push_back("full_rewrite");
+ }
+ args.push_back("-e");
+ args.push_back(class_name);
+ args.push_back("-o");
+ args.push_back(data->out_temp_dex);
+ args.push_back(data->in_temp_dex);
+ std::string error;
+ if (ExecAndReturnCode(args, &error) != 0) {
+ LOG(ERROR) << "unable to execute dexter: " << error;
+ return false;
+ }
+ return ReadIntoBuffer(data->out_temp_dex, dex);
+}
+
+// The hook we are using.
+void JNICALL ClassFileLoadHookSecretNoOp(jvmtiEnv* jvmti,
+ JNIEnv* jni_env ATTRIBUTE_UNUSED,
+ jclass class_being_redefined ATTRIBUTE_UNUSED,
+ jobject loader ATTRIBUTE_UNUSED,
+ const char* name,
+ jobject protection_domain ATTRIBUTE_UNUSED,
+ jint class_data_len,
+ const unsigned char* class_data,
+ jint* new_class_data_len,
+ unsigned char** new_class_data) {
+ std::vector<unsigned char> out;
+ std::string name_str(name);
+ // Make the jvmti semi-descriptor into the java style descriptor (though with $ for inner
+ // classes).
+ std::replace(name_str.begin(), name_str.end(), '/', '.');
+ StressData* data = nullptr;
+ CHECK_EQ(jvmti->GetEnvironmentLocalStorage(reinterpret_cast<void**>(&data)),
+ JVMTI_ERROR_NONE);
+ if (!data->vm_class_loader_initialized) {
+ LOG(WARNING) << "Ignoring load of class " << name << " because VMClassLoader is not yet "
+ << "initialized. Transforming this class could cause spurious test failures.";
+ return;
+ } else if (DoExtractClassFromData(data, name_str, class_data_len, class_data, /*out*/ &out)) {
+ LOG(INFO) << "Extracted class: " << name;
+ unsigned char* new_data;
+ CHECK_EQ(JVMTI_ERROR_NONE, jvmti->Allocate(out.size(), &new_data));
+ memcpy(new_data, out.data(), out.size());
+ *new_class_data_len = static_cast<jint>(out.size());
+ *new_class_data = new_data;
+ } else {
+ std::cerr << "Unable to extract class " << name_str << std::endl;
+ *new_class_data_len = 0;
+ *new_class_data = nullptr;
+ }
+}
+
+// Options are ${DEXTER_BINARY},${TEMP_FILE_1},${TEMP_FILE_2}
+static void ReadOptions(StressData* data, char* options) {
+ std::string ops(options);
+ data->dexter_cmd = ops.substr(0, ops.find(','));
+ ops = ops.substr(ops.find(',') + 1);
+ data->in_temp_dex = ops.substr(0, ops.find(','));
+ ops = ops.substr(ops.find(',') + 1);
+ data->out_temp_dex = ops;
+}
+
+// We need to make sure that VMClassLoader is initialized before we start redefining anything since
+// it can give (non-fatal) error messages if it's initialized after we've redefined BCP classes.
+// These error messages are expected and no problem but they will mess up our testing
+// infrastructure.
+static void JNICALL EnsureVMClassloaderInitializedCB(jvmtiEnv *jvmti_env,
+ JNIEnv* jni_env,
+ jthread thread ATTRIBUTE_UNUSED) {
+ // Load the VMClassLoader class. We will get a ClassNotFound exception because we don't have
+ // visibility but the class will be loaded behind the scenes.
+ LOG(INFO) << "manual load & initialization of class java/lang/VMClassLoader!";
+ jclass klass = jni_env->FindClass("java/lang/VMClassLoader");
+ if (klass == nullptr) {
+ LOG(ERROR) << "Unable to find VMClassLoader class!";
+ } else {
+ // GetMethodID is spec'd to cause the class to be initialized.
+ jni_env->GetMethodID(klass, "hashCode", "()I");
+ jni_env->DeleteLocalRef(klass);
+ StressData* data = nullptr;
+ CHECK_EQ(jvmti_env->GetEnvironmentLocalStorage(reinterpret_cast<void**>(&data)),
+ JVMTI_ERROR_NONE);
+ data->vm_class_loader_initialized = true;
+ }
+}
+
+extern "C" JNIEXPORT jint JNICALL Agent_OnLoad(JavaVM* vm,
+ char* options,
+ void* reserved ATTRIBUTE_UNUSED) {
+ jvmtiEnv* jvmti = nullptr;
+ if (vm->GetEnv(reinterpret_cast<void**>(&jvmti), JVMTI_VERSION_1_0)) {
+ LOG(ERROR) << "Unable to get jvmti env.";
+ return 1;
+ }
+ StressData* data = nullptr;
+ if (JVMTI_ERROR_NONE != jvmti->Allocate(sizeof(StressData),
+ reinterpret_cast<unsigned char**>(&data))) {
+ LOG(ERROR) << "Unable to allocate data for stress test.";
+ return 1;
+ }
+ memset(data, 0, sizeof(StressData));
+ // Read the options into the static variables that hold them.
+ ReadOptions(data, options);
+ // Save the data
+ if (JVMTI_ERROR_NONE != jvmti->SetEnvironmentLocalStorage(data)) {
+ LOG(ERROR) << "Unable to save stress test data.";
+ return 1;
+ }
+
+ // Just get all capabilities.
+ jvmtiCapabilities caps;
+ jvmti->GetPotentialCapabilities(&caps);
+ jvmti->AddCapabilities(&caps);
+
+ // Set callbacks.
+ jvmtiEventCallbacks cb;
+ memset(&cb, 0, sizeof(cb));
+ cb.ClassFileLoadHook = ClassFileLoadHookSecretNoOp;
+ cb.VMInit = EnsureVMClassloaderInitializedCB;
+ if (jvmti->SetEventCallbacks(&cb, sizeof(cb)) != JVMTI_ERROR_NONE) {
+ LOG(ERROR) << "Unable to set class file load hook cb!";
+ return 1;
+ }
+ if (jvmti->SetEventNotificationMode(JVMTI_ENABLE,
+ JVMTI_EVENT_VM_INIT,
+ nullptr) != JVMTI_ERROR_NONE) {
+ LOG(ERROR) << "Unable to enable JVMTI_EVENT_VM_INIT event!";
+ return 1;
+ }
+ if (jvmti->SetEventNotificationMode(JVMTI_ENABLE,
+ JVMTI_EVENT_CLASS_FILE_LOAD_HOOK,
+ nullptr) != JVMTI_ERROR_NONE) {
+ LOG(ERROR) << "Unable to enable CLASS_FILE_LOAD_HOOK event!";
+ return 1;
+ }
+ return 0;
+}
+
+} // namespace art