| 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_IA32 | 5 #if V8_TARGET_ARCH_IA32 |
| 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 | |
| 22 // storage. This function may fail to load a property even though it is | |
| 23 // in the dictionary, so code at miss_label must always call a backup | |
| 24 // property load that is complete. This function is safe to call if | |
| 25 // name is not internalized, and will jump to the miss_label in that | |
| 26 // case. The generated code assumes that the receiver has slow | |
| 27 // properties, 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 // Scratch registers: | |
| 38 // | |
| 39 // r0 - used for the index into the property dictionary | |
| 40 // | |
| 41 // r1 - used to hold the capacity of the property dictionary. | |
| 42 // | |
| 43 // result - holds the result on exit. | |
| 44 | |
| 45 Label done; | |
| 46 | |
| 47 // Probe the dictionary. | |
| 48 NameDictionaryLookupStub::GeneratePositiveLookup(masm, miss_label, &done, | |
| 49 elements, name, r0, r1); | |
| 50 | |
| 51 // If probing finds an entry in the dictionary, r0 contains the | |
| 52 // index into the dictionary. Check that the value is a normal | |
| 53 // property. | |
| 54 __ bind(&done); | |
| 55 const int kElementsStartOffset = | |
| 56 NameDictionary::kHeaderSize + | |
| 57 NameDictionary::kElementsStartIndex * kPointerSize; | |
| 58 const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize; | |
| 59 __ test(Operand(elements, r0, times_4, kDetailsOffset - kHeapObjectTag), | |
| 60 Immediate(PropertyDetails::TypeField::kMask << kSmiTagSize)); | |
| 61 __ j(not_zero, miss_label); | |
| 62 | |
| 63 // Get the value at the masked, scaled index. | |
| 64 const int kValueOffset = kElementsStartOffset + kPointerSize; | |
| 65 __ mov(result, Operand(elements, r0, times_4, 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 eventhough 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 internalized, and will jump to the miss_label in | |
| 74 // 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 r0, Register r1) { | |
| 79 // Register use: | |
| 80 // | |
| 81 // elements - holds the property dictionary on entry and is clobbered. | |
| 82 // | |
| 83 // name - holds the name of the property on entry and is unchanged. | |
| 84 // | |
| 85 // value - holds the value to store and is unchanged. | |
| 86 // | |
| 87 // r0 - used for index into the property dictionary and is clobbered. | |
| 88 // | |
| 89 // r1 - used to hold the capacity of the property dictionary and is clobbered. | |
| 90 Label done; | |
| 91 | |
| 92 | |
| 93 // Probe the dictionary. | |
| 94 NameDictionaryLookupStub::GeneratePositiveLookup(masm, miss_label, &done, | |
| 95 elements, name, r0, r1); | |
| 96 | |
| 97 // If probing finds an entry in the dictionary, r0 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 << kSmiTagSize; | |
| 109 __ test(Operand(elements, r0, times_4, kDetailsOffset - kHeapObjectTag), | |
| 110 Immediate(kTypeAndReadOnlyMask)); | |
| 111 __ j(not_zero, miss_label); | |
| 112 | |
| 113 // Store the value at the masked, scaled index. | |
| 114 const int kValueOffset = kElementsStartOffset + kPointerSize; | |
| 115 __ lea(r0, Operand(elements, r0, times_4, kValueOffset - kHeapObjectTag)); | |
| 116 __ mov(Operand(r0, 0), value); | |
| 117 | |
| 118 // Update write barrier. Make sure not to clobber the value. | |
| 119 __ mov(r1, value); | |
| 120 __ RecordWrite(elements, r0, r1, kDontSaveFPRegs); | |
| 121 } | |
| 122 | |
| 123 void LoadIC::GenerateNormal(MacroAssembler* masm) { | |
| 124 Register dictionary = eax; | |
| 125 DCHECK(!dictionary.is(LoadDescriptor::ReceiverRegister())); | |
| 126 DCHECK(!dictionary.is(LoadDescriptor::NameRegister())); | |
| 127 | |
| 128 Label slow; | |
| 129 | |
| 130 __ mov(dictionary, FieldOperand(LoadDescriptor::ReceiverRegister(), | |
| 131 JSObject::kPropertiesOffset)); | |
| 132 GenerateDictionaryLoad(masm, &slow, dictionary, | |
| 133 LoadDescriptor::NameRegister(), edi, ebx, eax); | |
| 134 __ ret(0); | |
| 135 | |
| 136 // Dictionary load failed, go slow (but don't miss). | |
| 137 __ bind(&slow); | |
| 138 GenerateRuntimeGetProperty(masm); | |
| 139 } | |
| 140 | |
| 141 void LoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) { | |
| 142 // Return address is on the stack. | |
| 143 Register receiver = LoadDescriptor::ReceiverRegister(); | |
| 144 Register name = LoadDescriptor::NameRegister(); | |
| 145 DCHECK(!ebx.is(receiver) && !ebx.is(name)); | |
| 146 | |
| 147 __ pop(ebx); | |
| 148 __ push(receiver); | |
| 149 __ push(name); | |
| 150 __ push(ebx); | |
| 151 | |
| 152 // Do tail-call to runtime routine. | |
| 153 __ TailCallRuntime(Runtime::kGetProperty); | |
| 154 } | |
| 155 | |
| 156 static void StoreIC_PushArgs(MacroAssembler* masm) { | 21 static void StoreIC_PushArgs(MacroAssembler* masm) { |
| 157 Register receiver = StoreWithVectorDescriptor::ReceiverRegister(); | 22 Register receiver = StoreWithVectorDescriptor::ReceiverRegister(); |
| 158 Register name = StoreWithVectorDescriptor::NameRegister(); | 23 Register name = StoreWithVectorDescriptor::NameRegister(); |
| 159 | 24 |
| 160 STATIC_ASSERT(StoreWithVectorDescriptor::kStackArgumentsCount == 3); | 25 STATIC_ASSERT(StoreWithVectorDescriptor::kStackArgumentsCount == 3); |
| 161 // Current stack layout: | 26 // Current stack layout: |
| 162 // - esp[12] -- value | 27 // - esp[12] -- value |
| 163 // - esp[8] -- slot | 28 // - esp[8] -- slot |
| 164 // - esp[4] -- vector | 29 // - esp[4] -- vector |
| 165 // - esp[0] -- return address | 30 // - esp[0] -- return address |
| 166 | 31 |
| 167 Register return_address = StoreWithVectorDescriptor::SlotRegister(); | 32 Register return_address = StoreWithVectorDescriptor::SlotRegister(); |
| 168 __ pop(return_address); | 33 __ pop(return_address); |
| 169 __ push(receiver); | 34 __ push(receiver); |
| 170 __ push(name); | 35 __ push(name); |
| 171 __ push(return_address); | 36 __ push(return_address); |
| 172 } | 37 } |
| 173 | 38 |
| 174 | |
| 175 void StoreIC::GenerateMiss(MacroAssembler* masm) { | |
| 176 // Return address is on the stack. | |
| 177 StoreIC_PushArgs(masm); | |
| 178 | |
| 179 // Perform tail call to the entry. | |
| 180 __ TailCallRuntime(Runtime::kStoreIC_Miss); | |
| 181 } | |
| 182 | |
| 183 | |
| 184 void StoreIC::GenerateNormal(MacroAssembler* masm) { | |
| 185 typedef StoreWithVectorDescriptor Descriptor; | |
| 186 Label restore_miss; | |
| 187 Register receiver = Descriptor::ReceiverRegister(); | |
| 188 Register name = Descriptor::NameRegister(); | |
| 189 Register value = Descriptor::ValueRegister(); | |
| 190 // Since the slot and vector values are passed on the stack we can use | |
| 191 // respective registers as scratch registers. | |
| 192 Register scratch1 = Descriptor::VectorRegister(); | |
| 193 Register scratch2 = Descriptor::SlotRegister(); | |
| 194 | |
| 195 __ LoadParameterFromStack<Descriptor>(value, Descriptor::kValue); | |
| 196 | |
| 197 // A lot of registers are needed for storing to slow case objects. | |
| 198 // Push and restore receiver but rely on GenerateDictionaryStore preserving | |
| 199 // the value and name. | |
| 200 __ push(receiver); | |
| 201 | |
| 202 Register dictionary = receiver; | |
| 203 __ mov(dictionary, FieldOperand(receiver, JSObject::kPropertiesOffset)); | |
| 204 GenerateDictionaryStore(masm, &restore_miss, dictionary, name, value, | |
| 205 scratch1, scratch2); | |
| 206 __ Drop(1); | |
| 207 Counters* counters = masm->isolate()->counters(); | |
| 208 __ IncrementCounter(counters->ic_store_normal_hit(), 1); | |
| 209 __ ret(Descriptor::kStackArgumentsCount * kPointerSize); | |
| 210 | |
| 211 __ bind(&restore_miss); | |
| 212 __ pop(receiver); | |
| 213 __ IncrementCounter(counters->ic_store_normal_miss(), 1); | |
| 214 GenerateMiss(masm); | |
| 215 } | |
| 216 | |
| 217 | |
| 218 void KeyedStoreIC::GenerateMiss(MacroAssembler* masm) { | 39 void KeyedStoreIC::GenerateMiss(MacroAssembler* masm) { |
| 219 // Return address is on the stack. | 40 // Return address is on the stack. |
| 220 StoreIC_PushArgs(masm); | 41 StoreIC_PushArgs(masm); |
| 221 | 42 |
| 222 // Do tail-call to runtime routine. | 43 // Do tail-call to runtime routine. |
| 223 __ TailCallRuntime(Runtime::kKeyedStoreIC_Miss); | 44 __ TailCallRuntime(Runtime::kKeyedStoreIC_Miss); |
| 224 } | 45 } |
| 225 | 46 |
| 226 void KeyedStoreIC::GenerateSlow(MacroAssembler* masm) { | 47 void KeyedStoreIC::GenerateSlow(MacroAssembler* masm) { |
| 227 // 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... |
| 300 Condition cc = | 121 Condition cc = |
| 301 (check == ENABLE_INLINED_SMI_CHECK) | 122 (check == ENABLE_INLINED_SMI_CHECK) |
| 302 ? (*jmp_address == Assembler::kJncShortOpcode ? not_zero : zero) | 123 ? (*jmp_address == Assembler::kJncShortOpcode ? not_zero : zero) |
| 303 : (*jmp_address == Assembler::kJnzShortOpcode ? not_carry : carry); | 124 : (*jmp_address == Assembler::kJnzShortOpcode ? not_carry : carry); |
| 304 *jmp_address = static_cast<byte>(Assembler::kJccShortPrefix | cc); | 125 *jmp_address = static_cast<byte>(Assembler::kJccShortPrefix | cc); |
| 305 } | 126 } |
| 306 } // namespace internal | 127 } // namespace internal |
| 307 } // namespace v8 | 128 } // namespace v8 |
| 308 | 129 |
| 309 #endif // V8_TARGET_ARCH_IA32 | 130 #endif // V8_TARGET_ARCH_IA32 |
| OLD | NEW |