| OLD | NEW |
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_X64. | 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_X64. |
| 6 #if defined(TARGET_ARCH_X64) | 6 #if defined(TARGET_ARCH_X64) |
| 7 | 7 |
| 8 #include "vm/intrinsifier.h" | 8 #include "vm/intrinsifier.h" |
| 9 | 9 |
| 10 #include "vm/assembler.h" | 10 #include "vm/assembler.h" |
| 11 #include "vm/flow_graph_compiler.h" | 11 #include "vm/flow_graph_compiler.h" |
| 12 #include "vm/instructions.h" | 12 #include "vm/instructions.h" |
| 13 #include "vm/object_store.h" | 13 #include "vm/object_store.h" |
| 14 #include "vm/symbols.h" | 14 #include "vm/symbols.h" |
| 15 | 15 |
| 16 namespace dart { | 16 namespace dart { |
| 17 | 17 |
| 18 DECLARE_FLAG(bool, enable_type_checks); | 18 DECLARE_FLAG(bool, enable_type_checks); |
| 19 | 19 |
| 20 // When entering intrinsics code: | 20 // When entering intrinsics code: |
| 21 // RBX: IC Data | 21 // RBX: IC Data |
| 22 // R10: Arguments descriptor | 22 // R10: Arguments descriptor |
| 23 // TOS: Return address | 23 // TOS: Return address |
| 24 // The RBX, R10 registers can be destroyed only if there is no slow-path (i.e., | 24 // The RBX, R10 registers can be destroyed only if there is no slow-path (i.e., |
| 25 // the methods returns true). | 25 // the methods returns true). |
| 26 | 26 |
| 27 #define __ assembler-> | 27 #define __ assembler-> |
| 28 | 28 |
| 29 | 29 |
| 30 void Intrinsifier::ObjectArray_Allocate(Assembler* assembler) { | 30 void Intrinsifier::List_Allocate(Assembler* assembler) { |
| 31 // This snippet of inlined code uses the following registers: | 31 // This snippet of inlined code uses the following registers: |
| 32 // RAX, RCX, RDI, R13 | 32 // RAX, RCX, RDI, R13 |
| 33 // and the newly allocated object is returned in RAX. | 33 // and the newly allocated object is returned in RAX. |
| 34 const intptr_t kTypeArgumentsOffset = 2 * kWordSize; | 34 const intptr_t kTypeArgumentsOffset = 2 * kWordSize; |
| 35 const intptr_t kArrayLengthOffset = 1 * kWordSize; | 35 const intptr_t kArrayLengthOffset = 1 * kWordSize; |
| 36 Label fall_through; | 36 Label fall_through; |
| 37 | 37 |
| 38 // Compute the size to be allocated, it is based on the array length | 38 // Compute the size to be allocated, it is based on the array length |
| 39 // and is computed as: | 39 // and is computed as: |
| 40 // RoundedAllocationSize((array_length * kwordSize) + sizeof(RawArray)). | 40 // RoundedAllocationSize((array_length * kwordSize) + sizeof(RawArray)). |
| (...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 134 } | 134 } |
| 135 | 135 |
| 136 | 136 |
| 137 void Intrinsifier::Array_getLength(Assembler* assembler) { | 137 void Intrinsifier::Array_getLength(Assembler* assembler) { |
| 138 __ movq(RAX, Address(RSP, + 1 * kWordSize)); | 138 __ movq(RAX, Address(RSP, + 1 * kWordSize)); |
| 139 __ movq(RAX, FieldAddress(RAX, Array::length_offset())); | 139 __ movq(RAX, FieldAddress(RAX, Array::length_offset())); |
| 140 __ ret(); | 140 __ ret(); |
| 141 } | 141 } |
| 142 | 142 |
| 143 | 143 |
| 144 void Intrinsifier::ImmutableArray_getLength(Assembler* assembler) { | 144 void Intrinsifier::ImmutableList_getLength(Assembler* assembler) { |
| 145 return Array_getLength(assembler); | 145 return Array_getLength(assembler); |
| 146 } | 146 } |
| 147 | 147 |
| 148 | 148 |
| 149 void Intrinsifier::Array_getIndexed(Assembler* assembler) { | 149 void Intrinsifier::Array_getIndexed(Assembler* assembler) { |
| 150 Label fall_through; | 150 Label fall_through; |
| 151 __ movq(RCX, Address(RSP, + 1 * kWordSize)); // Index. | 151 __ movq(RCX, Address(RSP, + 1 * kWordSize)); // Index. |
| 152 __ movq(RAX, Address(RSP, + 2 * kWordSize)); // Array. | 152 __ movq(RAX, Address(RSP, + 2 * kWordSize)); // Array. |
| 153 __ testq(RCX, Immediate(kSmiTagMask)); | 153 __ testq(RCX, Immediate(kSmiTagMask)); |
| 154 __ j(NOT_ZERO, &fall_through, Assembler::kNearJump); // Non-smi index. | 154 __ j(NOT_ZERO, &fall_through, Assembler::kNearJump); // Non-smi index. |
| 155 // Range check. | 155 // Range check. |
| 156 __ cmpq(RCX, FieldAddress(RAX, Array::length_offset())); | 156 __ cmpq(RCX, FieldAddress(RAX, Array::length_offset())); |
| 157 // Runtime throws exception. | 157 // Runtime throws exception. |
| 158 __ j(ABOVE_EQUAL, &fall_through, Assembler::kNearJump); | 158 __ j(ABOVE_EQUAL, &fall_through, Assembler::kNearJump); |
| 159 // Note that RBX is Smi, i.e, times 2. | 159 // Note that RBX is Smi, i.e, times 2. |
| 160 ASSERT(kSmiTagShift == 1); | 160 ASSERT(kSmiTagShift == 1); |
| 161 __ movq(RAX, FieldAddress(RAX, RCX, TIMES_4, Array::data_offset())); | 161 __ movq(RAX, FieldAddress(RAX, RCX, TIMES_4, Array::data_offset())); |
| 162 __ ret(); | 162 __ ret(); |
| 163 __ Bind(&fall_through); | 163 __ Bind(&fall_through); |
| 164 } | 164 } |
| 165 | 165 |
| 166 | 166 |
| 167 void Intrinsifier::ImmutableArray_getIndexed(Assembler* assembler) { | 167 void Intrinsifier::ImmutableList_getIndexed(Assembler* assembler) { |
| 168 return Array_getIndexed(assembler); | 168 return Array_getIndexed(assembler); |
| 169 } | 169 } |
| 170 | 170 |
| 171 | 171 |
| 172 void Intrinsifier::Array_setIndexed(Assembler* assembler) { | 172 void Intrinsifier::Array_setIndexed(Assembler* assembler) { |
| 173 if (FLAG_enable_type_checks) { | 173 if (FLAG_enable_type_checks) { |
| 174 return; | 174 return; |
| 175 } | 175 } |
| 176 __ movq(RDX, Address(RSP, + 1 * kWordSize)); // Value. | 176 __ movq(RDX, Address(RSP, + 1 * kWordSize)); // Value. |
| 177 __ movq(RCX, Address(RSP, + 2 * kWordSize)); // Index. | 177 __ movq(RCX, Address(RSP, + 2 * kWordSize)); // Index. |
| (...skipping 12 matching lines...) Expand all Loading... |
| 190 FieldAddress(RAX, RCX, TIMES_4, Array::data_offset()), | 190 FieldAddress(RAX, RCX, TIMES_4, Array::data_offset()), |
| 191 RDX); | 191 RDX); |
| 192 // Caller is responsible of preserving the value if necessary. | 192 // Caller is responsible of preserving the value if necessary. |
| 193 __ ret(); | 193 __ ret(); |
| 194 __ Bind(&fall_through); | 194 __ Bind(&fall_through); |
| 195 } | 195 } |
| 196 | 196 |
| 197 | 197 |
| 198 // Allocate a GrowableObjectArray using the backing array specified. | 198 // Allocate a GrowableObjectArray using the backing array specified. |
| 199 // On stack: type argument (+2), data (+1), return-address (+0). | 199 // On stack: type argument (+2), data (+1), return-address (+0). |
| 200 void Intrinsifier::GrowableArray_Allocate(Assembler* assembler) { | 200 void Intrinsifier::GrowableList_Allocate(Assembler* assembler) { |
| 201 // This snippet of inlined code uses the following registers: | 201 // This snippet of inlined code uses the following registers: |
| 202 // RAX, RCX, R13 | 202 // RAX, RCX, R13 |
| 203 // and the newly allocated object is returned in RAX. | 203 // and the newly allocated object is returned in RAX. |
| 204 const intptr_t kTypeArgumentsOffset = 2 * kWordSize; | 204 const intptr_t kTypeArgumentsOffset = 2 * kWordSize; |
| 205 const intptr_t kArrayOffset = 1 * kWordSize; | 205 const intptr_t kArrayOffset = 1 * kWordSize; |
| 206 Label fall_through; | 206 Label fall_through; |
| 207 | 207 |
| 208 // Compute the size to be allocated, it is based on the array length | 208 // Compute the size to be allocated, it is based on the array length |
| 209 // and is computed as: | 209 // and is computed as: |
| 210 // RoundedAllocationSize(sizeof(RawGrowableObjectArray)) + | 210 // RoundedAllocationSize(sizeof(RawGrowableObjectArray)) + |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 260 __ movq(FieldAddress(RAX, GrowableObjectArray::length_offset()), | 260 __ movq(FieldAddress(RAX, GrowableObjectArray::length_offset()), |
| 261 Immediate(0)); | 261 Immediate(0)); |
| 262 __ ret(); // returns the newly allocated object in RAX. | 262 __ ret(); // returns the newly allocated object in RAX. |
| 263 | 263 |
| 264 __ Bind(&fall_through); | 264 __ Bind(&fall_through); |
| 265 } | 265 } |
| 266 | 266 |
| 267 | 267 |
| 268 // Get length of growable object array. | 268 // Get length of growable object array. |
| 269 // On stack: growable array (+1), return-address (+0). | 269 // On stack: growable array (+1), return-address (+0). |
| 270 void Intrinsifier::GrowableArray_getLength(Assembler* assembler) { | 270 void Intrinsifier::GrowableList_getLength(Assembler* assembler) { |
| 271 __ movq(RAX, Address(RSP, + 1 * kWordSize)); | 271 __ movq(RAX, Address(RSP, + 1 * kWordSize)); |
| 272 __ movq(RAX, FieldAddress(RAX, GrowableObjectArray::length_offset())); | 272 __ movq(RAX, FieldAddress(RAX, GrowableObjectArray::length_offset())); |
| 273 __ ret(); | 273 __ ret(); |
| 274 } | 274 } |
| 275 | 275 |
| 276 | 276 |
| 277 void Intrinsifier::GrowableArray_getCapacity(Assembler* assembler) { | 277 void Intrinsifier::GrowableList_getCapacity(Assembler* assembler) { |
| 278 __ movq(RAX, Address(RSP, + 1 * kWordSize)); | 278 __ movq(RAX, Address(RSP, + 1 * kWordSize)); |
| 279 __ movq(RAX, FieldAddress(RAX, GrowableObjectArray::data_offset())); | 279 __ movq(RAX, FieldAddress(RAX, GrowableObjectArray::data_offset())); |
| 280 __ movq(RAX, FieldAddress(RAX, Array::length_offset())); | 280 __ movq(RAX, FieldAddress(RAX, Array::length_offset())); |
| 281 __ ret(); | 281 __ ret(); |
| 282 } | 282 } |
| 283 | 283 |
| 284 | 284 |
| 285 // Access growable object array at specified index. | 285 // Access growable object array at specified index. |
| 286 // On stack: growable array (+2), index (+1), return-address (+0). | 286 // On stack: growable array (+2), index (+1), return-address (+0). |
| 287 void Intrinsifier::GrowableArray_getIndexed(Assembler* assembler) { | 287 void Intrinsifier::GrowableList_getIndexed(Assembler* assembler) { |
| 288 Label fall_through; | 288 Label fall_through; |
| 289 __ movq(RCX, Address(RSP, + 1 * kWordSize)); // Index. | 289 __ movq(RCX, Address(RSP, + 1 * kWordSize)); // Index. |
| 290 __ movq(RAX, Address(RSP, + 2 * kWordSize)); // GrowableArray. | 290 __ movq(RAX, Address(RSP, + 2 * kWordSize)); // GrowableArray. |
| 291 __ testq(RCX, Immediate(kSmiTagMask)); | 291 __ testq(RCX, Immediate(kSmiTagMask)); |
| 292 __ j(NOT_ZERO, &fall_through, Assembler::kNearJump); // Non-smi index. | 292 __ j(NOT_ZERO, &fall_through, Assembler::kNearJump); // Non-smi index. |
| 293 // Range check using _length field. | 293 // Range check using _length field. |
| 294 __ cmpq(RCX, FieldAddress(RAX, GrowableObjectArray::length_offset())); | 294 __ cmpq(RCX, FieldAddress(RAX, GrowableObjectArray::length_offset())); |
| 295 // Runtime throws exception. | 295 // Runtime throws exception. |
| 296 __ j(ABOVE_EQUAL, &fall_through, Assembler::kNearJump); | 296 __ j(ABOVE_EQUAL, &fall_through, Assembler::kNearJump); |
| 297 __ movq(RAX, FieldAddress(RAX, GrowableObjectArray::data_offset())); // data. | 297 __ movq(RAX, FieldAddress(RAX, GrowableObjectArray::data_offset())); // data. |
| 298 | 298 |
| 299 // Note that RCX is Smi, i.e, times 4. | 299 // Note that RCX is Smi, i.e, times 4. |
| 300 ASSERT(kSmiTagShift == 1); | 300 ASSERT(kSmiTagShift == 1); |
| 301 __ movq(RAX, FieldAddress(RAX, RCX, TIMES_4, Array::data_offset())); | 301 __ movq(RAX, FieldAddress(RAX, RCX, TIMES_4, Array::data_offset())); |
| 302 __ ret(); | 302 __ ret(); |
| 303 __ Bind(&fall_through); | 303 __ Bind(&fall_through); |
| 304 } | 304 } |
| 305 | 305 |
| 306 | 306 |
| 307 // Set value into growable object array at specified index. | 307 // Set value into growable object array at specified index. |
| 308 // On stack: growable array (+3), index (+2), value (+1), return-address (+0). | 308 // On stack: growable array (+3), index (+2), value (+1), return-address (+0). |
| 309 void Intrinsifier::GrowableArray_setIndexed(Assembler* assembler) { | 309 void Intrinsifier::GrowableList_setIndexed(Assembler* assembler) { |
| 310 if (FLAG_enable_type_checks) { | 310 if (FLAG_enable_type_checks) { |
| 311 return; | 311 return; |
| 312 } | 312 } |
| 313 __ movq(RDX, Address(RSP, + 1 * kWordSize)); // Value. | 313 __ movq(RDX, Address(RSP, + 1 * kWordSize)); // Value. |
| 314 __ movq(RCX, Address(RSP, + 2 * kWordSize)); // Index. | 314 __ movq(RCX, Address(RSP, + 2 * kWordSize)); // Index. |
| 315 __ movq(RAX, Address(RSP, + 3 * kWordSize)); // GrowableArray. | 315 __ movq(RAX, Address(RSP, + 3 * kWordSize)); // GrowableArray. |
| 316 Label fall_through; | 316 Label fall_through; |
| 317 __ testq(RCX, Immediate(kSmiTagMask)); | 317 __ testq(RCX, Immediate(kSmiTagMask)); |
| 318 __ j(NOT_ZERO, &fall_through); // Non-smi index. | 318 __ j(NOT_ZERO, &fall_through); // Non-smi index. |
| 319 // Range check using _length field. | 319 // Range check using _length field. |
| 320 __ cmpq(RCX, FieldAddress(RAX, GrowableObjectArray::length_offset())); | 320 __ cmpq(RCX, FieldAddress(RAX, GrowableObjectArray::length_offset())); |
| 321 // Runtime throws exception. | 321 // Runtime throws exception. |
| 322 __ j(ABOVE_EQUAL, &fall_through); | 322 __ j(ABOVE_EQUAL, &fall_through); |
| 323 __ movq(RAX, FieldAddress(RAX, GrowableObjectArray::data_offset())); // data. | 323 __ movq(RAX, FieldAddress(RAX, GrowableObjectArray::data_offset())); // data. |
| 324 // Note that RCX is Smi, i.e, times 4. | 324 // Note that RCX is Smi, i.e, times 4. |
| 325 ASSERT(kSmiTagShift == 1); | 325 ASSERT(kSmiTagShift == 1); |
| 326 __ StoreIntoObject(RAX, | 326 __ StoreIntoObject(RAX, |
| 327 FieldAddress(RAX, RCX, TIMES_4, Array::data_offset()), | 327 FieldAddress(RAX, RCX, TIMES_4, Array::data_offset()), |
| 328 RDX); | 328 RDX); |
| 329 __ ret(); | 329 __ ret(); |
| 330 __ Bind(&fall_through); | 330 __ Bind(&fall_through); |
| 331 } | 331 } |
| 332 | 332 |
| 333 | 333 |
| 334 // Set length of growable object array. The length cannot | 334 // Set length of growable object array. The length cannot |
| 335 // be greater than the length of the data container. | 335 // be greater than the length of the data container. |
| 336 // On stack: growable array (+2), length (+1), return-address (+0). | 336 // On stack: growable array (+2), length (+1), return-address (+0). |
| 337 void Intrinsifier::GrowableArray_setLength(Assembler* assembler) { | 337 void Intrinsifier::GrowableList_setLength(Assembler* assembler) { |
| 338 Label fall_through; | 338 Label fall_through; |
| 339 __ movq(RAX, Address(RSP, + 2 * kWordSize)); // Growable array. | 339 __ movq(RAX, Address(RSP, + 2 * kWordSize)); // Growable array. |
| 340 __ movq(RCX, Address(RSP, + 1 * kWordSize)); // Length value. | 340 __ movq(RCX, Address(RSP, + 1 * kWordSize)); // Length value. |
| 341 __ testq(RCX, Immediate(kSmiTagMask)); | 341 __ testq(RCX, Immediate(kSmiTagMask)); |
| 342 __ j(NOT_ZERO, &fall_through, Assembler::kNearJump); // Non-smi length. | 342 __ j(NOT_ZERO, &fall_through, Assembler::kNearJump); // Non-smi length. |
| 343 __ movq(FieldAddress(RAX, GrowableObjectArray::length_offset()), RCX); | 343 __ movq(FieldAddress(RAX, GrowableObjectArray::length_offset()), RCX); |
| 344 __ ret(); | 344 __ ret(); |
| 345 __ Bind(&fall_through); | 345 __ Bind(&fall_through); |
| 346 } | 346 } |
| 347 | 347 |
| 348 | 348 |
| 349 // Set data of growable object array. | 349 // Set data of growable object array. |
| 350 // On stack: growable array (+2), data (+1), return-address (+0). | 350 // On stack: growable array (+2), data (+1), return-address (+0). |
| 351 void Intrinsifier::GrowableArray_setData(Assembler* assembler) { | 351 void Intrinsifier::GrowableList_setData(Assembler* assembler) { |
| 352 if (FLAG_enable_type_checks) { | 352 if (FLAG_enable_type_checks) { |
| 353 return; | 353 return; |
| 354 } | 354 } |
| 355 Label fall_through; | 355 Label fall_through; |
| 356 __ movq(RBX, Address(RSP, + 1 * kWordSize)); /// Data. | 356 __ movq(RBX, Address(RSP, + 1 * kWordSize)); /// Data. |
| 357 __ testq(RBX, Immediate(kSmiTagMask)); | 357 __ testq(RBX, Immediate(kSmiTagMask)); |
| 358 __ j(ZERO, &fall_through); // Data is Smi. | 358 __ j(ZERO, &fall_through); // Data is Smi. |
| 359 __ CompareClassId(RBX, kArrayCid); | 359 __ CompareClassId(RBX, kArrayCid); |
| 360 __ j(NOT_EQUAL, &fall_through); | 360 __ j(NOT_EQUAL, &fall_through); |
| 361 __ movq(RAX, Address(RSP, + 2 * kWordSize)); // Growable array. | 361 __ movq(RAX, Address(RSP, + 2 * kWordSize)); // Growable array. |
| 362 __ StoreIntoObject(RAX, | 362 __ StoreIntoObject(RAX, |
| 363 FieldAddress(RAX, GrowableObjectArray::data_offset()), | 363 FieldAddress(RAX, GrowableObjectArray::data_offset()), |
| 364 RBX); | 364 RBX); |
| 365 __ ret(); | 365 __ ret(); |
| 366 __ Bind(&fall_through); | 366 __ Bind(&fall_through); |
| 367 } | 367 } |
| 368 | 368 |
| 369 | 369 |
| 370 // Add an element to growable array if it doesn't need to grow, otherwise | 370 // Add an element to growable array if it doesn't need to grow, otherwise |
| 371 // call into regular code. | 371 // call into regular code. |
| 372 // On stack: growable array (+2), value (+1), return-address (+0). | 372 // On stack: growable array (+2), value (+1), return-address (+0). |
| 373 void Intrinsifier::GrowableArray_add(Assembler* assembler) { | 373 void Intrinsifier::GrowableList_add(Assembler* assembler) { |
| 374 // In checked mode we need to check the incoming argument. | 374 // In checked mode we need to check the incoming argument. |
| 375 if (FLAG_enable_type_checks) return; | 375 if (FLAG_enable_type_checks) return; |
| 376 Label fall_through; | 376 Label fall_through; |
| 377 __ movq(RAX, Address(RSP, + 2 * kWordSize)); // Array. | 377 __ movq(RAX, Address(RSP, + 2 * kWordSize)); // Array. |
| 378 __ movq(RCX, FieldAddress(RAX, GrowableObjectArray::length_offset())); | 378 __ movq(RCX, FieldAddress(RAX, GrowableObjectArray::length_offset())); |
| 379 // RCX: length. | 379 // RCX: length. |
| 380 __ movq(RDX, FieldAddress(RAX, GrowableObjectArray::data_offset())); | 380 __ movq(RDX, FieldAddress(RAX, GrowableObjectArray::data_offset())); |
| 381 // RDX: data. | 381 // RDX: data. |
| 382 // Compare length with capacity. | 382 // Compare length with capacity. |
| 383 __ cmpq(RCX, FieldAddress(RDX, Array::length_offset())); | 383 __ cmpq(RCX, FieldAddress(RDX, Array::length_offset())); |
| (...skipping 1261 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1645 | 1645 |
| 1646 __ Bind(&fall_through); | 1646 __ Bind(&fall_through); |
| 1647 } | 1647 } |
| 1648 | 1648 |
| 1649 | 1649 |
| 1650 #undef __ | 1650 #undef __ |
| 1651 | 1651 |
| 1652 } // namespace dart | 1652 } // namespace dart |
| 1653 | 1653 |
| 1654 #endif // defined TARGET_ARCH_X64 | 1654 #endif // defined TARGET_ARCH_X64 |
| OLD | NEW |