Index: src/arm/codegen-arm.cc |
diff --git a/src/arm/codegen-arm.cc b/src/arm/codegen-arm.cc |
index 1bcf3e3a605b051571dc9c51912264c65b90e14e..fff8d5e71553ad375785e1dea1dbd39c7cdfa969 100644 |
--- a/src/arm/codegen-arm.cc |
+++ b/src/arm/codegen-arm.cc |
@@ -826,6 +826,7 @@ void MathExpGenerator::EmitMathExp(MacroAssembler* masm, |
// add(r0, pc, Operand(-8)) |
static const uint32_t kCodeAgePatchFirstInstruction = 0xe24f0008; |
+static const uint32_t kThumbCodeAgePatchFirstInstruction = 0x3f2af; |
static byte* GetNoCodeAgeSequence(uint32_t* length) { |
// The sequence of instructions that is patched out for aging code is the |
@@ -846,19 +847,43 @@ static byte* GetNoCodeAgeSequence(uint32_t* length) { |
} |
-bool Code::IsYoungSequence(byte* sequence) { |
+static byte* GetThumbNoCodeAgeSequence(uint32_t* length) { |
+ // The sequence of instructions that is patched out for aging code is the |
+ // following boilerplate stack-building prologue that is found in FUNCTIONS |
+ static bool initialized = false; |
+ static uint32_t sequence[kNoCodeAgeSequenceLength]; |
+ byte* byte_sequence = reinterpret_cast<byte*>(sequence); |
+ *length = kNoCodeAgeSequenceLength * Assembler::kInstrSize; |
+ if (!initialized) { |
+ CodePatcher patcher(byte_sequence, kNoCodeAgeSequenceLength); |
+ PredictableCodeSizeScope scope(patcher.masm(), *length); |
+ patcher.masm()->set_thumb_mode(); |
+ patcher.masm()->stm(db_w, sp, r1.bit() | cp.bit() | fp.bit() | lr.bit()); |
+ patcher.masm()->nop(ip.code()); |
+ patcher.masm()->nop(ip.code()); |
+ patcher.masm()->add(fp, sp, Operand(2 * kPointerSize)); |
+ initialized = true; |
+ } |
+ return byte_sequence; |
+} |
+ |
+ |
+bool Code::IsYoungSequence(byte* sequence, bool thumb_mode) { |
uint32_t young_length; |
- byte* young_sequence = GetNoCodeAgeSequence(&young_length); |
+ byte* young_sequence = thumb_mode ? GetThumbNoCodeAgeSequence(&young_length) : |
+ GetNoCodeAgeSequence(&young_length); |
bool result = !memcmp(sequence, young_sequence, young_length); |
ASSERT(result || |
- Memory::uint32_at(sequence) == kCodeAgePatchFirstInstruction); |
+ Memory::uint32_at(sequence) == kCodeAgePatchFirstInstruction || |
+ Memory::uint32_at(sequence) == kThumbCodeAgePatchFirstInstruction); |
return result; |
} |
void Code::GetCodeAgeAndParity(byte* sequence, Age* age, |
- MarkingParity* parity) { |
- if (IsYoungSequence(sequence)) { |
+ MarkingParity* parity, |
+ bool thumb_mode) { |
+ if (IsYoungSequence(sequence, thumb_mode)) { |
*age = kNoAge; |
*parity = NO_MARKING_PARITY; |
} else { |
@@ -872,17 +897,29 @@ void Code::GetCodeAgeAndParity(byte* sequence, Age* age, |
void Code::PatchPlatformCodeAge(byte* sequence, |
Code::Age age, |
- MarkingParity parity) { |
+ MarkingParity parity, |
+ bool thumb_mode) { |
uint32_t young_length; |
- byte* young_sequence = GetNoCodeAgeSequence(&young_length); |
+ if (((uint32_t)sequence & 1) == 1) { |
+ thumb_mode = true; |
+ sequence = reinterpret_cast<byte*>((uint32_t)sequence & ~1); |
+ } |
+ byte* young_sequence = thumb_mode? GetThumbNoCodeAgeSequence(&young_length) : |
+ GetNoCodeAgeSequence(&young_length); |
if (age == kNoAge) { |
CopyBytes(sequence, young_sequence, young_length); |
CPU::FlushICache(sequence, young_length); |
} else { |
Code* stub = GetCodeAgeStub(age, parity); |
CodePatcher patcher(sequence, young_length / Assembler::kInstrSize); |
- patcher.masm()->add(r0, pc, Operand(-8)); |
- patcher.masm()->ldr(pc, MemOperand(pc, -4)); |
+ if (thumb_mode) { |
+ patcher.masm()->set_thumb_mode(); |
+ patcher.masm()->sub(r0, pc, Operand(3)); |
+ patcher.masm()->ldr(pc, MemOperand(pc, 0)); |
+ } else { |
+ patcher.masm()->sub(r0, pc, Operand(8)); |
+ patcher.masm()->ldr(pc, MemOperand(pc, -4)); |
+ } |
patcher.masm()->dd(reinterpret_cast<uint32_t>(stub->instruction_start())); |
} |
} |