[ic] Port {Load,Store}IC_Normal to TF

BUG=v8:5269

Review-Url: https://codereview.chromium.org/2622003004
Cr-Commit-Position: refs/heads/master@{#42261}
This commit is contained in:
jkummerow 2017-01-12 02:53:09 -08:00 committed by Commit bot
parent 3d9e2ea32d
commit d23e7d2f81
30 changed files with 71 additions and 2218 deletions

View File

@ -2650,84 +2650,6 @@ void NameDictionaryLookupStub::GenerateNegativeLookup(MacroAssembler* masm,
__ b(ne, miss);
}
// Probe the name dictionary in the |elements| register. Jump to the
// |done| label if a property with the given name is found. Jump to
// the |miss| label otherwise.
// If lookup was successful |scratch2| will be equal to elements + 4 * index.
void NameDictionaryLookupStub::GeneratePositiveLookup(MacroAssembler* masm,
Label* miss,
Label* done,
Register elements,
Register name,
Register scratch1,
Register scratch2) {
DCHECK(!elements.is(scratch1));
DCHECK(!elements.is(scratch2));
DCHECK(!name.is(scratch1));
DCHECK(!name.is(scratch2));
__ AssertName(name);
// Compute the capacity mask.
__ ldr(scratch1, FieldMemOperand(elements, kCapacityOffset));
__ SmiUntag(scratch1);
__ sub(scratch1, scratch1, Operand(1));
// Generate an unrolled loop that performs a few probes before
// giving up. Measurements done on Gmail indicate that 2 probes
// cover ~93% of loads from dictionaries.
for (int i = 0; i < kInlinedProbes; i++) {
// Compute the masked index: (hash + i + i * i) & mask.
__ ldr(scratch2, FieldMemOperand(name, Name::kHashFieldOffset));
if (i > 0) {
// Add the probe offset (i + i * i) left shifted to avoid right shifting
// the hash in a separate instruction. The value hash + i + i * i is right
// shifted in the following and instruction.
DCHECK(NameDictionary::GetProbeOffset(i) <
1 << (32 - Name::kHashFieldOffset));
__ add(scratch2, scratch2, Operand(
NameDictionary::GetProbeOffset(i) << Name::kHashShift));
}
__ and_(scratch2, scratch1, Operand(scratch2, LSR, Name::kHashShift));
// Scale the index by multiplying by the entry size.
STATIC_ASSERT(NameDictionary::kEntrySize == 3);
// scratch2 = scratch2 * 3.
__ add(scratch2, scratch2, Operand(scratch2, LSL, 1));
// Check if the key is identical to the name.
__ add(scratch2, elements, Operand(scratch2, LSL, 2));
__ ldr(ip, FieldMemOperand(scratch2, kElementsStartOffset));
__ cmp(name, Operand(ip));
__ b(eq, done);
}
const int spill_mask =
(lr.bit() | r6.bit() | r5.bit() | r4.bit() |
r3.bit() | r2.bit() | r1.bit() | r0.bit()) &
~(scratch1.bit() | scratch2.bit());
__ stm(db_w, sp, spill_mask);
if (name.is(r0)) {
DCHECK(!elements.is(r1));
__ Move(r1, name);
__ Move(r0, elements);
} else {
__ Move(r0, elements);
__ Move(r1, name);
}
NameDictionaryLookupStub stub(masm->isolate(), POSITIVE_LOOKUP);
__ CallStub(&stub);
__ cmp(r0, Operand::Zero());
__ mov(scratch2, Operand(r2));
__ ldm(ia_w, sp, spill_mask);
__ b(ne, done);
__ b(eq, miss);
}
void NameDictionaryLookupStub::Generate(MacroAssembler* masm) {
// This stub overrides SometimesSetsUpAFrame() to return false. That means
// we cannot call anything that could cause a GC from this stub.

View File

@ -269,14 +269,6 @@ class NameDictionaryLookupStub: public PlatformCodeStub {
Handle<Name> name,
Register scratch0);
static void GeneratePositiveLookup(MacroAssembler* masm,
Label* miss,
Label* done,
Register elements,
Register name,
Register r0,
Register r1);
bool SometimesSetsUpAFrame() override { return false; }
private:

View File

@ -3081,91 +3081,6 @@ void DirectCEntryStub::GenerateCall(MacroAssembler* masm,
__ Blr(lr);
}
// Probe the name dictionary in the 'elements' register.
// Jump to the 'done' label if a property with the given name is found.
// Jump to the 'miss' label otherwise.
//
// If lookup was successful 'scratch2' will be equal to elements + 4 * index.
// 'elements' and 'name' registers are preserved on miss.
void NameDictionaryLookupStub::GeneratePositiveLookup(
MacroAssembler* masm,
Label* miss,
Label* done,
Register elements,
Register name,
Register scratch1,
Register scratch2) {
DCHECK(!AreAliased(elements, name, scratch1, scratch2));
// Assert that name contains a string.
__ AssertName(name);
// Compute the capacity mask.
__ Ldrsw(scratch1, UntagSmiFieldMemOperand(elements, kCapacityOffset));
__ Sub(scratch1, scratch1, 1);
// Generate an unrolled loop that performs a few probes before giving up.
for (int i = 0; i < kInlinedProbes; i++) {
// Compute the masked index: (hash + i + i * i) & mask.
__ Ldr(scratch2, FieldMemOperand(name, Name::kHashFieldOffset));
if (i > 0) {
// Add the probe offset (i + i * i) left shifted to avoid right shifting
// the hash in a separate instruction. The value hash + i + i * i is right
// shifted in the following and instruction.
DCHECK(NameDictionary::GetProbeOffset(i) <
1 << (32 - Name::kHashFieldOffset));
__ Add(scratch2, scratch2, Operand(
NameDictionary::GetProbeOffset(i) << Name::kHashShift));
}
__ And(scratch2, scratch1, Operand(scratch2, LSR, Name::kHashShift));
// Scale the index by multiplying by the element size.
STATIC_ASSERT(NameDictionary::kEntrySize == 3);
__ Add(scratch2, scratch2, Operand(scratch2, LSL, 1));
// Check if the key is identical to the name.
UseScratchRegisterScope temps(masm);
Register scratch3 = temps.AcquireX();
__ Add(scratch2, elements, Operand(scratch2, LSL, kPointerSizeLog2));
__ Ldr(scratch3, FieldMemOperand(scratch2, kElementsStartOffset));
__ Cmp(name, scratch3);
__ B(eq, done);
}
// The inlined probes didn't find the entry.
// Call the complete stub to scan the whole dictionary.
CPURegList spill_list(CPURegister::kRegister, kXRegSizeInBits, 0, 6);
spill_list.Combine(lr);
spill_list.Remove(scratch1);
spill_list.Remove(scratch2);
__ PushCPURegList(spill_list);
if (name.is(x0)) {
DCHECK(!elements.is(x1));
__ Mov(x1, name);
__ Mov(x0, elements);
} else {
__ Mov(x0, elements);
__ Mov(x1, name);
}
Label not_found;
NameDictionaryLookupStub stub(masm->isolate(), POSITIVE_LOOKUP);
__ CallStub(&stub);
__ Cbz(x0, &not_found);
__ Mov(scratch2, x2); // Move entry index into scratch2.
__ PopCPURegList(spill_list);
__ B(done);
__ Bind(&not_found);
__ PopCPURegList(spill_list);
__ B(miss);
}
void NameDictionaryLookupStub::GenerateNegativeLookup(MacroAssembler* masm,
Label* miss,
Label* done,

View File

@ -355,14 +355,6 @@ class NameDictionaryLookupStub: public PlatformCodeStub {
Handle<Name> name,
Register scratch0);
static void GeneratePositiveLookup(MacroAssembler* masm,
Label* miss,
Label* done,
Register elements,
Register name,
Register scratch1,
Register scratch2);
bool SometimesSetsUpAFrame() override { return false; }
private:

View File

@ -108,8 +108,34 @@ void Builtins::Generate_LoadIC_Miss(compiler::CodeAssemblerState* state) {
slot, vector);
}
void Builtins::Generate_LoadIC_Normal(MacroAssembler* masm) {
LoadIC::GenerateNormal(masm);
TF_BUILTIN(LoadIC_Normal, CodeStubAssembler) {
typedef LoadWithVectorDescriptor Descriptor;
Node* receiver = Parameter(Descriptor::kReceiver);
Node* name = Parameter(Descriptor::kName);
Node* context = Parameter(Descriptor::kContext);
Label slow(this);
{
Node* properties = LoadProperties(receiver);
Variable var_name_index(this, MachineType::PointerRepresentation());
Label found(this, &var_name_index);
NameDictionaryLookup<NameDictionary>(properties, name, &found,
&var_name_index, &slow);
Bind(&found);
{
Variable var_details(this, MachineRepresentation::kWord32);
Variable var_value(this, MachineRepresentation::kTagged);
LoadPropertyFromNameDictionary(properties, var_name_index.value(),
&var_details, &var_value);
Node* value = CallGetterIfAccessor(var_value.value(), var_details.value(),
context, receiver, &slow);
Return(value);
}
}
Bind(&slow);
TailCallRuntime(Runtime::kGetProperty, context, receiver, name);
}
void Builtins::Generate_LoadIC_Slow(compiler::CodeAssemblerState* state) {
@ -140,8 +166,47 @@ void Builtins::Generate_StoreIC_Miss(compiler::CodeAssemblerState* state) {
vector, receiver, name);
}
void Builtins::Generate_StoreIC_Normal(MacroAssembler* masm) {
StoreIC::GenerateNormal(masm);
TF_BUILTIN(StoreIC_Normal, CodeStubAssembler) {
typedef StoreWithVectorDescriptor Descriptor;
Node* receiver = Parameter(Descriptor::kReceiver);
Node* name = Parameter(Descriptor::kName);
Node* value = Parameter(Descriptor::kValue);
Node* slot = Parameter(Descriptor::kSlot);
Node* vector = Parameter(Descriptor::kVector);
Node* context = Parameter(Descriptor::kContext);
Label slow(this);
{
Node* properties = LoadProperties(receiver);
Variable var_name_index(this, MachineType::PointerRepresentation());
Label found(this, &var_name_index);
NameDictionaryLookup<NameDictionary>(properties, name, &found,
&var_name_index, &slow);
Bind(&found);
{
const int kNameToDetailsOffset = (NameDictionary::kEntryDetailsIndex -
NameDictionary::kEntryKeyIndex) *
kPointerSize;
Node* details = LoadFixedArrayElement(properties, var_name_index.value(),
kNameToDetailsOffset);
// Check that the property is a writable data property (no accessor).
const int kTypeAndReadOnlyMask = PropertyDetails::KindField::kMask |
PropertyDetails::kAttributesReadOnlyMask;
STATIC_ASSERT(kData == 0);
GotoIf(IsSetSmi(details, kTypeAndReadOnlyMask), &slow);
const int kNameToValueOffset =
(NameDictionary::kEntryValueIndex - NameDictionary::kEntryKeyIndex) *
kPointerSize;
StoreFixedArrayElement(properties, var_name_index.value(), value,
UPDATE_WRITE_BARRIER, kNameToValueOffset);
Return(value);
}
}
Bind(&slow);
TailCallRuntime(Runtime::kStoreIC_Miss, context, value, slot, vector,
receiver, name);
}
void Builtins::Generate_StoreIC_Setter_ForDeopt(MacroAssembler* masm) {

View File

@ -224,10 +224,10 @@ namespace internal {
TFS(LoadGlobalIC_Slow, HANDLER, Code::LOAD_GLOBAL_IC, LoadGlobalWithVector) \
ASH(LoadIC_Getter_ForDeopt, LOAD_IC, kNoExtraICState) \
TFS(LoadIC_Miss, BUILTIN, kNoExtraICState, LoadWithVector) \
ASH(LoadIC_Normal, HANDLER, Code::LOAD_IC) \
TFS(LoadIC_Normal, HANDLER, Code::LOAD_IC, LoadWithVector) \
TFS(LoadIC_Slow, HANDLER, Code::LOAD_IC, LoadWithVector) \
TFS(StoreIC_Miss, BUILTIN, kNoExtraICState, StoreWithVector) \
ASH(StoreIC_Normal, HANDLER, Code::STORE_IC) \
TFS(StoreIC_Normal, HANDLER, Code::STORE_IC, StoreWithVector) \
ASH(StoreIC_Setter_ForDeopt, STORE_IC, StoreICState::kStrictModeState) \
TFS(StoreIC_SlowSloppy, HANDLER, Code::STORE_IC, StoreWithVector) \
TFS(StoreIC_SlowStrict, HANDLER, Code::STORE_IC, StoreWithVector) \

View File

@ -2644,67 +2644,6 @@ void NameDictionaryLookupStub::GenerateNegativeLookup(MacroAssembler* masm,
__ jmp(done);
}
// Probe the name dictionary in the |elements| register. Jump to the
// |done| label if a property with the given name is found leaving the
// index into the dictionary in |r0|. Jump to the |miss| label
// otherwise.
void NameDictionaryLookupStub::GeneratePositiveLookup(MacroAssembler* masm,
Label* miss,
Label* done,
Register elements,
Register name,
Register r0,
Register r1) {
DCHECK(!elements.is(r0));
DCHECK(!elements.is(r1));
DCHECK(!name.is(r0));
DCHECK(!name.is(r1));
__ AssertName(name);
__ mov(r1, FieldOperand(elements, kCapacityOffset));
__ shr(r1, kSmiTagSize); // convert smi to int
__ dec(r1);
// Generate an unrolled loop that performs a few probes before
// giving up. Measurements done on Gmail indicate that 2 probes
// cover ~93% of loads from dictionaries.
for (int i = 0; i < kInlinedProbes; i++) {
// Compute the masked index: (hash + i + i * i) & mask.
__ mov(r0, FieldOperand(name, Name::kHashFieldOffset));
__ shr(r0, Name::kHashShift);
if (i > 0) {
__ add(r0, Immediate(NameDictionary::GetProbeOffset(i)));
}
__ and_(r0, r1);
// Scale the index by multiplying by the entry size.
STATIC_ASSERT(NameDictionary::kEntrySize == 3);
__ lea(r0, Operand(r0, r0, times_2, 0)); // r0 = r0 * 3
// Check if the key is identical to the name.
__ cmp(name, Operand(elements,
r0,
times_4,
kElementsStartOffset - kHeapObjectTag));
__ j(equal, done);
}
NameDictionaryLookupStub stub(masm->isolate(), elements, r1, r0,
POSITIVE_LOOKUP);
__ push(name);
__ mov(r0, FieldOperand(name, Name::kHashFieldOffset));
__ shr(r0, Name::kHashShift);
__ push(r0);
__ CallStub(&stub);
__ test(r1, r1);
__ j(zero, miss);
__ jmp(done);
}
void NameDictionaryLookupStub::Generate(MacroAssembler* masm) {
// This stub overrides SometimesSetsUpAFrame() to return false. That means
// we cannot call anything that could cause a GC from this stub.

View File

@ -58,14 +58,6 @@ class NameDictionaryLookupStub: public PlatformCodeStub {
Handle<Name> name,
Register r0);
static void GeneratePositiveLookup(MacroAssembler* masm,
Label* miss,
Label* done,
Register elements,
Register name,
Register r0,
Register r1);
bool SometimesSetsUpAFrame() override { return false; }
private:

View File

@ -19,133 +19,6 @@ namespace internal {
#define __ ACCESS_MASM(masm)
// Helper function used from LoadIC GenerateNormal.
//
// elements: Property dictionary. It is not clobbered if a jump to the miss
// label is done.
// name: Property name. It is not clobbered if a jump to the miss label is
// done
// result: Register for the result. It is only updated if a jump to the miss
// label is not done. Can be the same as elements or name clobbering
// one of these in the case of not jumping to the miss label.
// The two scratch registers need to be different from elements, name and
// result.
// The generated code assumes that the receiver has slow properties,
// is not a global object and does not have interceptors.
static void GenerateDictionaryLoad(MacroAssembler* masm, Label* miss,
Register elements, Register name,
Register result, Register scratch1,
Register scratch2) {
// Main use of the scratch registers.
// scratch1: Used as temporary and to hold the capacity of the property
// dictionary.
// scratch2: Used as temporary.
Label done;
// Probe the dictionary.
NameDictionaryLookupStub::GeneratePositiveLookup(masm, miss, &done, elements,
name, scratch1, scratch2);
// If probing finds an entry check that the value is a normal
// property.
__ bind(&done); // scratch2 == elements + 4 * index
const int kElementsStartOffset =
NameDictionary::kHeaderSize +
NameDictionary::kElementsStartIndex * kPointerSize;
const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize;
__ ldr(scratch1, FieldMemOperand(scratch2, kDetailsOffset));
__ tst(scratch1, Operand(PropertyDetails::TypeField::kMask << kSmiTagSize));
__ b(ne, miss);
// Get the value at the masked, scaled index and return.
__ ldr(result,
FieldMemOperand(scratch2, kElementsStartOffset + 1 * kPointerSize));
}
// Helper function used from StoreIC::GenerateNormal.
//
// elements: Property dictionary. It is not clobbered if a jump to the miss
// label is done.
// name: Property name. It is not clobbered if a jump to the miss label is
// done
// value: The value to store.
// The two scratch registers need to be different from elements, name and
// result.
// The generated code assumes that the receiver has slow properties,
// is not a global object and does not have interceptors.
static void GenerateDictionaryStore(MacroAssembler* masm, Label* miss,
Register elements, Register name,
Register value, Register scratch1,
Register scratch2) {
// Main use of the scratch registers.
// scratch1: Used as temporary and to hold the capacity of the property
// dictionary.
// scratch2: Used as temporary.
Label done;
// Probe the dictionary.
NameDictionaryLookupStub::GeneratePositiveLookup(masm, miss, &done, elements,
name, scratch1, scratch2);
// If probing finds an entry in the dictionary check that the value
// is a normal property that is not read only.
__ bind(&done); // scratch2 == elements + 4 * index
const int kElementsStartOffset =
NameDictionary::kHeaderSize +
NameDictionary::kElementsStartIndex * kPointerSize;
const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize;
const int kTypeAndReadOnlyMask =
(PropertyDetails::TypeField::kMask |
PropertyDetails::AttributesField::encode(READ_ONLY))
<< kSmiTagSize;
__ ldr(scratch1, FieldMemOperand(scratch2, kDetailsOffset));
__ tst(scratch1, Operand(kTypeAndReadOnlyMask));
__ b(ne, miss);
// Store the value at the masked, scaled index and return.
const int kValueOffset = kElementsStartOffset + kPointerSize;
__ add(scratch2, scratch2, Operand(kValueOffset - kHeapObjectTag));
__ str(value, MemOperand(scratch2));
// Update the write barrier. Make sure not to clobber the value.
__ mov(scratch1, value);
__ RecordWrite(elements, scratch2, scratch1, kLRHasNotBeenSaved,
kDontSaveFPRegs);
}
void LoadIC::GenerateNormal(MacroAssembler* masm) {
Register dictionary = r0;
DCHECK(!dictionary.is(LoadDescriptor::ReceiverRegister()));
DCHECK(!dictionary.is(LoadDescriptor::NameRegister()));
Label slow;
__ ldr(dictionary, FieldMemOperand(LoadDescriptor::ReceiverRegister(),
JSObject::kPropertiesOffset));
GenerateDictionaryLoad(masm, &slow, dictionary,
LoadDescriptor::NameRegister(), r0, r3, r4);
__ Ret();
// Dictionary load failed, go slow (but don't miss).
__ bind(&slow);
GenerateRuntimeGetProperty(masm);
}
// A register that isn't one of the parameters to the load ic.
static const Register LoadIC_TempRegister() { return r3; }
void LoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) {
// The return address is in lr.
__ mov(LoadIC_TempRegister(), LoadDescriptor::ReceiverRegister());
__ Push(LoadIC_TempRegister(), LoadDescriptor::NameRegister());
// Do tail-call to runtime routine.
__ TailCallRuntime(Runtime::kGetProperty);
}
static void StoreIC_PushArgs(MacroAssembler* masm) {
__ Push(StoreWithVectorDescriptor::ValueRegister(),
StoreWithVectorDescriptor::SlotRegister(),
@ -169,39 +42,6 @@ void KeyedStoreIC::GenerateSlow(MacroAssembler* masm) {
__ TailCallRuntime(Runtime::kKeyedStoreIC_Slow);
}
void StoreIC::GenerateMiss(MacroAssembler* masm) {
StoreIC_PushArgs(masm);
// Perform tail call to the entry.
__ TailCallRuntime(Runtime::kStoreIC_Miss);
}
void StoreIC::GenerateNormal(MacroAssembler* masm) {
Label miss;
Register receiver = StoreDescriptor::ReceiverRegister();
Register name = StoreDescriptor::NameRegister();
Register value = StoreDescriptor::ValueRegister();
Register dictionary = r5;
DCHECK(receiver.is(r1));
DCHECK(name.is(r2));
DCHECK(value.is(r0));
DCHECK(StoreWithVectorDescriptor::VectorRegister().is(r3));
DCHECK(StoreWithVectorDescriptor::SlotRegister().is(r4));
__ ldr(dictionary, FieldMemOperand(receiver, JSObject::kPropertiesOffset));
GenerateDictionaryStore(masm, &miss, dictionary, name, value, r6, r9);
Counters* counters = masm->isolate()->counters();
__ IncrementCounter(counters->ic_store_normal_hit(), 1, r6, r9);
__ Ret();
__ bind(&miss);
__ IncrementCounter(counters->ic_store_normal_miss(), 1, r6, r9);
GenerateMiss(masm);
}
#undef __

View File

@ -15,120 +15,6 @@ namespace internal {
#define __ ACCESS_MASM(masm)
// Helper function used from LoadIC GenerateNormal.
//
// elements: Property dictionary. It is not clobbered if a jump to the miss
// label is done.
// name: Property name. It is not clobbered if a jump to the miss label is
// done
// result: Register for the result. It is only updated if a jump to the miss
// label is not done.
// The scratch registers need to be different from elements, name and result.
// The generated code assumes that the receiver has slow properties,
// is not a global object and does not have interceptors.
static void GenerateDictionaryLoad(MacroAssembler* masm, Label* miss,
Register elements, Register name,
Register result, Register scratch1,
Register scratch2) {
DCHECK(!AreAliased(elements, name, scratch1, scratch2));
DCHECK(!AreAliased(result, scratch1, scratch2));
Label done;
// Probe the dictionary.
NameDictionaryLookupStub::GeneratePositiveLookup(masm, miss, &done, elements,
name, scratch1, scratch2);
// If probing finds an entry check that the value is a normal property.
__ Bind(&done);
static const int kElementsStartOffset =
NameDictionary::kHeaderSize +
NameDictionary::kElementsStartIndex * kPointerSize;
static const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize;
__ Ldr(scratch1, FieldMemOperand(scratch2, kDetailsOffset));
__ Tst(scratch1, Smi::FromInt(PropertyDetails::TypeField::kMask));
__ B(ne, miss);
// Get the value at the masked, scaled index and return.
__ Ldr(result,
FieldMemOperand(scratch2, kElementsStartOffset + 1 * kPointerSize));
}
// Helper function used from StoreIC::GenerateNormal.
//
// elements: Property dictionary. It is not clobbered if a jump to the miss
// label is done.
// name: Property name. It is not clobbered if a jump to the miss label is
// done
// value: The value to store (never clobbered).
//
// The generated code assumes that the receiver has slow properties,
// is not a global object and does not have interceptors.
static void GenerateDictionaryStore(MacroAssembler* masm, Label* miss,
Register elements, Register name,
Register value, Register scratch1,
Register scratch2) {
DCHECK(!AreAliased(elements, name, value, scratch1, scratch2));
Label done;
// Probe the dictionary.
NameDictionaryLookupStub::GeneratePositiveLookup(masm, miss, &done, elements,
name, scratch1, scratch2);
// If probing finds an entry in the dictionary check that the value
// is a normal property that is not read only.
__ Bind(&done);
static const int kElementsStartOffset =
NameDictionary::kHeaderSize +
NameDictionary::kElementsStartIndex * kPointerSize;
static const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize;
static const int kTypeAndReadOnlyMask =
PropertyDetails::TypeField::kMask |
PropertyDetails::AttributesField::encode(READ_ONLY);
__ Ldrsw(scratch1, UntagSmiFieldMemOperand(scratch2, kDetailsOffset));
__ Tst(scratch1, kTypeAndReadOnlyMask);
__ B(ne, miss);
// Store the value at the masked, scaled index and return.
static const int kValueOffset = kElementsStartOffset + kPointerSize;
__ Add(scratch2, scratch2, kValueOffset - kHeapObjectTag);
__ Str(value, MemOperand(scratch2));
// Update the write barrier. Make sure not to clobber the value.
__ Mov(scratch1, value);
__ RecordWrite(elements, scratch2, scratch1, kLRHasNotBeenSaved,
kDontSaveFPRegs);
}
void LoadIC::GenerateNormal(MacroAssembler* masm) {
Register dictionary = x0;
DCHECK(!dictionary.is(LoadDescriptor::ReceiverRegister()));
DCHECK(!dictionary.is(LoadDescriptor::NameRegister()));
Label slow;
__ Ldr(dictionary, FieldMemOperand(LoadDescriptor::ReceiverRegister(),
JSObject::kPropertiesOffset));
GenerateDictionaryLoad(masm, &slow, dictionary,
LoadDescriptor::NameRegister(), x0, x3, x4);
__ Ret();
// Dictionary load failed, go slow (but don't miss).
__ Bind(&slow);
GenerateRuntimeGetProperty(masm);
}
void LoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) {
// The return address is in lr.
__ Push(LoadDescriptor::ReceiverRegister(), LoadDescriptor::NameRegister());
// Do tail-call to runtime routine.
__ TailCallRuntime(Runtime::kGetProperty);
}
static void StoreIC_PushArgs(MacroAssembler* masm) {
__ Push(StoreWithVectorDescriptor::ValueRegister(),
StoreWithVectorDescriptor::SlotRegister(),
@ -153,38 +39,6 @@ void KeyedStoreIC::GenerateSlow(MacroAssembler* masm) {
__ TailCallRuntime(Runtime::kKeyedStoreIC_Slow);
}
void StoreIC::GenerateMiss(MacroAssembler* masm) {
StoreIC_PushArgs(masm);
// Tail call to the entry.
__ TailCallRuntime(Runtime::kStoreIC_Miss);
}
void StoreIC::GenerateNormal(MacroAssembler* masm) {
Label miss;
Register value = StoreDescriptor::ValueRegister();
Register receiver = StoreDescriptor::ReceiverRegister();
Register name = StoreDescriptor::NameRegister();
Register dictionary = x5;
DCHECK(!AreAliased(value, receiver, name,
StoreWithVectorDescriptor::SlotRegister(),
StoreWithVectorDescriptor::VectorRegister(), x5, x6, x7));
__ Ldr(dictionary, FieldMemOperand(receiver, JSObject::kPropertiesOffset));
GenerateDictionaryStore(masm, &miss, dictionary, name, value, x6, x7);
Counters* counters = masm->isolate()->counters();
__ IncrementCounter(counters->ic_store_normal_hit(), 1, x6, x7);
__ Ret();
// Cache miss: Jump to runtime.
__ Bind(&miss);
__ IncrementCounter(counters->ic_store_normal_miss(), 1, x6, x7);
GenerateMiss(masm);
}
Condition CompareIC::ComputeCondition(Token::Value op) {
switch (op) {
case Token::EQ_STRICT:

View File

@ -18,141 +18,6 @@ namespace internal {
#define __ ACCESS_MASM(masm)
// Helper function used to load a property from a dictionary backing
// storage. This function may fail to load a property even though it is
// in the dictionary, so code at miss_label must always call a backup
// property load that is complete. This function is safe to call if
// name is not internalized, and will jump to the miss_label in that
// case. The generated code assumes that the receiver has slow
// properties, is not a global object and does not have interceptors.
static void GenerateDictionaryLoad(MacroAssembler* masm, Label* miss_label,
Register elements, Register name,
Register r0, Register r1, Register result) {
// Register use:
//
// elements - holds the property dictionary on entry and is unchanged.
//
// name - holds the name of the property on entry and is unchanged.
//
// Scratch registers:
//
// r0 - used for the index into the property dictionary
//
// r1 - used to hold the capacity of the property dictionary.
//
// result - holds the result on exit.
Label done;
// Probe the dictionary.
NameDictionaryLookupStub::GeneratePositiveLookup(masm, miss_label, &done,
elements, name, r0, r1);
// If probing finds an entry in the dictionary, r0 contains the
// index into the dictionary. Check that the value is a normal
// property.
__ bind(&done);
const int kElementsStartOffset =
NameDictionary::kHeaderSize +
NameDictionary::kElementsStartIndex * kPointerSize;
const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize;
__ test(Operand(elements, r0, times_4, kDetailsOffset - kHeapObjectTag),
Immediate(PropertyDetails::TypeField::kMask << kSmiTagSize));
__ j(not_zero, miss_label);
// Get the value at the masked, scaled index.
const int kValueOffset = kElementsStartOffset + kPointerSize;
__ mov(result, Operand(elements, r0, times_4, kValueOffset - kHeapObjectTag));
}
// Helper function used to store a property to a dictionary backing
// storage. This function may fail to store a property eventhough it
// is in the dictionary, so code at miss_label must always call a
// backup property store that is complete. This function is safe to
// call if name is not internalized, and will jump to the miss_label in
// that case. The generated code assumes that the receiver has slow
// properties, is not a global object and does not have interceptors.
static void GenerateDictionaryStore(MacroAssembler* masm, Label* miss_label,
Register elements, Register name,
Register value, Register r0, Register r1) {
// Register use:
//
// elements - holds the property dictionary on entry and is clobbered.
//
// name - holds the name of the property on entry and is unchanged.
//
// value - holds the value to store and is unchanged.
//
// r0 - used for index into the property dictionary and is clobbered.
//
// r1 - used to hold the capacity of the property dictionary and is clobbered.
Label done;
// Probe the dictionary.
NameDictionaryLookupStub::GeneratePositiveLookup(masm, miss_label, &done,
elements, name, r0, r1);
// If probing finds an entry in the dictionary, r0 contains the
// index into the dictionary. Check that the value is a normal
// property that is not read only.
__ bind(&done);
const int kElementsStartOffset =
NameDictionary::kHeaderSize +
NameDictionary::kElementsStartIndex * kPointerSize;
const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize;
const int kTypeAndReadOnlyMask =
(PropertyDetails::TypeField::kMask |
PropertyDetails::AttributesField::encode(READ_ONLY))
<< kSmiTagSize;
__ test(Operand(elements, r0, times_4, kDetailsOffset - kHeapObjectTag),
Immediate(kTypeAndReadOnlyMask));
__ j(not_zero, miss_label);
// Store the value at the masked, scaled index.
const int kValueOffset = kElementsStartOffset + kPointerSize;
__ lea(r0, Operand(elements, r0, times_4, kValueOffset - kHeapObjectTag));
__ mov(Operand(r0, 0), value);
// Update write barrier. Make sure not to clobber the value.
__ mov(r1, value);
__ RecordWrite(elements, r0, r1, kDontSaveFPRegs);
}
void LoadIC::GenerateNormal(MacroAssembler* masm) {
Register dictionary = eax;
DCHECK(!dictionary.is(LoadDescriptor::ReceiverRegister()));
DCHECK(!dictionary.is(LoadDescriptor::NameRegister()));
Label slow;
__ mov(dictionary, FieldOperand(LoadDescriptor::ReceiverRegister(),
JSObject::kPropertiesOffset));
GenerateDictionaryLoad(masm, &slow, dictionary,
LoadDescriptor::NameRegister(), edi, ebx, eax);
__ ret(0);
// Dictionary load failed, go slow (but don't miss).
__ bind(&slow);
GenerateRuntimeGetProperty(masm);
}
void LoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) {
// Return address is on the stack.
Register receiver = LoadDescriptor::ReceiverRegister();
Register name = LoadDescriptor::NameRegister();
DCHECK(!ebx.is(receiver) && !ebx.is(name));
__ pop(ebx);
__ push(receiver);
__ push(name);
__ push(ebx);
// Do tail-call to runtime routine.
__ TailCallRuntime(Runtime::kGetProperty);
}
static void StoreIC_PushArgs(MacroAssembler* masm) {
Register receiver = StoreWithVectorDescriptor::ReceiverRegister();
Register name = StoreWithVectorDescriptor::NameRegister();
@ -171,50 +36,6 @@ static void StoreIC_PushArgs(MacroAssembler* masm) {
__ push(return_address);
}
void StoreIC::GenerateMiss(MacroAssembler* masm) {
// Return address is on the stack.
StoreIC_PushArgs(masm);
// Perform tail call to the entry.
__ TailCallRuntime(Runtime::kStoreIC_Miss);
}
void StoreIC::GenerateNormal(MacroAssembler* masm) {
typedef StoreWithVectorDescriptor Descriptor;
Label restore_miss;
Register receiver = Descriptor::ReceiverRegister();
Register name = Descriptor::NameRegister();
Register value = Descriptor::ValueRegister();
// Since the slot and vector values are passed on the stack we can use
// respective registers as scratch registers.
Register scratch1 = Descriptor::VectorRegister();
Register scratch2 = Descriptor::SlotRegister();
__ LoadParameterFromStack<Descriptor>(value, Descriptor::kValue);
// A lot of registers are needed for storing to slow case objects.
// Push and restore receiver but rely on GenerateDictionaryStore preserving
// the value and name.
__ push(receiver);
Register dictionary = receiver;
__ mov(dictionary, FieldOperand(receiver, JSObject::kPropertiesOffset));
GenerateDictionaryStore(masm, &restore_miss, dictionary, name, value,
scratch1, scratch2);
__ Drop(1);
Counters* counters = masm->isolate()->counters();
__ IncrementCounter(counters->ic_store_normal_hit(), 1);
__ ret(Descriptor::kStackArgumentsCount * kPointerSize);
__ bind(&restore_miss);
__ pop(receiver);
__ IncrementCounter(counters->ic_store_normal_miss(), 1);
GenerateMiss(masm);
}
void KeyedStoreIC::GenerateMiss(MacroAssembler* masm) {
// Return address is on the stack.
StoreIC_PushArgs(masm);

View File

@ -285,10 +285,6 @@ class LoadIC : public IC {
NOT_INSIDE_TYPEOF;
}
// Code generator routines.
static void GenerateRuntimeGetProperty(MacroAssembler* masm);
static void GenerateNormal(MacroAssembler* masm);
MUST_USE_RESULT MaybeHandle<Object> Load(Handle<Object> object,
Handle<Name> name);
@ -374,11 +370,6 @@ class StoreIC : public IC {
return StoreICState::GetLanguageMode(extra_ic_state());
}
// Code generators for stub routines. Only called once at startup.
static void GenerateSlow(MacroAssembler* masm);
static void GenerateMiss(MacroAssembler* masm);
static void GenerateNormal(MacroAssembler* masm);
MUST_USE_RESULT MaybeHandle<Object> Store(
Handle<Object> object, Handle<Name> name, Handle<Object> value,
JSReceiver::StoreFromKeyed store_mode =

View File

@ -19,138 +19,6 @@ namespace internal {
#define __ ACCESS_MASM(masm)
// Helper function used from LoadIC GenerateNormal.
//
// elements: Property dictionary. It is not clobbered if a jump to the miss
// label is done.
// name: Property name. It is not clobbered if a jump to the miss label is
// done
// result: Register for the result. It is only updated if a jump to the miss
// label is not done. Can be the same as elements or name clobbering
// one of these in the case of not jumping to the miss label.
// The two scratch registers need to be different from elements, name and
// result.
// The generated code assumes that the receiver has slow properties,
// is not a global object and does not have interceptors.
// The address returned from GenerateStringDictionaryProbes() in scratch2
// is used.
static void GenerateDictionaryLoad(MacroAssembler* masm, Label* miss,
Register elements, Register name,
Register result, Register scratch1,
Register scratch2) {
// Main use of the scratch registers.
// scratch1: Used as temporary and to hold the capacity of the property
// dictionary.
// scratch2: Used as temporary.
Label done;
// Probe the dictionary.
NameDictionaryLookupStub::GeneratePositiveLookup(masm, miss, &done, elements,
name, scratch1, scratch2);
// If probing finds an entry check that the value is a normal
// property.
__ bind(&done); // scratch2 == elements + 4 * index.
const int kElementsStartOffset =
NameDictionary::kHeaderSize +
NameDictionary::kElementsStartIndex * kPointerSize;
const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize;
__ lw(scratch1, FieldMemOperand(scratch2, kDetailsOffset));
__ And(at, scratch1,
Operand(PropertyDetails::TypeField::kMask << kSmiTagSize));
__ Branch(miss, ne, at, Operand(zero_reg));
// Get the value at the masked, scaled index and return.
__ lw(result,
FieldMemOperand(scratch2, kElementsStartOffset + 1 * kPointerSize));
}
// Helper function used from StoreIC::GenerateNormal.
//
// elements: Property dictionary. It is not clobbered if a jump to the miss
// label is done.
// name: Property name. It is not clobbered if a jump to the miss label is
// done
// value: The value to store.
// The two scratch registers need to be different from elements, name and
// result.
// The generated code assumes that the receiver has slow properties,
// is not a global object and does not have interceptors.
// The address returned from GenerateStringDictionaryProbes() in scratch2
// is used.
static void GenerateDictionaryStore(MacroAssembler* masm, Label* miss,
Register elements, Register name,
Register value, Register scratch1,
Register scratch2) {
// Main use of the scratch registers.
// scratch1: Used as temporary and to hold the capacity of the property
// dictionary.
// scratch2: Used as temporary.
Label done;
// Probe the dictionary.
NameDictionaryLookupStub::GeneratePositiveLookup(masm, miss, &done, elements,
name, scratch1, scratch2);
// If probing finds an entry in the dictionary check that the value
// is a normal property that is not read only.
__ bind(&done); // scratch2 == elements + 4 * index.
const int kElementsStartOffset =
NameDictionary::kHeaderSize +
NameDictionary::kElementsStartIndex * kPointerSize;
const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize;
const int kTypeAndReadOnlyMask =
(PropertyDetails::TypeField::kMask |
PropertyDetails::AttributesField::encode(READ_ONLY))
<< kSmiTagSize;
__ lw(scratch1, FieldMemOperand(scratch2, kDetailsOffset));
__ And(at, scratch1, Operand(kTypeAndReadOnlyMask));
__ Branch(miss, ne, at, Operand(zero_reg));
// Store the value at the masked, scaled index and return.
const int kValueOffset = kElementsStartOffset + kPointerSize;
__ Addu(scratch2, scratch2, Operand(kValueOffset - kHeapObjectTag));
__ sw(value, MemOperand(scratch2));
// Update the write barrier. Make sure not to clobber the value.
__ mov(scratch1, value);
__ RecordWrite(elements, scratch2, scratch1, kRAHasNotBeenSaved,
kDontSaveFPRegs);
}
void LoadIC::GenerateNormal(MacroAssembler* masm) {
Register dictionary = a0;
DCHECK(!dictionary.is(LoadDescriptor::ReceiverRegister()));
DCHECK(!dictionary.is(LoadDescriptor::NameRegister()));
Label slow;
__ lw(dictionary, FieldMemOperand(LoadDescriptor::ReceiverRegister(),
JSObject::kPropertiesOffset));
GenerateDictionaryLoad(masm, &slow, dictionary,
LoadDescriptor::NameRegister(), v0, a3, t0);
__ Ret();
// Dictionary load failed, go slow (but don't miss).
__ bind(&slow);
GenerateRuntimeGetProperty(masm);
}
// A register that isn't one of the parameters to the load ic.
static const Register LoadIC_TempRegister() { return a3; }
void LoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) {
// The return address is in ra.
__ mov(LoadIC_TempRegister(), LoadDescriptor::ReceiverRegister());
__ Push(LoadIC_TempRegister(), LoadDescriptor::NameRegister());
// Do tail-call to runtime routine.
__ TailCallRuntime(Runtime::kGetProperty);
}
static void StoreIC_PushArgs(MacroAssembler* masm) {
__ Push(StoreWithVectorDescriptor::ValueRegister(),
StoreWithVectorDescriptor::SlotRegister(),
@ -174,40 +42,6 @@ void KeyedStoreIC::GenerateSlow(MacroAssembler* masm) {
__ TailCallRuntime(Runtime::kKeyedStoreIC_Slow);
}
void StoreIC::GenerateMiss(MacroAssembler* masm) {
StoreIC_PushArgs(masm);
// Perform tail call to the entry.
__ TailCallRuntime(Runtime::kStoreIC_Miss);
}
void StoreIC::GenerateNormal(MacroAssembler* masm) {
Label miss;
Register receiver = StoreDescriptor::ReceiverRegister();
Register name = StoreDescriptor::NameRegister();
Register value = StoreDescriptor::ValueRegister();
Register dictionary = t1;
DCHECK(receiver.is(a1));
DCHECK(name.is(a2));
DCHECK(value.is(a0));
DCHECK(StoreWithVectorDescriptor::VectorRegister().is(a3));
DCHECK(StoreWithVectorDescriptor::SlotRegister().is(t0));
__ lw(dictionary, FieldMemOperand(receiver, JSObject::kPropertiesOffset));
GenerateDictionaryStore(masm, &miss, dictionary, name, value, t2, t5);
Counters* counters = masm->isolate()->counters();
__ IncrementCounter(counters->ic_store_normal_hit(), 1, t2, t5);
__ Ret(USE_DELAY_SLOT);
__ Move(v0, value); // Ensure the stub returns correct value.
__ bind(&miss);
__ IncrementCounter(counters->ic_store_normal_miss(), 1, t2, t5);
GenerateMiss(masm);
}
#undef __

View File

@ -19,136 +19,6 @@ namespace internal {
#define __ ACCESS_MASM(masm)
// Helper function used from LoadIC GenerateNormal.
//
// elements: Property dictionary. It is not clobbered if a jump to the miss
// label is done.
// name: Property name. It is not clobbered if a jump to the miss label is
// done
// result: Register for the result. It is only updated if a jump to the miss
// label is not done. Can be the same as elements or name clobbering
// one of these in the case of not jumping to the miss label.
// The two scratch registers need to be different from elements, name and
// result.
// The generated code assumes that the receiver has slow properties,
// is not a global object and does not have interceptors.
// The address returned from GenerateStringDictionaryProbes() in scratch2
// is used.
static void GenerateDictionaryLoad(MacroAssembler* masm, Label* miss,
Register elements, Register name,
Register result, Register scratch1,
Register scratch2) {
// Main use of the scratch registers.
// scratch1: Used as temporary and to hold the capacity of the property
// dictionary.
// scratch2: Used as temporary.
Label done;
// Probe the dictionary.
NameDictionaryLookupStub::GeneratePositiveLookup(masm, miss, &done, elements,
name, scratch1, scratch2);
// If probing finds an entry check that the value is a normal
// property.
__ bind(&done); // scratch2 == elements + 4 * index.
const int kElementsStartOffset =
NameDictionary::kHeaderSize +
NameDictionary::kElementsStartIndex * kPointerSize;
const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize;
__ ld(scratch1, FieldMemOperand(scratch2, kDetailsOffset));
__ And(at, scratch1,
Operand(Smi::FromInt(PropertyDetails::TypeField::kMask)));
__ Branch(miss, ne, at, Operand(zero_reg));
// Get the value at the masked, scaled index and return.
__ ld(result,
FieldMemOperand(scratch2, kElementsStartOffset + 1 * kPointerSize));
}
// Helper function used from StoreIC::GenerateNormal.
//
// elements: Property dictionary. It is not clobbered if a jump to the miss
// label is done.
// name: Property name. It is not clobbered if a jump to the miss label is
// done
// value: The value to store.
// The two scratch registers need to be different from elements, name and
// result.
// The generated code assumes that the receiver has slow properties,
// is not a global object and does not have interceptors.
// The address returned from GenerateStringDictionaryProbes() in scratch2
// is used.
static void GenerateDictionaryStore(MacroAssembler* masm, Label* miss,
Register elements, Register name,
Register value, Register scratch1,
Register scratch2) {
// Main use of the scratch registers.
// scratch1: Used as temporary and to hold the capacity of the property
// dictionary.
// scratch2: Used as temporary.
Label done;
// Probe the dictionary.
NameDictionaryLookupStub::GeneratePositiveLookup(masm, miss, &done, elements,
name, scratch1, scratch2);
// If probing finds an entry in the dictionary check that the value
// is a normal property that is not read only.
__ bind(&done); // scratch2 == elements + 4 * index.
const int kElementsStartOffset =
NameDictionary::kHeaderSize +
NameDictionary::kElementsStartIndex * kPointerSize;
const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize;
const int kTypeAndReadOnlyMask =
(PropertyDetails::TypeField::kMask |
PropertyDetails::AttributesField::encode(READ_ONLY));
__ ld(scratch1, FieldMemOperand(scratch2, kDetailsOffset));
__ And(at, scratch1, Operand(Smi::FromInt(kTypeAndReadOnlyMask)));
__ Branch(miss, ne, at, Operand(zero_reg));
// Store the value at the masked, scaled index and return.
const int kValueOffset = kElementsStartOffset + kPointerSize;
__ Daddu(scratch2, scratch2, Operand(kValueOffset - kHeapObjectTag));
__ sd(value, MemOperand(scratch2));
// Update the write barrier. Make sure not to clobber the value.
__ mov(scratch1, value);
__ RecordWrite(elements, scratch2, scratch1, kRAHasNotBeenSaved,
kDontSaveFPRegs);
}
void LoadIC::GenerateNormal(MacroAssembler* masm) {
Register dictionary = a0;
DCHECK(!dictionary.is(LoadDescriptor::ReceiverRegister()));
DCHECK(!dictionary.is(LoadDescriptor::NameRegister()));
Label slow;
__ ld(dictionary, FieldMemOperand(LoadDescriptor::ReceiverRegister(),
JSObject::kPropertiesOffset));
GenerateDictionaryLoad(masm, &slow, dictionary,
LoadDescriptor::NameRegister(), v0, a3, a4);
__ Ret();
// Dictionary load failed, go slow (but don't miss).
__ bind(&slow);
GenerateRuntimeGetProperty(masm);
}
// A register that isn't one of the parameters to the load ic.
static const Register LoadIC_TempRegister() { return a3; }
void LoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) {
// The return address is in ra.
__ mov(LoadIC_TempRegister(), LoadDescriptor::ReceiverRegister());
__ Push(LoadIC_TempRegister(), LoadDescriptor::NameRegister());
// Do tail-call to runtime routine.
__ TailCallRuntime(Runtime::kGetProperty);
}
static void StoreIC_PushArgs(MacroAssembler* masm) {
__ Push(StoreWithVectorDescriptor::ValueRegister(),
StoreWithVectorDescriptor::SlotRegister(),
@ -172,38 +42,6 @@ void KeyedStoreIC::GenerateSlow(MacroAssembler* masm) {
__ TailCallRuntime(Runtime::kKeyedStoreIC_Slow);
}
void StoreIC::GenerateMiss(MacroAssembler* masm) {
StoreIC_PushArgs(masm);
// Perform tail call to the entry.
__ TailCallRuntime(Runtime::kStoreIC_Miss);
}
void StoreIC::GenerateNormal(MacroAssembler* masm) {
Label miss;
Register receiver = StoreDescriptor::ReceiverRegister();
Register name = StoreDescriptor::NameRegister();
Register value = StoreDescriptor::ValueRegister();
Register dictionary = a5;
DCHECK(!AreAliased(
value, receiver, name, StoreWithVectorDescriptor::VectorRegister(),
StoreWithVectorDescriptor::SlotRegister(), dictionary, a6, a7));
__ ld(dictionary, FieldMemOperand(receiver, JSObject::kPropertiesOffset));
GenerateDictionaryStore(masm, &miss, dictionary, name, value, a6, a7);
Counters* counters = masm->isolate()->counters();
__ IncrementCounter(counters->ic_store_normal_hit(), 1, a6, a7);
__ Ret(USE_DELAY_SLOT);
__ Move(v0, value); // Ensure the stub returns correct value.
__ bind(&miss);
__ IncrementCounter(counters->ic_store_normal_miss(), 1, a6, a7);
GenerateMiss(masm);
}
#undef __

View File

@ -19,138 +19,6 @@ namespace internal {
#define __ ACCESS_MASM(masm)
// Helper function used from LoadIC GenerateNormal.
//
// elements: Property dictionary. It is not clobbered if a jump to the miss
// label is done.
// name: Property name. It is not clobbered if a jump to the miss label is
// done
// result: Register for the result. It is only updated if a jump to the miss
// label is not done. Can be the same as elements or name clobbering
// one of these in the case of not jumping to the miss label.
// The two scratch registers need to be different from elements, name and
// result.
// The generated code assumes that the receiver has slow properties,
// is not a global object and does not have interceptors.
static void GenerateDictionaryLoad(MacroAssembler* masm, Label* miss,
Register elements, Register name,
Register result, Register scratch1,
Register scratch2) {
// Main use of the scratch registers.
// scratch1: Used as temporary and to hold the capacity of the property
// dictionary.
// scratch2: Used as temporary.
Label done;
// Probe the dictionary.
NameDictionaryLookupStub::GeneratePositiveLookup(masm, miss, &done, elements,
name, scratch1, scratch2);
// If probing finds an entry check that the value is a normal
// property.
__ bind(&done); // scratch2 == elements + 4 * index
const int kElementsStartOffset =
NameDictionary::kHeaderSize +
NameDictionary::kElementsStartIndex * kPointerSize;
const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize;
__ LoadP(scratch1, FieldMemOperand(scratch2, kDetailsOffset));
__ mr(r0, scratch2);
__ LoadSmiLiteral(scratch2, Smi::FromInt(PropertyDetails::TypeField::kMask));
__ and_(scratch2, scratch1, scratch2, SetRC);
__ bne(miss, cr0);
__ mr(scratch2, r0);
// Get the value at the masked, scaled index and return.
__ LoadP(result,
FieldMemOperand(scratch2, kElementsStartOffset + 1 * kPointerSize));
}
// Helper function used from StoreIC::GenerateNormal.
//
// elements: Property dictionary. It is not clobbered if a jump to the miss
// label is done.
// name: Property name. It is not clobbered if a jump to the miss label is
// done
// value: The value to store.
// The two scratch registers need to be different from elements, name and
// result.
// The generated code assumes that the receiver has slow properties,
// is not a global object and does not have interceptors.
static void GenerateDictionaryStore(MacroAssembler* masm, Label* miss,
Register elements, Register name,
Register value, Register scratch1,
Register scratch2) {
// Main use of the scratch registers.
// scratch1: Used as temporary and to hold the capacity of the property
// dictionary.
// scratch2: Used as temporary.
Label done;
// Probe the dictionary.
NameDictionaryLookupStub::GeneratePositiveLookup(masm, miss, &done, elements,
name, scratch1, scratch2);
// If probing finds an entry in the dictionary check that the value
// is a normal property that is not read only.
__ bind(&done); // scratch2 == elements + 4 * index
const int kElementsStartOffset =
NameDictionary::kHeaderSize +
NameDictionary::kElementsStartIndex * kPointerSize;
const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize;
int kTypeAndReadOnlyMask =
PropertyDetails::TypeField::kMask |
PropertyDetails::AttributesField::encode(READ_ONLY);
__ LoadP(scratch1, FieldMemOperand(scratch2, kDetailsOffset));
__ mr(r0, scratch2);
__ LoadSmiLiteral(scratch2, Smi::FromInt(kTypeAndReadOnlyMask));
__ and_(scratch2, scratch1, scratch2, SetRC);
__ bne(miss, cr0);
__ mr(scratch2, r0);
// Store the value at the masked, scaled index and return.
const int kValueOffset = kElementsStartOffset + kPointerSize;
__ addi(scratch2, scratch2, Operand(kValueOffset - kHeapObjectTag));
__ StoreP(value, MemOperand(scratch2));
// Update the write barrier. Make sure not to clobber the value.
__ mr(scratch1, value);
__ RecordWrite(elements, scratch2, scratch1, kLRHasNotBeenSaved,
kDontSaveFPRegs);
}
void LoadIC::GenerateNormal(MacroAssembler* masm) {
Register dictionary = r3;
DCHECK(!dictionary.is(LoadDescriptor::ReceiverRegister()));
DCHECK(!dictionary.is(LoadDescriptor::NameRegister()));
Label slow;
__ LoadP(dictionary, FieldMemOperand(LoadDescriptor::ReceiverRegister(),
JSObject::kPropertiesOffset));
GenerateDictionaryLoad(masm, &slow, dictionary,
LoadDescriptor::NameRegister(), r3, r6, r7);
__ Ret();
// Dictionary load failed, go slow (but don't miss).
__ bind(&slow);
GenerateRuntimeGetProperty(masm);
}
// A register that isn't one of the parameters to the load ic.
static const Register LoadIC_TempRegister() { return r6; }
void LoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) {
// The return address is in lr.
__ mr(LoadIC_TempRegister(), LoadDescriptor::ReceiverRegister());
__ Push(LoadIC_TempRegister(), LoadDescriptor::NameRegister());
// Do tail-call to runtime routine.
__ TailCallRuntime(Runtime::kGetProperty);
}
static void StoreIC_PushArgs(MacroAssembler* masm) {
__ Push(StoreWithVectorDescriptor::ValueRegister(),
StoreWithVectorDescriptor::SlotRegister(),
@ -174,39 +42,6 @@ void KeyedStoreIC::GenerateSlow(MacroAssembler* masm) {
__ TailCallRuntime(Runtime::kKeyedStoreIC_Slow);
}
void StoreIC::GenerateMiss(MacroAssembler* masm) {
StoreIC_PushArgs(masm);
// Perform tail call to the entry.
__ TailCallRuntime(Runtime::kStoreIC_Miss);
}
void StoreIC::GenerateNormal(MacroAssembler* masm) {
Label miss;
Register receiver = StoreDescriptor::ReceiverRegister();
Register name = StoreDescriptor::NameRegister();
Register value = StoreDescriptor::ValueRegister();
Register dictionary = r8;
DCHECK(receiver.is(r4));
DCHECK(name.is(r5));
DCHECK(value.is(r3));
DCHECK(StoreWithVectorDescriptor::VectorRegister().is(r6));
DCHECK(StoreWithVectorDescriptor::SlotRegister().is(r7));
__ LoadP(dictionary, FieldMemOperand(receiver, JSObject::kPropertiesOffset));
GenerateDictionaryStore(masm, &miss, dictionary, name, value, r9, r10);
Counters* counters = masm->isolate()->counters();
__ IncrementCounter(counters->ic_store_normal_hit(), 1, r9, r10);
__ Ret();
__ bind(&miss);
__ IncrementCounter(counters->ic_store_normal_miss(), 1, r9, r10);
GenerateMiss(masm);
}
#undef __

View File

@ -18,136 +18,6 @@ namespace internal {
#define __ ACCESS_MASM(masm)
// Helper function used from LoadIC GenerateNormal.
//
// elements: Property dictionary. It is not clobbered if a jump to the miss
// label is done.
// name: Property name. It is not clobbered if a jump to the miss label is
// done
// result: Register for the result. It is only updated if a jump to the miss
// label is not done. Can be the same as elements or name clobbering
// one of these in the case of not jumping to the miss label.
// The two scratch registers need to be different from elements, name and
// result.
// The generated code assumes that the receiver has slow properties,
// is not a global object and does not have interceptors.
static void GenerateDictionaryLoad(MacroAssembler* masm, Label* miss,
Register elements, Register name,
Register result, Register scratch1,
Register scratch2) {
// Main use of the scratch registers.
// scratch1: Used as temporary and to hold the capacity of the property
// dictionary.
// scratch2: Used as temporary.
Label done;
// Probe the dictionary.
NameDictionaryLookupStub::GeneratePositiveLookup(masm, miss, &done, elements,
name, scratch1, scratch2);
// If probing finds an entry check that the value is a normal
// property.
__ bind(&done); // scratch2 == elements + 4 * index
const int kElementsStartOffset =
NameDictionary::kHeaderSize +
NameDictionary::kElementsStartIndex * kPointerSize;
const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize;
__ LoadP(scratch1, FieldMemOperand(scratch2, kDetailsOffset));
__ LoadRR(r0, scratch2);
__ LoadSmiLiteral(scratch2, Smi::FromInt(PropertyDetails::TypeField::kMask));
__ AndP(scratch2, scratch1);
__ bne(miss);
__ LoadRR(scratch2, r0);
// Get the value at the masked, scaled index and return.
__ LoadP(result,
FieldMemOperand(scratch2, kElementsStartOffset + 1 * kPointerSize));
}
// Helper function used from StoreIC::GenerateNormal.
//
// elements: Property dictionary. It is not clobbered if a jump to the miss
// label is done.
// name: Property name. It is not clobbered if a jump to the miss label is
// done
// value: The value to store.
// The two scratch registers need to be different from elements, name and
// result.
// The generated code assumes that the receiver has slow properties,
// is not a global object and does not have interceptors.
static void GenerateDictionaryStore(MacroAssembler* masm, Label* miss,
Register elements, Register name,
Register value, Register scratch1,
Register scratch2) {
// Main use of the scratch registers.
// scratch1: Used as temporary and to hold the capacity of the property
// dictionary.
// scratch2: Used as temporary.
Label done;
// Probe the dictionary.
NameDictionaryLookupStub::GeneratePositiveLookup(masm, miss, &done, elements,
name, scratch1, scratch2);
// If probing finds an entry in the dictionary check that the value
// is a normal property that is not read only.
__ bind(&done); // scratch2 == elements + 4 * index
const int kElementsStartOffset =
NameDictionary::kHeaderSize +
NameDictionary::kElementsStartIndex * kPointerSize;
const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize;
int kTypeAndReadOnlyMask =
PropertyDetails::TypeField::kMask |
PropertyDetails::AttributesField::encode(READ_ONLY);
__ LoadP(scratch1, FieldMemOperand(scratch2, kDetailsOffset));
__ LoadRR(r0, scratch2);
__ LoadSmiLiteral(scratch2, Smi::FromInt(kTypeAndReadOnlyMask));
__ AndP(scratch2, scratch1);
__ bne(miss /*, cr0*/);
__ LoadRR(scratch2, r0);
// Store the value at the masked, scaled index and return.
const int kValueOffset = kElementsStartOffset + kPointerSize;
__ AddP(scratch2, Operand(kValueOffset - kHeapObjectTag));
__ StoreP(value, MemOperand(scratch2));
// Update the write barrier. Make sure not to clobber the value.
__ LoadRR(scratch1, value);
__ RecordWrite(elements, scratch2, scratch1, kLRHasNotBeenSaved,
kDontSaveFPRegs);
}
void LoadIC::GenerateNormal(MacroAssembler* masm) {
Register dictionary = r2;
DCHECK(!dictionary.is(LoadDescriptor::ReceiverRegister()));
DCHECK(!dictionary.is(LoadDescriptor::NameRegister()));
Label slow;
__ LoadP(dictionary, FieldMemOperand(LoadDescriptor::ReceiverRegister(),
JSObject::kPropertiesOffset));
GenerateDictionaryLoad(masm, &slow, dictionary,
LoadDescriptor::NameRegister(), r2, r5, r6);
__ Ret();
// Dictionary load failed, go slow (but don't miss).
__ bind(&slow);
GenerateRuntimeGetProperty(masm);
}
// A register that isn't one of the parameters to the load ic.
static const Register LoadIC_TempRegister() { return r5; }
void LoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) {
// The return address is in lr.
__ LoadRR(LoadIC_TempRegister(), LoadDescriptor::ReceiverRegister());
__ Push(LoadIC_TempRegister(), LoadDescriptor::NameRegister());
// Do tail-call to runtime routine.
__ TailCallRuntime(Runtime::kGetProperty);
}
static void StoreIC_PushArgs(MacroAssembler* masm) {
__ Push(StoreWithVectorDescriptor::ValueRegister(),
StoreWithVectorDescriptor::SlotRegister(),
@ -170,37 +40,6 @@ void KeyedStoreIC::GenerateSlow(MacroAssembler* masm) {
__ TailCallRuntime(Runtime::kKeyedStoreIC_Slow);
}
void StoreIC::GenerateMiss(MacroAssembler* masm) {
StoreIC_PushArgs(masm);
// Perform tail call to the entry.
__ TailCallRuntime(Runtime::kStoreIC_Miss);
}
void StoreIC::GenerateNormal(MacroAssembler* masm) {
Label miss;
Register receiver = StoreDescriptor::ReceiverRegister();
Register name = StoreDescriptor::NameRegister();
Register value = StoreDescriptor::ValueRegister();
Register dictionary = r7;
DCHECK(receiver.is(r3));
DCHECK(name.is(r4));
DCHECK(value.is(r2));
DCHECK(StoreWithVectorDescriptor::VectorRegister().is(r5));
DCHECK(StoreWithVectorDescriptor::SlotRegister().is(r6));
__ LoadP(dictionary, FieldMemOperand(receiver, JSObject::kPropertiesOffset));
GenerateDictionaryStore(masm, &miss, dictionary, name, value, r8, r9);
Counters* counters = masm->isolate()->counters();
__ IncrementCounter(counters->ic_store_normal_hit(), 1, r8, r9);
__ Ret();
__ bind(&miss);
__ IncrementCounter(counters->ic_store_normal_miss(), 1, r8, r9);
GenerateMiss(masm);
}
#undef __
Condition CompareIC::ComputeCondition(Token::Value op) {

View File

@ -18,143 +18,6 @@ namespace internal {
#define __ ACCESS_MASM(masm)
// Helper function used to load a property from a dictionary backing storage.
// This function may return false negatives, so miss_label
// must always call a backup property load that is complete.
// This function is safe to call if name is not an internalized string,
// and will jump to the miss_label in that case.
// The generated code assumes that the receiver has slow properties,
// is not a global object and does not have interceptors.
static void GenerateDictionaryLoad(MacroAssembler* masm, Label* miss_label,
Register elements, Register name,
Register r0, Register r1, Register result) {
// Register use:
//
// elements - holds the property dictionary on entry and is unchanged.
//
// name - holds the name of the property on entry and is unchanged.
//
// r0 - used to hold the capacity of the property dictionary.
//
// r1 - used to hold the index into the property dictionary.
//
// result - holds the result on exit if the load succeeded.
Label done;
// Probe the dictionary.
NameDictionaryLookupStub::GeneratePositiveLookup(masm, miss_label, &done,
elements, name, r0, r1);
// If probing finds an entry in the dictionary, r1 contains the
// index into the dictionary. Check that the value is a normal
// property.
__ bind(&done);
const int kElementsStartOffset =
NameDictionary::kHeaderSize +
NameDictionary::kElementsStartIndex * kPointerSize;
const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize;
__ Test(Operand(elements, r1, times_pointer_size,
kDetailsOffset - kHeapObjectTag),
Smi::FromInt(PropertyDetails::TypeField::kMask));
__ j(not_zero, miss_label);
// Get the value at the masked, scaled index.
const int kValueOffset = kElementsStartOffset + kPointerSize;
__ movp(result, Operand(elements, r1, times_pointer_size,
kValueOffset - kHeapObjectTag));
}
// Helper function used to store a property to a dictionary backing
// storage. This function may fail to store a property even though it
// is in the dictionary, so code at miss_label must always call a
// backup property store that is complete. This function is safe to
// call if name is not an internalized string, and will jump to the miss_label
// in that case. The generated code assumes that the receiver has slow
// properties, is not a global object and does not have interceptors.
static void GenerateDictionaryStore(MacroAssembler* masm, Label* miss_label,
Register elements, Register name,
Register value, Register scratch0,
Register scratch1) {
// Register use:
//
// elements - holds the property dictionary on entry and is clobbered.
//
// name - holds the name of the property on entry and is unchanged.
//
// value - holds the value to store and is unchanged.
//
// scratch0 - used during the positive dictionary lookup and is clobbered.
//
// scratch1 - used for index into the property dictionary and is clobbered.
Label done;
// Probe the dictionary.
NameDictionaryLookupStub::GeneratePositiveLookup(
masm, miss_label, &done, elements, name, scratch0, scratch1);
// If probing finds an entry in the dictionary, scratch0 contains the
// index into the dictionary. Check that the value is a normal
// property that is not read only.
__ bind(&done);
const int kElementsStartOffset =
NameDictionary::kHeaderSize +
NameDictionary::kElementsStartIndex * kPointerSize;
const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize;
const int kTypeAndReadOnlyMask =
PropertyDetails::TypeField::kMask |
PropertyDetails::AttributesField::encode(READ_ONLY);
__ Test(Operand(elements, scratch1, times_pointer_size,
kDetailsOffset - kHeapObjectTag),
Smi::FromInt(kTypeAndReadOnlyMask));
__ j(not_zero, miss_label);
// Store the value at the masked, scaled index.
const int kValueOffset = kElementsStartOffset + kPointerSize;
__ leap(scratch1, Operand(elements, scratch1, times_pointer_size,
kValueOffset - kHeapObjectTag));
__ movp(Operand(scratch1, 0), value);
// Update write barrier. Make sure not to clobber the value.
__ movp(scratch0, value);
__ RecordWrite(elements, scratch1, scratch0, kDontSaveFPRegs);
}
void LoadIC::GenerateNormal(MacroAssembler* masm) {
Register dictionary = rax;
DCHECK(!dictionary.is(LoadDescriptor::ReceiverRegister()));
DCHECK(!dictionary.is(LoadDescriptor::NameRegister()));
Label slow;
__ movp(dictionary, FieldOperand(LoadDescriptor::ReceiverRegister(),
JSObject::kPropertiesOffset));
GenerateDictionaryLoad(masm, &slow, dictionary,
LoadDescriptor::NameRegister(), rbx, rdi, rax);
__ ret(0);
// Dictionary load failed, go slow (but don't miss).
__ bind(&slow);
LoadIC::GenerateRuntimeGetProperty(masm);
}
void LoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) {
// The return address is on the stack.
Register receiver = LoadDescriptor::ReceiverRegister();
Register name = LoadDescriptor::NameRegister();
DCHECK(!rbx.is(receiver) && !rbx.is(name));
__ PopReturnAddressTo(rbx);
__ Push(receiver);
__ Push(name);
__ PushReturnAddressFrom(rbx);
// Do tail-call to runtime routine.
__ TailCallRuntime(Runtime::kGetProperty);
}
static void StoreIC_PushArgs(MacroAssembler* masm) {
Register receiver = StoreWithVectorDescriptor::ReceiverRegister();
Register name = StoreWithVectorDescriptor::NameRegister();
@ -173,38 +36,6 @@ static void StoreIC_PushArgs(MacroAssembler* masm) {
__ PushReturnAddressFrom(temp);
}
void StoreIC::GenerateMiss(MacroAssembler* masm) {
// Return address is on the stack.
StoreIC_PushArgs(masm);
// Perform tail call to the entry.
__ TailCallRuntime(Runtime::kStoreIC_Miss);
}
void StoreIC::GenerateNormal(MacroAssembler* masm) {
Register receiver = StoreDescriptor::ReceiverRegister();
Register name = StoreDescriptor::NameRegister();
Register value = StoreDescriptor::ValueRegister();
Register dictionary = r11;
DCHECK(!AreAliased(dictionary, StoreWithVectorDescriptor::VectorRegister(),
StoreWithVectorDescriptor::SlotRegister()));
Label miss;
__ movp(dictionary, FieldOperand(receiver, JSObject::kPropertiesOffset));
GenerateDictionaryStore(masm, &miss, dictionary, name, value, r8, r9);
Counters* counters = masm->isolate()->counters();
__ IncrementCounter(counters->ic_store_normal_hit(), 1);
__ ret(0);
__ bind(&miss);
__ IncrementCounter(counters->ic_store_normal_miss(), 1);
GenerateMiss(masm);
}
void KeyedStoreIC::GenerateMiss(MacroAssembler* masm) {
// Return address is on the stack.
StoreIC_PushArgs(masm);

View File

@ -18,141 +18,6 @@ namespace internal {
#define __ ACCESS_MASM(masm)
// Helper function used to load a property from a dictionary backing
// storage. This function may fail to load a property even though it is
// in the dictionary, so code at miss_label must always call a backup
// property load that is complete. This function is safe to call if
// name is not internalized, and will jump to the miss_label in that
// case. The generated code assumes that the receiver has slow
// properties, is not a global object and does not have interceptors.
static void GenerateDictionaryLoad(MacroAssembler* masm, Label* miss_label,
Register elements, Register name,
Register r0, Register r1, Register result) {
// Register use:
//
// elements - holds the property dictionary on entry and is unchanged.
//
// name - holds the name of the property on entry and is unchanged.
//
// Scratch registers:
//
// r0 - used for the index into the property dictionary
//
// r1 - used to hold the capacity of the property dictionary.
//
// result - holds the result on exit.
Label done;
// Probe the dictionary.
NameDictionaryLookupStub::GeneratePositiveLookup(masm, miss_label, &done,
elements, name, r0, r1);
// If probing finds an entry in the dictionary, r0 contains the
// index into the dictionary. Check that the value is a normal
// property.
__ bind(&done);
const int kElementsStartOffset =
NameDictionary::kHeaderSize +
NameDictionary::kElementsStartIndex * kPointerSize;
const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize;
__ test(Operand(elements, r0, times_4, kDetailsOffset - kHeapObjectTag),
Immediate(PropertyDetails::TypeField::kMask << kSmiTagSize));
__ j(not_zero, miss_label);
// Get the value at the masked, scaled index.
const int kValueOffset = kElementsStartOffset + kPointerSize;
__ mov(result, Operand(elements, r0, times_4, kValueOffset - kHeapObjectTag));
}
// Helper function used to store a property to a dictionary backing
// storage. This function may fail to store a property eventhough it
// is in the dictionary, so code at miss_label must always call a
// backup property store that is complete. This function is safe to
// call if name is not internalized, and will jump to the miss_label in
// that case. The generated code assumes that the receiver has slow
// properties, is not a global object and does not have interceptors.
static void GenerateDictionaryStore(MacroAssembler* masm, Label* miss_label,
Register elements, Register name,
Register value, Register r0, Register r1) {
// Register use:
//
// elements - holds the property dictionary on entry and is clobbered.
//
// name - holds the name of the property on entry and is unchanged.
//
// value - holds the value to store and is unchanged.
//
// r0 - used for index into the property dictionary and is clobbered.
//
// r1 - used to hold the capacity of the property dictionary and is clobbered.
Label done;
// Probe the dictionary.
NameDictionaryLookupStub::GeneratePositiveLookup(masm, miss_label, &done,
elements, name, r0, r1);
// If probing finds an entry in the dictionary, r0 contains the
// index into the dictionary. Check that the value is a normal
// property that is not read only.
__ bind(&done);
const int kElementsStartOffset =
NameDictionary::kHeaderSize +
NameDictionary::kElementsStartIndex * kPointerSize;
const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize;
const int kTypeAndReadOnlyMask =
(PropertyDetails::TypeField::kMask |
PropertyDetails::AttributesField::encode(READ_ONLY))
<< kSmiTagSize;
__ test(Operand(elements, r0, times_4, kDetailsOffset - kHeapObjectTag),
Immediate(kTypeAndReadOnlyMask));
__ j(not_zero, miss_label);
// Store the value at the masked, scaled index.
const int kValueOffset = kElementsStartOffset + kPointerSize;
__ lea(r0, Operand(elements, r0, times_4, kValueOffset - kHeapObjectTag));
__ mov(Operand(r0, 0), value);
// Update write barrier. Make sure not to clobber the value.
__ mov(r1, value);
__ RecordWrite(elements, r0, r1, kDontSaveFPRegs);
}
void LoadIC::GenerateNormal(MacroAssembler* masm) {
Register dictionary = eax;
DCHECK(!dictionary.is(LoadDescriptor::ReceiverRegister()));
DCHECK(!dictionary.is(LoadDescriptor::NameRegister()));
Label slow;
__ mov(dictionary, FieldOperand(LoadDescriptor::ReceiverRegister(),
JSObject::kPropertiesOffset));
GenerateDictionaryLoad(masm, &slow, dictionary,
LoadDescriptor::NameRegister(), edi, ebx, eax);
__ ret(0);
// Dictionary load failed, go slow (but don't miss).
__ bind(&slow);
GenerateRuntimeGetProperty(masm);
}
void LoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) {
// Return address is on the stack.
Register receiver = LoadDescriptor::ReceiverRegister();
Register name = LoadDescriptor::NameRegister();
DCHECK(!ebx.is(receiver) && !ebx.is(name));
__ pop(ebx);
__ push(receiver);
__ push(name);
__ push(ebx);
// Do tail-call to runtime routine.
__ TailCallRuntime(Runtime::kGetProperty);
}
static void StoreIC_PushArgs(MacroAssembler* masm) {
Register receiver = StoreWithVectorDescriptor::ReceiverRegister();
Register name = StoreWithVectorDescriptor::NameRegister();
@ -171,50 +36,6 @@ static void StoreIC_PushArgs(MacroAssembler* masm) {
__ push(return_address);
}
void StoreIC::GenerateMiss(MacroAssembler* masm) {
// Return address is on the stack.
StoreIC_PushArgs(masm);
// Perform tail call to the entry.
__ TailCallRuntime(Runtime::kStoreIC_Miss);
}
void StoreIC::GenerateNormal(MacroAssembler* masm) {
typedef StoreWithVectorDescriptor Descriptor;
Label restore_miss;
Register receiver = Descriptor::ReceiverRegister();
Register name = Descriptor::NameRegister();
Register value = Descriptor::ValueRegister();
// Since the slot and vector values are passed on the stack we can use
// respective registers as scratch registers.
Register scratch1 = Descriptor::VectorRegister();
Register scratch2 = Descriptor::SlotRegister();
__ LoadParameterFromStack<Descriptor>(value, Descriptor::kValue);
// A lot of registers are needed for storing to slow case objects.
// Push and restore receiver but rely on GenerateDictionaryStore preserving
// the value and name.
__ push(receiver);
Register dictionary = receiver;
__ mov(dictionary, FieldOperand(receiver, JSObject::kPropertiesOffset));
GenerateDictionaryStore(masm, &restore_miss, dictionary, name, value,
scratch1, scratch2);
__ Drop(1);
Counters* counters = masm->isolate()->counters();
__ IncrementCounter(counters->ic_store_normal_hit(), 1);
__ ret(Descriptor::kStackArgumentsCount * kPointerSize);
__ bind(&restore_miss);
__ pop(receiver);
__ IncrementCounter(counters->ic_store_normal_miss(), 1);
GenerateMiss(masm);
}
void KeyedStoreIC::GenerateMiss(MacroAssembler* masm) {
// Return address is on the stack.
StoreIC_PushArgs(masm);

View File

@ -2843,85 +2843,6 @@ void NameDictionaryLookupStub::GenerateNegativeLookup(MacroAssembler* masm,
__ Branch(miss, ne, at, Operand(zero_reg));
}
// Probe the name dictionary in the |elements| register. Jump to the
// |done| label if a property with the given name is found. Jump to
// the |miss| label otherwise.
// If lookup was successful |scratch2| will be equal to elements + 4 * index.
void NameDictionaryLookupStub::GeneratePositiveLookup(MacroAssembler* masm,
Label* miss,
Label* done,
Register elements,
Register name,
Register scratch1,
Register scratch2) {
DCHECK(!elements.is(scratch1));
DCHECK(!elements.is(scratch2));
DCHECK(!name.is(scratch1));
DCHECK(!name.is(scratch2));
__ AssertName(name);
// Compute the capacity mask.
__ lw(scratch1, FieldMemOperand(elements, kCapacityOffset));
__ sra(scratch1, scratch1, kSmiTagSize); // convert smi to int
__ Subu(scratch1, scratch1, Operand(1));
// Generate an unrolled loop that performs a few probes before
// giving up. Measurements done on Gmail indicate that 2 probes
// cover ~93% of loads from dictionaries.
for (int i = 0; i < kInlinedProbes; i++) {
// Compute the masked index: (hash + i + i * i) & mask.
__ lw(scratch2, FieldMemOperand(name, Name::kHashFieldOffset));
if (i > 0) {
// Add the probe offset (i + i * i) left shifted to avoid right shifting
// the hash in a separate instruction. The value hash + i + i * i is right
// shifted in the following and instruction.
DCHECK(NameDictionary::GetProbeOffset(i) <
1 << (32 - Name::kHashFieldOffset));
__ Addu(scratch2, scratch2, Operand(
NameDictionary::GetProbeOffset(i) << Name::kHashShift));
}
__ srl(scratch2, scratch2, Name::kHashShift);
__ And(scratch2, scratch1, scratch2);
// Scale the index by multiplying by the element size.
STATIC_ASSERT(NameDictionary::kEntrySize == 3);
// scratch2 = scratch2 * 3.
__ Lsa(scratch2, scratch2, scratch2, 1);
// Check if the key is identical to the name.
__ Lsa(scratch2, elements, scratch2, 2);
__ lw(at, FieldMemOperand(scratch2, kElementsStartOffset));
__ Branch(done, eq, name, Operand(at));
}
const int spill_mask =
(ra.bit() | t2.bit() | t1.bit() | t0.bit() |
a3.bit() | a2.bit() | a1.bit() | a0.bit() | v0.bit()) &
~(scratch1.bit() | scratch2.bit());
__ MultiPush(spill_mask);
if (name.is(a0)) {
DCHECK(!elements.is(a1));
__ Move(a1, name);
__ Move(a0, elements);
} else {
__ Move(a0, elements);
__ Move(a1, name);
}
NameDictionaryLookupStub stub(masm->isolate(), POSITIVE_LOOKUP);
__ CallStub(&stub);
__ mov(scratch2, a2);
__ mov(at, v0);
__ MultiPop(spill_mask);
__ Branch(done, ne, at, Operand(zero_reg));
__ Branch(miss, eq, at, Operand(zero_reg));
}
void NameDictionaryLookupStub::Generate(MacroAssembler* masm) {
// This stub overrides SometimesSetsUpAFrame() to return false. That means
// we cannot call anything that could cause a GC from this stub.

View File

@ -300,14 +300,6 @@ class NameDictionaryLookupStub: public PlatformCodeStub {
Handle<Name> name,
Register scratch0);
static void GeneratePositiveLookup(MacroAssembler* masm,
Label* miss,
Label* done,
Register elements,
Register name,
Register r0,
Register r1);
bool SometimesSetsUpAFrame() override { return false; }
private:

View File

@ -2847,84 +2847,6 @@ void NameDictionaryLookupStub::GenerateNegativeLookup(MacroAssembler* masm,
__ Branch(miss, ne, at, Operand(zero_reg));
}
// Probe the name dictionary in the |elements| register. Jump to the
// |done| label if a property with the given name is found. Jump to
// the |miss| label otherwise.
// If lookup was successful |scratch2| will be equal to elements + 4 * index.
void NameDictionaryLookupStub::GeneratePositiveLookup(MacroAssembler* masm,
Label* miss,
Label* done,
Register elements,
Register name,
Register scratch1,
Register scratch2) {
DCHECK(!elements.is(scratch1));
DCHECK(!elements.is(scratch2));
DCHECK(!name.is(scratch1));
DCHECK(!name.is(scratch2));
__ AssertName(name);
// Compute the capacity mask.
__ ld(scratch1, FieldMemOperand(elements, kCapacityOffset));
__ SmiUntag(scratch1);
__ Dsubu(scratch1, scratch1, Operand(1));
// Generate an unrolled loop that performs a few probes before
// giving up. Measurements done on Gmail indicate that 2 probes
// cover ~93% of loads from dictionaries.
for (int i = 0; i < kInlinedProbes; i++) {
// Compute the masked index: (hash + i + i * i) & mask.
__ lwu(scratch2, FieldMemOperand(name, Name::kHashFieldOffset));
if (i > 0) {
// Add the probe offset (i + i * i) left shifted to avoid right shifting
// the hash in a separate instruction. The value hash + i + i * i is right
// shifted in the following and instruction.
DCHECK(NameDictionary::GetProbeOffset(i) <
1 << (32 - Name::kHashFieldOffset));
__ Daddu(scratch2, scratch2, Operand(
NameDictionary::GetProbeOffset(i) << Name::kHashShift));
}
__ dsrl(scratch2, scratch2, Name::kHashShift);
__ And(scratch2, scratch1, scratch2);
// Scale the index by multiplying by the entry size.
STATIC_ASSERT(NameDictionary::kEntrySize == 3);
// scratch2 = scratch2 * 3.
__ Dlsa(scratch2, scratch2, scratch2, 1);
// Check if the key is identical to the name.
__ Dlsa(scratch2, elements, scratch2, kPointerSizeLog2);
__ ld(at, FieldMemOperand(scratch2, kElementsStartOffset));
__ Branch(done, eq, name, Operand(at));
}
const int spill_mask =
(ra.bit() | a6.bit() | a5.bit() | a4.bit() |
a3.bit() | a2.bit() | a1.bit() | a0.bit() | v0.bit()) &
~(scratch1.bit() | scratch2.bit());
__ MultiPush(spill_mask);
if (name.is(a0)) {
DCHECK(!elements.is(a1));
__ Move(a1, name);
__ Move(a0, elements);
} else {
__ Move(a0, elements);
__ Move(a1, name);
}
NameDictionaryLookupStub stub(masm->isolate(), POSITIVE_LOOKUP);
__ CallStub(&stub);
__ mov(scratch2, a2);
__ mov(at, v0);
__ MultiPop(spill_mask);
__ Branch(done, ne, at, Operand(zero_reg));
__ Branch(miss, eq, at, Operand(zero_reg));
}
void NameDictionaryLookupStub::Generate(MacroAssembler* masm) {
// This stub overrides SometimesSetsUpAFrame() to return false. That means
// we cannot call anything that could cause a GC from this stub.

View File

@ -301,14 +301,6 @@ class NameDictionaryLookupStub: public PlatformCodeStub {
Handle<Name> name,
Register scratch0);
static void GeneratePositiveLookup(MacroAssembler* masm,
Label* miss,
Label* done,
Register elements,
Register name,
Register r0,
Register r1);
bool SometimesSetsUpAFrame() override { return false; }
private:

View File

@ -2803,84 +2803,6 @@ void NameDictionaryLookupStub::GenerateNegativeLookup(
__ bne(miss);
}
// Probe the name dictionary in the |elements| register. Jump to the
// |done| label if a property with the given name is found. Jump to
// the |miss| label otherwise.
// If lookup was successful |scratch2| will be equal to elements + 4 * index.
void NameDictionaryLookupStub::GeneratePositiveLookup(
MacroAssembler* masm, Label* miss, Label* done, Register elements,
Register name, Register scratch1, Register scratch2) {
DCHECK(!elements.is(scratch1));
DCHECK(!elements.is(scratch2));
DCHECK(!name.is(scratch1));
DCHECK(!name.is(scratch2));
__ AssertName(name);
// Compute the capacity mask.
__ LoadP(scratch1, FieldMemOperand(elements, kCapacityOffset));
__ SmiUntag(scratch1); // convert smi to int
__ subi(scratch1, scratch1, Operand(1));
// Generate an unrolled loop that performs a few probes before
// giving up. Measurements done on Gmail indicate that 2 probes
// cover ~93% of loads from dictionaries.
for (int i = 0; i < kInlinedProbes; i++) {
// Compute the masked index: (hash + i + i * i) & mask.
__ lwz(scratch2, FieldMemOperand(name, Name::kHashFieldOffset));
if (i > 0) {
// Add the probe offset (i + i * i) left shifted to avoid right shifting
// the hash in a separate instruction. The value hash + i + i * i is right
// shifted in the following and instruction.
DCHECK(NameDictionary::GetProbeOffset(i) <
1 << (32 - Name::kHashFieldOffset));
__ addi(scratch2, scratch2,
Operand(NameDictionary::GetProbeOffset(i) << Name::kHashShift));
}
__ srwi(scratch2, scratch2, Operand(Name::kHashShift));
__ and_(scratch2, scratch1, scratch2);
// Scale the index by multiplying by the entry size.
STATIC_ASSERT(NameDictionary::kEntrySize == 3);
// scratch2 = scratch2 * 3.
__ ShiftLeftImm(ip, scratch2, Operand(1));
__ add(scratch2, scratch2, ip);
// Check if the key is identical to the name.
__ ShiftLeftImm(ip, scratch2, Operand(kPointerSizeLog2));
__ add(scratch2, elements, ip);
__ LoadP(ip, FieldMemOperand(scratch2, kElementsStartOffset));
__ cmp(name, ip);
__ beq(done);
}
const int spill_mask = (r0.bit() | r9.bit() | r8.bit() | r7.bit() | r6.bit() |
r5.bit() | r4.bit() | r3.bit()) &
~(scratch1.bit() | scratch2.bit());
__ mflr(r0);
__ MultiPush(spill_mask);
if (name.is(r3)) {
DCHECK(!elements.is(r4));
__ mr(r4, name);
__ mr(r3, elements);
} else {
__ mr(r3, elements);
__ mr(r4, name);
}
NameDictionaryLookupStub stub(masm->isolate(), POSITIVE_LOOKUP);
__ CallStub(&stub);
__ cmpi(r3, Operand::Zero());
__ mr(scratch2, r5);
__ MultiPop(spill_mask);
__ mtlr(r0);
__ bne(done);
__ beq(miss);
}
void NameDictionaryLookupStub::Generate(MacroAssembler* masm) {
// This stub overrides SometimesSetsUpAFrame() to return false. That means
// we cannot call anything that could cause a GC from this stub.

View File

@ -288,10 +288,6 @@ class NameDictionaryLookupStub : public PlatformCodeStub {
Register properties, Handle<Name> name,
Register scratch0);
static void GeneratePositiveLookup(MacroAssembler* masm, Label* miss,
Label* done, Register elements,
Register name, Register r0, Register r1);
bool SometimesSetsUpAFrame() override { return false; }
private:

View File

@ -2754,83 +2754,6 @@ void NameDictionaryLookupStub::GenerateNegativeLookup(
__ bne(miss);
}
// Probe the name dictionary in the |elements| register. Jump to the
// |done| label if a property with the given name is found. Jump to
// the |miss| label otherwise.
// If lookup was successful |scratch2| will be equal to elements + 4 * index.
void NameDictionaryLookupStub::GeneratePositiveLookup(
MacroAssembler* masm, Label* miss, Label* done, Register elements,
Register name, Register scratch1, Register scratch2) {
DCHECK(!elements.is(scratch1));
DCHECK(!elements.is(scratch2));
DCHECK(!name.is(scratch1));
DCHECK(!name.is(scratch2));
__ AssertName(name);
// Compute the capacity mask.
__ LoadP(scratch1, FieldMemOperand(elements, kCapacityOffset));
__ SmiUntag(scratch1); // convert smi to int
__ SubP(scratch1, Operand(1));
// Generate an unrolled loop that performs a few probes before
// giving up. Measurements done on Gmail indicate that 2 probes
// cover ~93% of loads from dictionaries.
for (int i = 0; i < kInlinedProbes; i++) {
// Compute the masked index: (hash + i + i * i) & mask.
__ LoadlW(scratch2, FieldMemOperand(name, String::kHashFieldOffset));
if (i > 0) {
// Add the probe offset (i + i * i) left shifted to avoid right shifting
// the hash in a separate instruction. The value hash + i + i * i is right
// shifted in the following and instruction.
DCHECK(NameDictionary::GetProbeOffset(i) <
1 << (32 - Name::kHashFieldOffset));
__ AddP(scratch2,
Operand(NameDictionary::GetProbeOffset(i) << Name::kHashShift));
}
__ srl(scratch2, Operand(String::kHashShift));
__ AndP(scratch2, scratch1);
// Scale the index by multiplying by the entry size.
STATIC_ASSERT(NameDictionary::kEntrySize == 3);
// scratch2 = scratch2 * 3.
__ ShiftLeftP(ip, scratch2, Operand(1));
__ AddP(scratch2, ip);
// Check if the key is identical to the name.
__ ShiftLeftP(ip, scratch2, Operand(kPointerSizeLog2));
__ AddP(scratch2, elements, ip);
__ LoadP(ip, FieldMemOperand(scratch2, kElementsStartOffset));
__ CmpP(name, ip);
__ beq(done);
}
const int spill_mask = (r0.bit() | r8.bit() | r7.bit() | r6.bit() | r5.bit() |
r4.bit() | r3.bit() | r2.bit()) &
~(scratch1.bit() | scratch2.bit());
__ LoadRR(r0, r14);
__ MultiPush(spill_mask);
if (name.is(r2)) {
DCHECK(!elements.is(r3));
__ LoadRR(r3, name);
__ LoadRR(r2, elements);
} else {
__ LoadRR(r2, elements);
__ LoadRR(r3, name);
}
NameDictionaryLookupStub stub(masm->isolate(), POSITIVE_LOOKUP);
__ CallStub(&stub);
__ LoadRR(r1, r2);
__ LoadRR(scratch2, r4);
__ MultiPop(spill_mask);
__ LoadRR(r14, r0);
__ CmpP(r1, Operand::Zero());
__ bne(done);
__ beq(miss);
}
void NameDictionaryLookupStub::Generate(MacroAssembler* masm) {
// This stub overrides SometimesSetsUpAFrame() to return false. That means
// we cannot call anything that could cause a GC from this stub.

View File

@ -312,10 +312,6 @@ class NameDictionaryLookupStub : public PlatformCodeStub {
Register properties, Handle<Name> name,
Register scratch0);
static void GeneratePositiveLookup(MacroAssembler* masm, Label* miss,
Label* done, Register elements,
Register name, Register r0, Register r1);
bool SometimesSetsUpAFrame() override { return false; }
private:

View File

@ -2584,61 +2584,6 @@ void NameDictionaryLookupStub::GenerateNegativeLookup(MacroAssembler* masm,
__ jmp(done);
}
// Probe the name dictionary in the |elements| register. Jump to the
// |done| label if a property with the given name is found leaving the
// index into the dictionary in |r1|. Jump to the |miss| label
// otherwise.
void NameDictionaryLookupStub::GeneratePositiveLookup(MacroAssembler* masm,
Label* miss,
Label* done,
Register elements,
Register name,
Register r0,
Register r1) {
DCHECK(!elements.is(r0));
DCHECK(!elements.is(r1));
DCHECK(!name.is(r0));
DCHECK(!name.is(r1));
__ AssertName(name);
__ SmiToInteger32(r0, FieldOperand(elements, kCapacityOffset));
__ decl(r0);
for (int i = 0; i < kInlinedProbes; i++) {
// Compute the masked index: (hash + i + i * i) & mask.
__ movl(r1, FieldOperand(name, Name::kHashFieldOffset));
__ shrl(r1, Immediate(Name::kHashShift));
if (i > 0) {
__ addl(r1, Immediate(NameDictionary::GetProbeOffset(i)));
}
__ andp(r1, r0);
// Scale the index by multiplying by the entry size.
STATIC_ASSERT(NameDictionary::kEntrySize == 3);
__ leap(r1, Operand(r1, r1, times_2, 0)); // r1 = r1 * 3
// Check if the key is identical to the name.
__ cmpp(name, Operand(elements, r1, times_pointer_size,
kElementsStartOffset - kHeapObjectTag));
__ j(equal, done);
}
NameDictionaryLookupStub stub(masm->isolate(), elements, r0, r1,
POSITIVE_LOOKUP);
__ Push(name);
__ movl(r0, FieldOperand(name, Name::kHashFieldOffset));
__ shrl(r0, Immediate(Name::kHashShift));
__ Push(r0);
__ CallStub(&stub);
__ testp(r0, r0);
__ j(zero, miss);
__ jmp(done);
}
void NameDictionaryLookupStub::Generate(MacroAssembler* masm) {
// This stub overrides SometimesSetsUpAFrame() to return false. That means
// we cannot call anything that could cause a GC from this stub.

View File

@ -54,14 +54,6 @@ class NameDictionaryLookupStub: public PlatformCodeStub {
Handle<Name> name,
Register r0);
static void GeneratePositiveLookup(MacroAssembler* masm,
Label* miss,
Label* done,
Register elements,
Register name,
Register r0,
Register r1);
bool SometimesSetsUpAFrame() override { return false; }
private:

View File

@ -2462,67 +2462,6 @@ void NameDictionaryLookupStub::GenerateNegativeLookup(MacroAssembler* masm,
__ jmp(done);
}
// Probe the name dictionary in the |elements| register. Jump to the
// |done| label if a property with the given name is found leaving the
// index into the dictionary in |r0|. Jump to the |miss| label
// otherwise.
void NameDictionaryLookupStub::GeneratePositiveLookup(MacroAssembler* masm,
Label* miss,
Label* done,
Register elements,
Register name,
Register r0,
Register r1) {
DCHECK(!elements.is(r0));
DCHECK(!elements.is(r1));
DCHECK(!name.is(r0));
DCHECK(!name.is(r1));
__ AssertName(name);
__ mov(r1, FieldOperand(elements, kCapacityOffset));
__ shr(r1, kSmiTagSize); // convert smi to int
__ dec(r1);
// Generate an unrolled loop that performs a few probes before
// giving up. Measurements done on Gmail indicate that 2 probes
// cover ~93% of loads from dictionaries.
for (int i = 0; i < kInlinedProbes; i++) {
// Compute the masked index: (hash + i + i * i) & mask.
__ mov(r0, FieldOperand(name, Name::kHashFieldOffset));
__ shr(r0, Name::kHashShift);
if (i > 0) {
__ add(r0, Immediate(NameDictionary::GetProbeOffset(i)));
}
__ and_(r0, r1);
// Scale the index by multiplying by the entry size.
STATIC_ASSERT(NameDictionary::kEntrySize == 3);
__ lea(r0, Operand(r0, r0, times_2, 0)); // r0 = r0 * 3
// Check if the key is identical to the name.
__ cmp(name, Operand(elements,
r0,
times_4,
kElementsStartOffset - kHeapObjectTag));
__ j(equal, done);
}
NameDictionaryLookupStub stub(masm->isolate(), elements, r1, r0,
POSITIVE_LOOKUP);
__ push(name);
__ mov(r0, FieldOperand(name, Name::kHashFieldOffset));
__ shr(r0, Name::kHashShift);
__ push(r0);
__ CallStub(&stub);
__ test(r1, r1);
__ j(zero, miss);
__ jmp(done);
}
void NameDictionaryLookupStub::Generate(MacroAssembler* masm) {
// This stub overrides SometimesSetsUpAFrame() to return false. That means
// we cannot call anything that could cause a GC from this stub.

View File

@ -58,14 +58,6 @@ class NameDictionaryLookupStub: public PlatformCodeStub {
Handle<Name> name,
Register r0);
static void GeneratePositiveLookup(MacroAssembler* masm,
Label* miss,
Label* done,
Register elements,
Register name,
Register r0,
Register r1);
bool SometimesSetsUpAFrame() override { return false; }
private: