diff options
Diffstat (limited to 'src/stack.h')
-rw-r--r-- | src/stack.h | 94 |
1 files changed, 91 insertions, 3 deletions
diff --git a/src/stack.h b/src/stack.h index fd2fd155da..5b5609c2c6 100644 --- a/src/stack.h +++ b/src/stack.h @@ -29,12 +29,27 @@ namespace art { class AbstractMethod; +class Context; class Object; class ShadowFrame; class StackIndirectReferenceTable; class ScopedObjectAccess; class Thread; +// The kind of vreg being accessed in calls to Set/GetVReg. +enum VRegKind { + kReferenceVReg, + kIntVReg, + kFloatVReg, + kLongLoVReg, + kLongHiVReg, + kDoubleLoVReg, + kDoubleHiVReg, + kConstant, + kImpreciseConstant, + kUndefined, +}; + class ShadowFrame { public: static ShadowFrame* Create(uint16_t num_refs, uint16_t num_vregs, ShadowFrame* link, @@ -366,15 +381,17 @@ class StackVisitor { return num_frames_; } - uint32_t GetVReg(AbstractMethod* m, int vreg) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + uint32_t GetVReg(AbstractMethod* m, uint16_t vreg, VRegKind kind) const + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - void SetVReg(AbstractMethod* m, int vreg, uint32_t new_value) + void SetVReg(AbstractMethod* m, uint16_t vreg, uint32_t new_value, VRegKind kind) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); uintptr_t GetGPR(uint32_t reg) const; uint32_t GetVReg(AbstractMethod** cur_quick_frame, const DexFile::CodeItem* code_item, - uint32_t core_spills, uint32_t fp_spills, size_t frame_size, int vreg) const { + uint32_t core_spills, uint32_t fp_spills, size_t frame_size, + uint16_t vreg) const { int offset = GetVRegOffset(code_item, core_spills, fp_spills, frame_size, vreg); DCHECK_EQ(cur_quick_frame, GetCurrentQuickFrame()); byte* vreg_addr = reinterpret_cast<byte*>(cur_quick_frame) + offset; @@ -482,6 +499,77 @@ class StackVisitor { Context* const context_; }; +class VmapTable { + public: + explicit VmapTable(const uint16_t* table) : table_(table) { + } + + uint16_t operator[](size_t i) const { + return table_[i + 1]; + } + + size_t size() const { + return table_[0]; + } + + // Is the dex register 'vreg' in the context or on the stack? Should not be called when the + // 'kind' is unknown or constant. + bool IsInContext(size_t vreg, uint32_t& vmap_offset, VRegKind kind) const { + DCHECK(kind == kReferenceVReg || kind == kIntVReg || kind == kFloatVReg || + kind == kLongLoVReg || kind == kLongHiVReg || kind == kDoubleLoVReg || + kind == kDoubleHiVReg || kind == kImpreciseConstant); + vmap_offset = 0xEBAD0FF5; + // TODO: take advantage of the registers being ordered + // TODO: we treat kImpreciseConstant as an integer below, need to ensure that such values + // are never promoted to floating point registers. + bool is_float = (kind == kFloatVReg) || (kind == kDoubleLoVReg) || (kind == kDoubleHiVReg); + bool in_floats = false; + for (size_t i = 0; i < size(); ++i) { + // Stop if we find what we are are looking for. + if ((table_[i + 1] == vreg) && (in_floats == is_float)) { + vmap_offset = i; + return true; + } + // 0xffff is the marker for LR (return PC on x86), following it are spilled float registers. + if (table_[i + 1] == 0xffff) { + in_floats = true; + } + } + return false; + } + + // Compute the register number that corresponds to the entry in the vmap (vmap_offset, computed + // by IsInContext above). If the kind is floating point then the result will be a floating point + // register number, otherwise it will be an integer register number. + uint32_t ComputeRegister(uint32_t spill_mask, uint32_t vmap_offset, VRegKind kind) const { + // Compute the register we need to load from the context. + DCHECK(kind == kReferenceVReg || kind == kIntVReg || kind == kFloatVReg || + kind == kLongLoVReg || kind == kLongHiVReg || kind == kDoubleLoVReg || + kind == kDoubleHiVReg || kind == kImpreciseConstant); + // TODO: we treat kImpreciseConstant as an integer below, need to ensure that such values + // are never promoted to floating point registers. + bool is_float = (kind == kFloatVReg) || (kind == kDoubleLoVReg) || (kind == kDoubleHiVReg); + uint32_t matches = 0; + if (is_float) { + while (table_[matches] != 0xffff) { + matches++; + } + } + CHECK_LT(vmap_offset - matches, static_cast<uint32_t>(__builtin_popcount(spill_mask))); + uint32_t spill_shifts = 0; + while (matches != (vmap_offset + 1)) { + DCHECK_NE(spill_mask, 0u); + matches += spill_mask & 1; // Add 1 if the low bit is set + spill_mask >>= 1; + spill_shifts++; + } + spill_shifts--; // wind back one as we want the last match + return spill_shifts; + } + private: + const uint16_t* table_; +}; + } // namespace art #endif // ART_SRC_STACK_H_ |