From acab11e0cb719e7ff7dc3f5b73782b332860d338 Mon Sep 17 00:00:00 2001 From: "zhengxing.li" Date: Thu, 4 Feb 2016 23:05:40 -0800 Subject: [PATCH] X87: Write barrier for storing a code entry, and usage in CompileLazy builtin. port 477e133698aa2f0a40643f316c31d17347be2de7 (r33718) original commit message: BUG= Review URL: https://codereview.chromium.org/1673533002 Cr-Commit-Position: refs/heads/master@{#33758} --- src/x87/code-stubs-x87.h | 16 +---- src/x87/macro-assembler-x87.cc | 112 +++++++++++++++++++++++++++++++++ src/x87/macro-assembler-x87.h | 15 +++++ 3 files changed, 129 insertions(+), 14 deletions(-) diff --git a/src/x87/code-stubs-x87.h b/src/x87/code-stubs-x87.h index a6a2a13057..39a4603626 100644 --- a/src/x87/code-stubs-x87.h +++ b/src/x87/code-stubs-x87.h @@ -271,24 +271,12 @@ class RecordWriteStub: public PlatformCodeStub { // registers are eax, ecx and edx. The three scratch registers (incl. ecx) // will be restored by other means so we don't bother pushing them here. void SaveCallerSaveRegisters(MacroAssembler* masm, SaveFPRegsMode mode) { - if (!scratch0_.is(eax) && !scratch1_.is(eax)) masm->push(eax); - if (!scratch0_.is(edx) && !scratch1_.is(edx)) masm->push(edx); - if (mode == kSaveFPRegs) { - // Save FPU state in m108byte. - masm->sub(esp, Immediate(108)); - masm->fnsave(Operand(esp, 0)); - } + masm->PushCallerSaved(mode, ecx, scratch0_, scratch1_); } inline void RestoreCallerSaveRegisters(MacroAssembler* masm, SaveFPRegsMode mode) { - if (mode == kSaveFPRegs) { - // Restore FPU state in m108byte. - masm->frstor(Operand(esp, 0)); - masm->add(esp, Immediate(108)); - } - if (!scratch0_.is(edx) && !scratch1_.is(edx)) masm->pop(edx); - if (!scratch0_.is(eax) && !scratch1_.is(eax)) masm->pop(eax); + masm->PopCallerSaved(mode, ecx, scratch0_, scratch1_); } inline Register object() { return object_; } diff --git a/src/x87/macro-assembler-x87.cc b/src/x87/macro-assembler-x87.cc index 706d151e5a..bb8654a4c3 100644 --- a/src/x87/macro-assembler-x87.cc +++ b/src/x87/macro-assembler-x87.cc @@ -120,6 +120,49 @@ void MacroAssembler::PushRoot(Heap::RootListIndex index) { Push(isolate()->heap()->root_handle(index)); } +#define REG(Name) \ + { Register::kCode_##Name } + +static const Register saved_regs[] = {REG(eax), REG(ecx), REG(edx)}; + +#undef REG + +static const int kNumberOfSavedRegs = sizeof(saved_regs) / sizeof(Register); + +void MacroAssembler::PushCallerSaved(SaveFPRegsMode fp_mode, + Register exclusion1, Register exclusion2, + Register exclusion3) { + // We don't allow a GC during a store buffer overflow so there is no need to + // store the registers in any particular way, but we do have to store and + // restore them. + for (int i = 0; i < kNumberOfSavedRegs; i++) { + Register reg = saved_regs[i]; + if (!reg.is(exclusion1) && !reg.is(exclusion2) && !reg.is(exclusion3)) { + push(reg); + } + } + if (fp_mode == kSaveFPRegs) { + // Save FPU state in m108byte. + sub(esp, Immediate(108)); + fnsave(Operand(esp, 0)); + } +} + +void MacroAssembler::PopCallerSaved(SaveFPRegsMode fp_mode, Register exclusion1, + Register exclusion2, Register exclusion3) { + if (fp_mode == kSaveFPRegs) { + // Restore FPU state in m108byte. + frstor(Operand(esp, 0)); + add(esp, Immediate(108)); + } + + for (int i = kNumberOfSavedRegs - 1; i >= 0; i--) { + Register reg = saved_regs[i]; + if (!reg.is(exclusion1) && !reg.is(exclusion2) && !reg.is(exclusion3)) { + pop(reg); + } + } +} void MacroAssembler::InNewSpace( Register object, @@ -492,6 +535,75 @@ void MacroAssembler::RecordWrite( } } +void MacroAssembler::RecordWriteCodeEntryField(Register js_function, + Register code_entry, + Register scratch) { + const int offset = JSFunction::kCodeEntryOffset; + + // Since a code entry (value) is always in old space, we don't need to update + // remembered set. If incremental marking is off, there is nothing for us to + // do. + if (!FLAG_incremental_marking) return; + + DCHECK(!js_function.is(code_entry)); + DCHECK(!js_function.is(scratch)); + DCHECK(!code_entry.is(scratch)); + AssertNotSmi(js_function); + + if (emit_debug_code()) { + Label ok; + lea(scratch, FieldOperand(js_function, offset)); + cmp(code_entry, Operand(scratch, 0)); + j(equal, &ok, Label::kNear); + int3(); + bind(&ok); + } + + // First, check if a write barrier is even needed. The tests below + // catch stores of Smis and stores into young gen. + Label done; + + CheckPageFlag(code_entry, scratch, + MemoryChunk::kPointersToHereAreInterestingMask, zero, &done, + Label::kNear); + CheckPageFlag(js_function, scratch, + MemoryChunk::kPointersFromHereAreInterestingMask, zero, &done, + Label::kNear); + + // Save input registers. + push(js_function); + push(code_entry); + + const Register dst = scratch; + lea(dst, FieldOperand(js_function, offset)); + + // Save caller-saved registers. + PushCallerSaved(kDontSaveFPRegs, js_function, code_entry); + + int argument_count = 3; + PrepareCallCFunction(argument_count, code_entry); + mov(Operand(esp, 0 * kPointerSize), js_function); + mov(Operand(esp, 1 * kPointerSize), dst); // Slot. + mov(Operand(esp, 2 * kPointerSize), + Immediate(ExternalReference::isolate_address(isolate()))); + + { + AllowExternalCallThatCantCauseGC scope(this); + CallCFunction( + ExternalReference::incremental_marking_record_write_code_entry_function( + isolate()), + argument_count); + } + + // Restore caller-saved registers. + PopCallerSaved(kDontSaveFPRegs, js_function, code_entry); + + // Restore input registers. + pop(code_entry); + pop(js_function); + + bind(&done); +} void MacroAssembler::DebugBreak() { Move(eax, Immediate(0)); diff --git a/src/x87/macro-assembler-x87.h b/src/x87/macro-assembler-x87.h index efab3f7890..a51e951b0a 100644 --- a/src/x87/macro-assembler-x87.h +++ b/src/x87/macro-assembler-x87.h @@ -107,6 +107,16 @@ class MacroAssembler: public Assembler { j(not_equal, if_not_equal, if_not_equal_distance); } + // These functions do not arrange the registers in any particular order so + // they are not useful for calls that can cause a GC. The caller can + // exclude up to 3 registers that do not need to be saved and restored. + void PushCallerSaved(SaveFPRegsMode fp_mode, Register exclusion1 = no_reg, + Register exclusion2 = no_reg, + Register exclusion3 = no_reg); + void PopCallerSaved(SaveFPRegsMode fp_mode, Register exclusion1 = no_reg, + Register exclusion2 = no_reg, + Register exclusion3 = no_reg); + // --------------------------------------------------------------------------- // GC Support enum RememberedSetFinalAction { kReturnAtEnd, kFallThroughAtEnd }; @@ -207,6 +217,11 @@ class MacroAssembler: public Assembler { PointersToHereCheck pointers_to_here_check_for_value = kPointersToHereMaybeInteresting); + // Notify the garbage collector that we wrote a code entry into a + // JSFunction. Only scratch is clobbered by the operation. + void RecordWriteCodeEntryField(Register js_function, Register code_entry, + Register scratch); + // For page containing |object| mark the region covering the object's map // dirty. |object| is the object being stored into, |map| is the Map object // that was stored.