| OLD | NEW |
| 1 // Copyright 2013 the V8 project authors. All rights reserved. | 1 // Copyright 2013 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 #include "src/v8.h" | 5 #include "src/v8.h" |
| 6 | 6 |
| 7 #if V8_TARGET_ARCH_ARM64 | 7 #if V8_TARGET_ARCH_ARM64 |
| 8 | 8 |
| 9 #include "src/arm64/assembler-arm64.h" | |
| 10 #include "src/code-stubs.h" | |
| 11 #include "src/codegen.h" | 9 #include "src/codegen.h" |
| 12 #include "src/disasm.h" | 10 #include "src/ic/ic.h" |
| 13 #include "src/ic-inl.h" | 11 #include "src/ic/stub-cache.h" |
| 14 #include "src/runtime.h" | |
| 15 #include "src/stub-cache.h" | |
| 16 | 12 |
| 17 namespace v8 { | 13 namespace v8 { |
| 18 namespace internal { | 14 namespace internal { |
| 19 | 15 |
| 20 | 16 |
| 21 #define __ ACCESS_MASM(masm) | 17 #define __ ACCESS_MASM(masm) |
| 22 | 18 |
| 23 | 19 |
| 24 // "type" holds an instance type on entry and is not clobbered. | 20 // "type" holds an instance type on entry and is not clobbered. |
| 25 // Generated code branch on "global_object" if type is any kind of global | 21 // Generated code branch on "global_object" if type is any kind of global |
| 26 // JS object. | 22 // JS object. |
| 27 static void GenerateGlobalInstanceTypeCheck(MacroAssembler* masm, | 23 static void GenerateGlobalInstanceTypeCheck(MacroAssembler* masm, Register type, |
| 28 Register type, | |
| 29 Label* global_object) { | 24 Label* global_object) { |
| 30 __ Cmp(type, JS_GLOBAL_OBJECT_TYPE); | 25 __ Cmp(type, JS_GLOBAL_OBJECT_TYPE); |
| 31 __ Ccmp(type, JS_BUILTINS_OBJECT_TYPE, ZFlag, ne); | 26 __ Ccmp(type, JS_BUILTINS_OBJECT_TYPE, ZFlag, ne); |
| 32 __ Ccmp(type, JS_GLOBAL_PROXY_TYPE, ZFlag, ne); | 27 __ Ccmp(type, JS_GLOBAL_PROXY_TYPE, ZFlag, ne); |
| 33 __ B(eq, global_object); | 28 __ B(eq, global_object); |
| 34 } | 29 } |
| 35 | 30 |
| 36 | 31 |
| 37 // Helper function used from LoadIC GenerateNormal. | 32 // Helper function used from LoadIC GenerateNormal. |
| 38 // | 33 // |
| 39 // elements: Property dictionary. It is not clobbered if a jump to the miss | 34 // elements: Property dictionary. It is not clobbered if a jump to the miss |
| 40 // label is done. | 35 // label is done. |
| 41 // name: Property name. It is not clobbered if a jump to the miss label is | 36 // name: Property name. It is not clobbered if a jump to the miss label is |
| 42 // done | 37 // done |
| 43 // result: Register for the result. It is only updated if a jump to the miss | 38 // result: Register for the result. It is only updated if a jump to the miss |
| 44 // label is not done. | 39 // label is not done. |
| 45 // The scratch registers need to be different from elements, name and result. | 40 // The scratch registers need to be different from elements, name and result. |
| 46 // The generated code assumes that the receiver has slow properties, | 41 // The generated code assumes that the receiver has slow properties, |
| 47 // is not a global object and does not have interceptors. | 42 // is not a global object and does not have interceptors. |
| 48 static void GenerateDictionaryLoad(MacroAssembler* masm, | 43 static void GenerateDictionaryLoad(MacroAssembler* masm, Label* miss, |
| 49 Label* miss, | 44 Register elements, Register name, |
| 50 Register elements, | 45 Register result, Register scratch1, |
| 51 Register name, | |
| 52 Register result, | |
| 53 Register scratch1, | |
| 54 Register scratch2) { | 46 Register scratch2) { |
| 55 DCHECK(!AreAliased(elements, name, scratch1, scratch2)); | 47 DCHECK(!AreAliased(elements, name, scratch1, scratch2)); |
| 56 DCHECK(!AreAliased(result, scratch1, scratch2)); | 48 DCHECK(!AreAliased(result, scratch1, scratch2)); |
| 57 | 49 |
| 58 Label done; | 50 Label done; |
| 59 | 51 |
| 60 // Probe the dictionary. | 52 // Probe the dictionary. |
| 61 NameDictionaryLookupStub::GeneratePositiveLookup(masm, | 53 NameDictionaryLookupStub::GeneratePositiveLookup(masm, miss, &done, elements, |
| 62 miss, | 54 name, scratch1, scratch2); |
| 63 &done, | |
| 64 elements, | |
| 65 name, | |
| 66 scratch1, | |
| 67 scratch2); | |
| 68 | 55 |
| 69 // If probing finds an entry check that the value is a normal property. | 56 // If probing finds an entry check that the value is a normal property. |
| 70 __ Bind(&done); | 57 __ Bind(&done); |
| 71 | 58 |
| 72 static const int kElementsStartOffset = NameDictionary::kHeaderSize + | 59 static const int kElementsStartOffset = |
| 60 NameDictionary::kHeaderSize + |
| 73 NameDictionary::kElementsStartIndex * kPointerSize; | 61 NameDictionary::kElementsStartIndex * kPointerSize; |
| 74 static const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize; | 62 static const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize; |
| 75 __ Ldr(scratch1, FieldMemOperand(scratch2, kDetailsOffset)); | 63 __ Ldr(scratch1, FieldMemOperand(scratch2, kDetailsOffset)); |
| 76 __ Tst(scratch1, Smi::FromInt(PropertyDetails::TypeField::kMask)); | 64 __ Tst(scratch1, Smi::FromInt(PropertyDetails::TypeField::kMask)); |
| 77 __ B(ne, miss); | 65 __ B(ne, miss); |
| 78 | 66 |
| 79 // Get the value at the masked, scaled index and return. | 67 // Get the value at the masked, scaled index and return. |
| 80 __ Ldr(result, | 68 __ Ldr(result, |
| 81 FieldMemOperand(scratch2, kElementsStartOffset + 1 * kPointerSize)); | 69 FieldMemOperand(scratch2, kElementsStartOffset + 1 * kPointerSize)); |
| 82 } | 70 } |
| 83 | 71 |
| 84 | 72 |
| 85 // Helper function used from StoreIC::GenerateNormal. | 73 // Helper function used from StoreIC::GenerateNormal. |
| 86 // | 74 // |
| 87 // elements: Property dictionary. It is not clobbered if a jump to the miss | 75 // elements: Property dictionary. It is not clobbered if a jump to the miss |
| 88 // label is done. | 76 // label is done. |
| 89 // name: Property name. It is not clobbered if a jump to the miss label is | 77 // name: Property name. It is not clobbered if a jump to the miss label is |
| 90 // done | 78 // done |
| 91 // value: The value to store (never clobbered). | 79 // value: The value to store (never clobbered). |
| 92 // | 80 // |
| 93 // The generated code assumes that the receiver has slow properties, | 81 // The generated code assumes that the receiver has slow properties, |
| 94 // is not a global object and does not have interceptors. | 82 // is not a global object and does not have interceptors. |
| 95 static void GenerateDictionaryStore(MacroAssembler* masm, | 83 static void GenerateDictionaryStore(MacroAssembler* masm, Label* miss, |
| 96 Label* miss, | 84 Register elements, Register name, |
| 97 Register elements, | 85 Register value, Register scratch1, |
| 98 Register name, | |
| 99 Register value, | |
| 100 Register scratch1, | |
| 101 Register scratch2) { | 86 Register scratch2) { |
| 102 DCHECK(!AreAliased(elements, name, value, scratch1, scratch2)); | 87 DCHECK(!AreAliased(elements, name, value, scratch1, scratch2)); |
| 103 | 88 |
| 104 Label done; | 89 Label done; |
| 105 | 90 |
| 106 // Probe the dictionary. | 91 // Probe the dictionary. |
| 107 NameDictionaryLookupStub::GeneratePositiveLookup(masm, | 92 NameDictionaryLookupStub::GeneratePositiveLookup(masm, miss, &done, elements, |
| 108 miss, | 93 name, scratch1, scratch2); |
| 109 &done, | |
| 110 elements, | |
| 111 name, | |
| 112 scratch1, | |
| 113 scratch2); | |
| 114 | 94 |
| 115 // If probing finds an entry in the dictionary check that the value | 95 // If probing finds an entry in the dictionary check that the value |
| 116 // is a normal property that is not read only. | 96 // is a normal property that is not read only. |
| 117 __ Bind(&done); | 97 __ Bind(&done); |
| 118 | 98 |
| 119 static const int kElementsStartOffset = NameDictionary::kHeaderSize + | 99 static const int kElementsStartOffset = |
| 100 NameDictionary::kHeaderSize + |
| 120 NameDictionary::kElementsStartIndex * kPointerSize; | 101 NameDictionary::kElementsStartIndex * kPointerSize; |
| 121 static const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize; | 102 static const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize; |
| 122 static const int kTypeAndReadOnlyMask = | 103 static const int kTypeAndReadOnlyMask = |
| 123 PropertyDetails::TypeField::kMask | | 104 PropertyDetails::TypeField::kMask | |
| 124 PropertyDetails::AttributesField::encode(READ_ONLY); | 105 PropertyDetails::AttributesField::encode(READ_ONLY); |
| 125 __ Ldrsw(scratch1, UntagSmiFieldMemOperand(scratch2, kDetailsOffset)); | 106 __ Ldrsw(scratch1, UntagSmiFieldMemOperand(scratch2, kDetailsOffset)); |
| 126 __ Tst(scratch1, kTypeAndReadOnlyMask); | 107 __ Tst(scratch1, kTypeAndReadOnlyMask); |
| 127 __ B(ne, miss); | 108 __ B(ne, miss); |
| 128 | 109 |
| 129 // Store the value at the masked, scaled index and return. | 110 // Store the value at the masked, scaled index and return. |
| 130 static const int kValueOffset = kElementsStartOffset + kPointerSize; | 111 static const int kValueOffset = kElementsStartOffset + kPointerSize; |
| 131 __ Add(scratch2, scratch2, kValueOffset - kHeapObjectTag); | 112 __ Add(scratch2, scratch2, kValueOffset - kHeapObjectTag); |
| 132 __ Str(value, MemOperand(scratch2)); | 113 __ Str(value, MemOperand(scratch2)); |
| 133 | 114 |
| 134 // Update the write barrier. Make sure not to clobber the value. | 115 // Update the write barrier. Make sure not to clobber the value. |
| 135 __ Mov(scratch1, value); | 116 __ Mov(scratch1, value); |
| 136 __ RecordWrite( | 117 __ RecordWrite(elements, scratch2, scratch1, kLRHasNotBeenSaved, |
| 137 elements, scratch2, scratch1, kLRHasNotBeenSaved, kDontSaveFPRegs); | 118 kDontSaveFPRegs); |
| 138 } | 119 } |
| 139 | 120 |
| 140 | 121 |
| 141 // Checks the receiver for special cases (value type, slow case bits). | 122 // Checks the receiver for special cases (value type, slow case bits). |
| 142 // Falls through for regular JS object and return the map of the | 123 // Falls through for regular JS object and return the map of the |
| 143 // receiver in 'map_scratch' if the receiver is not a SMI. | 124 // receiver in 'map_scratch' if the receiver is not a SMI. |
| 144 static void GenerateKeyedLoadReceiverCheck(MacroAssembler* masm, | 125 static void GenerateKeyedLoadReceiverCheck(MacroAssembler* masm, |
| 145 Register receiver, | 126 Register receiver, |
| 146 Register map_scratch, | 127 Register map_scratch, |
| 147 Register scratch, | 128 Register scratch, |
| 148 int interceptor_bit, | 129 int interceptor_bit, Label* slow) { |
| 149 Label* slow) { | |
| 150 DCHECK(!AreAliased(map_scratch, scratch)); | 130 DCHECK(!AreAliased(map_scratch, scratch)); |
| 151 | 131 |
| 152 // Check that the object isn't a smi. | 132 // Check that the object isn't a smi. |
| 153 __ JumpIfSmi(receiver, slow); | 133 __ JumpIfSmi(receiver, slow); |
| 154 // Get the map of the receiver. | 134 // Get the map of the receiver. |
| 155 __ Ldr(map_scratch, FieldMemOperand(receiver, HeapObject::kMapOffset)); | 135 __ Ldr(map_scratch, FieldMemOperand(receiver, HeapObject::kMapOffset)); |
| 156 // Check bit field. | 136 // Check bit field. |
| 157 __ Ldrb(scratch, FieldMemOperand(map_scratch, Map::kBitFieldOffset)); | 137 __ Ldrb(scratch, FieldMemOperand(map_scratch, Map::kBitFieldOffset)); |
| 158 __ Tbnz(scratch, Map::kIsAccessCheckNeeded, slow); | 138 __ Tbnz(scratch, Map::kIsAccessCheckNeeded, slow); |
| 159 __ Tbnz(scratch, interceptor_bit, slow); | 139 __ Tbnz(scratch, interceptor_bit, slow); |
| (...skipping 20 matching lines...) Expand all Loading... |
| 180 // | 160 // |
| 181 // elements - holds the elements of the receiver on exit. | 161 // elements - holds the elements of the receiver on exit. |
| 182 // | 162 // |
| 183 // elements_map - holds the elements map on exit if the not_fast_array branch is | 163 // elements_map - holds the elements map on exit if the not_fast_array branch is |
| 184 // taken. Otherwise, this is used as a scratch register. | 164 // taken. Otherwise, this is used as a scratch register. |
| 185 // | 165 // |
| 186 // result - holds the result on exit if the load succeeded. | 166 // result - holds the result on exit if the load succeeded. |
| 187 // Allowed to be the the same as 'receiver' or 'key'. | 167 // Allowed to be the the same as 'receiver' or 'key'. |
| 188 // Unchanged on bailout so 'receiver' and 'key' can be safely | 168 // Unchanged on bailout so 'receiver' and 'key' can be safely |
| 189 // used by further computation. | 169 // used by further computation. |
| 190 static void GenerateFastArrayLoad(MacroAssembler* masm, | 170 static void GenerateFastArrayLoad(MacroAssembler* masm, Register receiver, |
| 191 Register receiver, | 171 Register key, Register elements, |
| 192 Register key, | 172 Register elements_map, Register scratch2, |
| 193 Register elements, | 173 Register result, Label* not_fast_array, |
| 194 Register elements_map, | |
| 195 Register scratch2, | |
| 196 Register result, | |
| 197 Label* not_fast_array, | |
| 198 Label* slow) { | 174 Label* slow) { |
| 199 DCHECK(!AreAliased(receiver, key, elements, elements_map, scratch2)); | 175 DCHECK(!AreAliased(receiver, key, elements, elements_map, scratch2)); |
| 200 | 176 |
| 201 // Check for fast array. | 177 // Check for fast array. |
| 202 __ Ldr(elements, FieldMemOperand(receiver, JSObject::kElementsOffset)); | 178 __ Ldr(elements, FieldMemOperand(receiver, JSObject::kElementsOffset)); |
| 203 if (not_fast_array != NULL) { | 179 if (not_fast_array != NULL) { |
| 204 // Check that the object is in fast mode and writable. | 180 // Check that the object is in fast mode and writable. |
| 205 __ Ldr(elements_map, FieldMemOperand(elements, HeapObject::kMapOffset)); | 181 __ Ldr(elements_map, FieldMemOperand(elements, HeapObject::kMapOffset)); |
| 206 __ JumpIfNotRoot(elements_map, Heap::kFixedArrayMapRootIndex, | 182 __ JumpIfNotRoot(elements_map, Heap::kFixedArrayMapRootIndex, |
| 207 not_fast_array); | 183 not_fast_array); |
| (...skipping 24 matching lines...) Expand all Loading... |
| 232 // preserved if we jump to 'slow'. | 208 // preserved if we jump to 'slow'. |
| 233 __ Mov(result, scratch2); | 209 __ Mov(result, scratch2); |
| 234 } | 210 } |
| 235 | 211 |
| 236 | 212 |
| 237 // Checks whether a key is an array index string or a unique name. | 213 // Checks whether a key is an array index string or a unique name. |
| 238 // Falls through if a key is a unique name. | 214 // Falls through if a key is a unique name. |
| 239 // The map of the key is returned in 'map_scratch'. | 215 // The map of the key is returned in 'map_scratch'. |
| 240 // If the jump to 'index_string' is done the hash of the key is left | 216 // If the jump to 'index_string' is done the hash of the key is left |
| 241 // in 'hash_scratch'. | 217 // in 'hash_scratch'. |
| 242 static void GenerateKeyNameCheck(MacroAssembler* masm, | 218 static void GenerateKeyNameCheck(MacroAssembler* masm, Register key, |
| 243 Register key, | 219 Register map_scratch, Register hash_scratch, |
| 244 Register map_scratch, | 220 Label* index_string, Label* not_unique) { |
| 245 Register hash_scratch, | |
| 246 Label* index_string, | |
| 247 Label* not_unique) { | |
| 248 DCHECK(!AreAliased(key, map_scratch, hash_scratch)); | 221 DCHECK(!AreAliased(key, map_scratch, hash_scratch)); |
| 249 | 222 |
| 250 // Is the key a name? | 223 // Is the key a name? |
| 251 Label unique; | 224 Label unique; |
| 252 __ JumpIfObjectType(key, map_scratch, hash_scratch, LAST_UNIQUE_NAME_TYPE, | 225 __ JumpIfObjectType(key, map_scratch, hash_scratch, LAST_UNIQUE_NAME_TYPE, |
| 253 not_unique, hi); | 226 not_unique, hi); |
| 254 STATIC_ASSERT(LAST_UNIQUE_NAME_TYPE == FIRST_NONSTRING_TYPE); | 227 STATIC_ASSERT(LAST_UNIQUE_NAME_TYPE == FIRST_NONSTRING_TYPE); |
| 255 __ B(eq, &unique); | 228 __ B(eq, &unique); |
| 256 | 229 |
| 257 // Is the string an array index with cached numeric value? | 230 // Is the string an array index with cached numeric value? |
| 258 __ Ldr(hash_scratch.W(), FieldMemOperand(key, Name::kHashFieldOffset)); | 231 __ Ldr(hash_scratch.W(), FieldMemOperand(key, Name::kHashFieldOffset)); |
| 259 __ TestAndBranchIfAllClear(hash_scratch, | 232 __ TestAndBranchIfAllClear(hash_scratch, Name::kContainsCachedArrayIndexMask, |
| 260 Name::kContainsCachedArrayIndexMask, | |
| 261 index_string); | 233 index_string); |
| 262 | 234 |
| 263 // Is the string internalized? We know it's a string, so a single bit test is | 235 // Is the string internalized? We know it's a string, so a single bit test is |
| 264 // enough. | 236 // enough. |
| 265 __ Ldrb(hash_scratch, FieldMemOperand(map_scratch, Map::kInstanceTypeOffset)); | 237 __ Ldrb(hash_scratch, FieldMemOperand(map_scratch, Map::kInstanceTypeOffset)); |
| 266 STATIC_ASSERT(kInternalizedTag == 0); | 238 STATIC_ASSERT(kInternalizedTag == 0); |
| 267 __ TestAndBranchIfAnySet(hash_scratch, kIsNotInternalizedMask, not_unique); | 239 __ TestAndBranchIfAnySet(hash_scratch, kIsNotInternalizedMask, not_unique); |
| 268 | 240 |
| 269 __ Bind(&unique); | 241 __ Bind(&unique); |
| 270 // Fall through if the key is a unique name. | 242 // Fall through if the key is a unique name. |
| 271 } | 243 } |
| 272 | 244 |
| 273 | 245 |
| 274 // Neither 'object' nor 'key' are modified by this function. | 246 // Neither 'object' nor 'key' are modified by this function. |
| 275 // | 247 // |
| 276 // If the 'unmapped_case' or 'slow_case' exit is taken, the 'map' register is | 248 // If the 'unmapped_case' or 'slow_case' exit is taken, the 'map' register is |
| 277 // left with the object's elements map. Otherwise, it is used as a scratch | 249 // left with the object's elements map. Otherwise, it is used as a scratch |
| 278 // register. | 250 // register. |
| 279 static MemOperand GenerateMappedArgumentsLookup(MacroAssembler* masm, | 251 static MemOperand GenerateMappedArgumentsLookup(MacroAssembler* masm, |
| 280 Register object, | 252 Register object, Register key, |
| 281 Register key, | 253 Register map, Register scratch1, |
| 282 Register map, | |
| 283 Register scratch1, | |
| 284 Register scratch2, | 254 Register scratch2, |
| 285 Label* unmapped_case, | 255 Label* unmapped_case, |
| 286 Label* slow_case) { | 256 Label* slow_case) { |
| 287 DCHECK(!AreAliased(object, key, map, scratch1, scratch2)); | 257 DCHECK(!AreAliased(object, key, map, scratch1, scratch2)); |
| 288 | 258 |
| 289 Heap* heap = masm->isolate()->heap(); | 259 Heap* heap = masm->isolate()->heap(); |
| 290 | 260 |
| 291 // Check that the receiver is a JSObject. Because of the elements | 261 // Check that the receiver is a JSObject. Because of the elements |
| 292 // map check later, we do not need to check for interceptors or | 262 // map check later, we do not need to check for interceptors or |
| 293 // whether it requires access checks. | 263 // whether it requires access checks. |
| 294 __ JumpIfSmi(object, slow_case); | 264 __ JumpIfSmi(object, slow_case); |
| 295 // Check that the object is some kind of JSObject. | 265 // Check that the object is some kind of JSObject. |
| 296 __ JumpIfObjectType(object, map, scratch1, FIRST_JS_RECEIVER_TYPE, | 266 __ JumpIfObjectType(object, map, scratch1, FIRST_JS_RECEIVER_TYPE, slow_case, |
| 297 slow_case, lt); | 267 lt); |
| 298 | 268 |
| 299 // Check that the key is a positive smi. | 269 // Check that the key is a positive smi. |
| 300 __ JumpIfNotSmi(key, slow_case); | 270 __ JumpIfNotSmi(key, slow_case); |
| 301 __ Tbnz(key, kXSignBit, slow_case); | 271 __ Tbnz(key, kXSignBit, slow_case); |
| 302 | 272 |
| 303 // Load the elements object and check its map. | 273 // Load the elements object and check its map. |
| 304 Handle<Map> arguments_map(heap->sloppy_arguments_elements_map()); | 274 Handle<Map> arguments_map(heap->sloppy_arguments_elements_map()); |
| 305 __ Ldr(map, FieldMemOperand(object, JSObject::kElementsOffset)); | 275 __ Ldr(map, FieldMemOperand(object, JSObject::kElementsOffset)); |
| 306 __ CheckMap(map, scratch1, arguments_map, slow_case, DONT_DO_SMI_CHECK); | 276 __ CheckMap(map, scratch1, arguments_map, slow_case, DONT_DO_SMI_CHECK); |
| 307 | 277 |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 340 Register scratch, | 310 Register scratch, |
| 341 Label* slow_case) { | 311 Label* slow_case) { |
| 342 DCHECK(!AreAliased(key, parameter_map, scratch)); | 312 DCHECK(!AreAliased(key, parameter_map, scratch)); |
| 343 | 313 |
| 344 // Element is in arguments backing store, which is referenced by the | 314 // Element is in arguments backing store, which is referenced by the |
| 345 // second element of the parameter_map. | 315 // second element of the parameter_map. |
| 346 const int kBackingStoreOffset = FixedArray::kHeaderSize + kPointerSize; | 316 const int kBackingStoreOffset = FixedArray::kHeaderSize + kPointerSize; |
| 347 Register backing_store = parameter_map; | 317 Register backing_store = parameter_map; |
| 348 __ Ldr(backing_store, FieldMemOperand(parameter_map, kBackingStoreOffset)); | 318 __ Ldr(backing_store, FieldMemOperand(parameter_map, kBackingStoreOffset)); |
| 349 Handle<Map> fixed_array_map(masm->isolate()->heap()->fixed_array_map()); | 319 Handle<Map> fixed_array_map(masm->isolate()->heap()->fixed_array_map()); |
| 350 __ CheckMap( | 320 __ CheckMap(backing_store, scratch, fixed_array_map, slow_case, |
| 351 backing_store, scratch, fixed_array_map, slow_case, DONT_DO_SMI_CHECK); | 321 DONT_DO_SMI_CHECK); |
| 352 __ Ldr(scratch, FieldMemOperand(backing_store, FixedArray::kLengthOffset)); | 322 __ Ldr(scratch, FieldMemOperand(backing_store, FixedArray::kLengthOffset)); |
| 353 __ Cmp(key, scratch); | 323 __ Cmp(key, scratch); |
| 354 __ B(hs, slow_case); | 324 __ B(hs, slow_case); |
| 355 | 325 |
| 356 __ Add(backing_store, | 326 __ Add(backing_store, backing_store, |
| 357 backing_store, | |
| 358 FixedArray::kHeaderSize - kHeapObjectTag); | 327 FixedArray::kHeaderSize - kHeapObjectTag); |
| 359 __ SmiUntag(scratch, key); | 328 __ SmiUntag(scratch, key); |
| 360 return MemOperand(backing_store, scratch, LSL, kPointerSizeLog2); | 329 return MemOperand(backing_store, scratch, LSL, kPointerSizeLog2); |
| 361 } | 330 } |
| 362 | 331 |
| 363 | 332 |
| 364 void LoadIC::GenerateMegamorphic(MacroAssembler* masm) { | 333 void LoadIC::GenerateMegamorphic(MacroAssembler* masm) { |
| 365 // The return address is in lr. | 334 // The return address is in lr. |
| 366 Register receiver = ReceiverRegister(); | 335 Register receiver = ReceiverRegister(); |
| 367 Register name = NameRegister(); | 336 Register name = NameRegister(); |
| 368 DCHECK(receiver.is(x1)); | 337 DCHECK(receiver.is(x1)); |
| 369 DCHECK(name.is(x2)); | 338 DCHECK(name.is(x2)); |
| 370 | 339 |
| 371 // Probe the stub cache. | 340 // Probe the stub cache. |
| 372 Code::Flags flags = Code::RemoveTypeAndHolderFromFlags( | 341 Code::Flags flags = Code::RemoveTypeAndHolderFromFlags( |
| 373 Code::ComputeHandlerFlags(Code::LOAD_IC)); | 342 Code::ComputeHandlerFlags(Code::LOAD_IC)); |
| 374 masm->isolate()->stub_cache()->GenerateProbe( | 343 masm->isolate()->stub_cache()->GenerateProbe(masm, flags, receiver, name, x3, |
| 375 masm, flags, receiver, name, x3, x4, x5, x6); | 344 x4, x5, x6); |
| 376 | 345 |
| 377 // Cache miss: Jump to runtime. | 346 // Cache miss: Jump to runtime. |
| 378 GenerateMiss(masm); | 347 GenerateMiss(masm); |
| 379 } | 348 } |
| 380 | 349 |
| 381 | 350 |
| 382 void LoadIC::GenerateNormal(MacroAssembler* masm) { | 351 void LoadIC::GenerateNormal(MacroAssembler* masm) { |
| 383 Register dictionary = x0; | 352 Register dictionary = x0; |
| 384 DCHECK(!dictionary.is(ReceiverRegister())); | 353 DCHECK(!dictionary.is(ReceiverRegister())); |
| 385 DCHECK(!dictionary.is(NameRegister())); | 354 DCHECK(!dictionary.is(NameRegister())); |
| (...skipping 12 matching lines...) Expand all Loading... |
| 398 | 367 |
| 399 void LoadIC::GenerateMiss(MacroAssembler* masm) { | 368 void LoadIC::GenerateMiss(MacroAssembler* masm) { |
| 400 // The return address is in lr. | 369 // The return address is in lr. |
| 401 Isolate* isolate = masm->isolate(); | 370 Isolate* isolate = masm->isolate(); |
| 402 ASM_LOCATION("LoadIC::GenerateMiss"); | 371 ASM_LOCATION("LoadIC::GenerateMiss"); |
| 403 | 372 |
| 404 __ IncrementCounter(isolate->counters()->load_miss(), 1, x3, x4); | 373 __ IncrementCounter(isolate->counters()->load_miss(), 1, x3, x4); |
| 405 | 374 |
| 406 // Perform tail call to the entry. | 375 // Perform tail call to the entry. |
| 407 __ Push(ReceiverRegister(), NameRegister()); | 376 __ Push(ReceiverRegister(), NameRegister()); |
| 408 ExternalReference ref = | 377 ExternalReference ref = ExternalReference(IC_Utility(kLoadIC_Miss), isolate); |
| 409 ExternalReference(IC_Utility(kLoadIC_Miss), isolate); | |
| 410 __ TailCallExternalReference(ref, 2, 1); | 378 __ TailCallExternalReference(ref, 2, 1); |
| 411 } | 379 } |
| 412 | 380 |
| 413 | 381 |
| 414 void LoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) { | 382 void LoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) { |
| 415 // The return address is in lr. | 383 // The return address is in lr. |
| 416 __ Push(ReceiverRegister(), NameRegister()); | 384 __ Push(ReceiverRegister(), NameRegister()); |
| 417 __ TailCallRuntime(Runtime::kGetProperty, 2, 1); | 385 __ TailCallRuntime(Runtime::kGetProperty, 2, 1); |
| 418 } | 386 } |
| 419 | 387 |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 457 DCHECK(key.is(x2)); | 425 DCHECK(key.is(x2)); |
| 458 DCHECK(value.is(x0)); | 426 DCHECK(value.is(x0)); |
| 459 | 427 |
| 460 Register map = x3; | 428 Register map = x3; |
| 461 | 429 |
| 462 // These registers are used by GenerateMappedArgumentsLookup to build a | 430 // These registers are used by GenerateMappedArgumentsLookup to build a |
| 463 // MemOperand. They are live for as long as the MemOperand is live. | 431 // MemOperand. They are live for as long as the MemOperand is live. |
| 464 Register mapped1 = x4; | 432 Register mapped1 = x4; |
| 465 Register mapped2 = x5; | 433 Register mapped2 = x5; |
| 466 | 434 |
| 467 MemOperand mapped = | 435 MemOperand mapped = GenerateMappedArgumentsLookup( |
| 468 GenerateMappedArgumentsLookup(masm, receiver, key, map, | 436 masm, receiver, key, map, mapped1, mapped2, ¬in, &slow); |
| 469 mapped1, mapped2, | |
| 470 ¬in, &slow); | |
| 471 Operand mapped_offset = mapped.OffsetAsOperand(); | 437 Operand mapped_offset = mapped.OffsetAsOperand(); |
| 472 __ Str(value, mapped); | 438 __ Str(value, mapped); |
| 473 __ Add(x10, mapped.base(), mapped_offset); | 439 __ Add(x10, mapped.base(), mapped_offset); |
| 474 __ Mov(x11, value); | 440 __ Mov(x11, value); |
| 475 __ RecordWrite(mapped.base(), x10, x11, kLRHasNotBeenSaved, kDontSaveFPRegs); | 441 __ RecordWrite(mapped.base(), x10, x11, kLRHasNotBeenSaved, kDontSaveFPRegs); |
| 476 __ Ret(); | 442 __ Ret(); |
| 477 | 443 |
| 478 __ Bind(¬in); | 444 __ Bind(¬in); |
| 479 | 445 |
| 480 // These registers are used by GenerateMappedArgumentsLookup to build a | 446 // These registers are used by GenerateMappedArgumentsLookup to build a |
| 481 // MemOperand. They are live for as long as the MemOperand is live. | 447 // MemOperand. They are live for as long as the MemOperand is live. |
| 482 Register unmapped1 = map; // This is assumed to alias 'map'. | 448 Register unmapped1 = map; // This is assumed to alias 'map'. |
| 483 Register unmapped2 = x4; | 449 Register unmapped2 = x4; |
| 484 MemOperand unmapped = | 450 MemOperand unmapped = |
| 485 GenerateUnmappedArgumentsLookup(masm, key, unmapped1, unmapped2, &slow); | 451 GenerateUnmappedArgumentsLookup(masm, key, unmapped1, unmapped2, &slow); |
| 486 Operand unmapped_offset = unmapped.OffsetAsOperand(); | 452 Operand unmapped_offset = unmapped.OffsetAsOperand(); |
| 487 __ Str(value, unmapped); | 453 __ Str(value, unmapped); |
| 488 __ Add(x10, unmapped.base(), unmapped_offset); | 454 __ Add(x10, unmapped.base(), unmapped_offset); |
| 489 __ Mov(x11, value); | 455 __ Mov(x11, value); |
| 490 __ RecordWrite(unmapped.base(), x10, x11, | 456 __ RecordWrite(unmapped.base(), x10, x11, kLRHasNotBeenSaved, |
| 491 kLRHasNotBeenSaved, kDontSaveFPRegs); | 457 kDontSaveFPRegs); |
| 492 __ Ret(); | 458 __ Ret(); |
| 493 __ Bind(&slow); | 459 __ Bind(&slow); |
| 494 GenerateMiss(masm); | 460 GenerateMiss(masm); |
| 495 } | 461 } |
| 496 | 462 |
| 497 | 463 |
| 498 void KeyedLoadIC::GenerateMiss(MacroAssembler* masm) { | 464 void KeyedLoadIC::GenerateMiss(MacroAssembler* masm) { |
| 499 // The return address is in lr. | 465 // The return address is in lr. |
| 500 Isolate* isolate = masm->isolate(); | 466 Isolate* isolate = masm->isolate(); |
| 501 | 467 |
| (...skipping 23 matching lines...) Expand all Loading... |
| 525 DCHECK(FLAG_vector_ics); | 491 DCHECK(FLAG_vector_ics); |
| 526 return x3; | 492 return x3; |
| 527 } | 493 } |
| 528 | 494 |
| 529 | 495 |
| 530 const Register StoreIC::ReceiverRegister() { return x1; } | 496 const Register StoreIC::ReceiverRegister() { return x1; } |
| 531 const Register StoreIC::NameRegister() { return x2; } | 497 const Register StoreIC::NameRegister() { return x2; } |
| 532 const Register StoreIC::ValueRegister() { return x0; } | 498 const Register StoreIC::ValueRegister() { return x0; } |
| 533 | 499 |
| 534 | 500 |
| 535 const Register KeyedStoreIC::MapRegister() { | 501 const Register KeyedStoreIC::MapRegister() { return x3; } |
| 536 return x3; | |
| 537 } | |
| 538 | 502 |
| 539 | 503 |
| 540 void KeyedLoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) { | 504 void KeyedLoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) { |
| 541 // The return address is in lr. | 505 // The return address is in lr. |
| 542 __ Push(ReceiverRegister(), NameRegister()); | 506 __ Push(ReceiverRegister(), NameRegister()); |
| 543 __ TailCallRuntime(Runtime::kKeyedGetProperty, 2, 1); | 507 __ TailCallRuntime(Runtime::kKeyedGetProperty, 2, 1); |
| 544 } | 508 } |
| 545 | 509 |
| 546 | 510 |
| 547 static void GenerateKeyedLoadWithSmiKey(MacroAssembler* masm, | 511 static void GenerateKeyedLoadWithSmiKey(MacroAssembler* masm, Register key, |
| 548 Register key, | 512 Register receiver, Register scratch1, |
| 549 Register receiver, | 513 Register scratch2, Register scratch3, |
| 550 Register scratch1, | 514 Register scratch4, Register scratch5, |
| 551 Register scratch2, | 515 Label* slow) { |
| 552 Register scratch3, | 516 DCHECK(!AreAliased(key, receiver, scratch1, scratch2, scratch3, scratch4, |
| 553 Register scratch4, | 517 scratch5)); |
| 554 Register scratch5, | |
| 555 Label *slow) { | |
| 556 DCHECK(!AreAliased( | |
| 557 key, receiver, scratch1, scratch2, scratch3, scratch4, scratch5)); | |
| 558 | 518 |
| 559 Isolate* isolate = masm->isolate(); | 519 Isolate* isolate = masm->isolate(); |
| 560 Label check_number_dictionary; | 520 Label check_number_dictionary; |
| 561 // If we can load the value, it should be returned in x0. | 521 // If we can load the value, it should be returned in x0. |
| 562 Register result = x0; | 522 Register result = x0; |
| 563 | 523 |
| 564 GenerateKeyedLoadReceiverCheck( | 524 GenerateKeyedLoadReceiverCheck(masm, receiver, scratch1, scratch2, |
| 565 masm, receiver, scratch1, scratch2, Map::kHasIndexedInterceptor, slow); | 525 Map::kHasIndexedInterceptor, slow); |
| 566 | 526 |
| 567 // Check the receiver's map to see if it has fast elements. | 527 // Check the receiver's map to see if it has fast elements. |
| 568 __ CheckFastElements(scratch1, scratch2, &check_number_dictionary); | 528 __ CheckFastElements(scratch1, scratch2, &check_number_dictionary); |
| 569 | 529 |
| 570 GenerateFastArrayLoad( | 530 GenerateFastArrayLoad(masm, receiver, key, scratch3, scratch2, scratch1, |
| 571 masm, receiver, key, scratch3, scratch2, scratch1, result, NULL, slow); | 531 result, NULL, slow); |
| 572 __ IncrementCounter( | 532 __ IncrementCounter(isolate->counters()->keyed_load_generic_smi(), 1, |
| 573 isolate->counters()->keyed_load_generic_smi(), 1, scratch1, scratch2); | 533 scratch1, scratch2); |
| 574 __ Ret(); | 534 __ Ret(); |
| 575 | 535 |
| 576 __ Bind(&check_number_dictionary); | 536 __ Bind(&check_number_dictionary); |
| 577 __ Ldr(scratch3, FieldMemOperand(receiver, JSObject::kElementsOffset)); | 537 __ Ldr(scratch3, FieldMemOperand(receiver, JSObject::kElementsOffset)); |
| 578 __ Ldr(scratch2, FieldMemOperand(scratch3, JSObject::kMapOffset)); | 538 __ Ldr(scratch2, FieldMemOperand(scratch3, JSObject::kMapOffset)); |
| 579 | 539 |
| 580 // Check whether we have a number dictionary. | 540 // Check whether we have a number dictionary. |
| 581 __ JumpIfNotRoot(scratch2, Heap::kHashTableMapRootIndex, slow); | 541 __ JumpIfNotRoot(scratch2, Heap::kHashTableMapRootIndex, slow); |
| 582 | 542 |
| 583 __ LoadFromNumberDictionary( | 543 __ LoadFromNumberDictionary(slow, scratch3, key, result, scratch1, scratch2, |
| 584 slow, scratch3, key, result, scratch1, scratch2, scratch4, scratch5); | 544 scratch4, scratch5); |
| 585 __ Ret(); | 545 __ Ret(); |
| 586 } | 546 } |
| 587 | 547 |
| 588 static void GenerateKeyedLoadWithNameKey(MacroAssembler* masm, | 548 static void GenerateKeyedLoadWithNameKey(MacroAssembler* masm, Register key, |
| 589 Register key, | 549 Register receiver, Register scratch1, |
| 590 Register receiver, | 550 Register scratch2, Register scratch3, |
| 591 Register scratch1, | 551 Register scratch4, Register scratch5, |
| 592 Register scratch2, | 552 Label* slow) { |
| 593 Register scratch3, | 553 DCHECK(!AreAliased(key, receiver, scratch1, scratch2, scratch3, scratch4, |
| 594 Register scratch4, | 554 scratch5)); |
| 595 Register scratch5, | |
| 596 Label *slow) { | |
| 597 DCHECK(!AreAliased( | |
| 598 key, receiver, scratch1, scratch2, scratch3, scratch4, scratch5)); | |
| 599 | 555 |
| 600 Isolate* isolate = masm->isolate(); | 556 Isolate* isolate = masm->isolate(); |
| 601 Label probe_dictionary, property_array_property; | 557 Label probe_dictionary, property_array_property; |
| 602 // If we can load the value, it should be returned in x0. | 558 // If we can load the value, it should be returned in x0. |
| 603 Register result = x0; | 559 Register result = x0; |
| 604 | 560 |
| 605 GenerateKeyedLoadReceiverCheck( | 561 GenerateKeyedLoadReceiverCheck(masm, receiver, scratch1, scratch2, |
| 606 masm, receiver, scratch1, scratch2, Map::kHasNamedInterceptor, slow); | 562 Map::kHasNamedInterceptor, slow); |
| 607 | 563 |
| 608 // If the receiver is a fast-case object, check the keyed lookup cache. | 564 // If the receiver is a fast-case object, check the keyed lookup cache. |
| 609 // Otherwise probe the dictionary. | 565 // Otherwise probe the dictionary. |
| 610 __ Ldr(scratch2, FieldMemOperand(receiver, JSObject::kPropertiesOffset)); | 566 __ Ldr(scratch2, FieldMemOperand(receiver, JSObject::kPropertiesOffset)); |
| 611 __ Ldr(scratch3, FieldMemOperand(scratch2, HeapObject::kMapOffset)); | 567 __ Ldr(scratch3, FieldMemOperand(scratch2, HeapObject::kMapOffset)); |
| 612 __ JumpIfRoot(scratch3, Heap::kHashTableMapRootIndex, &probe_dictionary); | 568 __ JumpIfRoot(scratch3, Heap::kHashTableMapRootIndex, &probe_dictionary); |
| 613 | 569 |
| 614 // We keep the map of the receiver in scratch1. | 570 // We keep the map of the receiver in scratch1. |
| 615 Register receiver_map = scratch1; | 571 Register receiver_map = scratch1; |
| 616 | 572 |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 671 __ Subs(scratch4, scratch4, scratch5); | 627 __ Subs(scratch4, scratch4, scratch5); |
| 672 __ B(ge, &property_array_property); | 628 __ B(ge, &property_array_property); |
| 673 if (i != 0) { | 629 if (i != 0) { |
| 674 __ B(&load_in_object_property); | 630 __ B(&load_in_object_property); |
| 675 } | 631 } |
| 676 } | 632 } |
| 677 | 633 |
| 678 // Load in-object property. | 634 // Load in-object property. |
| 679 __ Bind(&load_in_object_property); | 635 __ Bind(&load_in_object_property); |
| 680 __ Ldrb(scratch5, FieldMemOperand(receiver_map, Map::kInstanceSizeOffset)); | 636 __ Ldrb(scratch5, FieldMemOperand(receiver_map, Map::kInstanceSizeOffset)); |
| 681 __ Add(scratch5, scratch5, scratch4); // Index from start of object. | 637 __ Add(scratch5, scratch5, scratch4); // Index from start of object. |
| 682 __ Sub(receiver, receiver, kHeapObjectTag); // Remove the heap tag. | 638 __ Sub(receiver, receiver, kHeapObjectTag); // Remove the heap tag. |
| 683 __ Ldr(result, MemOperand(receiver, scratch5, LSL, kPointerSizeLog2)); | 639 __ Ldr(result, MemOperand(receiver, scratch5, LSL, kPointerSizeLog2)); |
| 684 __ IncrementCounter(isolate->counters()->keyed_load_generic_lookup_cache(), | 640 __ IncrementCounter(isolate->counters()->keyed_load_generic_lookup_cache(), 1, |
| 685 1, scratch1, scratch2); | 641 scratch1, scratch2); |
| 686 __ Ret(); | 642 __ Ret(); |
| 687 | 643 |
| 688 // Load property array property. | 644 // Load property array property. |
| 689 __ Bind(&property_array_property); | 645 __ Bind(&property_array_property); |
| 690 __ Ldr(scratch1, FieldMemOperand(receiver, JSObject::kPropertiesOffset)); | 646 __ Ldr(scratch1, FieldMemOperand(receiver, JSObject::kPropertiesOffset)); |
| 691 __ Add(scratch1, scratch1, FixedArray::kHeaderSize - kHeapObjectTag); | 647 __ Add(scratch1, scratch1, FixedArray::kHeaderSize - kHeapObjectTag); |
| 692 __ Ldr(result, MemOperand(scratch1, scratch4, LSL, kPointerSizeLog2)); | 648 __ Ldr(result, MemOperand(scratch1, scratch4, LSL, kPointerSizeLog2)); |
| 693 __ IncrementCounter(isolate->counters()->keyed_load_generic_lookup_cache(), | 649 __ IncrementCounter(isolate->counters()->keyed_load_generic_lookup_cache(), 1, |
| 694 1, scratch1, scratch2); | 650 scratch1, scratch2); |
| 695 __ Ret(); | 651 __ Ret(); |
| 696 | 652 |
| 697 // Do a quick inline probe of the receiver's dictionary, if it exists. | 653 // Do a quick inline probe of the receiver's dictionary, if it exists. |
| 698 __ Bind(&probe_dictionary); | 654 __ Bind(&probe_dictionary); |
| 699 __ Ldr(scratch1, FieldMemOperand(receiver, HeapObject::kMapOffset)); | 655 __ Ldr(scratch1, FieldMemOperand(receiver, HeapObject::kMapOffset)); |
| 700 __ Ldrb(scratch1, FieldMemOperand(scratch1, Map::kInstanceTypeOffset)); | 656 __ Ldrb(scratch1, FieldMemOperand(scratch1, Map::kInstanceTypeOffset)); |
| 701 GenerateGlobalInstanceTypeCheck(masm, scratch1, slow); | 657 GenerateGlobalInstanceTypeCheck(masm, scratch1, slow); |
| 702 // Load the property. | 658 // Load the property. |
| 703 GenerateDictionaryLoad(masm, slow, scratch2, key, result, scratch1, scratch3); | 659 GenerateDictionaryLoad(masm, slow, scratch2, key, result, scratch1, scratch3); |
| 704 __ IncrementCounter(isolate->counters()->keyed_load_generic_symbol(), | 660 __ IncrementCounter(isolate->counters()->keyed_load_generic_symbol(), 1, |
| 705 1, scratch1, scratch2); | 661 scratch1, scratch2); |
| 706 __ Ret(); | 662 __ Ret(); |
| 707 } | 663 } |
| 708 | 664 |
| 709 | 665 |
| 710 void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) { | 666 void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) { |
| 711 // The return address is in lr. | 667 // The return address is in lr. |
| 712 Label slow, check_name, index_smi, index_name; | 668 Label slow, check_name, index_smi, index_name; |
| 713 | 669 |
| 714 Register key = NameRegister(); | 670 Register key = NameRegister(); |
| 715 Register receiver = ReceiverRegister(); | 671 Register receiver = ReceiverRegister(); |
| 716 DCHECK(key.is(x2)); | 672 DCHECK(key.is(x2)); |
| 717 DCHECK(receiver.is(x1)); | 673 DCHECK(receiver.is(x1)); |
| 718 | 674 |
| 719 __ JumpIfNotSmi(key, &check_name); | 675 __ JumpIfNotSmi(key, &check_name); |
| 720 __ Bind(&index_smi); | 676 __ Bind(&index_smi); |
| 721 // Now the key is known to be a smi. This place is also jumped to from below | 677 // Now the key is known to be a smi. This place is also jumped to from below |
| 722 // where a numeric string is converted to a smi. | 678 // where a numeric string is converted to a smi. |
| 723 GenerateKeyedLoadWithSmiKey(masm, key, receiver, x7, x3, x4, x5, x6, &slow); | 679 GenerateKeyedLoadWithSmiKey(masm, key, receiver, x7, x3, x4, x5, x6, &slow); |
| 724 | 680 |
| 725 // Slow case. | 681 // Slow case. |
| 726 __ Bind(&slow); | 682 __ Bind(&slow); |
| 727 __ IncrementCounter( | 683 __ IncrementCounter(masm->isolate()->counters()->keyed_load_generic_slow(), 1, |
| 728 masm->isolate()->counters()->keyed_load_generic_slow(), 1, x4, x3); | 684 x4, x3); |
| 729 GenerateRuntimeGetProperty(masm); | 685 GenerateRuntimeGetProperty(masm); |
| 730 | 686 |
| 731 __ Bind(&check_name); | 687 __ Bind(&check_name); |
| 732 GenerateKeyNameCheck(masm, key, x0, x3, &index_name, &slow); | 688 GenerateKeyNameCheck(masm, key, x0, x3, &index_name, &slow); |
| 733 | 689 |
| 734 GenerateKeyedLoadWithNameKey(masm, key, receiver, x7, x3, x4, x5, x6, &slow); | 690 GenerateKeyedLoadWithNameKey(masm, key, receiver, x7, x3, x4, x5, x6, &slow); |
| 735 | 691 |
| 736 __ Bind(&index_name); | 692 __ Bind(&index_name); |
| 737 __ IndexFromHash(x3, key); | 693 __ IndexFromHash(x3, key); |
| 738 // Now jump to the place where smi keys are handled. | 694 // Now jump to the place where smi keys are handled. |
| 739 __ B(&index_smi); | 695 __ B(&index_smi); |
| 740 } | 696 } |
| 741 | 697 |
| 742 | 698 |
| 743 void KeyedLoadIC::GenerateString(MacroAssembler* masm) { | 699 void KeyedLoadIC::GenerateString(MacroAssembler* masm) { |
| 744 // Return address is in lr. | 700 // Return address is in lr. |
| 745 Label miss; | 701 Label miss; |
| 746 | 702 |
| 747 Register receiver = ReceiverRegister(); | 703 Register receiver = ReceiverRegister(); |
| 748 Register index = NameRegister(); | 704 Register index = NameRegister(); |
| 749 Register result = x0; | 705 Register result = x0; |
| 750 Register scratch = x3; | 706 Register scratch = x3; |
| 751 DCHECK(!scratch.is(receiver) && !scratch.is(index)); | 707 DCHECK(!scratch.is(receiver) && !scratch.is(index)); |
| 752 | 708 |
| 753 StringCharAtGenerator char_at_generator(receiver, | 709 StringCharAtGenerator char_at_generator(receiver, index, scratch, result, |
| 754 index, | |
| 755 scratch, | |
| 756 result, | |
| 757 &miss, // When not a string. | 710 &miss, // When not a string. |
| 758 &miss, // When not a number. | 711 &miss, // When not a number. |
| 759 &miss, // When index out of range. | 712 &miss, // When index out of range. |
| 760 STRING_INDEX_IS_ARRAY_INDEX); | 713 STRING_INDEX_IS_ARRAY_INDEX); |
| 761 char_at_generator.GenerateFast(masm); | 714 char_at_generator.GenerateFast(masm); |
| 762 __ Ret(); | 715 __ Ret(); |
| 763 | 716 |
| 764 StubRuntimeCallHelper call_helper; | 717 StubRuntimeCallHelper call_helper; |
| 765 char_at_generator.GenerateSlow(masm, call_helper); | 718 char_at_generator.GenerateSlow(masm, call_helper); |
| 766 | 719 |
| (...skipping 18 matching lines...) Expand all Loading... |
| 785 // Check that the key is an array index, that is Uint32. | 738 // Check that the key is an array index, that is Uint32. |
| 786 __ TestAndBranchIfAnySet(key, kSmiTagMask | kSmiSignMask, &slow); | 739 __ TestAndBranchIfAnySet(key, kSmiTagMask | kSmiSignMask, &slow); |
| 787 | 740 |
| 788 // Get the map of the receiver. | 741 // Get the map of the receiver. |
| 789 Register map = scratch1; | 742 Register map = scratch1; |
| 790 __ Ldr(map, FieldMemOperand(receiver, HeapObject::kMapOffset)); | 743 __ Ldr(map, FieldMemOperand(receiver, HeapObject::kMapOffset)); |
| 791 | 744 |
| 792 // Check that it has indexed interceptor and access checks | 745 // Check that it has indexed interceptor and access checks |
| 793 // are not enabled for this object. | 746 // are not enabled for this object. |
| 794 __ Ldrb(scratch2, FieldMemOperand(map, Map::kBitFieldOffset)); | 747 __ Ldrb(scratch2, FieldMemOperand(map, Map::kBitFieldOffset)); |
| 795 DCHECK(kSlowCaseBitFieldMask == | 748 DCHECK(kSlowCaseBitFieldMask == ((1 << Map::kIsAccessCheckNeeded) | |
| 796 ((1 << Map::kIsAccessCheckNeeded) | (1 << Map::kHasIndexedInterceptor))); | 749 (1 << Map::kHasIndexedInterceptor))); |
| 797 __ Tbnz(scratch2, Map::kIsAccessCheckNeeded, &slow); | 750 __ Tbnz(scratch2, Map::kIsAccessCheckNeeded, &slow); |
| 798 __ Tbz(scratch2, Map::kHasIndexedInterceptor, &slow); | 751 __ Tbz(scratch2, Map::kHasIndexedInterceptor, &slow); |
| 799 | 752 |
| 800 // Everything is fine, call runtime. | 753 // Everything is fine, call runtime. |
| 801 __ Push(receiver, key); | 754 __ Push(receiver, key); |
| 802 __ TailCallExternalReference( | 755 __ TailCallExternalReference( |
| 803 ExternalReference(IC_Utility(kLoadElementWithInterceptor), | 756 ExternalReference(IC_Utility(kLoadElementWithInterceptor), |
| 804 masm->isolate()), | 757 masm->isolate()), |
| 805 2, 1); | 758 2, 1); |
| 806 | 759 |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 844 | 797 |
| 845 // Push strict_mode for runtime call. | 798 // Push strict_mode for runtime call. |
| 846 __ Mov(x10, Smi::FromInt(strict_mode)); | 799 __ Mov(x10, Smi::FromInt(strict_mode)); |
| 847 __ Push(x10); | 800 __ Push(x10); |
| 848 | 801 |
| 849 __ TailCallRuntime(Runtime::kSetProperty, 4, 1); | 802 __ TailCallRuntime(Runtime::kSetProperty, 4, 1); |
| 850 } | 803 } |
| 851 | 804 |
| 852 | 805 |
| 853 static void KeyedStoreGenerateGenericHelper( | 806 static void KeyedStoreGenerateGenericHelper( |
| 854 MacroAssembler* masm, | 807 MacroAssembler* masm, Label* fast_object, Label* fast_double, Label* slow, |
| 855 Label* fast_object, | 808 KeyedStoreCheckMap check_map, KeyedStoreIncrementLength increment_length, |
| 856 Label* fast_double, | 809 Register value, Register key, Register receiver, Register receiver_map, |
| 857 Label* slow, | 810 Register elements_map, Register elements) { |
| 858 KeyedStoreCheckMap check_map, | 811 DCHECK(!AreAliased(value, key, receiver, receiver_map, elements_map, elements, |
| 859 KeyedStoreIncrementLength increment_length, | 812 x10, x11)); |
| 860 Register value, | |
| 861 Register key, | |
| 862 Register receiver, | |
| 863 Register receiver_map, | |
| 864 Register elements_map, | |
| 865 Register elements) { | |
| 866 DCHECK(!AreAliased( | |
| 867 value, key, receiver, receiver_map, elements_map, elements, x10, x11)); | |
| 868 | 813 |
| 869 Label transition_smi_elements; | 814 Label transition_smi_elements; |
| 870 Label transition_double_elements; | 815 Label transition_double_elements; |
| 871 Label fast_double_without_map_check; | 816 Label fast_double_without_map_check; |
| 872 Label non_double_value; | 817 Label non_double_value; |
| 873 Label finish_store; | 818 Label finish_store; |
| 874 | 819 |
| 875 __ Bind(fast_object); | 820 __ Bind(fast_object); |
| 876 if (check_map == kCheckMap) { | 821 if (check_map == kCheckMap) { |
| 877 __ Ldr(elements_map, FieldMemOperand(elements, HeapObject::kMapOffset)); | 822 __ Ldr(elements_map, FieldMemOperand(elements, HeapObject::kMapOffset)); |
| (...skipping 29 matching lines...) Expand all Loading... |
| 907 Register address = x11; | 852 Register address = x11; |
| 908 __ Add(address, elements, FixedArray::kHeaderSize - kHeapObjectTag); | 853 __ Add(address, elements, FixedArray::kHeaderSize - kHeapObjectTag); |
| 909 __ Add(address, address, Operand::UntagSmiAndScale(key, kPointerSizeLog2)); | 854 __ Add(address, address, Operand::UntagSmiAndScale(key, kPointerSizeLog2)); |
| 910 __ Str(value, MemOperand(address)); | 855 __ Str(value, MemOperand(address)); |
| 911 | 856 |
| 912 Label dont_record_write; | 857 Label dont_record_write; |
| 913 __ JumpIfSmi(value, &dont_record_write); | 858 __ JumpIfSmi(value, &dont_record_write); |
| 914 | 859 |
| 915 // Update write barrier for the elements array address. | 860 // Update write barrier for the elements array address. |
| 916 __ Mov(x10, value); // Preserve the value which is returned. | 861 __ Mov(x10, value); // Preserve the value which is returned. |
| 917 __ RecordWrite(elements, | 862 __ RecordWrite(elements, address, x10, kLRHasNotBeenSaved, kDontSaveFPRegs, |
| 918 address, | 863 EMIT_REMEMBERED_SET, OMIT_SMI_CHECK); |
| 919 x10, | |
| 920 kLRHasNotBeenSaved, | |
| 921 kDontSaveFPRegs, | |
| 922 EMIT_REMEMBERED_SET, | |
| 923 OMIT_SMI_CHECK); | |
| 924 | 864 |
| 925 __ Bind(&dont_record_write); | 865 __ Bind(&dont_record_write); |
| 926 __ Ret(); | 866 __ Ret(); |
| 927 | 867 |
| 928 | 868 |
| 929 __ Bind(fast_double); | 869 __ Bind(fast_double); |
| 930 if (check_map == kCheckMap) { | 870 if (check_map == kCheckMap) { |
| 931 // Check for fast double array case. If this fails, call through to the | 871 // Check for fast double array case. If this fails, call through to the |
| 932 // runtime. | 872 // runtime. |
| 933 __ JumpIfNotRoot(elements_map, Heap::kFixedDoubleArrayMapRootIndex, slow); | 873 __ JumpIfNotRoot(elements_map, Heap::kFixedDoubleArrayMapRootIndex, slow); |
| 934 } | 874 } |
| 935 | 875 |
| 936 // HOLECHECK: guards "A[i] double hole?" | 876 // HOLECHECK: guards "A[i] double hole?" |
| 937 // We have to see if the double version of the hole is present. If so go to | 877 // We have to see if the double version of the hole is present. If so go to |
| 938 // the runtime. | 878 // the runtime. |
| 939 __ Add(x10, elements, FixedDoubleArray::kHeaderSize - kHeapObjectTag); | 879 __ Add(x10, elements, FixedDoubleArray::kHeaderSize - kHeapObjectTag); |
| 940 __ Add(x10, x10, Operand::UntagSmiAndScale(key, kPointerSizeLog2)); | 880 __ Add(x10, x10, Operand::UntagSmiAndScale(key, kPointerSizeLog2)); |
| 941 __ Ldr(x11, MemOperand(x10)); | 881 __ Ldr(x11, MemOperand(x10)); |
| 942 __ CompareAndBranch(x11, kHoleNanInt64, ne, &fast_double_without_map_check); | 882 __ CompareAndBranch(x11, kHoleNanInt64, ne, &fast_double_without_map_check); |
| 943 __ JumpIfDictionaryInPrototypeChain(receiver, elements_map, x10, slow); | 883 __ JumpIfDictionaryInPrototypeChain(receiver, elements_map, x10, slow); |
| 944 | 884 |
| 945 __ Bind(&fast_double_without_map_check); | 885 __ Bind(&fast_double_without_map_check); |
| 946 __ StoreNumberToDoubleElements(value, | 886 __ StoreNumberToDoubleElements(value, key, elements, x10, d0, |
| 947 key, | |
| 948 elements, | |
| 949 x10, | |
| 950 d0, | |
| 951 &transition_double_elements); | 887 &transition_double_elements); |
| 952 if (increment_length == kIncrementLength) { | 888 if (increment_length == kIncrementLength) { |
| 953 // Add 1 to receiver->length. | 889 // Add 1 to receiver->length. |
| 954 __ Add(x10, key, Smi::FromInt(1)); | 890 __ Add(x10, key, Smi::FromInt(1)); |
| 955 __ Str(x10, FieldMemOperand(receiver, JSArray::kLengthOffset)); | 891 __ Str(x10, FieldMemOperand(receiver, JSArray::kLengthOffset)); |
| 956 } | 892 } |
| 957 __ Ret(); | 893 __ Ret(); |
| 958 | 894 |
| 959 | 895 |
| 960 __ Bind(&transition_smi_elements); | 896 __ Bind(&transition_smi_elements); |
| 961 // Transition the array appropriately depending on the value type. | 897 // Transition the array appropriately depending on the value type. |
| 962 __ Ldr(x10, FieldMemOperand(value, HeapObject::kMapOffset)); | 898 __ Ldr(x10, FieldMemOperand(value, HeapObject::kMapOffset)); |
| 963 __ JumpIfNotRoot(x10, Heap::kHeapNumberMapRootIndex, &non_double_value); | 899 __ JumpIfNotRoot(x10, Heap::kHeapNumberMapRootIndex, &non_double_value); |
| 964 | 900 |
| 965 // Value is a double. Transition FAST_SMI_ELEMENTS -> | 901 // Value is a double. Transition FAST_SMI_ELEMENTS -> |
| 966 // FAST_DOUBLE_ELEMENTS and complete the store. | 902 // FAST_DOUBLE_ELEMENTS and complete the store. |
| 967 __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS, | 903 __ LoadTransitionedArrayMapConditional( |
| 968 FAST_DOUBLE_ELEMENTS, | 904 FAST_SMI_ELEMENTS, FAST_DOUBLE_ELEMENTS, receiver_map, x10, x11, slow); |
| 969 receiver_map, | 905 AllocationSiteMode mode = |
| 970 x10, | 906 AllocationSite::GetMode(FAST_SMI_ELEMENTS, FAST_DOUBLE_ELEMENTS); |
| 971 x11, | 907 ElementsTransitionGenerator::GenerateSmiToDouble(masm, receiver, key, value, |
| 972 slow); | 908 receiver_map, mode, slow); |
| 973 AllocationSiteMode mode = AllocationSite::GetMode(FAST_SMI_ELEMENTS, | |
| 974 FAST_DOUBLE_ELEMENTS); | |
| 975 ElementsTransitionGenerator::GenerateSmiToDouble( | |
| 976 masm, receiver, key, value, receiver_map, mode, slow); | |
| 977 __ Ldr(elements, FieldMemOperand(receiver, JSObject::kElementsOffset)); | 909 __ Ldr(elements, FieldMemOperand(receiver, JSObject::kElementsOffset)); |
| 978 __ B(&fast_double_without_map_check); | 910 __ B(&fast_double_without_map_check); |
| 979 | 911 |
| 980 __ Bind(&non_double_value); | 912 __ Bind(&non_double_value); |
| 981 // Value is not a double, FAST_SMI_ELEMENTS -> FAST_ELEMENTS. | 913 // Value is not a double, FAST_SMI_ELEMENTS -> FAST_ELEMENTS. |
| 982 __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS, | 914 __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS, FAST_ELEMENTS, |
| 983 FAST_ELEMENTS, | 915 receiver_map, x10, x11, slow); |
| 984 receiver_map, | |
| 985 x10, | |
| 986 x11, | |
| 987 slow); | |
| 988 | 916 |
| 989 mode = AllocationSite::GetMode(FAST_SMI_ELEMENTS, FAST_ELEMENTS); | 917 mode = AllocationSite::GetMode(FAST_SMI_ELEMENTS, FAST_ELEMENTS); |
| 990 ElementsTransitionGenerator::GenerateMapChangeElementsTransition( | 918 ElementsTransitionGenerator::GenerateMapChangeElementsTransition( |
| 991 masm, receiver, key, value, receiver_map, mode, slow); | 919 masm, receiver, key, value, receiver_map, mode, slow); |
| 992 | 920 |
| 993 __ Ldr(elements, FieldMemOperand(receiver, JSObject::kElementsOffset)); | 921 __ Ldr(elements, FieldMemOperand(receiver, JSObject::kElementsOffset)); |
| 994 __ B(&finish_store); | 922 __ B(&finish_store); |
| 995 | 923 |
| 996 __ Bind(&transition_double_elements); | 924 __ Bind(&transition_double_elements); |
| 997 // Elements are FAST_DOUBLE_ELEMENTS, but value is an Object that's not a | 925 // Elements are FAST_DOUBLE_ELEMENTS, but value is an Object that's not a |
| 998 // HeapNumber. Make sure that the receiver is a Array with FAST_ELEMENTS and | 926 // HeapNumber. Make sure that the receiver is a Array with FAST_ELEMENTS and |
| 999 // transition array from FAST_DOUBLE_ELEMENTS to FAST_ELEMENTS | 927 // transition array from FAST_DOUBLE_ELEMENTS to FAST_ELEMENTS |
| 1000 __ LoadTransitionedArrayMapConditional(FAST_DOUBLE_ELEMENTS, | 928 __ LoadTransitionedArrayMapConditional(FAST_DOUBLE_ELEMENTS, FAST_ELEMENTS, |
| 1001 FAST_ELEMENTS, | 929 receiver_map, x10, x11, slow); |
| 1002 receiver_map, | |
| 1003 x10, | |
| 1004 x11, | |
| 1005 slow); | |
| 1006 mode = AllocationSite::GetMode(FAST_DOUBLE_ELEMENTS, FAST_ELEMENTS); | 930 mode = AllocationSite::GetMode(FAST_DOUBLE_ELEMENTS, FAST_ELEMENTS); |
| 1007 ElementsTransitionGenerator::GenerateDoubleToObject( | 931 ElementsTransitionGenerator::GenerateDoubleToObject( |
| 1008 masm, receiver, key, value, receiver_map, mode, slow); | 932 masm, receiver, key, value, receiver_map, mode, slow); |
| 1009 __ Ldr(elements, FieldMemOperand(receiver, JSObject::kElementsOffset)); | 933 __ Ldr(elements, FieldMemOperand(receiver, JSObject::kElementsOffset)); |
| 1010 __ B(&finish_store); | 934 __ B(&finish_store); |
| 1011 } | 935 } |
| 1012 | 936 |
| 1013 | 937 |
| 1014 void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm, | 938 void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm, |
| 1015 StrictMode strict_mode) { | 939 StrictMode strict_mode) { |
| (...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1094 // is the length is always a smi. | 1018 // is the length is always a smi. |
| 1095 | 1019 |
| 1096 __ Ldr(elements, FieldMemOperand(receiver, JSObject::kElementsOffset)); | 1020 __ Ldr(elements, FieldMemOperand(receiver, JSObject::kElementsOffset)); |
| 1097 | 1021 |
| 1098 // Check the key against the length in the array. | 1022 // Check the key against the length in the array. |
| 1099 __ Ldrsw(x10, UntagSmiFieldMemOperand(receiver, JSArray::kLengthOffset)); | 1023 __ Ldrsw(x10, UntagSmiFieldMemOperand(receiver, JSArray::kLengthOffset)); |
| 1100 __ Cmp(x10, Operand::UntagSmi(key)); | 1024 __ Cmp(x10, Operand::UntagSmi(key)); |
| 1101 __ B(eq, &extra); // We can handle the case where we are appending 1 element. | 1025 __ B(eq, &extra); // We can handle the case where we are appending 1 element. |
| 1102 __ B(lo, &slow); | 1026 __ B(lo, &slow); |
| 1103 | 1027 |
| 1104 KeyedStoreGenerateGenericHelper(masm, &fast_object, &fast_double, | 1028 KeyedStoreGenerateGenericHelper( |
| 1105 &slow, kCheckMap, kDontIncrementLength, | 1029 masm, &fast_object, &fast_double, &slow, kCheckMap, kDontIncrementLength, |
| 1106 value, key, receiver, receiver_map, | 1030 value, key, receiver, receiver_map, elements_map, elements); |
| 1107 elements_map, elements); | |
| 1108 KeyedStoreGenerateGenericHelper(masm, &fast_object_grow, &fast_double_grow, | 1031 KeyedStoreGenerateGenericHelper(masm, &fast_object_grow, &fast_double_grow, |
| 1109 &slow, kDontCheckMap, kIncrementLength, | 1032 &slow, kDontCheckMap, kIncrementLength, value, |
| 1110 value, key, receiver, receiver_map, | 1033 key, receiver, receiver_map, elements_map, |
| 1111 elements_map, elements); | 1034 elements); |
| 1112 } | 1035 } |
| 1113 | 1036 |
| 1114 | 1037 |
| 1115 void StoreIC::GenerateMegamorphic(MacroAssembler* masm) { | 1038 void StoreIC::GenerateMegamorphic(MacroAssembler* masm) { |
| 1116 Register receiver = ReceiverRegister(); | 1039 Register receiver = ReceiverRegister(); |
| 1117 Register name = NameRegister(); | 1040 Register name = NameRegister(); |
| 1118 DCHECK(!AreAliased(receiver, name, ValueRegister(), x3, x4, x5, x6)); | 1041 DCHECK(!AreAliased(receiver, name, ValueRegister(), x3, x4, x5, x6)); |
| 1119 | 1042 |
| 1120 // Probe the stub cache. | 1043 // Probe the stub cache. |
| 1121 Code::Flags flags = Code::RemoveTypeAndHolderFromFlags( | 1044 Code::Flags flags = Code::RemoveTypeAndHolderFromFlags( |
| 1122 Code::ComputeHandlerFlags(Code::STORE_IC)); | 1045 Code::ComputeHandlerFlags(Code::STORE_IC)); |
| 1123 masm->isolate()->stub_cache()->GenerateProbe( | 1046 masm->isolate()->stub_cache()->GenerateProbe(masm, flags, receiver, name, x3, |
| 1124 masm, flags, receiver, name, x3, x4, x5, x6); | 1047 x4, x5, x6); |
| 1125 | 1048 |
| 1126 // Cache miss: Jump to runtime. | 1049 // Cache miss: Jump to runtime. |
| 1127 GenerateMiss(masm); | 1050 GenerateMiss(masm); |
| 1128 } | 1051 } |
| 1129 | 1052 |
| 1130 | 1053 |
| 1131 void StoreIC::GenerateMiss(MacroAssembler* masm) { | 1054 void StoreIC::GenerateMiss(MacroAssembler* masm) { |
| 1132 __ Push(ReceiverRegister(), NameRegister(), ValueRegister()); | 1055 __ Push(ReceiverRegister(), NameRegister(), ValueRegister()); |
| 1133 | 1056 |
| 1134 // Tail call to the entry. | 1057 // Tail call to the entry. |
| (...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1208 return ge; | 1131 return ge; |
| 1209 default: | 1132 default: |
| 1210 UNREACHABLE(); | 1133 UNREACHABLE(); |
| 1211 return al; | 1134 return al; |
| 1212 } | 1135 } |
| 1213 } | 1136 } |
| 1214 | 1137 |
| 1215 | 1138 |
| 1216 bool CompareIC::HasInlinedSmiCode(Address address) { | 1139 bool CompareIC::HasInlinedSmiCode(Address address) { |
| 1217 // The address of the instruction following the call. | 1140 // The address of the instruction following the call. |
| 1218 Address info_address = | 1141 Address info_address = Assembler::return_address_from_call_start(address); |
| 1219 Assembler::return_address_from_call_start(address); | |
| 1220 | 1142 |
| 1221 InstructionSequence* patch_info = InstructionSequence::At(info_address); | 1143 InstructionSequence* patch_info = InstructionSequence::At(info_address); |
| 1222 return patch_info->IsInlineData(); | 1144 return patch_info->IsInlineData(); |
| 1223 } | 1145 } |
| 1224 | 1146 |
| 1225 | 1147 |
| 1226 // Activate a SMI fast-path by patching the instructions generated by | 1148 // Activate a SMI fast-path by patching the instructions generated by |
| 1227 // JumpPatchSite::EmitJumpIf(Not)Smi(), using the information encoded by | 1149 // JumpPatchSite::EmitJumpIf(Not)Smi(), using the information encoded by |
| 1228 // JumpPatchSite::EmitPatchInfo(). | 1150 // JumpPatchSite::EmitPatchInfo(). |
| 1229 void PatchInlinedSmiCode(Address address, InlinedSmiCheck check) { | 1151 void PatchInlinedSmiCode(Address address, InlinedSmiCheck check) { |
| 1230 // The patch information is encoded in the instruction stream using | 1152 // The patch information is encoded in the instruction stream using |
| 1231 // instructions which have no side effects, so we can safely execute them. | 1153 // instructions which have no side effects, so we can safely execute them. |
| 1232 // The patch information is encoded directly after the call to the helper | 1154 // The patch information is encoded directly after the call to the helper |
| 1233 // function which is requesting this patch operation. | 1155 // function which is requesting this patch operation. |
| 1234 Address info_address = | 1156 Address info_address = Assembler::return_address_from_call_start(address); |
| 1235 Assembler::return_address_from_call_start(address); | |
| 1236 InlineSmiCheckInfo info(info_address); | 1157 InlineSmiCheckInfo info(info_address); |
| 1237 | 1158 |
| 1238 // Check and decode the patch information instruction. | 1159 // Check and decode the patch information instruction. |
| 1239 if (!info.HasSmiCheck()) { | 1160 if (!info.HasSmiCheck()) { |
| 1240 return; | 1161 return; |
| 1241 } | 1162 } |
| 1242 | 1163 |
| 1243 if (FLAG_trace_ic) { | 1164 if (FLAG_trace_ic) { |
| 1244 PrintF("[ Patching ic at %p, marker=%p, SMI check=%p\n", | 1165 PrintF("[ Patching ic at %p, marker=%p, SMI check=%p\n", address, |
| 1245 address, info_address, reinterpret_cast<void*>(info.SmiCheck())); | 1166 info_address, reinterpret_cast<void*>(info.SmiCheck())); |
| 1246 } | 1167 } |
| 1247 | 1168 |
| 1248 // Patch and activate code generated by JumpPatchSite::EmitJumpIfNotSmi() | 1169 // Patch and activate code generated by JumpPatchSite::EmitJumpIfNotSmi() |
| 1249 // and JumpPatchSite::EmitJumpIfSmi(). | 1170 // and JumpPatchSite::EmitJumpIfSmi(). |
| 1250 // Changing | 1171 // Changing |
| 1251 // tb(n)z xzr, #0, <target> | 1172 // tb(n)z xzr, #0, <target> |
| 1252 // to | 1173 // to |
| 1253 // tb(!n)z test_reg, #0, <target> | 1174 // tb(!n)z test_reg, #0, <target> |
| 1254 Instruction* to_patch = info.SmiCheck(); | 1175 Instruction* to_patch = info.SmiCheck(); |
| 1255 PatchingAssembler patcher(to_patch, 1); | 1176 PatchingAssembler patcher(to_patch, 1); |
| (...skipping 17 matching lines...) Expand all Loading... |
| 1273 | 1194 |
| 1274 if (to_patch->Mask(TestBranchMask) == TBZ) { | 1195 if (to_patch->Mask(TestBranchMask) == TBZ) { |
| 1275 // This is JumpIfNotSmi(smi_reg, branch_imm). | 1196 // This is JumpIfNotSmi(smi_reg, branch_imm). |
| 1276 patcher.tbnz(smi_reg, 0, branch_imm); | 1197 patcher.tbnz(smi_reg, 0, branch_imm); |
| 1277 } else { | 1198 } else { |
| 1278 DCHECK(to_patch->Mask(TestBranchMask) == TBNZ); | 1199 DCHECK(to_patch->Mask(TestBranchMask) == TBNZ); |
| 1279 // This is JumpIfSmi(smi_reg, branch_imm). | 1200 // This is JumpIfSmi(smi_reg, branch_imm). |
| 1280 patcher.tbz(smi_reg, 0, branch_imm); | 1201 patcher.tbz(smi_reg, 0, branch_imm); |
| 1281 } | 1202 } |
| 1282 } | 1203 } |
| 1283 | 1204 } |
| 1284 | 1205 } // namespace v8::internal |
| 1285 } } // namespace v8::internal | |
| 1286 | 1206 |
| 1287 #endif // V8_TARGET_ARCH_ARM64 | 1207 #endif // V8_TARGET_ARCH_ARM64 |
| OLD | NEW |