Commit 3ba67835 authored by chunyang.dai's avatar chunyang.dai Committed by Commit bot

X87: New hydrogen instruction to reduce cost of growing an array on keyed stores.

port 3bce9c3a (r28359).

original commit message:

    HMaybeGrowElements moves the situation where you actually have to grow
    into deferred code. This means crankshaft doesn't have to spill registers
    just to make the bounds comparison to see if it'll need to grow or not.

    It makes the growing case a bit more expensive, but reduces the cost of
    the general case.

BUG=

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

Cr-Commit-Position: refs/heads/master@{#28388}
parent fecaed53
......@@ -58,7 +58,6 @@ const Register MathPowIntegerDescriptor::exponent() {
const Register GrowArrayElementsDescriptor::ObjectRegister() { return eax; }
const Register GrowArrayElementsDescriptor::KeyRegister() { return ebx; }
const Register GrowArrayElementsDescriptor::CapacityRegister() { return ecx; }
void FastNewClosureDescriptor::Initialize(CallInterfaceDescriptorData* data) {
......
......@@ -4815,6 +4815,97 @@ void LCodeGen::DoTrapAllocationMemento(LTrapAllocationMemento* instr) {
}
void LCodeGen::DoMaybeGrowElements(LMaybeGrowElements* instr) {
class DeferredMaybeGrowElements final : public LDeferredCode {
public:
DeferredMaybeGrowElements(LCodeGen* codegen,
LMaybeGrowElements* instr,
const X87Stack& x87_stack)
: LDeferredCode(codegen, x87_stack), instr_(instr) {}
void Generate() override { codegen()->DoDeferredMaybeGrowElements(instr_); }
LInstruction* instr() override { return instr_; }
private:
LMaybeGrowElements* instr_;
};
Register result = eax;
DeferredMaybeGrowElements* deferred =
new (zone()) DeferredMaybeGrowElements(this, instr, x87_stack_);
LOperand* key = instr->key();
LOperand* current_capacity = instr->current_capacity();
DCHECK(instr->hydrogen()->key()->representation().IsInteger32());
DCHECK(instr->hydrogen()->current_capacity()->representation().IsInteger32());
DCHECK(key->IsConstantOperand() || key->IsRegister());
DCHECK(current_capacity->IsConstantOperand() ||
current_capacity->IsRegister());
if (key->IsConstantOperand() && current_capacity->IsConstantOperand()) {
int32_t constant_key = ToInteger32(LConstantOperand::cast(key));
int32_t constant_capacity =
ToInteger32(LConstantOperand::cast(current_capacity));
if (constant_key >= constant_capacity) {
// Deferred case.
__ jmp(deferred->entry());
}
} else if (key->IsConstantOperand()) {
int32_t constant_key = ToInteger32(LConstantOperand::cast(key));
__ cmp(ToOperand(current_capacity), Immediate(constant_key));
__ j(less_equal, deferred->entry());
} else if (current_capacity->IsConstantOperand()) {
int32_t constant_capacity =
ToInteger32(LConstantOperand::cast(current_capacity));
__ cmp(ToRegister(key), Immediate(constant_capacity));
__ j(greater_equal, deferred->entry());
} else {
__ cmp(ToRegister(key), ToRegister(current_capacity));
__ j(greater_equal, deferred->entry());
}
__ mov(result, ToOperand(instr->elements()));
__ bind(deferred->exit());
}
void LCodeGen::DoDeferredMaybeGrowElements(LMaybeGrowElements* instr) {
// TODO(3095996): Get rid of this. For now, we need to make the
// result register contain a valid pointer because it is already
// contained in the register pointer map.
Register result = eax;
__ Move(result, Immediate(0));
// We have to call a stub.
{
PushSafepointRegistersScope scope(this);
if (instr->object()->IsRegister()) {
__ Move(result, ToRegister(instr->object()));
} else {
__ mov(result, ToOperand(instr->object()));
}
LOperand* key = instr->key();
if (key->IsConstantOperand()) {
__ mov(ebx, ToImmediate(key, Representation::Smi()));
} else {
__ Move(ebx, ToRegister(key));
__ SmiTag(ebx);
}
GrowArrayElementsStub stub(isolate(), instr->hydrogen()->is_js_array(),
instr->hydrogen()->kind());
__ CallStub(&stub);
RecordSafepointWithLazyDeopt(
instr, RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS);
__ StoreToSafepointRegisterSlot(result, result);
}
// Deopt on smi, which means the elements array changed to dictionary mode.
__ test(result, Immediate(kSmiTagMask));
DeoptimizeIf(equal, instr, Deoptimizer::kSmi);
}
void LCodeGen::DoTransitionElementsKind(LTransitionElementsKind* instr) {
Register object_reg = ToRegister(instr->object());
......
......@@ -135,6 +135,7 @@ class LCodeGen: public LCodeGenBase {
void DoDeferredTaggedToI(LTaggedToI* instr, Label* done);
void DoDeferredMathAbsTaggedHeapNumber(LMathAbs* instr);
void DoDeferredStackCheck(LStackCheck* instr);
void DoDeferredMaybeGrowElements(LMaybeGrowElements* instr);
void DoDeferredStringCharCodeAt(LStringCharCodeAt* instr);
void DoDeferredStringCharFromCode(LStringCharFromCode* instr);
void DoDeferredAllocate(LAllocate* instr);
......
......@@ -2397,6 +2397,21 @@ LInstruction* LChunkBuilder::DoTrapAllocationMemento(
}
LInstruction* LChunkBuilder::DoMaybeGrowElements(HMaybeGrowElements* instr) {
info()->MarkAsDeferredCalling();
LOperand* context = UseFixed(instr->context(), esi);
LOperand* object = Use(instr->object());
LOperand* elements = Use(instr->elements());
LOperand* key = UseRegisterOrConstant(instr->key());
LOperand* current_capacity = UseRegisterOrConstant(instr->current_capacity());
LMaybeGrowElements* result = new (zone())
LMaybeGrowElements(context, object, elements, key, current_capacity);
DefineFixed(result, eax);
return AssignPointerMap(AssignEnvironment(result));
}
LInstruction* LChunkBuilder::DoStoreNamedField(HStoreNamedField* instr) {
bool is_in_object = instr->access().IsInobject();
bool is_external_location = instr->access().IsExternalMemory() &&
......
......@@ -122,6 +122,7 @@ class LCodeGen;
V(MathPowHalf) \
V(MathRound) \
V(MathSqrt) \
V(MaybeGrowElements) \
V(ModByConstI) \
V(ModByPowerOf2I) \
V(ModI) \
......@@ -2325,6 +2326,28 @@ class LTrapAllocationMemento final : public LTemplateInstruction<0, 1, 1> {
};
class LMaybeGrowElements final : public LTemplateInstruction<1, 5, 0> {
public:
LMaybeGrowElements(LOperand* context, LOperand* object, LOperand* elements,
LOperand* key, LOperand* current_capacity) {
inputs_[0] = context;
inputs_[1] = object;
inputs_[2] = elements;
inputs_[3] = key;
inputs_[4] = current_capacity;
}
LOperand* context() { return inputs_[0]; }
LOperand* object() { return inputs_[1]; }
LOperand* elements() { return inputs_[2]; }
LOperand* key() { return inputs_[3]; }
LOperand* current_capacity() { return inputs_[4]; }
DECLARE_HYDROGEN_ACCESSOR(MaybeGrowElements)
DECLARE_CONCRETE_INSTRUCTION(MaybeGrowElements, "maybe-grow-elements")
};
class LStringAdd final : public LTemplateInstruction<1, 3, 0> {
public:
LStringAdd(LOperand* context, LOperand* left, LOperand* right) {
......
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