blob: 53b7a7648879d469534cc26921fc1599ed9d65cf [file] [log] [blame]
/*
* Copyright (C) 2012 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 "reg_type_cache.h"
#include "object_utils.h"
namespace art {
namespace verifier {
static RegType::Type RegTypeFromPrimitiveType(Primitive::Type prim_type) {
switch (prim_type) {
case Primitive::kPrimBoolean: return RegType::kRegTypeBoolean;
case Primitive::kPrimByte: return RegType::kRegTypeByte;
case Primitive::kPrimShort: return RegType::kRegTypeShort;
case Primitive::kPrimChar: return RegType::kRegTypeChar;
case Primitive::kPrimInt: return RegType::kRegTypeInteger;
case Primitive::kPrimLong: return RegType::kRegTypeLongLo;
case Primitive::kPrimFloat: return RegType::kRegTypeFloat;
case Primitive::kPrimDouble: return RegType::kRegTypeDoubleLo;
case Primitive::kPrimVoid:
default: return RegType::kRegTypeConflict;
}
}
static RegType::Type RegTypeFromDescriptor(const std::string& descriptor) {
if (descriptor.length() == 1) {
switch (descriptor[0]) {
case 'Z': return RegType::kRegTypeBoolean;
case 'B': return RegType::kRegTypeByte;
case 'S': return RegType::kRegTypeShort;
case 'C': return RegType::kRegTypeChar;
case 'I': return RegType::kRegTypeInteger;
case 'J': return RegType::kRegTypeLongLo;
case 'F': return RegType::kRegTypeFloat;
case 'D': return RegType::kRegTypeDoubleLo;
case 'V':
default: return RegType::kRegTypeConflict;
}
} else if (descriptor[0] == 'L' || descriptor[0] == '[') {
return RegType::kRegTypeReference;
} else {
return RegType::kRegTypeConflict;
}
}
const RegType& RegTypeCache::FromDescriptor(const ClassLoader* loader,
const char* descriptor) {
return From(RegTypeFromDescriptor(descriptor), loader, descriptor);
}
const RegType& RegTypeCache::From(RegType::Type type, const ClassLoader* loader,
const char* descriptor) {
if (type <= RegType::kRegTypeLastFixedLocation) {
// entries should be sized greater than primitive types
DCHECK_GT(entries_.size(), static_cast<size_t>(type));
RegType* entry = entries_[type];
if (entry == NULL) {
Class* klass = NULL;
if (strlen(descriptor) != 0) {
klass = Runtime::Current()->GetClassLinker()->FindSystemClass(descriptor);
}
entry = new RegType(type, klass, 0, type);
entries_[type] = entry;
}
return *entry;
} else {
DCHECK(type == RegType::kRegTypeReference);
ClassHelper kh;
for (size_t i = RegType::kRegTypeLastFixedLocation + 1; i < entries_.size(); i++) {
RegType* cur_entry = entries_[i];
// check resolved and unresolved references, ignore uninitialized references
if (cur_entry->IsReference()) {
kh.ChangeClass(cur_entry->GetClass());
if (strcmp(descriptor, kh.GetDescriptor()) == 0) {
return *cur_entry;
}
} else if (cur_entry->IsUnresolvedReference() &&
cur_entry->GetDescriptor()->Equals(descriptor)) {
return *cur_entry;
}
}
Class* klass = Runtime::Current()->GetClassLinker()->FindClass(descriptor, loader);
if (klass != NULL) {
// Able to resolve so create resolved register type
RegType* entry = new RegType(type, klass, 0, entries_.size());
entries_.push_back(entry);
return *entry;
} else {
// TODO: we assume unresolved, but we may be able to do better by validating whether the
// descriptor string is valid
// Unable to resolve so create unresolved register type
DCHECK(Thread::Current()->IsExceptionPending());
Thread::Current()->ClearException();
if (IsValidDescriptor(descriptor)) {
String* string_descriptor =
Runtime::Current()->GetInternTable()->InternStrong(descriptor);
RegType* entry = new RegType(RegType::kRegTypeUnresolvedReference, string_descriptor, 0,
entries_.size());
entries_.push_back(entry);
return *entry;
} else {
// The descriptor is broken return the unknown type as there's nothing sensible that
// could be done at runtime
return Conflict();
}
}
}
}
const RegType& RegTypeCache::FromClass(Class* klass) {
if (klass->IsPrimitive()) {
RegType::Type type = RegTypeFromPrimitiveType(klass->GetPrimitiveType());
// entries should be sized greater than primitive types
DCHECK_GT(entries_.size(), static_cast<size_t>(type));
RegType* entry = entries_[type];
if (entry == NULL) {
entry = new RegType(type, klass, 0, type);
entries_[type] = entry;
}
return *entry;
} else {
for (size_t i = RegType::kRegTypeLastFixedLocation + 1; i < entries_.size(); i++) {
RegType* cur_entry = entries_[i];
if (cur_entry->IsReference() && cur_entry->GetClass() == klass) {
return *cur_entry;
}
}
RegType* entry = new RegType(RegType::kRegTypeReference, klass, 0, entries_.size());
entries_.push_back(entry);
return *entry;
}
}
const RegType& RegTypeCache::Uninitialized(const RegType& type, uint32_t allocation_pc) {
RegType* entry;
if (type.IsUnresolvedTypes()) {
String* descriptor = type.GetDescriptor();
for (size_t i = RegType::kRegTypeLastFixedLocation + 1; i < entries_.size(); i++) {
RegType* cur_entry = entries_[i];
if (cur_entry->IsUnresolvedAndUninitializedReference() &&
cur_entry->GetAllocationPc() == allocation_pc &&
cur_entry->GetDescriptor() == descriptor) {
return *cur_entry;
}
}
entry = new RegType(RegType::kRegTypeUnresolvedAndUninitializedReference,
descriptor, allocation_pc, entries_.size());
} else {
Class* klass = type.GetClass();
for (size_t i = RegType::kRegTypeLastFixedLocation + 1; i < entries_.size(); i++) {
RegType* cur_entry = entries_[i];
if (cur_entry->IsUninitializedReference() &&
cur_entry->GetAllocationPc() == allocation_pc &&
cur_entry->GetClass() == klass) {
return *cur_entry;
}
}
entry = new RegType(RegType::kRegTypeUninitializedReference,
klass, allocation_pc, entries_.size());
}
entries_.push_back(entry);
return *entry;
}
const RegType& RegTypeCache::FromUninitialized(const RegType& uninit_type) {
RegType* entry;
if (uninit_type.IsUnresolvedTypes()) {
String* descriptor = uninit_type.GetDescriptor();
for (size_t i = RegType::kRegTypeLastFixedLocation + 1; i < entries_.size(); i++) {
RegType* cur_entry = entries_[i];
if (cur_entry->IsUnresolvedReference() && cur_entry->GetDescriptor() == descriptor) {
return *cur_entry;
}
}
entry = new RegType(RegType::kRegTypeUnresolvedReference, descriptor, 0, entries_.size());
} else {
Class* klass = uninit_type.GetClass();
for (size_t i = RegType::kRegTypeLastFixedLocation + 1; i < entries_.size(); i++) {
RegType* cur_entry = entries_[i];
if (cur_entry->IsReference() && cur_entry->GetClass() == klass) {
return *cur_entry;
}
}
entry = new RegType(RegType::kRegTypeReference, klass, 0, entries_.size());
}
entries_.push_back(entry);
return *entry;
}
const RegType& RegTypeCache::UninitializedThisArgument(const RegType& type) {
// TODO: implement descriptor version.
RegType* entry;
if (type.IsUnresolvedTypes()) {
String* descriptor = type.GetDescriptor();
for (size_t i = RegType::kRegTypeLastFixedLocation + 1; i < entries_.size(); i++) {
RegType* cur_entry = entries_[i];
if (cur_entry->IsUnresolvedAndUninitializedThisReference() &&
cur_entry->GetDescriptor() == descriptor) {
return *cur_entry;
}
}
entry = new RegType(RegType::kRegTypeUnresolvedAndUninitializedThisReference, descriptor, 0,
entries_.size());
} else {
Class* klass = type.GetClass();
for (size_t i = RegType::kRegTypeLastFixedLocation + 1; i < entries_.size(); i++) {
RegType* cur_entry = entries_[i];
if (cur_entry->IsUninitializedThisReference() && cur_entry->GetClass() == klass) {
return *cur_entry;
}
}
entry = new RegType(RegType::kRegTypeUninitializedThisReference, klass, 0, entries_.size());
}
entries_.push_back(entry);
return *entry;
}
const RegType& RegTypeCache::FromType(RegType::Type type) {
CHECK(type < RegType::kRegTypeReference);
switch (type) {
case RegType::kRegTypeBoolean: return From(type, NULL, "Z");
case RegType::kRegTypeByte: return From(type, NULL, "B");
case RegType::kRegTypeShort: return From(type, NULL, "S");
case RegType::kRegTypeChar: return From(type, NULL, "C");
case RegType::kRegTypeInteger: return From(type, NULL, "I");
case RegType::kRegTypeFloat: return From(type, NULL, "F");
case RegType::kRegTypeLongLo:
case RegType::kRegTypeLongHi: return From(type, NULL, "J");
case RegType::kRegTypeDoubleLo:
case RegType::kRegTypeDoubleHi: return From(type, NULL, "D");
default: return From(type, NULL, "");
}
}
const RegType& RegTypeCache::FromCat1Const(int32_t value) {
for (size_t i = RegType::kRegTypeLastFixedLocation + 1; i < entries_.size(); i++) {
RegType* cur_entry = entries_[i];
if (cur_entry->IsConstant() && cur_entry->ConstantValue() == value) {
return *cur_entry;
}
}
RegType* entry = new RegType(RegType::kRegTypeConst, NULL, value, entries_.size());
entries_.push_back(entry);
return *entry;
}
const RegType& RegTypeCache::GetComponentType(const RegType& array, const ClassLoader* loader) {
CHECK(array.IsArrayTypes());
if (array.IsUnresolvedTypes()) {
std::string descriptor(array.GetDescriptor()->ToModifiedUtf8());
std::string component(descriptor.substr(1, descriptor.size() - 1));
return FromDescriptor(loader, component.c_str());
} else {
return FromClass(array.GetClass()->GetComponentType());
}
}
} // verifier
} // art