vm/jitrino/src/shared/MemoryAttribute.h (267 lines of code) (raw):

/* * 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