Commit 663c73b3 authored by palfia@homejinni.com's avatar palfia@homejinni.com

MIPS: Fix for 3303 MultithreadedParallelIsolates has a race condition.

Port r21165 (50673b25)

Original commit message:
The fix is to make the code aging sequence hang off the isolate.

BUG=
R=plind44@gmail.com

Review URL: https://codereview.chromium.org/264823004

git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@21180 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 67ff6878
......@@ -255,7 +255,7 @@ void RelocInfo::set_target_cell(Cell* cell, WriteBarrierMode mode) {
}
static const int kNoCodeAgeSequenceLength = 7;
static const int kNoCodeAgeSequenceLength = 7 * Assembler::kInstrSize;
Handle<Object> RelocInfo::code_age_stub_handle(Assembler* origin) {
......
......@@ -865,7 +865,7 @@ static void GenerateMakeCodeYoungAgainCommon(MacroAssembler* masm) {
// Set a0 to point to the head of the PlatformCodeAge sequence.
__ Subu(a0, a0,
Operand((kNoCodeAgeSequenceLength - 1) * Assembler::kInstrSize));
Operand(kNoCodeAgeSequenceLength - Assembler::kInstrSize));
// The following registers must be saved and restored when calling through to
// the runtime:
......@@ -904,7 +904,7 @@ void Builtins::Generate_MarkCodeAsExecutedOnce(MacroAssembler* masm) {
// Set a0 to point to the head of the PlatformCodeAge sequence.
__ Subu(a0, a0,
Operand((kNoCodeAgeSequenceLength - 1) * Assembler::kInstrSize));
Operand(kNoCodeAgeSequenceLength - Assembler::kInstrSize));
// The following registers must be saved and restored when calling through to
// the runtime:
......@@ -926,7 +926,7 @@ void Builtins::Generate_MarkCodeAsExecutedOnce(MacroAssembler* masm) {
__ Addu(fp, sp, Operand(StandardFrameConstants::kFixedFrameSizeFromFp));
// Jump to point after the code-age stub.
__ Addu(a0, a0, Operand((kNoCodeAgeSequenceLength) * Assembler::kInstrSize));
__ Addu(a0, a0, Operand(kNoCodeAgeSequenceLength));
__ Jump(a0);
}
......
......@@ -1122,42 +1122,42 @@ void MathExpGenerator::EmitMathExp(MacroAssembler* masm,
static const uint32_t kCodeAgePatchFirstInstruction = 0x00010180;
#endif
static byte* GetNoCodeAgeSequence(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) {
// Since patcher is a large object, allocate it dynamically when needed,
// to avoid overloading the stack in stress conditions.
SmartPointer<CodePatcher>
patcher(new CodePatcher(byte_sequence, kNoCodeAgeSequenceLength));
PredictableCodeSizeScope scope(patcher->masm(), *length);
patcher->masm()->Push(ra, fp, cp, a1);
patcher->masm()->nop(Assembler::CODE_AGE_SEQUENCE_NOP);
patcher->masm()->Addu(
fp, sp, Operand(StandardFrameConstants::kFixedFrameSizeFromFp));
initialized = true;
}
return byte_sequence;
CodeAgingHelper::CodeAgingHelper() {
ASSERT(young_sequence_.length() == kNoCodeAgeSequenceLength);
// Since patcher is a large object, allocate it dynamically when needed,
// to avoid overloading the stack in stress conditions.
// DONT_FLUSH is used because the CodeAgingHelper is initialized early in
// the process, before MIPS simulator ICache is setup.
SmartPointer<CodePatcher> patcher(
new CodePatcher(young_sequence_.start(),
young_sequence_.length() / Assembler::kInstrSize,
CodePatcher::DONT_FLUSH));
PredictableCodeSizeScope scope(patcher->masm(), young_sequence_.length());
patcher->masm()->Push(ra, fp, cp, a1);
patcher->masm()->nop(Assembler::CODE_AGE_SEQUENCE_NOP);
patcher->masm()->Addu(
fp, sp, Operand(StandardFrameConstants::kFixedFrameSizeFromFp));
}
bool Code::IsYoungSequence(byte* sequence) {
uint32_t young_length;
byte* young_sequence = GetNoCodeAgeSequence(&young_length);
bool result = !memcmp(sequence, young_sequence, young_length);
ASSERT(result ||
Memory::uint32_at(sequence) == kCodeAgePatchFirstInstruction);
#ifdef DEBUG
bool CodeAgingHelper::IsOld(byte* candidate) const {
return Memory::uint32_at(candidate) == kCodeAgePatchFirstInstruction;
}
#endif
bool Code::IsYoungSequence(Isolate* isolate, byte* sequence) {
bool result = isolate->code_aging_helper()->IsYoung(sequence);
ASSERT(result || isolate->code_aging_helper()->IsOld(sequence));
return result;
}
void Code::GetCodeAgeAndParity(byte* sequence, Age* age,
void Code::GetCodeAgeAndParity(Isolate* isolate, byte* sequence, Age* age,
MarkingParity* parity) {
if (IsYoungSequence(sequence)) {
if (IsYoungSequence(isolate, sequence)) {
*age = kNoAgeCodeAge;
*parity = NO_MARKING_PARITY;
} else {
......@@ -1173,10 +1173,9 @@ void Code::PatchPlatformCodeAge(Isolate* isolate,
byte* sequence,
Code::Age age,
MarkingParity parity) {
uint32_t young_length;
byte* young_sequence = GetNoCodeAgeSequence(&young_length);
uint32_t young_length = isolate->code_aging_helper()->young_sequence_length();
if (age == kNoAgeCodeAge) {
CopyBytes(sequence, young_sequence, young_length);
isolate->code_aging_helper()->CopyYoungSequenceTo(sequence);
CPU::FlushICache(sequence, young_length);
} else {
Code* stub = GetCodeAgeStub(isolate, age, parity);
......
......@@ -30,7 +30,7 @@ void Deoptimizer::PatchCodeForDeoptimization(Isolate* isolate, Code* code) {
// Fail hard and early if we enter this code object again.
byte* pointer = code->FindCodeAgeSequence();
if (pointer != NULL) {
pointer += kNoCodeAgeSequenceLength * Assembler::kInstrSize;
pointer += kNoCodeAgeSequenceLength;
} else {
pointer = code->instruction_start();
}
......
......@@ -4460,7 +4460,7 @@ void MacroAssembler::Prologue(PrologueFrameMode frame_mode) {
Addu(fp, sp, Operand(StandardFrameConstants::kFixedFrameSizeFromFp));
} else {
PredictableCodeSizeScope predictible_code_size_scope(
this, kNoCodeAgeSequenceLength * Assembler::kInstrSize);
this, kNoCodeAgeSequenceLength);
// The following three instructions must remain together and unmodified
// for code aging to work properly.
if (isolate()->IsCodePreAgingActive()) {
......@@ -5664,10 +5664,13 @@ bool AreAliased(Register r1, Register r2, Register r3, Register r4) {
}
CodePatcher::CodePatcher(byte* address, int instructions)
CodePatcher::CodePatcher(byte* address,
int instructions,
FlushICache flush_cache)
: address_(address),
size_(instructions * Assembler::kInstrSize),
masm_(NULL, address, size_ + Assembler::kGap) {
masm_(NULL, address, size_ + Assembler::kGap),
flush_cache_(flush_cache) {
// Create a new macro assembler pointing to the address of the code to patch.
// The size is adjusted with kGap on order for the assembler to generate size
// bytes of instructions without failing with buffer size constraints.
......@@ -5677,7 +5680,9 @@ CodePatcher::CodePatcher(byte* address, int instructions)
CodePatcher::~CodePatcher() {
// Indicate that code has changed.
CPU::FlushICache(address_, size_);
if (flush_cache_ == FLUSH) {
CPU::FlushICache(address_, size_);
}
// Check that the code was patched as expected.
ASSERT(masm_.pc_ == address_ + size_);
......
......@@ -1614,7 +1614,14 @@ const Operand& rt = Operand(zero_reg), BranchDelaySlot bd = PROTECT
// an assertion to fail.
class CodePatcher {
public:
CodePatcher(byte* address, int instructions);
enum FlushICache {
FLUSH,
DONT_FLUSH
};
CodePatcher(byte* address,
int instructions,
FlushICache flush_cache = FLUSH);
virtual ~CodePatcher();
// Macro assembler to emit code.
......@@ -1634,6 +1641,7 @@ class CodePatcher {
byte* address_; // The address of the code being patched.
int size_; // Number of bytes of the expected patch size.
MacroAssembler masm_; // Macro assembler used to generate the code.
FlushICache flush_cache_; // Whether to flush the I cache after patching.
};
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment