aboutsummaryrefslogtreecommitdiff
path: root/src/ic/mips/ic-mips.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/ic/mips/ic-mips.cc')
-rw-r--r--src/ic/mips/ic-mips.cc520
1 files changed, 1 insertions, 519 deletions
diff --git a/src/ic/mips/ic-mips.cc b/src/ic/mips/ic-mips.cc
index 561c9d33..fd39972f 100644
--- a/src/ic/mips/ic-mips.cc
+++ b/src/ic/mips/ic-mips.cc
@@ -6,528 +6,12 @@
#include "src/codegen.h"
#include "src/ic/ic.h"
-#include "src/ic/ic-compiler.h"
#include "src/ic/stub-cache.h"
namespace v8 {
namespace internal {
-// ----------------------------------------------------------------------------
-// Static IC stub generators.
-//
-
-#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; }
-
-
-static void LoadIC_PushArgs(MacroAssembler* masm) {
- Register receiver = LoadDescriptor::ReceiverRegister();
- Register name = LoadDescriptor::NameRegister();
- Register slot = LoadDescriptor::SlotRegister();
- Register vector = LoadWithVectorDescriptor::VectorRegister();
-
- __ Push(receiver, name, slot, vector);
-}
-
-
-void LoadIC::GenerateMiss(MacroAssembler* masm) {
- // The return address is in ra.
- Isolate* isolate = masm->isolate();
-
- DCHECK(!AreAliased(t0, t1, LoadWithVectorDescriptor::SlotRegister(),
- LoadWithVectorDescriptor::VectorRegister()));
- __ IncrementCounter(isolate->counters()->ic_load_miss(), 1, t0, t1);
-
- LoadIC_PushArgs(masm);
-
- // Perform tail call to the entry.
- __ TailCallRuntime(Runtime::kLoadIC_Miss);
-}
-
-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);
-}
-
-
-void KeyedLoadIC::GenerateMiss(MacroAssembler* masm) {
- // The return address is in ra.
- Isolate* isolate = masm->isolate();
-
- DCHECK(!AreAliased(t0, t1, LoadWithVectorDescriptor::SlotRegister(),
- LoadWithVectorDescriptor::VectorRegister()));
- __ IncrementCounter(isolate->counters()->ic_keyed_load_miss(), 1, t0, t1);
-
- LoadIC_PushArgs(masm);
-
- // Perform tail call to the entry.
- __ TailCallRuntime(Runtime::kKeyedLoadIC_Miss);
-}
-
-void KeyedLoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) {
- // The return address is in ra.
-
- __ Push(LoadDescriptor::ReceiverRegister(), LoadDescriptor::NameRegister());
-
- // Do tail-call to runtime routine.
- __ TailCallRuntime(Runtime::kKeyedGetProperty);
-}
-
-static void KeyedStoreGenerateMegamorphicHelper(
- MacroAssembler* masm, Label* fast_object, Label* fast_double, Label* slow,
- KeyedStoreCheckMap check_map, KeyedStoreIncrementLength increment_length,
- Register value, Register key, Register receiver, Register receiver_map,
- Register elements_map, Register elements) {
- Label transition_smi_elements;
- Label finish_object_store, non_double_value, transition_double_elements;
- Label fast_double_without_map_check;
-
- // Fast case: Do the store, could be either Object or double.
- __ bind(fast_object);
- Register scratch = t0;
- Register scratch2 = t4;
- Register scratch3 = t5;
- Register address = t1;
- DCHECK(!AreAliased(value, key, receiver, receiver_map, elements_map, elements,
- scratch, scratch2, scratch3, address));
-
- if (check_map == kCheckMap) {
- __ lw(elements_map, FieldMemOperand(elements, HeapObject::kMapOffset));
- __ Branch(fast_double, ne, elements_map,
- Operand(masm->isolate()->factory()->fixed_array_map()));
- }
-
- // HOLECHECK: guards "A[i] = V"
- // We have to go to the runtime if the current value is the hole because
- // there may be a callback on the element.
- Label holecheck_passed1;
- __ Addu(address, elements, FixedArray::kHeaderSize - kHeapObjectTag);
- __ Lsa(address, address, key, kPointerSizeLog2 - kSmiTagSize);
- __ lw(scratch, MemOperand(address));
- __ Branch(&holecheck_passed1, ne, scratch,
- Operand(masm->isolate()->factory()->the_hole_value()));
- __ JumpIfDictionaryInPrototypeChain(receiver, elements_map, scratch, slow);
-
- __ bind(&holecheck_passed1);
-
- // Smi stores don't require further checks.
- Label non_smi_value;
- __ JumpIfNotSmi(value, &non_smi_value);
-
- if (increment_length == kIncrementLength) {
- // Add 1 to receiver->length.
- __ Addu(scratch, key, Operand(Smi::FromInt(1)));
- __ sw(scratch, FieldMemOperand(receiver, JSArray::kLengthOffset));
- }
- // It's irrelevant whether array is smi-only or not when writing a smi.
- __ Addu(address, elements, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
- __ Lsa(address, address, key, kPointerSizeLog2 - kSmiTagSize);
- __ sw(value, MemOperand(address));
- __ Ret(USE_DELAY_SLOT);
- __ Move(v0, value); // Ensure the stub returns correct value.
-
- __ bind(&non_smi_value);
- // Escape to elements kind transition case.
- __ CheckFastObjectElements(receiver_map, scratch, &transition_smi_elements);
-
- // Fast elements array, store the value to the elements backing store.
- __ bind(&finish_object_store);
- if (increment_length == kIncrementLength) {
- // Add 1 to receiver->length.
- __ Addu(scratch, key, Operand(Smi::FromInt(1)));
- __ sw(scratch, FieldMemOperand(receiver, JSArray::kLengthOffset));
- }
- __ Addu(address, elements, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
- __ Lsa(address, address, key, kPointerSizeLog2 - kSmiTagSize);
- __ sw(value, MemOperand(address));
- // Update write barrier for the elements array address.
- __ mov(scratch, value); // Preserve the value which is returned.
- __ RecordWrite(elements, address, scratch, kRAHasNotBeenSaved,
- kDontSaveFPRegs, EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
- __ Ret(USE_DELAY_SLOT);
- __ Move(v0, value); // Ensure the stub returns correct value.
-
- __ bind(fast_double);
- if (check_map == kCheckMap) {
- // Check for fast double array case. If this fails, call through to the
- // runtime.
- __ LoadRoot(at, Heap::kFixedDoubleArrayMapRootIndex);
- __ Branch(slow, ne, elements_map, Operand(at));
- }
-
- // HOLECHECK: guards "A[i] double hole?"
- // We have to see if the double version of the hole is present. If so
- // go to the runtime.
- __ Addu(address, elements, Operand(FixedDoubleArray::kHeaderSize +
- kHoleNanUpper32Offset - kHeapObjectTag));
- __ Lsa(address, address, key, kPointerSizeLog2);
- __ lw(scratch, MemOperand(address));
- __ Branch(&fast_double_without_map_check, ne, scratch,
- Operand(kHoleNanUpper32));
- __ JumpIfDictionaryInPrototypeChain(receiver, elements_map, scratch, slow);
-
- __ bind(&fast_double_without_map_check);
- __ StoreNumberToDoubleElements(value, key, elements, scratch, scratch2,
- scratch3, &transition_double_elements);
- if (increment_length == kIncrementLength) {
- // Add 1 to receiver->length.
- __ Addu(scratch, key, Operand(Smi::FromInt(1)));
- __ sw(scratch, FieldMemOperand(receiver, JSArray::kLengthOffset));
- }
- __ Ret(USE_DELAY_SLOT);
- __ Move(v0, value); // Ensure the stub returns correct value.
-
- __ bind(&transition_smi_elements);
- // Transition the array appropriately depending on the value type.
- __ lw(scratch, FieldMemOperand(value, HeapObject::kMapOffset));
- __ LoadRoot(at, Heap::kHeapNumberMapRootIndex);
- __ Branch(&non_double_value, ne, scratch, Operand(at));
-
- // Value is a double. Transition FAST_SMI_ELEMENTS ->
- // FAST_DOUBLE_ELEMENTS and complete the store.
- __ LoadTransitionedArrayMapConditional(
- FAST_SMI_ELEMENTS, FAST_DOUBLE_ELEMENTS, receiver_map, scratch, slow);
- AllocationSiteMode mode =
- AllocationSite::GetMode(FAST_SMI_ELEMENTS, FAST_DOUBLE_ELEMENTS);
- ElementsTransitionGenerator::GenerateSmiToDouble(masm, receiver, key, value,
- receiver_map, mode, slow);
- __ lw(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
- __ jmp(&fast_double_without_map_check);
-
- __ bind(&non_double_value);
- // Value is not a double, FAST_SMI_ELEMENTS -> FAST_ELEMENTS
- __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS, FAST_ELEMENTS,
- receiver_map, scratch, slow);
- mode = AllocationSite::GetMode(FAST_SMI_ELEMENTS, FAST_ELEMENTS);
- ElementsTransitionGenerator::GenerateMapChangeElementsTransition(
- masm, receiver, key, value, receiver_map, mode, slow);
- __ lw(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
- __ jmp(&finish_object_store);
-
- __ bind(&transition_double_elements);
- // Elements are FAST_DOUBLE_ELEMENTS, but value is an Object that's not a
- // HeapNumber. Make sure that the receiver is a Array with FAST_ELEMENTS and
- // transition array from FAST_DOUBLE_ELEMENTS to FAST_ELEMENTS
- __ LoadTransitionedArrayMapConditional(FAST_DOUBLE_ELEMENTS, FAST_ELEMENTS,
- receiver_map, scratch, slow);
- mode = AllocationSite::GetMode(FAST_DOUBLE_ELEMENTS, FAST_ELEMENTS);
- ElementsTransitionGenerator::GenerateDoubleToObject(
- masm, receiver, key, value, receiver_map, mode, slow);
- __ lw(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
- __ jmp(&finish_object_store);
-}
-
-
-void KeyedStoreIC::GenerateMegamorphic(MacroAssembler* masm,
- LanguageMode language_mode) {
- // ---------- S t a t e --------------
- // -- a0 : value
- // -- a1 : key
- // -- a2 : receiver
- // -- ra : return address
- // -----------------------------------
- Label slow, fast_object, fast_object_grow;
- Label fast_double, fast_double_grow;
- Label array, extra, check_if_double_array, maybe_name_key, miss;
-
- // Register usage.
- Register value = StoreDescriptor::ValueRegister();
- Register key = StoreDescriptor::NameRegister();
- Register receiver = StoreDescriptor::ReceiverRegister();
- DCHECK(value.is(a0));
- Register receiver_map = a3;
- Register elements_map = t2;
- Register elements = t3; // Elements array of the receiver.
- // t0 and t1 are used as general scratch registers.
-
- // Check that the key is a smi.
- __ JumpIfNotSmi(key, &maybe_name_key);
- // Check that the object isn't a smi.
- __ JumpIfSmi(receiver, &slow);
- // Get the map of the object.
- __ lw(receiver_map, FieldMemOperand(receiver, HeapObject::kMapOffset));
- // Check that the receiver does not require access checks.
- // The generic stub does not perform map checks.
- __ lbu(t0, FieldMemOperand(receiver_map, Map::kBitFieldOffset));
- __ And(t0, t0, Operand(1 << Map::kIsAccessCheckNeeded));
- __ Branch(&slow, ne, t0, Operand(zero_reg));
- // Check if the object is a JS array or not.
- __ lbu(t0, FieldMemOperand(receiver_map, Map::kInstanceTypeOffset));
- __ Branch(&array, eq, t0, Operand(JS_ARRAY_TYPE));
- // Check that the object is some kind of JS object EXCEPT JS Value type. In
- // the case that the object is a value-wrapper object, we enter the runtime
- // system to make sure that indexing into string objects works as intended.
- STATIC_ASSERT(JS_VALUE_TYPE < JS_OBJECT_TYPE);
- __ Branch(&slow, lo, t0, Operand(JS_OBJECT_TYPE));
-
- // Object case: Check key against length in the elements array.
- __ lw(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
- // Check array bounds. Both the key and the length of FixedArray are smis.
- __ lw(t0, FieldMemOperand(elements, FixedArray::kLengthOffset));
- __ Branch(&fast_object, lo, key, Operand(t0));
-
- // Slow case, handle jump to runtime.
- __ bind(&slow);
- // Entry registers are intact.
- // a0: value.
- // a1: key.
- // a2: receiver.
- PropertyICCompiler::GenerateRuntimeSetProperty(masm, language_mode);
- // Never returns to here.
-
- __ bind(&maybe_name_key);
- __ lw(t0, FieldMemOperand(key, HeapObject::kMapOffset));
- __ lb(t0, FieldMemOperand(t0, Map::kInstanceTypeOffset));
- __ JumpIfNotUniqueNameInstanceType(t0, &slow);
-
- // The handlers in the stub cache expect a vector and slot. Since we won't
- // change the IC from any downstream misses, a dummy vector can be used.
- Register vector = StoreWithVectorDescriptor::VectorRegister();
- Register slot = StoreWithVectorDescriptor::SlotRegister();
- DCHECK(!AreAliased(vector, slot, t1, t2, t4, t5));
- Handle<TypeFeedbackVector> dummy_vector =
- TypeFeedbackVector::DummyVector(masm->isolate());
- int slot_index = dummy_vector->GetIndex(
- FeedbackVectorSlot(TypeFeedbackVector::kDummyKeyedStoreICSlot));
- __ LoadRoot(vector, Heap::kDummyVectorRootIndex);
- __ li(slot, Operand(Smi::FromInt(slot_index)));
-
- masm->isolate()->store_stub_cache()->GenerateProbe(masm, receiver, key, t1,
- t2, t4, t5);
- // Cache miss.
- __ Branch(&miss);
-
- // Extra capacity case: Check if there is extra capacity to
- // perform the store and update the length. Used for adding one
- // element to the array by writing to array[array.length].
- __ bind(&extra);
- // Condition code from comparing key and array length is still available.
- // Only support writing to array[array.length].
- __ Branch(&slow, ne, key, Operand(t0));
- // Check for room in the elements backing store.
- // Both the key and the length of FixedArray are smis.
- __ lw(t0, FieldMemOperand(elements, FixedArray::kLengthOffset));
- __ Branch(&slow, hs, key, Operand(t0));
- __ lw(elements_map, FieldMemOperand(elements, HeapObject::kMapOffset));
- __ Branch(&check_if_double_array, ne, elements_map,
- Heap::kFixedArrayMapRootIndex);
-
- __ jmp(&fast_object_grow);
-
- __ bind(&check_if_double_array);
- __ Branch(&slow, ne, elements_map, Heap::kFixedDoubleArrayMapRootIndex);
- __ jmp(&fast_double_grow);
-
- // Array case: Get the length and the elements array from the JS
- // array. Check that the array is in fast mode (and writable); if it
- // is the length is always a smi.
- __ bind(&array);
- __ lw(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
-
- // Check the key against the length in the array.
- __ lw(t0, FieldMemOperand(receiver, JSArray::kLengthOffset));
- __ Branch(&extra, hs, key, Operand(t0));
-
- KeyedStoreGenerateMegamorphicHelper(
- masm, &fast_object, &fast_double, &slow, kCheckMap, kDontIncrementLength,
- value, key, receiver, receiver_map, elements_map, elements);
- KeyedStoreGenerateMegamorphicHelper(masm, &fast_object_grow,
- &fast_double_grow, &slow, kDontCheckMap,
- kIncrementLength, value, key, receiver,
- receiver_map, elements_map, elements);
-
- __ bind(&miss);
- GenerateMiss(masm);
-}
-
-
-static void StoreIC_PushArgs(MacroAssembler* masm) {
- __ Push(StoreWithVectorDescriptor::ValueRegister(),
- StoreWithVectorDescriptor::SlotRegister(),
- StoreWithVectorDescriptor::VectorRegister(),
- StoreWithVectorDescriptor::ReceiverRegister(),
- StoreWithVectorDescriptor::NameRegister());
-}
-
-
-void KeyedStoreIC::GenerateMiss(MacroAssembler* masm) {
- StoreIC_PushArgs(masm);
-
- __ TailCallRuntime(Runtime::kKeyedStoreIC_Miss);
-}
-
-void KeyedStoreIC::GenerateSlow(MacroAssembler* masm) {
- StoreIC_PushArgs(masm);
-
- // The slow case calls into the runtime to complete the store without causing
- // an IC miss that would otherwise cause a transition to the generic stub.
- __ 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 __
-
-
Condition CompareIC::ComputeCondition(Token::Value op) {
switch (op) {
case Token::EQ_STRICT:
@@ -585,9 +69,7 @@ void PatchInlinedSmiCode(Isolate* isolate, Address address,
}
if (FLAG_trace_ic) {
- PrintF("[ patching ic at %p, andi=%p, delta=%d\n",
- static_cast<void*>(address),
- static_cast<void*>(andi_instruction_address), delta);
+ LOG(isolate, PatchIC(address, andi_instruction_address, delta));
}
Address patch_address =