blob: ce8c5e5ec261caac0e76e64270acd434618a0e4e [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.
*/
/**
* @author Intel, Mikhail Y. Fursov
*
*/
#ifndef _MEMORY_ATTR_H
#define _MEMORY_ATTR_H
#include <iostream>
#include <assert.h>
#include "open/types.h"
#include "VMInterface.h"
namespace Jitrino {
#define UnknownMemoryContextId ((uint64)-1)
//
// Attributes of memory locations
//
class MemoryAttribute {
public:
//
// Storage class
//
enum StorageClass {
HeapStorage = 0x01,
StackStorage = 0x02,
JitDataStorage = 0x04,
VmDataStorage = 0x08,
AnyStorageClass = 0x0F
};
//
// Context
//
class Context {
public:
enum Tag {
NoContext = 0x00, // cannot be used in any context
AnyContext = 0x01, // can be used in any context
ObjectField = 0x02,
ArrayLength = 0x03,
ArrayElement = 0x04,
VtableAddr = 0x05,
ObjectLock = 0x06,
Unboxed = 0x07, // address of un-boxed value type inside the boxed value type
StackLocation = 0x08,
StackIncomingArg = 0x09,
StaticMethodAddr = 0x0A,
VirtualMethodAddr = 0x0B,
StringAddr = 0x0C,
StaticField = 0x0D,
JitConstant = 0x0E,
ProfileCounter = 0x0F,
ObjectFieldOffset = 0x10, // not a real address, must be added to an object
ArrayLengthOffset = 0x11, // not a real address
ArrayElementOffset = 0x12, // not a real address
NumTags = 0x13,
};
private:
// Kind of id
enum IdKind {
NoId,
StackId,
FieldId,
MethodId,
CounterId
};
public:
//
// Default constructor
//
Context() : tag(NoContext), size(0) {
id.all = UnknownMemoryContextId;
}
//
// Copy constructor
//
Context(const Context & mc) : tag(mc.tag), id(mc.id), size(mc.size) {
}
//
// Checks if memory location used in this context can be written by JIT'ed code
//
static bool isReadOnly(Tag tag) {
assert(info[tag].tag == tag);
return !info[tag].canBeWrittenByJittedCode;
}
bool isReadOnly() const {return isReadOnly(tag);}
//
// Checks if memory location used in this context can be written inside calls
//
static bool isKilledByCalls(Tag tag) {
assert(info[tag].tag == tag);
return info[tag].killedByCalls;
}
bool isKilledByCalls() const {return isKilledByCalls(tag);}
//
// Checks if managed pointers of different types can refer to the same memory location
// that has this context.
//
static bool maybeTypeAliased(Tag tag) {
assert(info[tag].tag == tag);
return info[tag].maybeTypeAliased;
}
bool maybeTypeAliased() const {return maybeTypeAliased(tag);}
//
// Storage class queries
//
bool isInHeap() const {return getStorageClass() == HeapStorage;}
bool isOnStack() const {return getStorageClass() == StackStorage;}
bool maybeInHeap() const {return (getStorageClass() & HeapStorage) != 0;}
bool maybeOnStack() const {return (getStorageClass() & StackStorage) != 0;}
//
// Tag queries
//
bool isValid() const {return tag != NoContext;}
bool isKnown() const {return tag != AnyContext;}
//
// Tag ids are sequential numbers for tags that allow for easy implementation
// of associative containers indexed by tags.
// This might be useful if tags become non sequential, e.g., bit positions
// so that we can encode multiple tag usage for managed pointers in CLI.
//
static U_32 getNumTagIds() {return NumTags;}
static U_32 getTagId(Tag tag) {return tag;}
U_32 getTagId() const {return getTagId(tag);}
static Tag mapIdToTag(U_32 _id) {return (Tag)_id;}
//
// Checks if memory context is exact
//
bool isExact() const {
assert(info[tag].tag == tag);
return tag > AnyContext &&
(info[tag].idKind == NoId || id.all != UnknownMemoryContextId);
}
//
// Checks if two contexts can refer to the same memory location
//
bool maybeAliased(const Context& mc) const;
//
// Checks if two contexts are the same
//
bool isEqual(Context& mc) const {
return tag == mc.tag && getId() == mc.getId() && size == mc.size;
}
//
// Unions this context with another one
//
void unionWith(Context& mc);
//
// Returns tag of the memory context
//
Tag getTag() const {return tag;}
//
// Returns storage class of memory locations used in this context
//
StorageClass getStorageClass() const {
assert(info[tag].tag == tag);
return info[tag].storageClass;
}
//
// Checks if context can refer to a certain storage class
//
bool canReferToStorageClass(StorageClass sc) const {
return (getStorageClass() & sc) != 0;
}
//
// Get various ids
//
U_32 getStackOffset() const {
assert(getIdKind() == StackId);
return id.stackOffset;
}
FieldDesc * getFieldDesc() const {
assert(getIdKind() == FieldId);
return id.fieldDesc;
}
MethodDesc * getMethodDesc() const {
assert(getIdKind() == MethodId);
return id.methodDesc;
}
U_32 getProfileCounterId() const {
assert(getIdKind() == CounterId);
return id.counterId;
}
//
// Prints tag
//
void print(::std::ostream& os) const {
assert(info[tag].tag == tag);
os << info[tag].name;
printId(os);
}
protected:
//
// Information about memory contexts
//
struct Info {
Tag tag;
const char * name;
bool canBeWrittenByJittedCode;
bool killedByCalls;
IdKind idKind;
StorageClass storageClass;
bool maybeTypeAliased;
};
private:
Context(Tag t, U_32 _size = 0)
: tag(t), size((U_8)_size) {
id.all = UnknownMemoryContextId;
assert(_size <= 0xff);
}
void unionIds(uint64 id1) {
if (id.all != id1)
id.all = UnknownMemoryContextId;
}
void unionSizes(U_8 size1) {
if (size < size1)
size = size1;
}
IdKind getIdKind() const {
assert(info[tag].tag == tag);
return info[tag].idKind;
}
bool hasUnknownId() const {return id.all == UnknownMemoryContextId;}
U_32 getId() const;
void printId(::std::ostream& os) const;
//
// Fields
//
Tag tag : 8;
union IdUnion {
U_32 stackOffset;
FieldDesc * fieldDesc;
MethodDesc * methodDesc;
U_32 counterId;
uint64 all;
} id;
U_8 size; // size of accessed memory in bytes; used for stack locations
static Info info[];
friend class MemoryAttributeManager;
}; // end class Context
};
//
// Memory attribute manager
//
class MemoryAttributeManager {
public:
//
// Factory methods to create various memory contexts
//
MemoryAttribute::Context getUnknownContext() {
return MemoryAttribute::Context(MemoryAttribute::Context::AnyContext);
}
MemoryAttribute::Context getObjectFieldContext(FieldDesc * fieldDesc) {
MemoryAttribute::Context c(MemoryAttribute::Context::ObjectField);
c.id.fieldDesc = fieldDesc;
return c;
}
MemoryAttribute::Context getArrayLengthContext() {
return MemoryAttribute::Context(MemoryAttribute::Context::ArrayLength);
}
MemoryAttribute::Context getArrayElementContext() {
return MemoryAttribute::Context(MemoryAttribute::Context::ArrayElement);
}
MemoryAttribute::Context getVtableAddrContext() {
return MemoryAttribute::Context(MemoryAttribute::Context::VtableAddr);
}
MemoryAttribute::Context getObjectLockContext() {
return MemoryAttribute::Context(MemoryAttribute::Context::ObjectLock);
}
MemoryAttribute::Context getUnboxedContext() {
return MemoryAttribute::Context(MemoryAttribute::Context::Unboxed);
}
MemoryAttribute::Context getObjectFieldOffsetContext(FieldDesc * fieldDesc) {
MemoryAttribute::Context c(MemoryAttribute::Context::ObjectFieldOffset);
c.id.fieldDesc = fieldDesc;
return c;
}
MemoryAttribute::Context getArrayLengthOffsetContext() {
return MemoryAttribute::Context(MemoryAttribute::Context::ArrayLengthOffset);
}
MemoryAttribute::Context getArrayElementOffsetContext() {
return MemoryAttribute::Context(MemoryAttribute::Context::ArrayElementOffset);
}
MemoryAttribute::Context getAddressContextFromOffsetContext(MemoryAttribute::Context &offsetContext) {
switch (offsetContext.tag) {
case MemoryAttribute::Context::ObjectFieldOffset:
return getObjectFieldContext(offsetContext.getFieldDesc());
case MemoryAttribute::Context::ArrayLengthOffset:
return getArrayLengthContext();
case MemoryAttribute::Context::ArrayElementOffset:
return getArrayElementContext();
default:
break;
}
assert(0);
return getUnknownContext();
}
//
// Get memory context for accessing stack memory of given size at given offset
//
MemoryAttribute::Context getStackContext(U_32 offset, U_32 size) {
assert(size <= 0xff);
MemoryAttribute::Context c(MemoryAttribute::Context::StackLocation,
(U_8)size);
c.id.stackOffset = offset;
return c;
}
//
// Get memory context for accessing a stack incoming argument at given slot.
// This is IPF specific as incoming arguments are in the previous frame
// and their stack offset is not known till the final register allocation.
//
MemoryAttribute::Context getStackIncomingArgContext(U_32 offset) {
MemoryAttribute::Context c(MemoryAttribute::Context::StackIncomingArg);
c.id.stackOffset = offset;
return c;
}
MemoryAttribute::Context getStaticMethodAddrContext(MethodDesc * desc) {
MemoryAttribute::Context c(MemoryAttribute::Context::StaticMethodAddr);
c.id.methodDesc = desc;
return c;
}
MemoryAttribute::Context getVirtualMethodAddrContext(MethodDesc * desc) {
MemoryAttribute::Context c(MemoryAttribute::Context::VirtualMethodAddr);
c.id.methodDesc = desc;
return c;
}
MemoryAttribute::Context getStringAddrContext() {
return MemoryAttribute::Context(MemoryAttribute::Context::StringAddr);
}
MemoryAttribute::Context getStaticFieldContext(FieldDesc * fieldDesc) {
MemoryAttribute::Context c(MemoryAttribute::Context::StaticField);
c.id.fieldDesc = fieldDesc;
return c;
}
MemoryAttribute::Context getJitConstantContext() {
return MemoryAttribute::Context(MemoryAttribute::Context::JitConstant);
}
MemoryAttribute::Context getProfileCounterContext(U_32 counterId) {
MemoryAttribute::Context c(MemoryAttribute::Context::ProfileCounter);
c.id.counterId = counterId;
return c;
}
//
// Returns a memory context at (offset, size) from the given context
//
MemoryAttribute::Context findContextAtOffset(MemoryAttribute::Context& mc,
U_32 _offset,
U_32 _size) {
MemoryAttribute::Context context(mc);
if (context.tag == MemoryAttribute::Context::StackLocation ||
context.tag == MemoryAttribute::Context::StackIncomingArg) {
assert(_size <= 0xff);
context.size = (U_8)_size;
if (context.id.all != UnknownMemoryContextId)
context.id.stackOffset += _offset;
}
return context;
}
};
} //namespace Jitrino
#endif