| OLD | NEW |
| 1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 the V8 project authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #if V8_TARGET_ARCH_X64 | 5 #if V8_TARGET_ARCH_X64 |
| 6 | 6 |
| 7 #include "src/codegen.h" | 7 #include "src/codegen.h" |
| 8 #include "src/ic/ic.h" | 8 #include "src/ic/ic.h" |
| 9 #include "src/ic/ic-compiler.h" | 9 #include "src/ic/ic-compiler.h" |
| 10 #include "src/ic/stub-cache.h" | 10 #include "src/ic/stub-cache.h" |
| 11 | 11 |
| 12 namespace v8 { | 12 namespace v8 { |
| 13 namespace internal { | 13 namespace internal { |
| 14 | 14 |
| 15 // ---------------------------------------------------------------------------- | 15 // ---------------------------------------------------------------------------- |
| 16 // Static IC stub generators. | 16 // Static IC stub generators. |
| 17 // | 17 // |
| 18 | 18 |
| 19 #define __ ACCESS_MASM(masm) | 19 #define __ ACCESS_MASM(masm) |
| 20 | 20 |
| 21 // Helper function used to load a property from a dictionary backing storage. | |
| 22 // This function may return false negatives, so miss_label | |
| 23 // must always call a backup property load that is complete. | |
| 24 // This function is safe to call if name is not an internalized string, | |
| 25 // and will jump to the miss_label in that case. | |
| 26 // The generated code assumes that the receiver has slow properties, | |
| 27 // is not a global object and does not have interceptors. | |
| 28 static void GenerateDictionaryLoad(MacroAssembler* masm, Label* miss_label, | |
| 29 Register elements, Register name, | |
| 30 Register r0, Register r1, Register result) { | |
| 31 // Register use: | |
| 32 // | |
| 33 // elements - holds the property dictionary on entry and is unchanged. | |
| 34 // | |
| 35 // name - holds the name of the property on entry and is unchanged. | |
| 36 // | |
| 37 // r0 - used to hold the capacity of the property dictionary. | |
| 38 // | |
| 39 // r1 - used to hold the index into the property dictionary. | |
| 40 // | |
| 41 // result - holds the result on exit if the load succeeded. | |
| 42 | |
| 43 Label done; | |
| 44 | |
| 45 // Probe the dictionary. | |
| 46 NameDictionaryLookupStub::GeneratePositiveLookup(masm, miss_label, &done, | |
| 47 elements, name, r0, r1); | |
| 48 | |
| 49 // If probing finds an entry in the dictionary, r1 contains the | |
| 50 // index into the dictionary. Check that the value is a normal | |
| 51 // property. | |
| 52 __ bind(&done); | |
| 53 const int kElementsStartOffset = | |
| 54 NameDictionary::kHeaderSize + | |
| 55 NameDictionary::kElementsStartIndex * kPointerSize; | |
| 56 const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize; | |
| 57 __ Test(Operand(elements, r1, times_pointer_size, | |
| 58 kDetailsOffset - kHeapObjectTag), | |
| 59 Smi::FromInt(PropertyDetails::TypeField::kMask)); | |
| 60 __ j(not_zero, miss_label); | |
| 61 | |
| 62 // Get the value at the masked, scaled index. | |
| 63 const int kValueOffset = kElementsStartOffset + kPointerSize; | |
| 64 __ movp(result, Operand(elements, r1, times_pointer_size, | |
| 65 kValueOffset - kHeapObjectTag)); | |
| 66 } | |
| 67 | |
| 68 | |
| 69 // Helper function used to store a property to a dictionary backing | |
| 70 // storage. This function may fail to store a property even though it | |
| 71 // is in the dictionary, so code at miss_label must always call a | |
| 72 // backup property store that is complete. This function is safe to | |
| 73 // call if name is not an internalized string, and will jump to the miss_label | |
| 74 // in that case. The generated code assumes that the receiver has slow | |
| 75 // properties, is not a global object and does not have interceptors. | |
| 76 static void GenerateDictionaryStore(MacroAssembler* masm, Label* miss_label, | |
| 77 Register elements, Register name, | |
| 78 Register value, Register scratch0, | |
| 79 Register scratch1) { | |
| 80 // Register use: | |
| 81 // | |
| 82 // elements - holds the property dictionary on entry and is clobbered. | |
| 83 // | |
| 84 // name - holds the name of the property on entry and is unchanged. | |
| 85 // | |
| 86 // value - holds the value to store and is unchanged. | |
| 87 // | |
| 88 // scratch0 - used during the positive dictionary lookup and is clobbered. | |
| 89 // | |
| 90 // scratch1 - used for index into the property dictionary and is clobbered. | |
| 91 Label done; | |
| 92 | |
| 93 // Probe the dictionary. | |
| 94 NameDictionaryLookupStub::GeneratePositiveLookup( | |
| 95 masm, miss_label, &done, elements, name, scratch0, scratch1); | |
| 96 | |
| 97 // If probing finds an entry in the dictionary, scratch0 contains the | |
| 98 // index into the dictionary. Check that the value is a normal | |
| 99 // property that is not read only. | |
| 100 __ bind(&done); | |
| 101 const int kElementsStartOffset = | |
| 102 NameDictionary::kHeaderSize + | |
| 103 NameDictionary::kElementsStartIndex * kPointerSize; | |
| 104 const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize; | |
| 105 const int kTypeAndReadOnlyMask = | |
| 106 PropertyDetails::TypeField::kMask | | |
| 107 PropertyDetails::AttributesField::encode(READ_ONLY); | |
| 108 __ Test(Operand(elements, scratch1, times_pointer_size, | |
| 109 kDetailsOffset - kHeapObjectTag), | |
| 110 Smi::FromInt(kTypeAndReadOnlyMask)); | |
| 111 __ j(not_zero, miss_label); | |
| 112 | |
| 113 // Store the value at the masked, scaled index. | |
| 114 const int kValueOffset = kElementsStartOffset + kPointerSize; | |
| 115 __ leap(scratch1, Operand(elements, scratch1, times_pointer_size, | |
| 116 kValueOffset - kHeapObjectTag)); | |
| 117 __ movp(Operand(scratch1, 0), value); | |
| 118 | |
| 119 // Update write barrier. Make sure not to clobber the value. | |
| 120 __ movp(scratch0, value); | |
| 121 __ RecordWrite(elements, scratch1, scratch0, kDontSaveFPRegs); | |
| 122 } | |
| 123 | |
| 124 void LoadIC::GenerateNormal(MacroAssembler* masm) { | |
| 125 Register dictionary = rax; | |
| 126 DCHECK(!dictionary.is(LoadDescriptor::ReceiverRegister())); | |
| 127 DCHECK(!dictionary.is(LoadDescriptor::NameRegister())); | |
| 128 | |
| 129 Label slow; | |
| 130 | |
| 131 __ movp(dictionary, FieldOperand(LoadDescriptor::ReceiverRegister(), | |
| 132 JSObject::kPropertiesOffset)); | |
| 133 GenerateDictionaryLoad(masm, &slow, dictionary, | |
| 134 LoadDescriptor::NameRegister(), rbx, rdi, rax); | |
| 135 __ ret(0); | |
| 136 | |
| 137 // Dictionary load failed, go slow (but don't miss). | |
| 138 __ bind(&slow); | |
| 139 LoadIC::GenerateRuntimeGetProperty(masm); | |
| 140 } | |
| 141 | |
| 142 void LoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) { | |
| 143 // The return address is on the stack. | |
| 144 Register receiver = LoadDescriptor::ReceiverRegister(); | |
| 145 Register name = LoadDescriptor::NameRegister(); | |
| 146 | |
| 147 DCHECK(!rbx.is(receiver) && !rbx.is(name)); | |
| 148 | |
| 149 __ PopReturnAddressTo(rbx); | |
| 150 __ Push(receiver); | |
| 151 __ Push(name); | |
| 152 __ PushReturnAddressFrom(rbx); | |
| 153 | |
| 154 // Do tail-call to runtime routine. | |
| 155 __ TailCallRuntime(Runtime::kGetProperty); | |
| 156 } | |
| 157 | |
| 158 static void StoreIC_PushArgs(MacroAssembler* masm) { | 21 static void StoreIC_PushArgs(MacroAssembler* masm) { |
| 159 Register receiver = StoreWithVectorDescriptor::ReceiverRegister(); | 22 Register receiver = StoreWithVectorDescriptor::ReceiverRegister(); |
| 160 Register name = StoreWithVectorDescriptor::NameRegister(); | 23 Register name = StoreWithVectorDescriptor::NameRegister(); |
| 161 Register value = StoreWithVectorDescriptor::ValueRegister(); | 24 Register value = StoreWithVectorDescriptor::ValueRegister(); |
| 162 Register slot = StoreWithVectorDescriptor::SlotRegister(); | 25 Register slot = StoreWithVectorDescriptor::SlotRegister(); |
| 163 Register vector = StoreWithVectorDescriptor::VectorRegister(); | 26 Register vector = StoreWithVectorDescriptor::VectorRegister(); |
| 164 Register temp = r11; | 27 Register temp = r11; |
| 165 DCHECK(!AreAliased(receiver, name, value, slot, vector, temp)); | 28 DCHECK(!AreAliased(receiver, name, value, slot, vector, temp)); |
| 166 | 29 |
| 167 __ PopReturnAddressTo(temp); | 30 __ PopReturnAddressTo(temp); |
| 168 __ Push(value); | 31 __ Push(value); |
| 169 __ Push(slot); | 32 __ Push(slot); |
| 170 __ Push(vector); | 33 __ Push(vector); |
| 171 __ Push(receiver); | 34 __ Push(receiver); |
| 172 __ Push(name); | 35 __ Push(name); |
| 173 __ PushReturnAddressFrom(temp); | 36 __ PushReturnAddressFrom(temp); |
| 174 } | 37 } |
| 175 | 38 |
| 176 | |
| 177 void StoreIC::GenerateMiss(MacroAssembler* masm) { | |
| 178 // Return address is on the stack. | |
| 179 StoreIC_PushArgs(masm); | |
| 180 | |
| 181 // Perform tail call to the entry. | |
| 182 __ TailCallRuntime(Runtime::kStoreIC_Miss); | |
| 183 } | |
| 184 | |
| 185 | |
| 186 void StoreIC::GenerateNormal(MacroAssembler* masm) { | |
| 187 Register receiver = StoreDescriptor::ReceiverRegister(); | |
| 188 Register name = StoreDescriptor::NameRegister(); | |
| 189 Register value = StoreDescriptor::ValueRegister(); | |
| 190 Register dictionary = r11; | |
| 191 DCHECK(!AreAliased(dictionary, StoreWithVectorDescriptor::VectorRegister(), | |
| 192 StoreWithVectorDescriptor::SlotRegister())); | |
| 193 | |
| 194 Label miss; | |
| 195 | |
| 196 __ movp(dictionary, FieldOperand(receiver, JSObject::kPropertiesOffset)); | |
| 197 GenerateDictionaryStore(masm, &miss, dictionary, name, value, r8, r9); | |
| 198 Counters* counters = masm->isolate()->counters(); | |
| 199 __ IncrementCounter(counters->ic_store_normal_hit(), 1); | |
| 200 __ ret(0); | |
| 201 | |
| 202 __ bind(&miss); | |
| 203 __ IncrementCounter(counters->ic_store_normal_miss(), 1); | |
| 204 GenerateMiss(masm); | |
| 205 } | |
| 206 | |
| 207 | |
| 208 void KeyedStoreIC::GenerateMiss(MacroAssembler* masm) { | 39 void KeyedStoreIC::GenerateMiss(MacroAssembler* masm) { |
| 209 // Return address is on the stack. | 40 // Return address is on the stack. |
| 210 StoreIC_PushArgs(masm); | 41 StoreIC_PushArgs(masm); |
| 211 | 42 |
| 212 // Do tail-call to runtime routine. | 43 // Do tail-call to runtime routine. |
| 213 __ TailCallRuntime(Runtime::kKeyedStoreIC_Miss); | 44 __ TailCallRuntime(Runtime::kKeyedStoreIC_Miss); |
| 214 } | 45 } |
| 215 | 46 |
| 216 void KeyedStoreIC::GenerateSlow(MacroAssembler* masm) { | 47 void KeyedStoreIC::GenerateSlow(MacroAssembler* masm) { |
| 217 // Return address is on the stack. | 48 // Return address is on the stack. |
| (...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 290 Condition cc = | 121 Condition cc = |
| 291 (check == ENABLE_INLINED_SMI_CHECK) | 122 (check == ENABLE_INLINED_SMI_CHECK) |
| 292 ? (*jmp_address == Assembler::kJncShortOpcode ? not_zero : zero) | 123 ? (*jmp_address == Assembler::kJncShortOpcode ? not_zero : zero) |
| 293 : (*jmp_address == Assembler::kJnzShortOpcode ? not_carry : carry); | 124 : (*jmp_address == Assembler::kJnzShortOpcode ? not_carry : carry); |
| 294 *jmp_address = static_cast<byte>(Assembler::kJccShortPrefix | cc); | 125 *jmp_address = static_cast<byte>(Assembler::kJccShortPrefix | cc); |
| 295 } | 126 } |
| 296 } // namespace internal | 127 } // namespace internal |
| 297 } // namespace v8 | 128 } // namespace v8 |
| 298 | 129 |
| 299 #endif // V8_TARGET_ARCH_X64 | 130 #endif // V8_TARGET_ARCH_X64 |
| OLD | NEW |