blob: 0c2b6a7e01ee1bdbd37ca2c4e827b39f6becb31e [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.
*/
#ifndef ART_COMPILER_DEX_LOCAL_VALUE_NUMBERING_H_
#define ART_COMPILER_DEX_LOCAL_VALUE_NUMBERING_H_
#include <memory>
#include "compiler_internals.h"
#include "utils/scoped_arena_allocator.h"
#include "utils/scoped_arena_containers.h"
#define NO_VALUE 0xffff
#define ARRAY_REF 0xfffe
namespace art {
class DexFile;
class LocalValueNumbering {
private:
// Field types correspond to the ordering of GET/PUT instructions; this order is the same
// for IGET, IPUT, SGET, SPUT, AGET and APUT:
// op 0
// op_WIDE 1
// op_OBJECT 2
// op_BOOLEAN 3
// op_BYTE 4
// op_CHAR 5
// op_SHORT 6
static constexpr size_t kFieldTypeCount = 7;
// FieldReference represents either a unique resolved field or all unresolved fields together.
struct FieldReference {
const DexFile* dex_file;
uint16_t field_idx;
};
struct FieldReferenceComparator {
bool operator()(const FieldReference& lhs, const FieldReference& rhs) const {
if (lhs.field_idx != rhs.field_idx) {
return lhs.field_idx < rhs.field_idx;
}
return lhs.dex_file < rhs.dex_file;
}
};
struct MemoryVersionKey {
uint16_t base;
uint16_t field_id;
uint16_t type;
};
struct MemoryVersionKeyComparator {
bool operator()(const MemoryVersionKey& lhs, const MemoryVersionKey& rhs) const {
if (lhs.base != rhs.base) {
return lhs.base < rhs.base;
}
if (lhs.field_id != rhs.field_id) {
return lhs.field_id < rhs.field_id;
}
return lhs.type < rhs.type;
}
};
// Key is s_reg, value is value name.
typedef ScopedArenaSafeMap<uint16_t, uint16_t> SregValueMap;
// Key is concatenation of opcode, operand1, operand2 and modifier, value is value name.
typedef ScopedArenaSafeMap<uint64_t, uint16_t> ValueMap;
// Key represents a memory address, value is generation.
typedef ScopedArenaSafeMap<MemoryVersionKey, uint16_t, MemoryVersionKeyComparator
> MemoryVersionMap;
// Maps field key to field id for resolved fields.
typedef ScopedArenaSafeMap<FieldReference, uint32_t, FieldReferenceComparator> FieldIndexMap;
// A set of value names.
typedef ScopedArenaSet<uint16_t> ValueNameSet;
public:
static LocalValueNumbering* Create(CompilationUnit* cu) {
std::unique_ptr<ScopedArenaAllocator> allocator(ScopedArenaAllocator::Create(&cu->arena_stack));
void* addr = allocator->Alloc(sizeof(LocalValueNumbering), kArenaAllocMisc);
return new(addr) LocalValueNumbering(cu, allocator.release());
}
static uint64_t BuildKey(uint16_t op, uint16_t operand1, uint16_t operand2, uint16_t modifier) {
return (static_cast<uint64_t>(op) << 48 | static_cast<uint64_t>(operand1) << 32 |
static_cast<uint64_t>(operand2) << 16 | static_cast<uint64_t>(modifier));
};
uint16_t LookupValue(uint16_t op, uint16_t operand1, uint16_t operand2, uint16_t modifier) {
uint16_t res;
uint64_t key = BuildKey(op, operand1, operand2, modifier);
ValueMap::iterator it = value_map_.find(key);
if (it != value_map_.end()) {
res = it->second;
} else {
res = value_map_.size() + 1;
value_map_.Put(key, res);
}
return res;
};
bool ValueExists(uint16_t op, uint16_t operand1, uint16_t operand2, uint16_t modifier) const {
uint64_t key = BuildKey(op, operand1, operand2, modifier);
ValueMap::const_iterator it = value_map_.find(key);
return (it != value_map_.end());
};
void SetOperandValue(uint16_t s_reg, uint16_t value) {
SregValueMap::iterator it = sreg_value_map_.find(s_reg);
if (it != sreg_value_map_.end()) {
DCHECK_EQ(it->second, value);
} else {
sreg_value_map_.Put(s_reg, value);
}
};
uint16_t GetOperandValue(int s_reg) {
uint16_t res = NO_VALUE;
SregValueMap::iterator it = sreg_value_map_.find(s_reg);
if (it != sreg_value_map_.end()) {
res = it->second;
} else {
// First use
res = LookupValue(NO_VALUE, s_reg, NO_VALUE, NO_VALUE);
sreg_value_map_.Put(s_reg, res);
}
return res;
};
void SetOperandValueWide(uint16_t s_reg, uint16_t value) {
SregValueMap::iterator it = sreg_wide_value_map_.find(s_reg);
if (it != sreg_wide_value_map_.end()) {
DCHECK_EQ(it->second, value);
} else {
sreg_wide_value_map_.Put(s_reg, value);
}
};
uint16_t GetOperandValueWide(int s_reg) {
uint16_t res = NO_VALUE;
SregValueMap::iterator it = sreg_wide_value_map_.find(s_reg);
if (it != sreg_wide_value_map_.end()) {
res = it->second;
} else {
// First use
res = LookupValue(NO_VALUE, s_reg, NO_VALUE, NO_VALUE);
sreg_wide_value_map_.Put(s_reg, res);
}
return res;
};
uint16_t GetValueNumber(MIR* mir);
// Allow delete-expression to destroy a LocalValueNumbering object without deallocation.
static void operator delete(void* ptr) { UNUSED(ptr); }
private:
LocalValueNumbering(CompilationUnit* cu, ScopedArenaAllocator* allocator)
: cu_(cu),
allocator_(allocator),
sreg_value_map_(std::less<uint16_t>(), allocator->Adapter()),
sreg_wide_value_map_(std::less<uint16_t>(), allocator->Adapter()),
value_map_(std::less<uint64_t>(), allocator->Adapter()),
next_memory_version_(1u),
global_memory_version_(0u),
memory_version_map_(MemoryVersionKeyComparator(), allocator->Adapter()),
field_index_map_(FieldReferenceComparator(), allocator->Adapter()),
non_aliasing_refs_(std::less<uint16_t>(), allocator->Adapter()),
null_checked_(std::less<uint16_t>(), allocator->Adapter()) {
std::fill_n(unresolved_sfield_version_, kFieldTypeCount, 0u);
std::fill_n(unresolved_ifield_version_, kFieldTypeCount, 0u);
}
uint16_t GetFieldId(const DexFile* dex_file, uint16_t field_idx);
void AdvanceGlobalMemory();
uint16_t GetMemoryVersion(uint16_t base, uint16_t field, uint16_t type);
uint16_t AdvanceMemoryVersion(uint16_t base, uint16_t field, uint16_t type);
uint16_t MarkNonAliasingNonNull(MIR* mir);
void MakeArgsAliasing(MIR* mir);
void HandleNullCheck(MIR* mir, uint16_t reg);
void HandleRangeCheck(MIR* mir, uint16_t array, uint16_t index);
void HandlePutObject(MIR* mir);
CompilationUnit* const cu_;
std::unique_ptr<ScopedArenaAllocator> allocator_;
SregValueMap sreg_value_map_;
SregValueMap sreg_wide_value_map_;
ValueMap value_map_;
uint16_t next_memory_version_;
uint16_t global_memory_version_;
uint16_t unresolved_sfield_version_[kFieldTypeCount];
uint16_t unresolved_ifield_version_[kFieldTypeCount];
MemoryVersionMap memory_version_map_;
FieldIndexMap field_index_map_;
// Value names of references to objects that cannot be reached through a different value name.
ValueNameSet non_aliasing_refs_;
ValueNameSet null_checked_;
DISALLOW_COPY_AND_ASSIGN(LocalValueNumbering);
};
} // namespace art
#endif // ART_COMPILER_DEX_LOCAL_VALUE_NUMBERING_H_