namespace mirror { class Object;
} // namespace mirror
class ArtMethod; class ShadowFrame; template<class MirrorType> class ObjPtr; class Thread; union JValue;
// Forward declaration. Just calls the destructor. struct ShadowFrameDeleter; using ShadowFrameAllocaUniquePtr = std::unique_ptr<ShadowFrame, ShadowFrameDeleter>;
// ShadowFrame has 2 possible layouts: // - interpreter - separate VRegs and reference arrays. References are in the reference array. // - JNI - just VRegs, but where every VReg holds a reference. class ShadowFrame { private: // Used to keep track of extra state the shadowframe has. enumclass FrameFlags : uint32_t { // We have been requested to notify when this frame gets popped.
kNotifyFramePop = 1 << 0, // We have been asked to pop this frame off the stack as soon as possible.
kForcePopFrame = 1 << 1, // We have been asked to re-execute the last instruction.
kForceRetryInst = 1 << 2, // Mark that we expect the next frame to retry the last instruction (used by instrumentation and // debuggers to keep track of required events)
kSkipMethodExitEvents = 1 << 3, // Used to suppress exception events caused by other instrumentation events.
kSkipNextExceptionEvent = 1 << 4, // Used to specify if DexPCMoveEvents have to be reported. These events will // only be reported if the method has a breakpoint set.
kNotifyDexPcMoveEvents = 1 << 5, // Used to specify if ExceptionHandledEvent has to be reported. When enabled these events are // reported when we reach the catch block after an exception was thrown. These events have to // be reported after the DexPCMoveEvent if enabled.
kNotifyExceptionHandledEvent = 1 << 6, // Mark that we already notified method exit event for tracing. Jvmti method exit handlers are // used to implement ForceEarlyReturn and PopFrame and are expected to be called multiple times. // Trace listeners that are used for method tracing are expected to be called only once. We // maintain a flag in the shadow frame to indicate if a method exit is already reported to the // trace listeners.
kSkipTraceMethodExitEvent = 1 << 7, // For low-overhead tracing, we don't report entry events for inlined methods. If there was a // deoptimization and we execute the method in the interpreter we should skip exit events for // those methods. The flag indicates if the frame was corresponding to an inlined frame.
kSkipLowOverheadTraceEvent = 1 << 8,
};
public: // Compute size of ShadowFrame in bytes assuming it has a reference array. static size_t ComputeSize(uint32_t num_vregs) { returnsizeof(ShadowFrame) + (sizeof(uint32_t) * num_vregs) +
(sizeof(StackReference<mirror::Object>) * num_vregs);
}
// Compute size of interpreter ShadowFrame in bytes without a reference array. static size_t ComputeSizeWithoutReferences(uint32_t num_vregs) { returnsizeof(ShadowFrame) + (sizeof(uint32_t) * num_vregs);
}
// Create ShadowFrame in heap for deoptimization. static ShadowFrame* CreateDeoptimizedFrame(uint32_t num_vregs,
ArtMethod* method,
uint32_t dex_pc) {
uint8_t* memory = new uint8_t[ComputeSize(num_vregs)]; return CreateShadowFrameImpl(num_vregs, method, dex_pc, memory);
}
// Delete a ShadowFrame allocated on the heap for deoptimization. staticvoid DeleteDeoptimizedFrame(ShadowFrame* sf) {
sf->~ShadowFrame(); // Explicitly destruct.
uint8_t* memory = reinterpret_cast<uint8_t*>(sf); delete[] memory;
}
// Create a shadow frame in a fresh alloca. This needs to be in the context of the caller. // Inlining doesn't work, the compiler will still undo the alloca. So this needs to be a macro. #define CREATE_SHADOW_FRAME(num_vregs, method, dex_pc) ({ \
size_t frame_size = ShadowFrame::ComputeSize(num_vregs); \ void* alloca_mem = alloca(frame_size); \
ShadowFrameAllocaUniquePtr( \
ShadowFrame::CreateShadowFrameImpl((num_vregs), (method), (dex_pc), (alloca_mem))); \
})
// Shorts are extended to Ints in VRegs. Interpreter intrinsics needs them as shorts.
int16_t GetVRegShort(size_t i) const { returnstatic_cast<int16_t>(GetVReg(i));
}
// Look up the reference given its virtual register number. // If this returns non-null then this does not mean the vreg is currently a reference // on non-moving collectors. Check that the raw reg with GetVReg is equal to this if not certain. template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
mirror::Object* GetVRegReference(size_t i) const REQUIRES_SHARED(Locks::mutator_lock_) {
DCHECK_LT(i, NumberOfVRegs());
mirror::Object* ref;
ref = References()[i].AsMirrorPtr();
ReadBarrier::MaybeAssertToSpaceInvariant(ref); if (kVerifyFlags & kVerifyReads) {
VerifyObject(ref);
} return ref;
}
// Get view of vregs as range of consecutive arguments starting at i.
uint32_t* GetVRegArgs(size_t i) { return &vregs_[i];
}
void SetVReg(size_t i, int32_t val) {
DCHECK_LT(i, NumberOfVRegs());
uint32_t* vreg = &vregs_[i];
*reinterpret_cast<int32_t*>(vreg) = val; // This is needed for moving collectors since these can update the vreg references if they // happen to agree with references in the reference array.
References()[i].Clear();
}
void SetVRegFloat(size_t i, float val) {
DCHECK_LT(i, NumberOfVRegs());
uint32_t* vreg = &vregs_[i];
*reinterpret_cast<float*>(vreg) = val; // This is needed for moving collectors since these can update the vreg references if they // happen to agree with references in the reference array.
References()[i].Clear();
}
void SetVRegLong(size_t i, int64_t val) {
DCHECK_LT(i + 1, NumberOfVRegs());
uint32_t* vreg = &vregs_[i]; using unaligned_int64 __attribute__((aligned(4))) = int64_t;
*reinterpret_cast<unaligned_int64*>(vreg) = val; // This is needed for moving collectors since these can update the vreg references if they // happen to agree with references in the reference array.
References()[i].Clear();
References()[i + 1].Clear();
}
void SetVRegDouble(size_t i, double val) {
DCHECK_LT(i + 1, NumberOfVRegs());
uint32_t* vreg = &vregs_[i]; using unaligned_double __attribute__((aligned(4))) = double;
*reinterpret_cast<unaligned_double*>(vreg) = val; // This is needed for moving collectors since these can update the vreg references if they // happen to agree with references in the reference array.
References()[i].Clear();
References()[i + 1].Clear();
}
template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags> void SetVRegReference(size_t i, ObjPtr<mirror::Object> val)
REQUIRES_SHARED(Locks::mutator_lock_);
void CheckConsistentVRegs() const { if (kIsDebugBuild) { // A shadow frame visible to GC requires the following rule: for a given vreg, // its vreg reference equivalent should be the same, or null. for (uint32_t i = 0; i < NumberOfVRegs(); ++i) {
int32_t reference_value = References()[i].AsVRegValue();
CHECK((GetVReg(i) == reference_value) || (reference_value == 0));
}
}
}
// Link to previous shadow frame or null.
ShadowFrame* link_;
ArtMethod* method_;
LockCountData lock_count_data_; // This may contain GC roots when lock counting is active. const uint32_t number_of_vregs_;
uint32_t dex_pc_;
// This is a set of ShadowFrame::FrameFlags which denote special states this frame is in. // NB alignment requires that this field takes 4 bytes no matter its size. Only 7 bits are // currently used.
uint32_t frame_flags_;
// This is a two-part array: // - [0..number_of_vregs) holds the raw virtual registers, and each element here is always 4 // bytes. // - [number_of_vregs..number_of_vregs*2) holds only reference registers. Each element here is // ptr-sized. // In other words when a primitive is stored in vX, the second (reference) part of the array will // be null. When a reference is stored in vX, the second (reference) part of the array will be a // copy of vX.
uint32_t vregs_[0];
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.