Commit f1478bd1 authored by zhengxing.li's avatar zhengxing.li Committed by Commit bot

X87: [turbofan] Avoid unnecessary write barriers and improve code generation.

   port 1e277012 (r31914)

   original commit message:
   Avoid write barriers when storing values in the root set, and use
   cheaper write barriers for storing maps or tagged pointers. Also
   improve the generated code for write barriers, utilizing the out
   of line code mechanism that is available to TurboFan backends,
   which moves the unlikely case out of the hot path.

BUG=

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

Cr-Commit-Position: refs/heads/master@{#31935}
parent e9528b83
...@@ -218,6 +218,46 @@ class OutOfLineTruncateDoubleToI final : public OutOfLineCode { ...@@ -218,6 +218,46 @@ class OutOfLineTruncateDoubleToI final : public OutOfLineCode {
X87Register const input_; X87Register const input_;
}; };
class OutOfLineRecordWrite final : public OutOfLineCode {
public:
OutOfLineRecordWrite(CodeGenerator* gen, Register object, Operand operand,
Register value, Register scratch0, Register scratch1,
RecordWriteMode mode)
: OutOfLineCode(gen),
object_(object),
operand_(operand),
value_(value),
scratch0_(scratch0),
scratch1_(scratch1),
mode_(mode) {}
void Generate() final {
if (mode_ > RecordWriteMode::kValueIsPointer) {
__ JumpIfSmi(value_, exit());
}
if (mode_ > RecordWriteMode::kValueIsMap) {
__ CheckPageFlag(value_, scratch0_,
MemoryChunk::kPointersToHereAreInterestingMask, zero,
exit());
}
SaveFPRegsMode const save_fp_mode =
frame()->DidAllocateDoubleRegisters() ? kSaveFPRegs : kDontSaveFPRegs;
RecordWriteStub stub(isolate(), object_, scratch0_, scratch1_,
EMIT_REMEMBERED_SET, save_fp_mode);
__ lea(scratch1_, operand_);
__ CallStub(&stub);
}
private:
Register const object_;
Operand const operand_;
Register const value_;
Register const scratch0_;
Register const scratch1_;
RecordWriteMode const mode_;
};
} // namespace } // namespace
...@@ -456,6 +496,24 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) { ...@@ -456,6 +496,24 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
} }
break; break;
} }
case kArchStoreWithWriteBarrier: {
RecordWriteMode mode =
static_cast<RecordWriteMode>(MiscField::decode(instr->opcode()));
Register object = i.InputRegister(0);
size_t index = 0;
Operand operand = i.MemoryOperand(&index);
Register value = i.InputRegister(index);
Register scratch0 = i.TempRegister(0);
Register scratch1 = i.TempRegister(1);
auto ool = new (zone()) OutOfLineRecordWrite(this, object, operand, value,
scratch0, scratch1, mode);
__ mov(operand, value);
__ CheckPageFlag(object, scratch0,
MemoryChunk::kPointersFromHereAreInterestingMask,
not_zero, ool->entry());
__ bind(ool->exit());
break;
}
case kX87Add: case kX87Add:
if (HasImmediateInput(instr, 1)) { if (HasImmediateInput(instr, 1)) {
__ add(i.InputOperand(0), i.InputImmediate(1)); __ add(i.InputOperand(0), i.InputImmediate(1));
...@@ -1216,24 +1274,6 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) { ...@@ -1216,24 +1274,6 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
UNREACHABLE(); UNREACHABLE();
} }
break; break;
case kX87StoreWriteBarrier: {
Register object = i.InputRegister(0);
Register value = i.InputRegister(2);
SaveFPRegsMode mode =
frame()->DidAllocateDoubleRegisters() ? kSaveFPRegs : kDontSaveFPRegs;
if (HasImmediateInput(instr, 1)) {
int index = i.InputInt32(1);
Register scratch = i.TempRegister(1);
__ mov(Operand(object, index), value);
__ RecordWriteContextSlot(object, index, value, scratch, mode);
} else {
Register index = i.InputRegister(1);
__ mov(Operand(object, index, times_1, 0), value);
__ lea(index, Operand(object, index, times_1, 0));
__ RecordWrite(object, index, value, mode);
}
break;
}
case kCheckedLoadInt8: case kCheckedLoadInt8:
ASSEMBLE_CHECKED_LOAD_INTEGER(movsx_b); ASSEMBLE_CHECKED_LOAD_INTEGER(movsx_b);
break; break;
......
...@@ -81,7 +81,6 @@ namespace compiler { ...@@ -81,7 +81,6 @@ namespace compiler {
V(X87PushFloat64) \ V(X87PushFloat64) \
V(X87PushFloat32) \ V(X87PushFloat32) \
V(X87Poke) \ V(X87Poke) \
V(X87StoreWriteBarrier) \
V(X87StackCheck) V(X87StackCheck)
......
...@@ -176,66 +176,89 @@ void InstructionSelector::VisitStore(Node* node) { ...@@ -176,66 +176,89 @@ void InstructionSelector::VisitStore(Node* node) {
Node* value = node->InputAt(2); Node* value = node->InputAt(2);
StoreRepresentation store_rep = OpParameter<StoreRepresentation>(node); StoreRepresentation store_rep = OpParameter<StoreRepresentation>(node);
WriteBarrierKind write_barrier_kind = store_rep.write_barrier_kind();
MachineType rep = RepresentationOf(store_rep.machine_type()); MachineType rep = RepresentationOf(store_rep.machine_type());
if (store_rep.write_barrier_kind() == kFullWriteBarrier) {
if (write_barrier_kind != kNoWriteBarrier) {
DCHECK_EQ(kRepTagged, rep); DCHECK_EQ(kRepTagged, rep);
// TODO(dcarney): refactor RecordWrite function to take temp registers AddressingMode addressing_mode;
// and pass them here instead of using fixed regs InstructionOperand inputs[3];
size_t input_count = 0;
inputs[input_count++] = g.UseUniqueRegister(base);
if (g.CanBeImmediate(index)) { if (g.CanBeImmediate(index)) {
InstructionOperand temps[] = {g.TempRegister(ecx), g.TempRegister()}; inputs[input_count++] = g.UseImmediate(index);
Emit(kX87StoreWriteBarrier, g.NoOutput(), g.UseFixed(base, ebx), addressing_mode = kMode_MRI;
g.UseImmediate(index), g.UseFixed(value, ecx), arraysize(temps),
temps);
} else { } else {
InstructionOperand temps[] = {g.TempRegister(ecx), g.TempRegister(edx)}; inputs[input_count++] = g.UseUniqueRegister(index);
Emit(kX87StoreWriteBarrier, g.NoOutput(), g.UseFixed(base, ebx), addressing_mode = kMode_MR1;
g.UseFixed(index, ecx), g.UseFixed(value, edx), arraysize(temps), }
temps); inputs[input_count++] = (write_barrier_kind == kMapWriteBarrier)
? g.UseRegister(value)
: g.UseUniqueRegister(value);
RecordWriteMode record_write_mode = RecordWriteMode::kValueIsAny;
switch (write_barrier_kind) {
case kNoWriteBarrier:
UNREACHABLE();
break;
case kMapWriteBarrier:
record_write_mode = RecordWriteMode::kValueIsMap;
break;
case kPointerWriteBarrier:
record_write_mode = RecordWriteMode::kValueIsPointer;
break;
case kFullWriteBarrier:
record_write_mode = RecordWriteMode::kValueIsAny;
break;
}
InstructionOperand temps[] = {g.TempRegister(), g.TempRegister()};
size_t const temp_count = arraysize(temps);
InstructionCode code = kArchStoreWithWriteBarrier;
code |= AddressingModeField::encode(addressing_mode);
code |= MiscField::encode(static_cast<int>(record_write_mode));
Emit(code, 0, nullptr, input_count, inputs, temp_count, temps);
} else {
ArchOpcode opcode;
switch (rep) {
case kRepFloat32:
opcode = kX87Movss;
break;
case kRepFloat64:
opcode = kX87Movsd;
break;
case kRepBit: // Fall through.
case kRepWord8:
opcode = kX87Movb;
break;
case kRepWord16:
opcode = kX87Movw;
break;
case kRepTagged: // Fall through.
case kRepWord32:
opcode = kX87Movl;
break;
default:
UNREACHABLE();
return;
} }
return;
}
DCHECK_EQ(kNoWriteBarrier, store_rep.write_barrier_kind());
ArchOpcode opcode; InstructionOperand val;
switch (rep) { if (g.CanBeImmediate(value)) {
case kRepFloat32: val = g.UseImmediate(value);
opcode = kX87Movss; } else if (rep == kRepWord8 || rep == kRepBit) {
break; val = g.UseByteRegister(value);
case kRepFloat64: } else {
opcode = kX87Movsd; val = g.UseRegister(value);
break; }
case kRepBit: // Fall through.
case kRepWord8:
opcode = kX87Movb;
break;
case kRepWord16:
opcode = kX87Movw;
break;
case kRepTagged: // Fall through.
case kRepWord32:
opcode = kX87Movl;
break;
default:
UNREACHABLE();
return;
}
InstructionOperand val; InstructionOperand inputs[4];
if (g.CanBeImmediate(value)) { size_t input_count = 0;
val = g.UseImmediate(value); AddressingMode addressing_mode =
} else if (rep == kRepWord8 || rep == kRepBit) { g.GetEffectiveAddressMemoryOperand(node, inputs, &input_count);
val = g.UseByteRegister(value); InstructionCode code =
} else { opcode | AddressingModeField::encode(addressing_mode);
val = g.UseRegister(value); inputs[input_count++] = val;
Emit(code, 0, static_cast<InstructionOperand*>(NULL), input_count, inputs);
} }
InstructionOperand inputs[4];
size_t input_count = 0;
AddressingMode mode =
g.GetEffectiveAddressMemoryOperand(node, inputs, &input_count);
InstructionCode code = opcode | AddressingModeField::encode(mode);
inputs[input_count++] = val;
Emit(code, 0, static_cast<InstructionOperand*>(NULL), input_count, inputs);
} }
......
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