VM: Clean up and fix bugs in instructions patterns

Fix bug in DecodeLoadWordFromPool: used Array::element_offset instead of ObjectPool::element_offset.
This only worked because they accidentally return the same value.

Remove virtual methods from InstructionsPatterns on ia32 and x64. Instead use a template for code reuse.
This avoids among others vtables for the *Pattern classes and saves >= 4K in VM binary code size.

BUG=
R=rmacnak@google.com

Review URL: https://codereview.chromium.org//1301963003 .
This commit is contained in:
Florian Schneider
2015-08-21 09:31:36 +02:00
parent 3aa62d03fc
commit b5966db69e
12 changed files with 158 additions and 201 deletions
+2 -2
View File
@@ -178,11 +178,11 @@ void CodePatcher::PatchInstanceCallAt(uword return_address,
void CodePatcher::InsertCallAt(uword start, uword target) {
// The inserted call should not overlap the lazy deopt jump code.
ASSERT(start + CallPattern::InstructionLength() <= target);
ASSERT(start + CallPattern::pattern_length_in_bytes() <= target);
*reinterpret_cast<uint8_t*>(start) = 0xE8;
CallPattern call(start);
call.SetTargetAddress(target);
CPU::FlushICache(start, CallPattern::InstructionLength());
CPU::FlushICache(start, CallPattern::pattern_length_in_bytes());
}
+7 -7
View File
@@ -41,17 +41,17 @@ class UnoptimizedCall : public ValueObject {
}
RawObject* ic_data() const {
intptr_t index = InstructionPattern::IndexFromPPLoad(start_ + 3);
intptr_t index = IndexFromPPLoad(start_ + 3);
return object_pool_.ObjectAt(index);
}
uword target() const {
intptr_t index = InstructionPattern::IndexFromPPLoad(start_ + 10);
intptr_t index = IndexFromPPLoad(start_ + 10);
return object_pool_.RawValueAt(index);
}
void set_target(uword target) const {
intptr_t index = InstructionPattern::IndexFromPPLoad(start_ + 10);
intptr_t index = IndexFromPPLoad(start_ + 10);
object_pool_.SetRawValueAt(index, target);
// No need to flush the instruction cache, since the code is not modified.
}
@@ -117,7 +117,7 @@ class PoolPointerCall : public ValueObject {
}
intptr_t pp_index() const {
return InstructionPattern::IndexFromPPLoad(start_ + 3);
return IndexFromPPLoad(start_ + 3);
}
uword Target() const {
@@ -190,11 +190,11 @@ intptr_t CodePatcher::InstanceCallSizeInBytes() {
void CodePatcher::InsertCallAt(uword start, uword target) {
// The inserted call should not overlap the lazy deopt jump code.
ASSERT(start + ShortCallPattern::InstructionLength() <= target);
ASSERT(start + ShortCallPattern::pattern_length_in_bytes() <= target);
*reinterpret_cast<uint8_t*>(start) = 0xE8;
ShortCallPattern call(start);
call.SetTargetAddress(target);
CPU::FlushICache(start, ShortCallPattern::InstructionLength());
CPU::FlushICache(start, ShortCallPattern::pattern_length_in_bytes());
}
@@ -227,7 +227,7 @@ class EdgeCounter : public ValueObject {
}
RawObject* edge_counter() const {
return object_pool_.ObjectAt(InstructionPattern::IndexFromPPLoad(end_ - 4));
return object_pool_.ObjectAt(IndexFromPPLoad(end_ - 4));
}
private:
+1 -3
View File
@@ -150,9 +150,7 @@ uword InstructionPattern::DecodeLoadWordFromPool(uword end,
end = DecodeLoadWordImmediate(end, reg, &offset);
}
}
offset += kHeapObjectTag;
ASSERT(Utils::IsAligned(offset, 4));
*index = (offset - Array::data_offset()) / 4;
*index = ObjectPool::IndexFromOffset(offset);
return start;
}
+2 -1
View File
@@ -208,8 +208,9 @@ uword InstructionPattern::DecodeLoadWordFromPool(uword end,
offset |= instr->Imm16Field();
}
}
// PP is untagged on ARM64.
ASSERT(Utils::IsAligned(offset, 8));
*index = (offset - Array::data_offset()) / 8;
*index = ObjectPool::IndexFromOffset(offset - kHeapObjectTag);
return start;
}
-55
View File
@@ -11,61 +11,6 @@
namespace dart {
bool InstructionPattern::TestBytesWith(const int* data, int num_bytes) const {
ASSERT(data != NULL);
const uint8_t* byte_array = reinterpret_cast<const uint8_t*>(start_);
for (int i = 0; i < num_bytes; i++) {
// Skip comparison for data[i] < 0.
if ((data[i] >= 0) && (byte_array[i] != (0xFF & data[i]))) {
return false;
}
}
return true;
}
uword CallOrJumpPattern::TargetAddress() const {
ASSERT(IsValid());
return start() + kLengthInBytes + *reinterpret_cast<uword*>(start() + 1);
}
void CallOrJumpPattern::SetTargetAddress(uword target) const {
ASSERT(IsValid());
*reinterpret_cast<uword*>(start() + 1) = target - start() - kLengthInBytes;
CPU::FlushICache(start() + 1, kWordSize);
}
const int* CallPattern::pattern() const {
static const int kCallPattern[kLengthInBytes] = {0xE8, -1, -1, -1, -1};
return kCallPattern;
}
const int* JumpPattern::pattern() const {
static const int kJumpPattern[kLengthInBytes] = {0xE9, -1, -1, -1, -1};
return kJumpPattern;
}
const int* ReturnPattern::pattern() const {
static const int kReturnPattern[kLengthInBytes] = { 0xC3 };
return kReturnPattern;
}
const int* ProloguePattern::pattern() const {
static const int kProloguePattern[kLengthInBytes] = { 0x55, 0x89, 0xe5 };
return kProloguePattern;
}
const int* SetFramePointerPattern::pattern() const {
static const int kFramePointerPattern[kLengthInBytes] = { 0x89, 0xe5 };
return kFramePointerPattern;
}
} // namespace dart
#endif // defined TARGET_ARCH_IA32
+71 -33
View File
@@ -11,6 +11,7 @@
#endif
#include "vm/allocation.h"
#include "vm/cpu.h"
#include "vm/object.h"
namespace dart {
@@ -20,24 +21,22 @@ class RawClass;
class Immediate;
class RawObject;
// Abstract class for all instruction pattern classes.
class InstructionPattern : public ValueObject {
// Template class for all instruction pattern classes.
// P has to specify a static pattern and a pattern length method.
template<class P> class InstructionPattern : public ValueObject {
public:
explicit InstructionPattern(uword pc) : start_(pc) {
ASSERT(pc != 0);
}
virtual ~InstructionPattern() {}
// Call to check if the instruction pattern at 'pc' match the instruction.
virtual bool IsValid() const {
return TestBytesWith(pattern(), pattern_length_in_bytes());
// 'P::pattern()' returns the expected byte pattern in form of an integer
// array with length of 'P::pattern_length_in_bytes()'. A '-1' element means
// 'any byte'.
bool IsValid() const {
return TestBytesWith(P::pattern(), P::pattern_length_in_bytes());
}
// 'pattern' returns the expected byte pattern in form of an integer array
// with length of 'pattern_length_in_bytes'. A '-1' element means 'any byte'.
virtual const int* pattern() const = 0;
virtual int pattern_length_in_bytes() const = 0;
protected:
uword start() const { return start_; }
@@ -45,7 +44,17 @@ class InstructionPattern : public ValueObject {
// Returns true if the 'num_bytes' bytes at 'start_' correspond to
// array of integers 'data'. 'data' elements are either a byte or -1, which
// represents any byte.
bool TestBytesWith(const int* data, int num_bytes) const;
bool TestBytesWith(const int* data, int num_bytes) const {
ASSERT(data != NULL);
const uint8_t* byte_array = reinterpret_cast<const uint8_t*>(start_);
for (int i = 0; i < num_bytes; i++) {
// Skip comparison for data[i] < 0.
if ((data[i] >= 0) && (byte_array[i] != (0xFF & data[i]))) {
return false;
}
}
return true;
}
const uword start_;
@@ -53,54 +62,74 @@ class InstructionPattern : public ValueObject {
};
class CallOrJumpPattern : public InstructionPattern {
template<class P>
class CallOrJumpPattern : public InstructionPattern<P> {
public:
virtual int pattern_length_in_bytes() const {
return kLengthInBytes;
uword TargetAddress() const {
ASSERT(this->IsValid());
return this->start() +
P::pattern_length_in_bytes() +
*reinterpret_cast<uword*>(this->start() + 1);
}
void SetTargetAddress(uword new_target) const {
ASSERT(this->IsValid());
*reinterpret_cast<uword*>(this->start() + 1) =
new_target - this->start() - P::pattern_length_in_bytes();
CPU::FlushICache(this->start() + 1, kWordSize);
}
uword TargetAddress() const;
void SetTargetAddress(uword new_target) const;
protected:
explicit CallOrJumpPattern(uword pc) : InstructionPattern(pc) {}
static const int kLengthInBytes = 5;
explicit CallOrJumpPattern(uword pc) : InstructionPattern<P>(pc) {}
private:
DISALLOW_COPY_AND_ASSIGN(CallOrJumpPattern);
};
class CallPattern : public CallOrJumpPattern {
class CallPattern : public CallOrJumpPattern<CallPattern> {
public:
explicit CallPattern(uword pc) : CallOrJumpPattern(pc) {}
static int InstructionLength() {
return kLengthInBytes;
static int pattern_length_in_bytes() { return kLengthInBytes; }
static const int* pattern() {
static const int kCallPattern[kLengthInBytes] = {0xE8, -1, -1, -1, -1};
return kCallPattern;
}
private:
virtual const int* pattern() const;
static const int kLengthInBytes = 5;
DISALLOW_COPY_AND_ASSIGN(CallPattern);
};
class JumpPattern : public CallOrJumpPattern {
class JumpPattern : public CallOrJumpPattern<JumpPattern> {
public:
JumpPattern(uword pc, const Code& code) : CallOrJumpPattern(pc) {}
static int pattern_length_in_bytes() { return kLengthInBytes; }
static const int* pattern() {
static const int kJumpPattern[kLengthInBytes] = {0xE9, -1, -1, -1, -1};
return kJumpPattern;
}
private:
virtual const int* pattern() const;
static const int kLengthInBytes = 5;
DISALLOW_COPY_AND_ASSIGN(JumpPattern);
};
class ReturnPattern : public InstructionPattern {
class ReturnPattern : public InstructionPattern<ReturnPattern> {
public:
explicit ReturnPattern(uword pc) : InstructionPattern(pc) {}
virtual const int* pattern() const;
virtual int pattern_length_in_bytes() const { return kLengthInBytes; }
static const int* pattern() {
static const int kReturnPattern[kLengthInBytes] = { 0xC3 };
return kReturnPattern;
}
static int pattern_length_in_bytes() { return kLengthInBytes; }
private:
static const int kLengthInBytes = 1;
@@ -109,12 +138,16 @@ class ReturnPattern : public InstructionPattern {
// push ebp
// mov ebp, esp
class ProloguePattern : public InstructionPattern {
class ProloguePattern : public InstructionPattern<ProloguePattern> {
public:
explicit ProloguePattern(uword pc) : InstructionPattern(pc) {}
virtual const int* pattern() const;
virtual int pattern_length_in_bytes() const { return kLengthInBytes; }
static const int* pattern() {
static const int kProloguePattern[kLengthInBytes] = { 0x55, 0x89, 0xe5 };
return kProloguePattern;
}
static int pattern_length_in_bytes() { return kLengthInBytes; }
private:
static const int kLengthInBytes = 3;
@@ -122,12 +155,17 @@ class ProloguePattern : public InstructionPattern {
// mov ebp, esp
class SetFramePointerPattern : public InstructionPattern {
class SetFramePointerPattern :
public InstructionPattern<SetFramePointerPattern> {
public:
explicit SetFramePointerPattern(uword pc) : InstructionPattern(pc) {}
virtual const int* pattern() const;
virtual int pattern_length_in_bytes() const { return kLengthInBytes; }
static const int* pattern() {
static const int kFramePointerPattern[kLengthInBytes] = { 0x89, 0xe5 };
return kFramePointerPattern;
}
static int pattern_length_in_bytes() { return kLengthInBytes; }
private:
static const int kLengthInBytes = 2;
+1 -3
View File
@@ -118,9 +118,7 @@ uword InstructionPattern::DecodeLoadWordFromPool(uword end,
// Offset is signed, so add the upper 16 bits.
offset += (instr->UImmField() << 16);
}
offset += kHeapObjectTag;
ASSERT(Utils::IsAligned(offset, 4));
*index = (offset - Array::data_offset()) / 4;
*index = ObjectPool::IndexFromOffset(offset);
return start;
}
+3 -54
View File
@@ -11,54 +11,27 @@
namespace dart {
intptr_t InstructionPattern::IndexFromPPLoad(uword start) {
intptr_t IndexFromPPLoad(uword start) {
int32_t offset = *reinterpret_cast<int32_t*>(start);
return ObjectPool::IndexFromOffset(offset);
}
intptr_t InstructionPattern::OffsetFromPPIndex(intptr_t index) {
intptr_t offset = ObjectPool::element_offset(index);
return offset - kHeapObjectTag;
}
bool InstructionPattern::TestBytesWith(const int* data, int num_bytes) const {
ASSERT(data != NULL);
const uint8_t* byte_array = reinterpret_cast<const uint8_t*>(start_);
for (int i = 0; i < num_bytes; i++) {
// Skip comparison for data[i] < 0.
if ((data[i] >= 0) && (byte_array[i] != (0xFF & data[i]))) {
return false;
}
}
return true;
}
uword JumpPattern::TargetAddress() const {
ASSERT(IsValid());
int index = InstructionPattern::IndexFromPPLoad(start() + 3);
int index = IndexFromPPLoad(start() + 3);
return object_pool_.RawValueAt(index);
}
void JumpPattern::SetTargetAddress(uword target) const {
ASSERT(IsValid());
int index = InstructionPattern::IndexFromPPLoad(start() + 3);
int index = IndexFromPPLoad(start() + 3);
object_pool_.SetRawValueAt(index, target);
// No need to flush the instruction cache, since the code is not modified.
}
const int* JumpPattern::pattern() const {
// 07: 41 ff a7 imm32 jmpq [reg + off]
static const int kJumpPattern[kLengthInBytes] =
{0x41, 0xFF, -1, -1, -1, -1, -1};
return kJumpPattern;
}
void ShortCallPattern::SetTargetAddress(uword target) const {
ASSERT(IsValid());
*reinterpret_cast<uint32_t*>(start() + 1) = target - start() - kLengthInBytes;
@@ -66,30 +39,6 @@ void ShortCallPattern::SetTargetAddress(uword target) const {
}
const int* ShortCallPattern::pattern() const {
static const int kCallPattern[kLengthInBytes] = {0xE8, -1, -1, -1, -1};
return kCallPattern;
}
const int* ReturnPattern::pattern() const {
static const int kReturnPattern[kLengthInBytes] = { 0xC3 };
return kReturnPattern;
}
const int* ProloguePattern::pattern() const {
static const int kProloguePattern[kLengthInBytes] =
{ 0x55, 0x48, 0x89, 0xe5 };
return kProloguePattern;
}
const int* SetFramePointerPattern::pattern() const {
static const int kFramePointerPattern[kLengthInBytes] = { 0x48, 0x89, 0xe5 };
return kFramePointerPattern;
}
} // namespace dart
#endif // defined TARGET_ARCH_X64
+63 -41
View File
@@ -20,27 +20,26 @@ class RawClass;
class Immediate;
class RawObject;
// Abstract class for all instruction pattern classes.
class InstructionPattern : public ValueObject {
intptr_t IndexFromPPLoad(uword start);
// Template class for all instruction pattern classes.
// P has to specify a static pattern and a pattern length method.
template<class P> class InstructionPattern : public ValueObject {
public:
explicit InstructionPattern(uword pc) : start_(pc) {
ASSERT(pc != 0);
}
virtual ~InstructionPattern() {}
// Call to check if the instruction pattern at 'pc' match the instruction.
virtual bool IsValid() const {
return TestBytesWith(pattern(), pattern_length_in_bytes());
// 'P::pattern()' returns the expected byte pattern in form of an integer
// array with length of 'P::pattern_length_in_bytes()'. A '-1' element means
// 'any byte'.
bool IsValid() const {
return TestBytesWith(P::pattern(), P::pattern_length_in_bytes());
}
// 'pattern' returns the expected byte pattern in form of an integer array
// with length of 'pattern_length_in_bytes'. A '-1' element means 'any byte'.
virtual const int* pattern() const = 0;
virtual int pattern_length_in_bytes() const = 0;
static intptr_t IndexFromPPLoad(uword start);
static intptr_t OffsetFromPPIndex(intptr_t index);
protected:
uword start() const { return start_; }
@@ -48,7 +47,17 @@ class InstructionPattern : public ValueObject {
// Returns true if the 'num_bytes' bytes at 'start_' correspond to
// array of integers 'data'. 'data' elements are either a byte or -1, which
// represents any byte.
bool TestBytesWith(const int* data, int num_bytes) const;
bool TestBytesWith(const int* data, int num_bytes) const {
ASSERT(data != NULL);
const uint8_t* byte_array = reinterpret_cast<const uint8_t*>(start_);
for (int i = 0; i < num_bytes; i++) {
// Skip comparison for data[i] < 0.
if ((data[i] >= 0) && (byte_array[i] != (0xFF & data[i]))) {
return false;
}
}
return true;
}
const uword start_;
@@ -56,23 +65,24 @@ class InstructionPattern : public ValueObject {
};
class JumpPattern : public InstructionPattern {
class JumpPattern : public InstructionPattern<JumpPattern> {
public:
JumpPattern(uword pc, const Code& code)
: InstructionPattern(pc),
object_pool_(ObjectPool::Handle(code.GetObjectPool())) {}
static int InstructionLength() {
return kLengthInBytes;
}
uword TargetAddress() const;
void SetTargetAddress(uword new_target) const;
virtual int pattern_length_in_bytes() const {
return kLengthInBytes;
}
static const int kLengthInBytes = 7;
static int pattern_length_in_bytes() { return kLengthInBytes; }
static const int* pattern() {
// 07: 41 ff a7 imm32 jmpq [reg + off]
static const int kJumpPattern[kLengthInBytes] =
{0x41, 0xFF, -1, -1, -1, -1, -1};
return kJumpPattern;
}
private:
virtual const int* pattern() const;
const ObjectPool& object_pool_;
DISALLOW_COPY_AND_ASSIGN(JumpPattern);
@@ -80,33 +90,34 @@ class JumpPattern : public InstructionPattern {
// 5 byte call instruction.
class ShortCallPattern : public InstructionPattern {
class ShortCallPattern : public InstructionPattern<ShortCallPattern> {
public:
explicit ShortCallPattern(uword pc) : InstructionPattern(pc) {}
static int InstructionLength() {
return kLengthInBytes;
}
virtual int pattern_length_in_bytes() const {
return kLengthInBytes;
}
void SetTargetAddress(uword new_target) const;
static int pattern_length_in_bytes() { return kLengthInBytes; }
static const int* pattern() {
static const int kCallPattern[kLengthInBytes] = {0xE8, -1, -1, -1, -1};
return kCallPattern;
}
private:
static const int kLengthInBytes = 5;
virtual const int* pattern() const;
DISALLOW_COPY_AND_ASSIGN(ShortCallPattern);
};
class ReturnPattern : public InstructionPattern {
class ReturnPattern : public InstructionPattern<ReturnPattern> {
public:
explicit ReturnPattern(uword pc) : InstructionPattern(pc) {}
virtual const int* pattern() const;
virtual int pattern_length_in_bytes() const { return kLengthInBytes; }
static const int* pattern() {
static const int kReturnPattern[kLengthInBytes] = { 0xC3 };
return kReturnPattern;
}
static int pattern_length_in_bytes() { return kLengthInBytes; }
private:
static const int kLengthInBytes = 1;
@@ -115,12 +126,17 @@ class ReturnPattern : public InstructionPattern {
// push rbp
// mov rbp, rsp
class ProloguePattern : public InstructionPattern {
class ProloguePattern : public InstructionPattern<ProloguePattern> {
public:
explicit ProloguePattern(uword pc) : InstructionPattern(pc) {}
virtual const int* pattern() const;
virtual int pattern_length_in_bytes() const { return kLengthInBytes; }
static const int* pattern() {
static const int kProloguePattern[kLengthInBytes] =
{ 0x55, 0x48, 0x89, 0xe5 };
return kProloguePattern;
}
static int pattern_length_in_bytes() { return kLengthInBytes; }
private:
static const int kLengthInBytes = 4;
@@ -128,12 +144,18 @@ class ProloguePattern : public InstructionPattern {
// mov rbp, rsp
class SetFramePointerPattern : public InstructionPattern {
class SetFramePointerPattern :
public InstructionPattern<SetFramePointerPattern> {
public:
explicit SetFramePointerPattern(uword pc) : InstructionPattern(pc) {}
virtual const int* pattern() const;
virtual int pattern_length_in_bytes() const { return kLengthInBytes; }
static const int* pattern() {
static const int kFramePointerPattern[kLengthInBytes] =
{ 0x48, 0x89, 0xe5 };
return kFramePointerPattern;
}
static int pattern_length_in_bytes() { return kLengthInBytes; }
private:
static const int kLengthInBytes = 3;
+6
View File
@@ -3625,10 +3625,16 @@ class ObjectPool : public Object {
static RawObjectPool* New(intptr_t len);
// Returns the pool index from the offset relative to a tagged RawObjectPool*,
// adjusting for the tag-bit.
static intptr_t IndexFromOffset(intptr_t offset) {
return (offset + kHeapObjectTag - data_offset()) / kBytesPerElement;
}
static intptr_t OffsetFromIndex(intptr_t index) {
return element_offset(index) - kHeapObjectTag;
}
void DebugPrint() const;
private:
+1 -1
View File
@@ -458,7 +458,7 @@ void StubCode::GenerateDeoptimizeLazyStub(Assembler* assembler) {
// Correct return address to point just after the call that is being
// deoptimized.
__ popl(EBX);
__ subl(EBX, Immediate(CallPattern::InstructionLength()));
__ subl(EBX, Immediate(CallPattern::pattern_length_in_bytes()));
__ pushl(EBX);
GenerateDeoptimizationSequence(assembler, true); // Preserve EAX.
}
+1 -1
View File
@@ -479,7 +479,7 @@ void StubCode::GenerateDeoptimizeLazyStub(Assembler* assembler) {
// Correct return address to point just after the call that is being
// deoptimized.
__ popq(RBX);
__ subq(RBX, Immediate(ShortCallPattern::InstructionLength()));
__ subq(RBX, Immediate(ShortCallPattern::pattern_length_in_bytes()));
__ pushq(RBX);
GenerateDeoptimizationSequence(assembler, true); // Preserve RAX.
}