summaryrefslogtreecommitdiff
path: root/compiler/optimizing/intrinsics.cc
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/optimizing/intrinsics.cc')
-rw-r--r--compiler/optimizing/intrinsics.cc222
1 files changed, 35 insertions, 187 deletions
diff --git a/compiler/optimizing/intrinsics.cc b/compiler/optimizing/intrinsics.cc
index d9623c0abb..d960d5f212 100644
--- a/compiler/optimizing/intrinsics.cc
+++ b/compiler/optimizing/intrinsics.cc
@@ -51,17 +51,6 @@ std::ostream& operator<<(std::ostream& os, const Intrinsics& intrinsic) {
return os;
}
-static const char kIntegerCacheDescriptor[] = "Ljava/lang/Integer$IntegerCache;";
-static const char kIntegerDescriptor[] = "Ljava/lang/Integer;";
-static const char kLowFieldName[] = "low";
-static const char kHighFieldName[] = "high";
-static const char kValueFieldName[] = "value";
-
-static constexpr int32_t kIntegerCacheLow = -128;
-static constexpr int32_t kIntegerCacheHigh = 127;
-static constexpr int32_t kIntegerCacheLength = kIntegerCacheHigh - kIntegerCacheLow + 1;
-
-
static ObjPtr<mirror::ObjectArray<mirror::Object>> GetBootImageLiveObjects()
REQUIRES_SHARED(Locks::mutator_lock_) {
gc::Heap* heap = Runtime::Current()->GetHeap();
@@ -76,80 +65,6 @@ static ObjPtr<mirror::ObjectArray<mirror::Object>> GetBootImageLiveObjects()
return boot_image_live_objects;
}
-static ObjPtr<mirror::ObjectArray<mirror::Object>> GetIntegerCacheArray(
- ObjPtr<mirror::Class> cache_class) REQUIRES_SHARED(Locks::mutator_lock_) {
- ArtField* cache_field = WellKnownClasses::java_lang_Integer_IntegerCache_cache;
- return ObjPtr<mirror::ObjectArray<mirror::Object>>::DownCast(cache_field->GetObject(cache_class));
-}
-
-static int32_t GetIntegerCacheField(ObjPtr<mirror::Class> cache_class, const char* field_name)
- REQUIRES_SHARED(Locks::mutator_lock_) {
- ArtField* field = cache_class->FindDeclaredStaticField(field_name, "I");
- DCHECK(field != nullptr);
- return field->GetInt(cache_class);
-}
-
-bool IntrinsicVisitor::CheckIntegerCacheFields(ObjPtr<mirror::ObjectArray<mirror::Object>> cache) {
- ObjPtr<mirror::Class> cache_class = WellKnownClasses::java_lang_Integer_IntegerCache.Get();
- // Check that the range matches the boot image cache length.
- int32_t low = GetIntegerCacheField(cache_class, kLowFieldName);
- int32_t high = GetIntegerCacheField(cache_class, kHighFieldName);
- if (low != kIntegerCacheLow || high != kIntegerCacheHigh) {
- return false;
- }
- if (cache->GetLength() != high - low + 1) {
- return false;
- }
-
- // Check that the elements match the values we expect.
- ObjPtr<mirror::Class> integer_class = WellKnownClasses::java_lang_Integer.Get();
- DCHECK(integer_class->IsInitialized());
- ArtField* value_field = integer_class->FindDeclaredInstanceField(kValueFieldName, "I");
- DCHECK(value_field != nullptr);
- for (int32_t i = 0, len = cache->GetLength(); i != len; ++i) {
- ObjPtr<mirror::Object> current_object = cache->Get(i);
- if (value_field->GetInt(current_object) != low + i) {
- return false;
- }
- }
- return true;
-}
-
-static bool CheckIntegerCache(ObjPtr<mirror::ObjectArray<mirror::Object>> boot_image_live_objects)
- REQUIRES_SHARED(Locks::mutator_lock_) {
- // Since we have a cache in the boot image, both java.lang.Integer and
- // java.lang.Integer$IntegerCache must be initialized in the boot image.
- ObjPtr<mirror::Class> cache_class = WellKnownClasses::java_lang_Integer_IntegerCache.Get();
- DCHECK(cache_class->IsInitialized());
- ObjPtr<mirror::Class> integer_class = WellKnownClasses::java_lang_Integer.Get();
- DCHECK(integer_class->IsInitialized());
-
- ObjPtr<mirror::ObjectArray<mirror::Object>> current_cache = GetIntegerCacheArray(cache_class);
- if (!IntrinsicVisitor::CheckIntegerCacheFields(current_cache)) {
- return false;
- }
-
- // Check that the elements match the boot image intrinsic objects and check their values as well.
- ArtField* value_field = integer_class->FindDeclaredInstanceField(kValueFieldName, "I");
- DCHECK(value_field != nullptr);
- for (int32_t i = 0, len = current_cache->GetLength(); i != len; ++i) {
- ObjPtr<mirror::Object> boot_image_object =
- IntrinsicObjects::GetIntegerValueOfObject(boot_image_live_objects, i);
- DCHECK(Runtime::Current()->GetHeap()->ObjectIsInBootImageSpace(boot_image_object));
- // No need for read barrier for comparison with a boot image object.
- ObjPtr<mirror::Object> current_object =
- current_cache->GetWithoutChecks<kVerifyNone, kWithoutReadBarrier>(i);
- if (boot_image_object != current_object) {
- return false; // Messed up IntegerCache.cache[i]
- }
- if (value_field->GetInt(boot_image_object) != kIntegerCacheLow + i) {
- return false; // Messed up IntegerCache.cache[i].value.
- }
- }
-
- return true;
-}
-
static bool CanReferenceBootImageObjects(HInvoke* invoke, const CompilerOptions& compiler_options) {
// Piggyback on the method load kind to determine whether we can use PC-relative addressing
// for AOT. This should cover both the testing config (non-PIC boot image) and codegens that
@@ -165,73 +80,24 @@ static bool CanReferenceBootImageObjects(HInvoke* invoke, const CompilerOptions&
return true;
}
-void IntrinsicVisitor::ComputeIntegerValueOfLocations(HInvoke* invoke,
- CodeGenerator* codegen,
- Location return_location,
- Location first_argument_location) {
- // The intrinsic will call if it needs to allocate a j.l.Integer.
+void IntrinsicVisitor::ComputeValueOfLocations(HInvoke* invoke,
+ CodeGenerator* codegen,
+ int32_t low,
+ int32_t length,
+ Location return_location,
+ Location first_argument_location) {
+ // The intrinsic will call if it needs to allocate a boxed object.
LocationSummary::CallKind call_kind = LocationSummary::kCallOnMainOnly;
const CompilerOptions& compiler_options = codegen->GetCompilerOptions();
if (!CanReferenceBootImageObjects(invoke, compiler_options)) {
return;
}
HInstruction* const input = invoke->InputAt(0);
- if (compiler_options.IsBootImage()) {
- if (!compiler_options.IsImageClass(kIntegerCacheDescriptor) ||
- !compiler_options.IsImageClass(kIntegerDescriptor)) {
- return;
- }
- ScopedObjectAccess soa(Thread::Current());
- ObjPtr<mirror::Class> cache_class = WellKnownClasses::java_lang_Integer_IntegerCache.Get();
- DCHECK(cache_class->IsInitialized());
- ObjPtr<mirror::Class> integer_class = WellKnownClasses::java_lang_Integer.Get();
- DCHECK(integer_class->IsInitialized());
- int32_t low = kIntegerCacheLow;
- int32_t high = kIntegerCacheHigh;
- if (kIsDebugBuild) {
- CHECK_EQ(low, GetIntegerCacheField(cache_class, kLowFieldName));
- CHECK_EQ(high, GetIntegerCacheField(cache_class, kHighFieldName));
- ObjPtr<mirror::ObjectArray<mirror::Object>> current_cache = GetIntegerCacheArray(cache_class);
- CHECK(current_cache != nullptr);
- CHECK_EQ(current_cache->GetLength(), high - low + 1);
- ArtField* value_field = integer_class->FindDeclaredInstanceField(kValueFieldName, "I");
- CHECK(value_field != nullptr);
- for (int32_t i = 0, len = current_cache->GetLength(); i != len; ++i) {
- ObjPtr<mirror::Object> current_object = current_cache->GetWithoutChecks(i);
- CHECK(current_object != nullptr);
- CHECK_EQ(value_field->GetInt(current_object), low + i);
- }
- }
- if (input->IsIntConstant()) {
- int32_t value = input->AsIntConstant()->GetValue();
- if (static_cast<uint32_t>(value) - static_cast<uint32_t>(low) <
- static_cast<uint32_t>(high - low + 1)) {
- // No call, we shall use direct pointer to the Integer object.
- call_kind = LocationSummary::kNoCall;
- }
- }
- } else {
- ScopedObjectAccess soa(Thread::Current());
- ObjPtr<mirror::ObjectArray<mirror::Object>> boot_image_live_objects = GetBootImageLiveObjects();
- DCHECK_IMPLIES(compiler_options.IsAotCompiler(), CheckIntegerCache(boot_image_live_objects));
-
- if (input->IsIntConstant()) {
- if (kIsDebugBuild) {
- // Check the `value` from the lowest cached Integer.
- ObjPtr<mirror::Object> low_integer =
- IntrinsicObjects::GetIntegerValueOfObject(boot_image_live_objects, 0u);
- ObjPtr<mirror::Class> integer_class =
- low_integer->GetClass<kVerifyNone, kWithoutReadBarrier>();
- ArtField* value_field = integer_class->FindDeclaredInstanceField(kValueFieldName, "I");
- DCHECK(value_field != nullptr);
- DCHECK_EQ(kIntegerCacheLow, value_field->GetInt(low_integer));
- }
- int32_t value = input->AsIntConstant()->GetValue();
- if (static_cast<uint32_t>(value) - static_cast<uint32_t>(kIntegerCacheLow) <
- static_cast<uint32_t>(kIntegerCacheLength)) {
- // No call, we shall use direct pointer to the Integer object.
- call_kind = LocationSummary::kNoCall;
- }
+ if (input->IsConstant()) {
+ int32_t value = input->AsIntConstant()->GetValue();
+ if (static_cast<uint32_t>(value) - static_cast<uint32_t>(low) < static_cast<uint32_t>(length)) {
+ // No call, we shall use direct pointer to the boxed object.
+ call_kind = LocationSummary::kNoCall;
}
}
@@ -247,76 +113,58 @@ void IntrinsicVisitor::ComputeIntegerValueOfLocations(HInvoke* invoke,
}
}
-inline IntrinsicVisitor::IntegerValueOfInfo::IntegerValueOfInfo()
+inline IntrinsicVisitor::ValueOfInfo::ValueOfInfo()
: value_offset(0),
low(0),
length(0u),
value_boot_image_reference(kInvalidReference) {}
-IntrinsicVisitor::IntegerValueOfInfo IntrinsicVisitor::ComputeIntegerValueOfInfo(
- HInvoke* invoke, const CompilerOptions& compiler_options) {
- // Note that we could cache all of the data looked up here. but there's no good
- // location for it. We don't want to add it to WellKnownClasses, to avoid creating global
- // jni values. Adding it as state to the compiler singleton seems like wrong
- // separation of concerns.
- // The need for this data should be pretty rare though.
-
- // Note that at this point we can no longer abort the code generation. Therefore,
- // we need to provide data that shall not lead to a crash even if the fields were
- // modified through reflection since ComputeIntegerValueOfLocations() when JITting.
-
- ScopedObjectAccess soa(Thread::Current());
- IntegerValueOfInfo info;
- info.low = kIntegerCacheLow;
- info.length = kIntegerCacheLength;
+IntrinsicVisitor::ValueOfInfo IntrinsicVisitor::ComputeValueOfInfo(
+ HInvoke* invoke,
+ const CompilerOptions& compiler_options,
+ ArtField* value_field,
+ int32_t low,
+ int32_t length,
+ size_t base) {
+ ValueOfInfo info;
+ info.low = low;
+ info.length = length;
+ info.value_offset = value_field->GetOffset().Uint32Value();
if (compiler_options.IsBootImage()) {
- ObjPtr<mirror::Class> integer_class = invoke->GetResolvedMethod()->GetDeclaringClass();
- DCHECK(integer_class->DescriptorEquals(kIntegerDescriptor));
- ArtField* value_field = integer_class->FindDeclaredInstanceField(kValueFieldName, "I");
- DCHECK(value_field != nullptr);
- info.value_offset = value_field->GetOffset().Uint32Value();
- ObjPtr<mirror::Class> cache_class = WellKnownClasses::java_lang_Integer_IntegerCache.Get();
- DCHECK_EQ(info.low, GetIntegerCacheField(cache_class, kLowFieldName));
- DCHECK_EQ(kIntegerCacheHigh, GetIntegerCacheField(cache_class, kHighFieldName));
-
- if (invoke->InputAt(0)->IsIntConstant()) {
+ if (invoke->InputAt(0)->IsConstant()) {
int32_t input_value = invoke->InputAt(0)->AsIntConstant()->GetValue();
uint32_t index = static_cast<uint32_t>(input_value) - static_cast<uint32_t>(info.low);
if (index < static_cast<uint32_t>(info.length)) {
info.value_boot_image_reference = IntrinsicObjects::EncodePatch(
- IntrinsicObjects::PatchType::kIntegerValueOfObject, index);
+ IntrinsicObjects::PatchType::kValueOfObject, index + base);
} else {
// Not in the cache.
- info.value_boot_image_reference = IntegerValueOfInfo::kInvalidReference;
+ info.value_boot_image_reference = ValueOfInfo::kInvalidReference;
}
} else {
info.array_data_boot_image_reference =
- IntrinsicObjects::EncodePatch(IntrinsicObjects::PatchType::kIntegerValueOfArray);
+ IntrinsicObjects::EncodePatch(IntrinsicObjects::PatchType::kValueOfArray, base);
}
} else {
+ ScopedObjectAccess soa(Thread::Current());
ObjPtr<mirror::ObjectArray<mirror::Object>> boot_image_live_objects = GetBootImageLiveObjects();
- ObjPtr<mirror::Object> low_integer =
- IntrinsicObjects::GetIntegerValueOfObject(boot_image_live_objects, 0u);
- ObjPtr<mirror::Class> integer_class = low_integer->GetClass<kVerifyNone, kWithoutReadBarrier>();
- ArtField* value_field = integer_class->FindDeclaredInstanceField(kValueFieldName, "I");
- DCHECK(value_field != nullptr);
- info.value_offset = value_field->GetOffset().Uint32Value();
if (invoke->InputAt(0)->IsIntConstant()) {
int32_t input_value = invoke->InputAt(0)->AsIntConstant()->GetValue();
uint32_t index = static_cast<uint32_t>(input_value) - static_cast<uint32_t>(info.low);
if (index < static_cast<uint32_t>(info.length)) {
- ObjPtr<mirror::Object> integer =
- IntrinsicObjects::GetIntegerValueOfObject(boot_image_live_objects, index);
- info.value_boot_image_reference = CodeGenerator::GetBootImageOffset(integer);
+ ObjPtr<mirror::Object> object =
+ IntrinsicObjects::GetValueOfObject(boot_image_live_objects, base, index);
+ info.value_boot_image_reference = CodeGenerator::GetBootImageOffset(object);
} else {
// Not in the cache.
- info.value_boot_image_reference = IntegerValueOfInfo::kInvalidReference;
+ info.value_boot_image_reference = ValueOfInfo::kInvalidReference;
}
} else {
info.array_data_boot_image_reference =
CodeGenerator::GetBootImageOffset(boot_image_live_objects) +
- IntrinsicObjects::GetIntegerValueOfArrayDataOffset(boot_image_live_objects).Uint32Value();
+ IntrinsicObjects::GetValueOfArrayDataOffset(
+ boot_image_live_objects, base).Uint32Value();
}
}