From f2903b6f6c3342fa57b6bc75be0d34c586c975bd Mon Sep 17 00:00:00 2001 From: "mvstanton@chromium.org" Date: Tue, 6 May 2014 11:25:37 +0000 Subject: [PATCH] Fix for 3303 MultithreadedParallelIsolates has a race condition. The fix is to make the code aging sequence hang off the isolate. BUG=v8:3303 R=svenpanne@chromium.org LOG=N Review URL: https://codereview.chromium.org/261953002 git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@21165 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- src/arm/assembler-arm-inl.h | 10 +++--- src/arm/builtins-arm.cc | 2 +- src/arm/codegen-arm.cc | 62 ++++++++++++++++++-------------------- src/arm/deoptimizer-arm.cc | 2 +- src/arm/macro-assembler-arm.cc | 2 +- src/arm64/assembler-arm64-inl.h | 5 ++- src/arm64/builtins-arm64.cc | 2 +- src/arm64/codegen-arm64.cc | 38 ++++++++++++++++++++--- src/arm64/macro-assembler-arm64.cc | 47 ++++++----------------------- src/arm64/macro-assembler-arm64.h | 8 +---- src/assembler.cc | 11 ++++--- src/assembler.h | 2 +- src/codegen.h | 27 +++++++++++++++++ src/ia32/codegen-ia32.cc | 47 +++++++++++++---------------- src/isolate.cc | 7 ++++- src/isolate.h | 3 ++ src/objects-debug.cc | 3 +- src/objects.cc | 7 +++-- src/objects.h | 4 +-- src/x64/codegen-x64.cc | 50 +++++++++++++++--------------- test/cctest/cctest.status | 3 -- 21 files changed, 182 insertions(+), 160 deletions(-) diff --git a/src/arm/assembler-arm-inl.h b/src/arm/assembler-arm-inl.h index 287ed09..f5612e4 100644 --- a/src/arm/assembler-arm-inl.h +++ b/src/arm/assembler-arm-inl.h @@ -222,7 +222,7 @@ void RelocInfo::set_target_cell(Cell* cell, WriteBarrierMode mode) { } -static const int kNoCodeAgeSequenceLength = 3; +static const int kNoCodeAgeSequenceLength = 3 * Assembler::kInstrSize; Handle RelocInfo::code_age_stub_handle(Assembler* origin) { @@ -234,15 +234,15 @@ Handle RelocInfo::code_age_stub_handle(Assembler* origin) { Code* RelocInfo::code_age_stub() { ASSERT(rmode_ == RelocInfo::CODE_AGE_SEQUENCE); return Code::GetCodeFromTargetAddress( - Memory::Address_at(pc_ + Assembler::kInstrSize * - (kNoCodeAgeSequenceLength - 1))); + Memory::Address_at(pc_ + + (kNoCodeAgeSequenceLength - Assembler::kInstrSize))); } void RelocInfo::set_code_age_stub(Code* stub) { ASSERT(rmode_ == RelocInfo::CODE_AGE_SEQUENCE); - Memory::Address_at(pc_ + Assembler::kInstrSize * - (kNoCodeAgeSequenceLength - 1)) = + Memory::Address_at(pc_ + + (kNoCodeAgeSequenceLength - Assembler::kInstrSize)) = stub->instruction_start(); } diff --git a/src/arm/builtins-arm.cc b/src/arm/builtins-arm.cc index 74fe5f1..2e5cc73 100644 --- a/src/arm/builtins-arm.cc +++ b/src/arm/builtins-arm.cc @@ -898,7 +898,7 @@ void Builtins::Generate_MarkCodeAsExecutedOnce(MacroAssembler* masm) { __ add(fp, sp, Operand(StandardFrameConstants::kFixedFrameSizeFromFp)); // Jump to point after the code-age stub. - __ add(r0, r0, Operand(kNoCodeAgeSequenceLength * Assembler::kInstrSize)); + __ add(r0, r0, Operand(kNoCodeAgeSequenceLength)); __ mov(pc, r0); } diff --git a/src/arm/codegen-arm.cc b/src/arm/codegen-arm.cc index a8e3877..8a46006 100644 --- a/src/arm/codegen-arm.cc +++ b/src/arm/codegen-arm.cc @@ -822,47 +822,46 @@ void MathExpGenerator::EmitMathExp(MacroAssembler* masm, static const uint32_t kCodeAgePatchFirstInstruction = 0xe24f0008; #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(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 - patcher(new CodePatcher(byte_sequence, kNoCodeAgeSequenceLength)); - PredictableCodeSizeScope scope(patcher->masm(), *length); - patcher->masm()->PushFixedFrame(r1); - patcher->masm()->nop(ip.code()); - patcher->masm()->add( - 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 ARM simulator ICache is setup. + SmartPointer patcher( + new CodePatcher(young_sequence_.start(), + young_sequence_.length() / Assembler::kInstrSize, + CodePatcher::DONT_FLUSH)); + PredictableCodeSizeScope scope(patcher->masm(), young_sequence_.length()); + patcher->masm()->PushFixedFrame(r1); + patcher->masm()->nop(ip.code()); + patcher->masm()->add( + fp, sp, Operand(StandardFrameConstants::kFixedFrameSizeFromFp)); +} + + +#ifdef DEBUG +bool CodeAgingHelper::IsOld(byte* candidate) const { + return Memory::uint32_at(candidate) == kCodeAgePatchFirstInstruction; } +#endif -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); +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 { Address target_address = Memory::Address_at( - sequence + Assembler::kInstrSize * (kNoCodeAgeSequenceLength - 1)); + sequence + (kNoCodeAgeSequenceLength - Assembler::kInstrSize)); Code* stub = GetCodeFromTargetAddress(target_address); GetCodeAgeAndParity(stub, age, parity); } @@ -873,10 +872,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); diff --git a/src/arm/deoptimizer-arm.cc b/src/arm/deoptimizer-arm.cc index cacaf73..aa98c8b 100644 --- a/src/arm/deoptimizer-arm.cc +++ b/src/arm/deoptimizer-arm.cc @@ -31,7 +31,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(); } diff --git a/src/arm/macro-assembler-arm.cc b/src/arm/macro-assembler-arm.cc index 4ffae76..9752622 100644 --- a/src/arm/macro-assembler-arm.cc +++ b/src/arm/macro-assembler-arm.cc @@ -910,7 +910,7 @@ void MacroAssembler::Prologue(PrologueFrameMode frame_mode) { add(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()) { diff --git a/src/arm64/assembler-arm64-inl.h b/src/arm64/assembler-arm64-inl.h index 683952e..175977c 100644 --- a/src/arm64/assembler-arm64-inl.h +++ b/src/arm64/assembler-arm64-inl.h @@ -715,7 +715,7 @@ void RelocInfo::set_target_cell(Cell* cell, WriteBarrierMode mode) { } -static const int kCodeAgeSequenceSize = 5 * kInstructionSize; +static const int kNoCodeAgeSequenceLength = 5 * kInstructionSize; static const int kCodeAgeStubEntryOffset = 3 * kInstructionSize; @@ -727,7 +727,6 @@ Handle RelocInfo::code_age_stub_handle(Assembler* origin) { Code* RelocInfo::code_age_stub() { ASSERT(rmode_ == RelocInfo::CODE_AGE_SEQUENCE); - ASSERT(!Code::IsYoungSequence(pc_)); // Read the stub entry point from the code age sequence. Address stub_entry_address = pc_ + kCodeAgeStubEntryOffset; return Code::GetCodeFromTargetAddress(Memory::Address_at(stub_entry_address)); @@ -736,7 +735,7 @@ Code* RelocInfo::code_age_stub() { void RelocInfo::set_code_age_stub(Code* stub) { ASSERT(rmode_ == RelocInfo::CODE_AGE_SEQUENCE); - ASSERT(!Code::IsYoungSequence(pc_)); + ASSERT(!Code::IsYoungSequence(stub->GetIsolate(), pc_)); // Overwrite the stub entry point in the code age sequence. This is loaded as // a literal so there is no need to call FlushICache here. Address stub_entry_address = pc_ + kCodeAgeStubEntryOffset; diff --git a/src/arm64/builtins-arm64.cc b/src/arm64/builtins-arm64.cc index 2aed6b3..fec5fef 100644 --- a/src/arm64/builtins-arm64.cc +++ b/src/arm64/builtins-arm64.cc @@ -887,7 +887,7 @@ void Builtins::Generate_MarkCodeAsExecutedOnce(MacroAssembler* masm) { } // Jump to point after the code-age stub. - __ Add(x0, x0, kCodeAgeSequenceSize); + __ Add(x0, x0, kNoCodeAgeSequenceLength); __ Br(x0); } diff --git a/src/arm64/codegen-arm64.cc b/src/arm64/codegen-arm64.cc index 7276024..ff06eda 100644 --- a/src/arm64/codegen-arm64.cc +++ b/src/arm64/codegen-arm64.cc @@ -350,14 +350,41 @@ void ElementsTransitionGenerator::GenerateDoubleToObject( } -bool Code::IsYoungSequence(byte* sequence) { - return MacroAssembler::IsYoungSequence(sequence); +CodeAgingHelper::CodeAgingHelper() { + ASSERT(young_sequence_.length() == kNoCodeAgeSequenceLength); + // The sequence of instructions that is patched out for aging code is the + // following boilerplate stack-building prologue that is found both in + // FUNCTION and OPTIMIZED_FUNCTION code: + PatchingAssembler patcher(young_sequence_.start(), + young_sequence_.length() / kInstructionSize); + // The young sequence is the frame setup code for FUNCTION code types. It is + // generated by FullCodeGenerator::Generate. + MacroAssembler::EmitFrameSetupForCodeAgePatching(&patcher); + +#ifdef DEBUG + const int length = kCodeAgeStubEntryOffset / kInstructionSize; + ASSERT(old_sequence_.length() >= kCodeAgeStubEntryOffset); + PatchingAssembler patcher_old(old_sequence_.start(), length); + MacroAssembler::EmitCodeAgeSequence(&patcher_old, NULL); +#endif +} + + +#ifdef DEBUG +bool CodeAgingHelper::IsOld(byte* candidate) const { + return memcmp(candidate, old_sequence_.start(), kCodeAgeStubEntryOffset) == 0; +} +#endif + + +bool Code::IsYoungSequence(Isolate* isolate, byte* sequence) { + return MacroAssembler::IsYoungSequence(isolate, sequence); } -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 { @@ -372,7 +399,8 @@ void Code::PatchPlatformCodeAge(Isolate* isolate, byte* sequence, Code::Age age, MarkingParity parity) { - PatchingAssembler patcher(sequence, kCodeAgeSequenceSize / kInstructionSize); + PatchingAssembler patcher(sequence, + kNoCodeAgeSequenceLength / kInstructionSize); if (age == kNoAgeCodeAge) { MacroAssembler::EmitFrameSetupForCodeAgePatching(&patcher); } else { diff --git a/src/arm64/macro-assembler-arm64.cc b/src/arm64/macro-assembler-arm64.cc index 00e6cd9..c5ce99b 100644 --- a/src/arm64/macro-assembler-arm64.cc +++ b/src/arm64/macro-assembler-arm64.cc @@ -5067,7 +5067,8 @@ void MacroAssembler::EmitFrameSetupForCodeAgePatching() { // TODO(jbramley): Other architectures use the internal memcpy to copy the // sequence. If this is a performance bottleneck, we should consider caching // the sequence and copying it in the same way. - InstructionAccurateScope scope(this, kCodeAgeSequenceSize / kInstructionSize); + InstructionAccurateScope scope(this, + kNoCodeAgeSequenceLength / kInstructionSize); ASSERT(jssp.Is(StackPointer())); EmitFrameSetupForCodeAgePatching(this); } @@ -5075,7 +5076,8 @@ void MacroAssembler::EmitFrameSetupForCodeAgePatching() { void MacroAssembler::EmitCodeAgeSequence(Code* stub) { - InstructionAccurateScope scope(this, kCodeAgeSequenceSize / kInstructionSize); + InstructionAccurateScope scope(this, + kNoCodeAgeSequenceLength / kInstructionSize); ASSERT(jssp.Is(StackPointer())); EmitCodeAgeSequence(this, stub); } @@ -5099,7 +5101,7 @@ void MacroAssembler::EmitFrameSetupForCodeAgePatching(Assembler * assm) { __ stp(fp, lr, MemOperand(jssp, 2 * kXRegSize)); __ add(fp, jssp, StandardFrameConstants::kFixedFrameSizeFromFp); - __ AssertSizeOfCodeGeneratedSince(&start, kCodeAgeSequenceSize); + __ AssertSizeOfCodeGeneratedSince(&start, kNoCodeAgeSequenceLength); } @@ -5122,48 +5124,19 @@ void MacroAssembler::EmitCodeAgeSequence(Assembler * assm, __ AssertSizeOfCodeGeneratedSince(&start, kCodeAgeStubEntryOffset); if (stub) { __ dc64(reinterpret_cast(stub->instruction_start())); - __ AssertSizeOfCodeGeneratedSince(&start, kCodeAgeSequenceSize); + __ AssertSizeOfCodeGeneratedSince(&start, kNoCodeAgeSequenceLength); } } -bool MacroAssembler::IsYoungSequence(byte* sequence) { - // Generate a young sequence to compare with. - const int length = kCodeAgeSequenceSize / kInstructionSize; - static bool initialized = false; - static byte young[kCodeAgeSequenceSize]; - if (!initialized) { - PatchingAssembler patcher(young, length); - // The young sequence is the frame setup code for FUNCTION code types. It is - // generated by FullCodeGenerator::Generate. - MacroAssembler::EmitFrameSetupForCodeAgePatching(&patcher); - initialized = true; - } - - bool is_young = (memcmp(sequence, young, kCodeAgeSequenceSize) == 0); - ASSERT(is_young || IsCodeAgeSequence(sequence)); +bool MacroAssembler::IsYoungSequence(Isolate* isolate, byte* sequence) { + bool is_young = isolate->code_aging_helper()->IsYoung(sequence); + ASSERT(is_young || + isolate->code_aging_helper()->IsOld(sequence)); return is_young; } -#ifdef DEBUG -bool MacroAssembler::IsCodeAgeSequence(byte* sequence) { - // The old sequence varies depending on the code age. However, the code up - // until kCodeAgeStubEntryOffset does not change, so we can check that part to - // get a reasonable level of verification. - const int length = kCodeAgeStubEntryOffset / kInstructionSize; - static bool initialized = false; - static byte old[kCodeAgeStubEntryOffset]; - if (!initialized) { - PatchingAssembler patcher(old, length); - MacroAssembler::EmitCodeAgeSequence(&patcher, NULL); - initialized = true; - } - return memcmp(sequence, old, kCodeAgeStubEntryOffset) == 0; -} -#endif - - void MacroAssembler::TruncatingDiv(Register result, Register dividend, int32_t divisor) { diff --git a/src/arm64/macro-assembler-arm64.h b/src/arm64/macro-assembler-arm64.h index 265a0ce..7d267a2 100644 --- a/src/arm64/macro-assembler-arm64.h +++ b/src/arm64/macro-assembler-arm64.h @@ -1987,13 +1987,7 @@ class MacroAssembler : public Assembler { // Return true if the sequence is a young sequence geneated by // EmitFrameSetupForCodeAgePatching. Otherwise, this method asserts that the // sequence is a code age sequence (emitted by EmitCodeAgeSequence). - static bool IsYoungSequence(byte* sequence); - -#ifdef DEBUG - // Return true if the sequence is a code age sequence generated by - // EmitCodeAgeSequence. - static bool IsCodeAgeSequence(byte* sequence); -#endif + static bool IsYoungSequence(Isolate* isolate, byte* sequence); // Jumps to found label if a prototype map has dictionary elements. void JumpIfDictionaryInPrototypeChain(Register object, Register scratch0, diff --git a/src/assembler.cc b/src/assembler.cc index 6d12569..3860453 100644 --- a/src/assembler.cc +++ b/src/assembler.cc @@ -724,7 +724,10 @@ RelocIterator::RelocIterator(Code* code, int mode_mask) { last_id_ = 0; last_position_ = 0; byte* sequence = code->FindCodeAgeSequence(); - if (sequence != NULL && !Code::IsYoungSequence(sequence)) { + // We get the isolate from the map, because at serialization time + // the code pointer has been cloned and isn't really in heap space. + Isolate* isolate = code->map()->GetIsolate(); + if (sequence != NULL && !Code::IsYoungSequence(isolate, sequence)) { code_age_sequence_ = sequence; } else { code_age_sequence_ = NULL; @@ -856,7 +859,7 @@ void RelocInfo::Print(Isolate* isolate, FILE* out) { #ifdef VERIFY_HEAP -void RelocInfo::Verify() { +void RelocInfo::Verify(Isolate* isolate) { switch (rmode_) { case EMBEDDED_OBJECT: Object::VerifyPointer(target_object()); @@ -873,7 +876,7 @@ void RelocInfo::Verify() { CHECK(addr != NULL); // Check that we can find the right code object. Code* code = Code::GetCodeFromTargetAddress(addr); - Object* found = code->GetIsolate()->FindCodeObject(addr); + Object* found = isolate->FindCodeObject(addr); CHECK(found->IsCode()); CHECK(code->address() == HeapObject::cast(found)->address()); break; @@ -895,7 +898,7 @@ void RelocInfo::Verify() { UNREACHABLE(); break; case CODE_AGE_SEQUENCE: - ASSERT(Code::IsYoungSequence(pc_) || code_age_stub()->IsCode()); + ASSERT(Code::IsYoungSequence(isolate, pc_) || code_age_stub()->IsCode()); break; } } diff --git a/src/assembler.h b/src/assembler.h index df1f187..c67253c 100644 --- a/src/assembler.h +++ b/src/assembler.h @@ -520,7 +520,7 @@ class RelocInfo { void Print(Isolate* isolate, FILE* out); #endif // ENABLE_DISASSEMBLER #ifdef VERIFY_HEAP - void Verify(); + void Verify(Isolate* isolate); #endif static const int kCodeTargetMask = (1 << (LAST_CODE_ENUM + 1)) - 1; diff --git a/src/codegen.h b/src/codegen.h index cf84e6a..fbaee97 100644 --- a/src/codegen.h +++ b/src/codegen.h @@ -130,6 +130,33 @@ class ElementsTransitionGenerator : public AllStatic { static const int kNumberDictionaryProbes = 4; +class CodeAgingHelper { + public: + CodeAgingHelper(); + + uint32_t young_sequence_length() const { return young_sequence_.length(); } + bool IsYoung(byte* candidate) const { + return memcmp(candidate, + young_sequence_.start(), + young_sequence_.length()) == 0; + } + void CopyYoungSequenceTo(byte* new_buffer) const { + CopyBytes(new_buffer, young_sequence_.start(), young_sequence_.length()); + } + +#ifdef DEBUG + bool IsOld(byte* candidate) const; +#endif + + protected: + const EmbeddedVector young_sequence_; +#ifdef DEBUG +#ifdef V8_TARGET_ARCH_ARM64 + const EmbeddedVector old_sequence_; +#endif +#endif +}; + } } // namespace v8::internal #endif // V8_CODEGEN_H_ diff --git a/src/ia32/codegen-ia32.cc b/src/ia32/codegen-ia32.cc index 0739cb0..19b66ae 100644 --- a/src/ia32/codegen-ia32.cc +++ b/src/ia32/codegen-ia32.cc @@ -1050,37 +1050,33 @@ void MathExpGenerator::EmitMathExp(MacroAssembler* masm, #undef __ -static byte* GetNoCodeAgeSequence(uint32_t* length) { - static bool initialized = false; - static byte sequence[kNoCodeAgeSequenceLength]; - *length = kNoCodeAgeSequenceLength; - if (!initialized) { - // The sequence of instructions that is patched out for aging code is the - // following boilerplate stack-building prologue that is found both in - // FUNCTION and OPTIMIZED_FUNCTION code: - CodePatcher patcher(sequence, kNoCodeAgeSequenceLength); - patcher.masm()->push(ebp); - patcher.masm()->mov(ebp, esp); - patcher.masm()->push(esi); - patcher.masm()->push(edi); - initialized = true; - } - return sequence; +CodeAgingHelper::CodeAgingHelper() { + ASSERT(young_sequence_.length() == kNoCodeAgeSequenceLength); + CodePatcher patcher(young_sequence_.start(), young_sequence_.length()); + patcher.masm()->push(ebp); + patcher.masm()->mov(ebp, esp); + patcher.masm()->push(esi); + patcher.masm()->push(edi); +} + + +#ifdef DEBUG +bool CodeAgingHelper::IsOld(byte* candidate) const { + return *candidate == kCallOpcode; } +#endif -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 || *sequence == kCallOpcode); +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 { @@ -1097,10 +1093,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); diff --git a/src/isolate.cc b/src/isolate.cc index b3b14a3..d93639b 100644 --- a/src/isolate.cc +++ b/src/isolate.cc @@ -133,8 +133,8 @@ Isolate::PerIsolateThreadData* per_thread = new PerIsolateThreadData(this, thread_id); thread_data_table_->Insert(per_thread); } + ASSERT(thread_data_table_->Lookup(this, thread_id) == per_thread); } - ASSERT(thread_data_table_->Lookup(this, thread_id) == per_thread); return per_thread; } @@ -1425,6 +1425,7 @@ Isolate::Isolate() logger_(NULL), stats_table_(NULL), stub_cache_(NULL), + code_aging_helper_(NULL), deoptimizer_data_(NULL), materialized_object_store_(NULL), capture_stack_trace_for_uncaught_exceptions_(false), @@ -1660,6 +1661,8 @@ Isolate::~Isolate() { delete stub_cache_; stub_cache_ = NULL; + delete code_aging_helper_; + code_aging_helper_ = NULL; delete stats_table_; stats_table_ = NULL; @@ -1834,6 +1837,8 @@ bool Isolate::Init(Deserializer* des) { #endif #endif + code_aging_helper_ = new CodeAgingHelper(); + { // NOLINT // Ensure that the thread has a valid stack guard. The v8::Locker object // will ensure this too, but we don't have to use lockers if we are only diff --git a/src/isolate.h b/src/isolate.h index 4edfd28..5b1e77f 100644 --- a/src/isolate.h +++ b/src/isolate.h @@ -54,6 +54,7 @@ class InlineRuntimeFunctionsTable; class InnerPointerToCodeCache; class MaterializedObjectStore; class NoAllocationStringAllocator; +class CodeAgingHelper; class RandomNumberGenerator; class RegExpStack; class SaveContext; @@ -836,6 +837,7 @@ class Isolate { Heap* heap() { return &heap_; } StatsTable* stats_table(); StubCache* stub_cache() { return stub_cache_; } + CodeAgingHelper* code_aging_helper() { return code_aging_helper_; } DeoptimizerData* deoptimizer_data() { return deoptimizer_data_; } ThreadLocalTop* thread_local_top() { return &thread_local_top_; } MaterializedObjectStore* materialized_object_store() { @@ -1197,6 +1199,7 @@ class Isolate { StackGuard stack_guard_; StatsTable* stats_table_; StubCache* stub_cache_; + CodeAgingHelper* code_aging_helper_; DeoptimizerData* deoptimizer_data_; MaterializedObjectStore* materialized_object_store_; ThreadLocalTop thread_local_top_; diff --git a/src/objects-debug.cc b/src/objects-debug.cc index df63924..7b7c9c9 100644 --- a/src/objects-debug.cc +++ b/src/objects-debug.cc @@ -627,8 +627,9 @@ void Code::CodeVerify() { kCodeAlignment)); relocation_info()->ObjectVerify(); Address last_gc_pc = NULL; + Isolate* isolate = GetIsolate(); for (RelocIterator it(this); !it.done(); it.next()) { - it.rinfo()->Verify(); + it.rinfo()->Verify(isolate); // Ensure that GC will not iterate twice over the same pointer. if (RelocInfo::IsGCRelocMode(it.rinfo()->rmode())) { CHECK(it.rinfo()->pc() != last_gc_pc); diff --git a/src/objects.cc b/src/objects.cc index 01de39f..956e46f 100644 --- a/src/objects.cc +++ b/src/objects.cc @@ -11291,10 +11291,11 @@ void Code::MakeOlder(MarkingParity current_parity) { if (sequence != NULL) { Age age; MarkingParity code_parity; - GetCodeAgeAndParity(sequence, &age, &code_parity); + Isolate* isolate = GetIsolate(); + GetCodeAgeAndParity(isolate, sequence, &age, &code_parity); age = EffectiveAge(age); if (age != kLastCodeAge && code_parity != current_parity) { - PatchPlatformCodeAge(GetIsolate(), + PatchPlatformCodeAge(isolate, sequence, static_cast(age + 1), current_parity); @@ -11330,7 +11331,7 @@ Code::Age Code::GetRawAge() { } Age age; MarkingParity parity; - GetCodeAgeAndParity(sequence, &age, &parity); + GetCodeAgeAndParity(GetIsolate(), sequence, &age, &parity); return age; } diff --git a/src/objects.h b/src/objects.h index 5086285..12f2ee0 100644 --- a/src/objects.h +++ b/src/objects.h @@ -5625,7 +5625,7 @@ class Code: public HeapObject { static void MakeCodeAgeSequenceYoung(byte* sequence, Isolate* isolate); static void MarkCodeAsExecuted(byte* sequence, Isolate* isolate); void MakeOlder(MarkingParity); - static bool IsYoungSequence(byte* sequence); + static bool IsYoungSequence(Isolate* isolate, byte* sequence); bool IsOld(); Age GetAge(); // Gets the raw code age, including psuedo code-age values such as @@ -5787,7 +5787,7 @@ class Code: public HeapObject { byte* FindCodeAgeSequence(); static void GetCodeAgeAndParity(Code* code, Age* age, MarkingParity* parity); - static void GetCodeAgeAndParity(byte* sequence, Age* age, + static void GetCodeAgeAndParity(Isolate* isolate, byte* sequence, Age* age, MarkingParity* parity); static Code* GetCodeAgeStub(Isolate* isolate, Age age, MarkingParity parity); diff --git a/src/x64/codegen-x64.cc b/src/x64/codegen-x64.cc index bc675a1..9903017 100644 --- a/src/x64/codegen-x64.cc +++ b/src/x64/codegen-x64.cc @@ -616,37 +616,36 @@ void MathExpGenerator::EmitMathExp(MacroAssembler* masm, #undef __ -static byte* GetNoCodeAgeSequence(uint32_t* length) { - static bool initialized = false; - static byte sequence[kNoCodeAgeSequenceLength]; - *length = kNoCodeAgeSequenceLength; - if (!initialized) { - // The sequence of instructions that is patched out for aging code is the - // following boilerplate stack-building prologue that is found both in - // FUNCTION and OPTIMIZED_FUNCTION code: - CodePatcher patcher(sequence, kNoCodeAgeSequenceLength); - patcher.masm()->pushq(rbp); - patcher.masm()->movp(rbp, rsp); - patcher.masm()->Push(rsi); - patcher.masm()->Push(rdi); - initialized = true; - } - return sequence; +CodeAgingHelper::CodeAgingHelper() { + ASSERT(young_sequence_.length() == kNoCodeAgeSequenceLength); + // The sequence of instructions that is patched out for aging code is the + // following boilerplate stack-building prologue that is found both in + // FUNCTION and OPTIMIZED_FUNCTION code: + CodePatcher patcher(young_sequence_.start(), young_sequence_.length()); + patcher.masm()->pushq(rbp); + patcher.masm()->movp(rbp, rsp); + patcher.masm()->Push(rsi); + patcher.masm()->Push(rdi); } -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 || *sequence == kCallOpcode); +#ifdef DEBUG +bool CodeAgingHelper::IsOld(byte* candidate) const { + return *candidate == kCallOpcode; +} +#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 { @@ -663,10 +662,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); diff --git a/test/cctest/cctest.status b/test/cctest/cctest.status index 98b7294..2aaaf74 100644 --- a/test/cctest/cctest.status +++ b/test/cctest/cctest.status @@ -30,9 +30,6 @@ # All tests prefixed with 'Bug' are expected to fail. 'test-api/Bug*': [FAIL], - # BUG(3303). Crashes on mac builds, known race condition. - 'test-lockers/MultithreadedParallelIsolates': [SKIP], - ############################################################################## # BUG(382): Weird test. Can't guarantee that it never times out. 'test-api/ApplyInterruption': [PASS, TIMEOUT], -- 2.7.4