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:
parent
f060922369
commit
acab11e0cb
@ -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_; }
|
||||
|
@ -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));
|
||||
|
@ -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.
|
||||
|
Loading…
Reference in New Issue
Block a user