X87: Write barrier for storing a code entry, and usage in CompileLazy builtin.

port 477e133698 (r33718)

  original commit message:

BUG=

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

Cr-Commit-Position: refs/heads/master@{#33758}
This commit is contained in:
zhengxing.li 2016-02-04 23:05:40 -08:00 committed by Commit bot
parent f060922369
commit acab11e0cb
3 changed files with 129 additions and 14 deletions

View File

@ -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_; }

View File

@ -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));

View File

@ -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.