| 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 bool Intrinsifier::ObjectArray_Allocate(Assembler* assembler) { | 30 void Intrinsifier::ObjectArray_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 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 125 __ Bind(&init_loop); | 125 __ Bind(&init_loop); |
| 126 __ cmpq(RDI, RCX); | 126 __ cmpq(RDI, RCX); |
| 127 __ j(ABOVE_EQUAL, &done, Assembler::kNearJump); | 127 __ j(ABOVE_EQUAL, &done, Assembler::kNearJump); |
| 128 __ movq(Address(RDI, 0), raw_null); | 128 __ movq(Address(RDI, 0), raw_null); |
| 129 __ addq(RDI, Immediate(kWordSize)); | 129 __ addq(RDI, Immediate(kWordSize)); |
| 130 __ jmp(&init_loop, Assembler::kNearJump); | 130 __ jmp(&init_loop, Assembler::kNearJump); |
| 131 __ Bind(&done); | 131 __ Bind(&done); |
| 132 __ ret(); // returns the newly allocated object in RAX. | 132 __ ret(); // returns the newly allocated object in RAX. |
| 133 | 133 |
| 134 __ Bind(&fall_through); | 134 __ Bind(&fall_through); |
| 135 return false; | |
| 136 } | 135 } |
| 137 | 136 |
| 138 | 137 |
| 139 bool Intrinsifier::Array_getLength(Assembler* assembler) { | 138 void Intrinsifier::Array_getLength(Assembler* assembler) { |
| 140 __ movq(RAX, Address(RSP, + 1 * kWordSize)); | 139 __ movq(RAX, Address(RSP, + 1 * kWordSize)); |
| 141 __ movq(RAX, FieldAddress(RAX, Array::length_offset())); | 140 __ movq(RAX, FieldAddress(RAX, Array::length_offset())); |
| 142 __ ret(); | 141 __ ret(); |
| 143 return true; | |
| 144 } | 142 } |
| 145 | 143 |
| 146 | 144 |
| 147 bool Intrinsifier::ImmutableArray_getLength(Assembler* assembler) { | 145 void Intrinsifier::ImmutableArray_getLength(Assembler* assembler) { |
| 148 return Array_getLength(assembler); | 146 return Array_getLength(assembler); |
| 149 } | 147 } |
| 150 | 148 |
| 151 | 149 |
| 152 bool Intrinsifier::Array_getIndexed(Assembler* assembler) { | 150 void Intrinsifier::Array_getIndexed(Assembler* assembler) { |
| 153 Label fall_through; | 151 Label fall_through; |
| 154 __ movq(RCX, Address(RSP, + 1 * kWordSize)); // Index. | 152 __ movq(RCX, Address(RSP, + 1 * kWordSize)); // Index. |
| 155 __ movq(RAX, Address(RSP, + 2 * kWordSize)); // Array. | 153 __ movq(RAX, Address(RSP, + 2 * kWordSize)); // Array. |
| 156 __ testq(RCX, Immediate(kSmiTagMask)); | 154 __ testq(RCX, Immediate(kSmiTagMask)); |
| 157 __ j(NOT_ZERO, &fall_through, Assembler::kNearJump); // Non-smi index. | 155 __ j(NOT_ZERO, &fall_through, Assembler::kNearJump); // Non-smi index. |
| 158 // Range check. | 156 // Range check. |
| 159 __ cmpq(RCX, FieldAddress(RAX, Array::length_offset())); | 157 __ cmpq(RCX, FieldAddress(RAX, Array::length_offset())); |
| 160 // Runtime throws exception. | 158 // Runtime throws exception. |
| 161 __ j(ABOVE_EQUAL, &fall_through, Assembler::kNearJump); | 159 __ j(ABOVE_EQUAL, &fall_through, Assembler::kNearJump); |
| 162 // Note that RBX is Smi, i.e, times 2. | 160 // Note that RBX is Smi, i.e, times 2. |
| 163 ASSERT(kSmiTagShift == 1); | 161 ASSERT(kSmiTagShift == 1); |
| 164 __ movq(RAX, FieldAddress(RAX, RCX, TIMES_4, Array::data_offset())); | 162 __ movq(RAX, FieldAddress(RAX, RCX, TIMES_4, Array::data_offset())); |
| 165 __ ret(); | 163 __ ret(); |
| 166 __ Bind(&fall_through); | 164 __ Bind(&fall_through); |
| 167 return false; | |
| 168 } | 165 } |
| 169 | 166 |
| 170 | 167 |
| 171 bool Intrinsifier::ImmutableArray_getIndexed(Assembler* assembler) { | 168 void Intrinsifier::ImmutableArray_getIndexed(Assembler* assembler) { |
| 172 return Array_getIndexed(assembler); | 169 return Array_getIndexed(assembler); |
| 173 } | 170 } |
| 174 | 171 |
| 175 | 172 |
| 176 bool Intrinsifier::Array_setIndexed(Assembler* assembler) { | 173 void Intrinsifier::Array_setIndexed(Assembler* assembler) { |
| 177 if (FLAG_enable_type_checks) { | 174 if (FLAG_enable_type_checks) { |
| 178 return false; | 175 return; |
| 179 } | 176 } |
| 180 __ movq(RDX, Address(RSP, + 1 * kWordSize)); // Value. | 177 __ movq(RDX, Address(RSP, + 1 * kWordSize)); // Value. |
| 181 __ movq(RCX, Address(RSP, + 2 * kWordSize)); // Index. | 178 __ movq(RCX, Address(RSP, + 2 * kWordSize)); // Index. |
| 182 __ movq(RAX, Address(RSP, + 3 * kWordSize)); // Array. | 179 __ movq(RAX, Address(RSP, + 3 * kWordSize)); // Array. |
| 183 Label fall_through; | 180 Label fall_through; |
| 184 __ testq(RCX, Immediate(kSmiTagMask)); | 181 __ testq(RCX, Immediate(kSmiTagMask)); |
| 185 __ j(NOT_ZERO, &fall_through); | 182 __ j(NOT_ZERO, &fall_through); |
| 186 // Range check. | 183 // Range check. |
| 187 __ cmpq(RCX, FieldAddress(RAX, Array::length_offset())); | 184 __ cmpq(RCX, FieldAddress(RAX, Array::length_offset())); |
| 188 // Runtime throws exception. | 185 // Runtime throws exception. |
| 189 __ j(ABOVE_EQUAL, &fall_through); | 186 __ j(ABOVE_EQUAL, &fall_through); |
| 190 // Note that RBX is Smi, i.e, times 2. | 187 // Note that RBX is Smi, i.e, times 2. |
| 191 ASSERT(kSmiTagShift == 1); | 188 ASSERT(kSmiTagShift == 1); |
| 192 // Destroy RCX (ic data) as we will not continue in the function. | 189 // Destroy RCX (ic data) as we will not continue in the function. |
| 193 __ StoreIntoObject(RAX, | 190 __ StoreIntoObject(RAX, |
| 194 FieldAddress(RAX, RCX, TIMES_4, Array::data_offset()), | 191 FieldAddress(RAX, RCX, TIMES_4, Array::data_offset()), |
| 195 RDX); | 192 RDX); |
| 196 // Caller is responsible of preserving the value if necessary. | 193 // Caller is responsible of preserving the value if necessary. |
| 197 __ ret(); | 194 __ ret(); |
| 198 __ Bind(&fall_through); | 195 __ Bind(&fall_through); |
| 199 return false; | |
| 200 } | 196 } |
| 201 | 197 |
| 202 | 198 |
| 203 // Allocate a GrowableObjectArray using the backing array specified. | 199 // Allocate a GrowableObjectArray using the backing array specified. |
| 204 // On stack: type argument (+2), data (+1), return-address (+0). | 200 // On stack: type argument (+2), data (+1), return-address (+0). |
| 205 bool Intrinsifier::GrowableArray_Allocate(Assembler* assembler) { | 201 void Intrinsifier::GrowableArray_Allocate(Assembler* assembler) { |
| 206 // This snippet of inlined code uses the following registers: | 202 // This snippet of inlined code uses the following registers: |
| 207 // RAX, RCX, R13 | 203 // RAX, RCX, R13 |
| 208 // and the newly allocated object is returned in RAX. | 204 // and the newly allocated object is returned in RAX. |
| 209 const intptr_t kTypeArgumentsOffset = 2 * kWordSize; | 205 const intptr_t kTypeArgumentsOffset = 2 * kWordSize; |
| 210 const intptr_t kArrayOffset = 1 * kWordSize; | 206 const intptr_t kArrayOffset = 1 * kWordSize; |
| 211 Label fall_through; | 207 Label fall_through; |
| 212 | 208 |
| 213 // Compute the size to be allocated, it is based on the array length | 209 // Compute the size to be allocated, it is based on the array length |
| 214 // and is computed as: | 210 // and is computed as: |
| 215 // RoundedAllocationSize(sizeof(RawGrowableObjectArray)) + | 211 // RoundedAllocationSize(sizeof(RawGrowableObjectArray)) + |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 260 RAX, | 256 RAX, |
| 261 FieldAddress(RAX, GrowableObjectArray::type_arguments_offset()), | 257 FieldAddress(RAX, GrowableObjectArray::type_arguments_offset()), |
| 262 RCX); | 258 RCX); |
| 263 | 259 |
| 264 // Set the length field in the growable array object to 0. | 260 // Set the length field in the growable array object to 0. |
| 265 __ movq(FieldAddress(RAX, GrowableObjectArray::length_offset()), | 261 __ movq(FieldAddress(RAX, GrowableObjectArray::length_offset()), |
| 266 Immediate(0)); | 262 Immediate(0)); |
| 267 __ ret(); // returns the newly allocated object in RAX. | 263 __ ret(); // returns the newly allocated object in RAX. |
| 268 | 264 |
| 269 __ Bind(&fall_through); | 265 __ Bind(&fall_through); |
| 270 return false; | |
| 271 } | 266 } |
| 272 | 267 |
| 273 | 268 |
| 274 // Get length of growable object array. | 269 // Get length of growable object array. |
| 275 // On stack: growable array (+1), return-address (+0). | 270 // On stack: growable array (+1), return-address (+0). |
| 276 bool Intrinsifier::GrowableArray_getLength(Assembler* assembler) { | 271 void Intrinsifier::GrowableArray_getLength(Assembler* assembler) { |
| 277 __ movq(RAX, Address(RSP, + 1 * kWordSize)); | 272 __ movq(RAX, Address(RSP, + 1 * kWordSize)); |
| 278 __ movq(RAX, FieldAddress(RAX, GrowableObjectArray::length_offset())); | 273 __ movq(RAX, FieldAddress(RAX, GrowableObjectArray::length_offset())); |
| 279 __ ret(); | 274 __ ret(); |
| 280 return true; | |
| 281 } | 275 } |
| 282 | 276 |
| 283 | 277 |
| 284 bool Intrinsifier::GrowableArray_getCapacity(Assembler* assembler) { | 278 void Intrinsifier::GrowableArray_getCapacity(Assembler* assembler) { |
| 285 __ movq(RAX, Address(RSP, + 1 * kWordSize)); | 279 __ movq(RAX, Address(RSP, + 1 * kWordSize)); |
| 286 __ movq(RAX, FieldAddress(RAX, GrowableObjectArray::data_offset())); | 280 __ movq(RAX, FieldAddress(RAX, GrowableObjectArray::data_offset())); |
| 287 __ movq(RAX, FieldAddress(RAX, Array::length_offset())); | 281 __ movq(RAX, FieldAddress(RAX, Array::length_offset())); |
| 288 __ ret(); | 282 __ ret(); |
| 289 return true; | |
| 290 } | 283 } |
| 291 | 284 |
| 292 | 285 |
| 293 // Access growable object array at specified index. | 286 // Access growable object array at specified index. |
| 294 // On stack: growable array (+2), index (+1), return-address (+0). | 287 // On stack: growable array (+2), index (+1), return-address (+0). |
| 295 bool Intrinsifier::GrowableArray_getIndexed(Assembler* assembler) { | 288 void Intrinsifier::GrowableArray_getIndexed(Assembler* assembler) { |
| 296 Label fall_through; | 289 Label fall_through; |
| 297 __ movq(RCX, Address(RSP, + 1 * kWordSize)); // Index. | 290 __ movq(RCX, Address(RSP, + 1 * kWordSize)); // Index. |
| 298 __ movq(RAX, Address(RSP, + 2 * kWordSize)); // GrowableArray. | 291 __ movq(RAX, Address(RSP, + 2 * kWordSize)); // GrowableArray. |
| 299 __ testq(RCX, Immediate(kSmiTagMask)); | 292 __ testq(RCX, Immediate(kSmiTagMask)); |
| 300 __ j(NOT_ZERO, &fall_through, Assembler::kNearJump); // Non-smi index. | 293 __ j(NOT_ZERO, &fall_through, Assembler::kNearJump); // Non-smi index. |
| 301 // Range check using _length field. | 294 // Range check using _length field. |
| 302 __ cmpq(RCX, FieldAddress(RAX, GrowableObjectArray::length_offset())); | 295 __ cmpq(RCX, FieldAddress(RAX, GrowableObjectArray::length_offset())); |
| 303 // Runtime throws exception. | 296 // Runtime throws exception. |
| 304 __ j(ABOVE_EQUAL, &fall_through, Assembler::kNearJump); | 297 __ j(ABOVE_EQUAL, &fall_through, Assembler::kNearJump); |
| 305 __ movq(RAX, FieldAddress(RAX, GrowableObjectArray::data_offset())); // data. | 298 __ movq(RAX, FieldAddress(RAX, GrowableObjectArray::data_offset())); // data. |
| 306 | 299 |
| 307 // Note that RCX is Smi, i.e, times 4. | 300 // Note that RCX is Smi, i.e, times 4. |
| 308 ASSERT(kSmiTagShift == 1); | 301 ASSERT(kSmiTagShift == 1); |
| 309 __ movq(RAX, FieldAddress(RAX, RCX, TIMES_4, Array::data_offset())); | 302 __ movq(RAX, FieldAddress(RAX, RCX, TIMES_4, Array::data_offset())); |
| 310 __ ret(); | 303 __ ret(); |
| 311 __ Bind(&fall_through); | 304 __ Bind(&fall_through); |
| 312 return false; | |
| 313 } | 305 } |
| 314 | 306 |
| 315 | 307 |
| 316 // Set value into growable object array at specified index. | 308 // Set value into growable object array at specified index. |
| 317 // On stack: growable array (+3), index (+2), value (+1), return-address (+0). | 309 // On stack: growable array (+3), index (+2), value (+1), return-address (+0). |
| 318 bool Intrinsifier::GrowableArray_setIndexed(Assembler* assembler) { | 310 void Intrinsifier::GrowableArray_setIndexed(Assembler* assembler) { |
| 319 if (FLAG_enable_type_checks) { | 311 if (FLAG_enable_type_checks) { |
| 320 return false; | 312 return; |
| 321 } | 313 } |
| 322 __ movq(RDX, Address(RSP, + 1 * kWordSize)); // Value. | 314 __ movq(RDX, Address(RSP, + 1 * kWordSize)); // Value. |
| 323 __ movq(RCX, Address(RSP, + 2 * kWordSize)); // Index. | 315 __ movq(RCX, Address(RSP, + 2 * kWordSize)); // Index. |
| 324 __ movq(RAX, Address(RSP, + 3 * kWordSize)); // GrowableArray. | 316 __ movq(RAX, Address(RSP, + 3 * kWordSize)); // GrowableArray. |
| 325 Label fall_through; | 317 Label fall_through; |
| 326 __ testq(RCX, Immediate(kSmiTagMask)); | 318 __ testq(RCX, Immediate(kSmiTagMask)); |
| 327 __ j(NOT_ZERO, &fall_through); // Non-smi index. | 319 __ j(NOT_ZERO, &fall_through); // Non-smi index. |
| 328 // Range check using _length field. | 320 // Range check using _length field. |
| 329 __ cmpq(RCX, FieldAddress(RAX, GrowableObjectArray::length_offset())); | 321 __ cmpq(RCX, FieldAddress(RAX, GrowableObjectArray::length_offset())); |
| 330 // Runtime throws exception. | 322 // Runtime throws exception. |
| 331 __ j(ABOVE_EQUAL, &fall_through); | 323 __ j(ABOVE_EQUAL, &fall_through); |
| 332 __ movq(RAX, FieldAddress(RAX, GrowableObjectArray::data_offset())); // data. | 324 __ movq(RAX, FieldAddress(RAX, GrowableObjectArray::data_offset())); // data. |
| 333 // Note that RCX is Smi, i.e, times 4. | 325 // Note that RCX is Smi, i.e, times 4. |
| 334 ASSERT(kSmiTagShift == 1); | 326 ASSERT(kSmiTagShift == 1); |
| 335 __ StoreIntoObject(RAX, | 327 __ StoreIntoObject(RAX, |
| 336 FieldAddress(RAX, RCX, TIMES_4, Array::data_offset()), | 328 FieldAddress(RAX, RCX, TIMES_4, Array::data_offset()), |
| 337 RDX); | 329 RDX); |
| 338 __ ret(); | 330 __ ret(); |
| 339 __ Bind(&fall_through); | 331 __ Bind(&fall_through); |
| 340 return false; | |
| 341 } | 332 } |
| 342 | 333 |
| 343 | 334 |
| 344 // Set length of growable object array. The length cannot | 335 // Set length of growable object array. The length cannot |
| 345 // be greater than the length of the data container. | 336 // be greater than the length of the data container. |
| 346 // On stack: growable array (+2), length (+1), return-address (+0). | 337 // On stack: growable array (+2), length (+1), return-address (+0). |
| 347 bool Intrinsifier::GrowableArray_setLength(Assembler* assembler) { | 338 void Intrinsifier::GrowableArray_setLength(Assembler* assembler) { |
| 348 Label fall_through; | 339 Label fall_through; |
| 349 __ movq(RAX, Address(RSP, + 2 * kWordSize)); // Growable array. | 340 __ movq(RAX, Address(RSP, + 2 * kWordSize)); // Growable array. |
| 350 __ movq(RCX, Address(RSP, + 1 * kWordSize)); // Length value. | 341 __ movq(RCX, Address(RSP, + 1 * kWordSize)); // Length value. |
| 351 __ testq(RCX, Immediate(kSmiTagMask)); | 342 __ testq(RCX, Immediate(kSmiTagMask)); |
| 352 __ j(NOT_ZERO, &fall_through, Assembler::kNearJump); // Non-smi length. | 343 __ j(NOT_ZERO, &fall_through, Assembler::kNearJump); // Non-smi length. |
| 353 __ movq(FieldAddress(RAX, GrowableObjectArray::length_offset()), RCX); | 344 __ movq(FieldAddress(RAX, GrowableObjectArray::length_offset()), RCX); |
| 354 __ ret(); | 345 __ ret(); |
| 355 __ Bind(&fall_through); | 346 __ Bind(&fall_through); |
| 356 return false; | |
| 357 } | 347 } |
| 358 | 348 |
| 359 | 349 |
| 360 // Set data of growable object array. | 350 // Set data of growable object array. |
| 361 // On stack: growable array (+2), data (+1), return-address (+0). | 351 // On stack: growable array (+2), data (+1), return-address (+0). |
| 362 bool Intrinsifier::GrowableArray_setData(Assembler* assembler) { | 352 void Intrinsifier::GrowableArray_setData(Assembler* assembler) { |
| 363 if (FLAG_enable_type_checks) { | 353 if (FLAG_enable_type_checks) { |
| 364 return false; | 354 return; |
| 365 } | 355 } |
| 366 Label fall_through; | 356 Label fall_through; |
| 367 __ movq(RBX, Address(RSP, + 1 * kWordSize)); /// Data. | 357 __ movq(RBX, Address(RSP, + 1 * kWordSize)); /// Data. |
| 368 __ testq(RBX, Immediate(kSmiTagMask)); | 358 __ testq(RBX, Immediate(kSmiTagMask)); |
| 369 __ j(ZERO, &fall_through); // Data is Smi. | 359 __ j(ZERO, &fall_through); // Data is Smi. |
| 370 __ CompareClassId(RBX, kArrayCid); | 360 __ CompareClassId(RBX, kArrayCid); |
| 371 __ j(NOT_EQUAL, &fall_through); | 361 __ j(NOT_EQUAL, &fall_through); |
| 372 __ movq(RAX, Address(RSP, + 2 * kWordSize)); // Growable array. | 362 __ movq(RAX, Address(RSP, + 2 * kWordSize)); // Growable array. |
| 373 __ StoreIntoObject(RAX, | 363 __ StoreIntoObject(RAX, |
| 374 FieldAddress(RAX, GrowableObjectArray::data_offset()), | 364 FieldAddress(RAX, GrowableObjectArray::data_offset()), |
| 375 RBX); | 365 RBX); |
| 376 __ ret(); | 366 __ ret(); |
| 377 __ Bind(&fall_through); | 367 __ Bind(&fall_through); |
| 378 return false; | |
| 379 } | 368 } |
| 380 | 369 |
| 381 | 370 |
| 382 // Add an element to growable array if it doesn't need to grow, otherwise | 371 // Add an element to growable array if it doesn't need to grow, otherwise |
| 383 // call into regular code. | 372 // call into regular code. |
| 384 // On stack: growable array (+2), value (+1), return-address (+0). | 373 // On stack: growable array (+2), value (+1), return-address (+0). |
| 385 bool Intrinsifier::GrowableArray_add(Assembler* assembler) { | 374 void Intrinsifier::GrowableArray_add(Assembler* assembler) { |
| 386 // In checked mode we need to check the incoming argument. | 375 // In checked mode we need to check the incoming argument. |
| 387 if (FLAG_enable_type_checks) return false; | 376 if (FLAG_enable_type_checks) return; |
| 388 Label fall_through; | 377 Label fall_through; |
| 389 __ movq(RAX, Address(RSP, + 2 * kWordSize)); // Array. | 378 __ movq(RAX, Address(RSP, + 2 * kWordSize)); // Array. |
| 390 __ movq(RCX, FieldAddress(RAX, GrowableObjectArray::length_offset())); | 379 __ movq(RCX, FieldAddress(RAX, GrowableObjectArray::length_offset())); |
| 391 // RCX: length. | 380 // RCX: length. |
| 392 __ movq(RDX, FieldAddress(RAX, GrowableObjectArray::data_offset())); | 381 __ movq(RDX, FieldAddress(RAX, GrowableObjectArray::data_offset())); |
| 393 // RDX: data. | 382 // RDX: data. |
| 394 // Compare length with capacity. | 383 // Compare length with capacity. |
| 395 __ cmpq(RCX, FieldAddress(RDX, Array::length_offset())); | 384 __ cmpq(RCX, FieldAddress(RDX, Array::length_offset())); |
| 396 __ j(EQUAL, &fall_through); // Must grow data. | 385 __ j(EQUAL, &fall_through); // Must grow data. |
| 397 const Immediate& value_one = | 386 const Immediate& value_one = |
| 398 Immediate(reinterpret_cast<int64_t>(Smi::New(1))); | 387 Immediate(reinterpret_cast<int64_t>(Smi::New(1))); |
| 399 // len = len + 1; | 388 // len = len + 1; |
| 400 __ addq(FieldAddress(RAX, GrowableObjectArray::length_offset()), value_one); | 389 __ addq(FieldAddress(RAX, GrowableObjectArray::length_offset()), value_one); |
| 401 __ movq(RAX, Address(RSP, + 1 * kWordSize)); // Value | 390 __ movq(RAX, Address(RSP, + 1 * kWordSize)); // Value |
| 402 ASSERT(kSmiTagShift == 1); | 391 ASSERT(kSmiTagShift == 1); |
| 403 __ StoreIntoObject(RDX, | 392 __ StoreIntoObject(RDX, |
| 404 FieldAddress(RDX, RCX, TIMES_4, Array::data_offset()), | 393 FieldAddress(RDX, RCX, TIMES_4, Array::data_offset()), |
| 405 RAX); | 394 RAX); |
| 406 const Immediate& raw_null = | 395 const Immediate& raw_null = |
| 407 Immediate(reinterpret_cast<int64_t>(Object::null())); | 396 Immediate(reinterpret_cast<int64_t>(Object::null())); |
| 408 __ movq(RAX, raw_null); | 397 __ movq(RAX, raw_null); |
| 409 __ ret(); | 398 __ ret(); |
| 410 __ Bind(&fall_through); | 399 __ Bind(&fall_through); |
| 411 return false; | |
| 412 } | 400 } |
| 413 | 401 |
| 414 | 402 |
| 415 #define TYPED_ARRAY_ALLOCATION(type_name, cid, max_len, scale_factor) \ | 403 #define TYPED_ARRAY_ALLOCATION(type_name, cid, max_len, scale_factor) \ |
| 416 Label fall_through; \ | 404 Label fall_through; \ |
| 417 const intptr_t kArrayLengthStackOffset = 1 * kWordSize; \ | 405 const intptr_t kArrayLengthStackOffset = 1 * kWordSize; \ |
| 418 __ movq(RDI, Address(RSP, kArrayLengthStackOffset)); /* Array length. */ \ | 406 __ movq(RDI, Address(RSP, kArrayLengthStackOffset)); /* Array length. */ \ |
| 419 /* Check that length is a positive Smi. */ \ | 407 /* Check that length is a positive Smi. */ \ |
| 420 /* RDI: requested array length argument. */ \ | 408 /* RDI: requested array length argument. */ \ |
| 421 __ testq(RDI, Immediate(kSmiTagMask)); \ | 409 __ testq(RDI, Immediate(kSmiTagMask)); \ |
| (...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 504 __ movq(Address(RDI, 0), RBX); \ | 492 __ movq(Address(RDI, 0), RBX); \ |
| 505 __ addq(RDI, Immediate(kWordSize)); \ | 493 __ addq(RDI, Immediate(kWordSize)); \ |
| 506 __ jmp(&init_loop, Assembler::kNearJump); \ | 494 __ jmp(&init_loop, Assembler::kNearJump); \ |
| 507 __ Bind(&done); \ | 495 __ Bind(&done); \ |
| 508 \ | 496 \ |
| 509 __ ret(); \ | 497 __ ret(); \ |
| 510 __ Bind(&fall_through); \ | 498 __ Bind(&fall_through); \ |
| 511 | 499 |
| 512 | 500 |
| 513 // Gets the length of a TypedData. | 501 // Gets the length of a TypedData. |
| 514 bool Intrinsifier::TypedData_getLength(Assembler* assembler) { | 502 void Intrinsifier::TypedData_getLength(Assembler* assembler) { |
| 515 __ movq(RAX, Address(RSP, + 1 * kWordSize)); | 503 __ movq(RAX, Address(RSP, + 1 * kWordSize)); |
| 516 __ movq(RAX, FieldAddress(RAX, TypedData::length_offset())); | 504 __ movq(RAX, FieldAddress(RAX, TypedData::length_offset())); |
| 517 __ ret(); | 505 __ ret(); |
| 518 // Generate enough code to satisfy patchability constraint. | |
| 519 intptr_t offset = __ CodeSize(); | |
| 520 __ nop(JumpPattern::InstructionLength() - offset); | |
| 521 return true; | |
| 522 } | 506 } |
| 523 | 507 |
| 524 | 508 |
| 525 static ScaleFactor GetScaleFactor(intptr_t size) { | 509 static ScaleFactor GetScaleFactor(intptr_t size) { |
| 526 switch (size) { | 510 switch (size) { |
| 527 case 1: return TIMES_1; | 511 case 1: return TIMES_1; |
| 528 case 2: return TIMES_2; | 512 case 2: return TIMES_2; |
| 529 case 4: return TIMES_4; | 513 case 4: return TIMES_4; |
| 530 case 8: return TIMES_8; | 514 case 8: return TIMES_8; |
| 531 case 16: return TIMES_16; | 515 case 16: return TIMES_16; |
| 532 } | 516 } |
| 533 UNREACHABLE(); | 517 UNREACHABLE(); |
| 534 return static_cast<ScaleFactor>(0); | 518 return static_cast<ScaleFactor>(0); |
| 535 }; | 519 }; |
| 536 | 520 |
| 537 | 521 |
| 538 #define TYPED_DATA_ALLOCATOR(clazz) \ | 522 #define TYPED_DATA_ALLOCATOR(clazz) \ |
| 539 bool Intrinsifier::TypedData_##clazz##_new(Assembler* assembler) { \ | 523 void Intrinsifier::TypedData_##clazz##_new(Assembler* assembler) { \ |
| 540 intptr_t size = TypedData::ElementSizeInBytes(kTypedData##clazz##Cid); \ | 524 intptr_t size = TypedData::ElementSizeInBytes(kTypedData##clazz##Cid); \ |
| 541 intptr_t max_len = TypedData::MaxElements(kTypedData##clazz##Cid); \ | 525 intptr_t max_len = TypedData::MaxElements(kTypedData##clazz##Cid); \ |
| 542 ScaleFactor scale = GetScaleFactor(size); \ | 526 ScaleFactor scale = GetScaleFactor(size); \ |
| 543 TYPED_ARRAY_ALLOCATION(TypedData, kTypedData##clazz##Cid, max_len, scale); \ | 527 TYPED_ARRAY_ALLOCATION(TypedData, kTypedData##clazz##Cid, max_len, scale); \ |
| 544 return false; \ | |
| 545 } \ | 528 } \ |
| 546 bool Intrinsifier::TypedData_##clazz##_factory(Assembler* assembler) { \ | 529 void Intrinsifier::TypedData_##clazz##_factory(Assembler* assembler) { \ |
| 547 intptr_t size = TypedData::ElementSizeInBytes(kTypedData##clazz##Cid); \ | 530 intptr_t size = TypedData::ElementSizeInBytes(kTypedData##clazz##Cid); \ |
| 548 intptr_t max_len = TypedData::MaxElements(kTypedData##clazz##Cid); \ | 531 intptr_t max_len = TypedData::MaxElements(kTypedData##clazz##Cid); \ |
| 549 ScaleFactor scale = GetScaleFactor(size); \ | 532 ScaleFactor scale = GetScaleFactor(size); \ |
| 550 TYPED_ARRAY_ALLOCATION(TypedData, kTypedData##clazz##Cid, max_len, scale); \ | 533 TYPED_ARRAY_ALLOCATION(TypedData, kTypedData##clazz##Cid, max_len, scale); \ |
| 551 return false; \ | |
| 552 } | 534 } |
| 553 CLASS_LIST_TYPED_DATA(TYPED_DATA_ALLOCATOR) | 535 CLASS_LIST_TYPED_DATA(TYPED_DATA_ALLOCATOR) |
| 554 #undef TYPED_DATA_ALLOCATOR | 536 #undef TYPED_DATA_ALLOCATOR |
| 555 | 537 |
| 556 | 538 |
| 557 // Tests if two top most arguments are smis, jumps to label not_smi if not. | 539 // Tests if two top most arguments are smis, jumps to label not_smi if not. |
| 558 // Topmost argument is in RAX. | 540 // Topmost argument is in RAX. |
| 559 static void TestBothArgumentsSmis(Assembler* assembler, Label* not_smi) { | 541 static void TestBothArgumentsSmis(Assembler* assembler, Label* not_smi) { |
| 560 __ movq(RAX, Address(RSP, + 1 * kWordSize)); | 542 __ movq(RAX, Address(RSP, + 1 * kWordSize)); |
| 561 __ movq(RCX, Address(RSP, + 2 * kWordSize)); | 543 __ movq(RCX, Address(RSP, + 2 * kWordSize)); |
| 562 __ orq(RCX, RAX); | 544 __ orq(RCX, RAX); |
| 563 __ testq(RCX, Immediate(kSmiTagMask)); | 545 __ testq(RCX, Immediate(kSmiTagMask)); |
| 564 __ j(NOT_ZERO, not_smi); | 546 __ j(NOT_ZERO, not_smi); |
| 565 } | 547 } |
| 566 | 548 |
| 567 | 549 |
| 568 bool Intrinsifier::Integer_addFromInteger(Assembler* assembler) { | 550 void Intrinsifier::Integer_addFromInteger(Assembler* assembler) { |
| 569 Label fall_through; | 551 Label fall_through; |
| 570 TestBothArgumentsSmis(assembler, &fall_through); | 552 TestBothArgumentsSmis(assembler, &fall_through); |
| 571 // RAX contains right argument. | 553 // RAX contains right argument. |
| 572 __ addq(RAX, Address(RSP, + 2 * kWordSize)); | 554 __ addq(RAX, Address(RSP, + 2 * kWordSize)); |
| 573 __ j(OVERFLOW, &fall_through, Assembler::kNearJump); | 555 __ j(OVERFLOW, &fall_through, Assembler::kNearJump); |
| 574 // Result is in RAX. | 556 // Result is in RAX. |
| 575 __ ret(); | 557 __ ret(); |
| 576 __ Bind(&fall_through); | 558 __ Bind(&fall_through); |
| 577 return false; | |
| 578 } | 559 } |
| 579 | 560 |
| 580 | 561 |
| 581 bool Intrinsifier::Integer_add(Assembler* assembler) { | 562 void Intrinsifier::Integer_add(Assembler* assembler) { |
| 582 return Integer_addFromInteger(assembler); | 563 return Integer_addFromInteger(assembler); |
| 583 } | 564 } |
| 584 | 565 |
| 585 | 566 |
| 586 bool Intrinsifier::Integer_subFromInteger(Assembler* assembler) { | 567 void Intrinsifier::Integer_subFromInteger(Assembler* assembler) { |
| 587 Label fall_through; | 568 Label fall_through; |
| 588 TestBothArgumentsSmis(assembler, &fall_through); | 569 TestBothArgumentsSmis(assembler, &fall_through); |
| 589 // RAX contains right argument, which is the actual minuend of subtraction. | 570 // RAX contains right argument, which is the actual minuend of subtraction. |
| 590 __ subq(RAX, Address(RSP, + 2 * kWordSize)); | 571 __ subq(RAX, Address(RSP, + 2 * kWordSize)); |
| 591 __ j(OVERFLOW, &fall_through, Assembler::kNearJump); | 572 __ j(OVERFLOW, &fall_through, Assembler::kNearJump); |
| 592 // Result is in RAX. | 573 // Result is in RAX. |
| 593 __ ret(); | 574 __ ret(); |
| 594 __ Bind(&fall_through); | 575 __ Bind(&fall_through); |
| 595 return false; | |
| 596 } | 576 } |
| 597 | 577 |
| 598 | 578 |
| 599 bool Intrinsifier::Integer_sub(Assembler* assembler) { | 579 void Intrinsifier::Integer_sub(Assembler* assembler) { |
| 600 Label fall_through; | 580 Label fall_through; |
| 601 TestBothArgumentsSmis(assembler, &fall_through); | 581 TestBothArgumentsSmis(assembler, &fall_through); |
| 602 // RAX contains right argument, which is the actual subtrahend of subtraction. | 582 // RAX contains right argument, which is the actual subtrahend of subtraction. |
| 603 __ movq(RCX, RAX); | 583 __ movq(RCX, RAX); |
| 604 __ movq(RAX, Address(RSP, + 2 * kWordSize)); | 584 __ movq(RAX, Address(RSP, + 2 * kWordSize)); |
| 605 __ subq(RAX, RCX); | 585 __ subq(RAX, RCX); |
| 606 __ j(OVERFLOW, &fall_through, Assembler::kNearJump); | 586 __ j(OVERFLOW, &fall_through, Assembler::kNearJump); |
| 607 // Result is in RAX. | 587 // Result is in RAX. |
| 608 __ ret(); | 588 __ ret(); |
| 609 __ Bind(&fall_through); | 589 __ Bind(&fall_through); |
| 610 return false; | |
| 611 } | 590 } |
| 612 | 591 |
| 613 | 592 |
| 614 | 593 |
| 615 bool Intrinsifier::Integer_mulFromInteger(Assembler* assembler) { | 594 void Intrinsifier::Integer_mulFromInteger(Assembler* assembler) { |
| 616 Label fall_through; | 595 Label fall_through; |
| 617 TestBothArgumentsSmis(assembler, &fall_through); | 596 TestBothArgumentsSmis(assembler, &fall_through); |
| 618 // RAX is the right argument. | 597 // RAX is the right argument. |
| 619 ASSERT(kSmiTag == 0); // Adjust code below if not the case. | 598 ASSERT(kSmiTag == 0); // Adjust code below if not the case. |
| 620 __ SmiUntag(RAX); | 599 __ SmiUntag(RAX); |
| 621 __ imulq(RAX, Address(RSP, + 2 * kWordSize)); | 600 __ imulq(RAX, Address(RSP, + 2 * kWordSize)); |
| 622 __ j(OVERFLOW, &fall_through, Assembler::kNearJump); | 601 __ j(OVERFLOW, &fall_through, Assembler::kNearJump); |
| 623 // Result is in RAX. | 602 // Result is in RAX. |
| 624 __ ret(); | 603 __ ret(); |
| 625 __ Bind(&fall_through); | 604 __ Bind(&fall_through); |
| 626 return false; | |
| 627 } | 605 } |
| 628 | 606 |
| 629 | 607 |
| 630 bool Intrinsifier::Integer_mul(Assembler* assembler) { | 608 void Intrinsifier::Integer_mul(Assembler* assembler) { |
| 631 return Integer_mulFromInteger(assembler); | 609 return Integer_mulFromInteger(assembler); |
| 632 } | 610 } |
| 633 | 611 |
| 634 | 612 |
| 635 // Optimizations: | 613 // Optimizations: |
| 636 // - result is 0 if: | 614 // - result is 0 if: |
| 637 // - left is 0 | 615 // - left is 0 |
| 638 // - left equals right | 616 // - left equals right |
| 639 // - result is left if | 617 // - result is left if |
| 640 // - left > 0 && left < right | 618 // - left > 0 && left < right |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 696 | 674 |
| 697 // Implementation: | 675 // Implementation: |
| 698 // res = left % right; | 676 // res = left % right; |
| 699 // if (res < 0) { | 677 // if (res < 0) { |
| 700 // if (right < 0) { | 678 // if (right < 0) { |
| 701 // res = res - right; | 679 // res = res - right; |
| 702 // } else { | 680 // } else { |
| 703 // res = res + right; | 681 // res = res + right; |
| 704 // } | 682 // } |
| 705 // } | 683 // } |
| 706 bool Intrinsifier::Integer_moduloFromInteger(Assembler* assembler) { | 684 void Intrinsifier::Integer_moduloFromInteger(Assembler* assembler) { |
| 707 Label fall_through, negative_result; | 685 Label fall_through, negative_result; |
| 708 TestBothArgumentsSmis(assembler, &fall_through); | 686 TestBothArgumentsSmis(assembler, &fall_through); |
| 709 __ movq(RCX, Address(RSP, + 2 * kWordSize)); | 687 __ movq(RCX, Address(RSP, + 2 * kWordSize)); |
| 710 // RAX: Tagged left (dividend). | 688 // RAX: Tagged left (dividend). |
| 711 // RCX: Tagged right (divisor). | 689 // RCX: Tagged right (divisor). |
| 712 __ cmpq(RCX, Immediate(0)); | 690 __ cmpq(RCX, Immediate(0)); |
| 713 __ j(EQUAL, &fall_through); | 691 __ j(EQUAL, &fall_through); |
| 714 EmitRemainderOperation(assembler); | 692 EmitRemainderOperation(assembler); |
| 715 // Untagged remainder result in RAX. | 693 // Untagged remainder result in RAX. |
| 716 __ cmpq(RAX, Immediate(0)); | 694 __ cmpq(RAX, Immediate(0)); |
| (...skipping 10 matching lines...) Expand all Loading... |
| 727 __ addq(RAX, RCX); | 705 __ addq(RAX, RCX); |
| 728 __ SmiTag(RAX); | 706 __ SmiTag(RAX); |
| 729 __ ret(); | 707 __ ret(); |
| 730 | 708 |
| 731 __ Bind(&subtract); | 709 __ Bind(&subtract); |
| 732 __ subq(RAX, RCX); | 710 __ subq(RAX, RCX); |
| 733 __ SmiTag(RAX); | 711 __ SmiTag(RAX); |
| 734 __ ret(); | 712 __ ret(); |
| 735 | 713 |
| 736 __ Bind(&fall_through); | 714 __ Bind(&fall_through); |
| 737 return false; | |
| 738 } | 715 } |
| 739 | 716 |
| 740 | 717 |
| 741 bool Intrinsifier::Integer_remainder(Assembler* assembler) { | 718 void Intrinsifier::Integer_remainder(Assembler* assembler) { |
| 742 Label fall_through; | 719 Label fall_through; |
| 743 TestBothArgumentsSmis(assembler, &fall_through); | 720 TestBothArgumentsSmis(assembler, &fall_through); |
| 744 // RAX: right argument (divisor) | 721 // RAX: right argument (divisor) |
| 745 __ movq(RCX, RAX); | 722 __ movq(RCX, RAX); |
| 746 __ movq(RAX, Address(RSP, + 2 * kWordSize)); // Left argument (dividend). | 723 __ movq(RAX, Address(RSP, + 2 * kWordSize)); // Left argument (dividend). |
| 747 // RAX: Tagged left (dividend). | 724 // RAX: Tagged left (dividend). |
| 748 // RCX: Tagged right (divisor). | 725 // RCX: Tagged right (divisor). |
| 749 __ cmpq(RCX, Immediate(0)); | 726 __ cmpq(RCX, Immediate(0)); |
| 750 __ j(EQUAL, &fall_through); | 727 __ j(EQUAL, &fall_through); |
| 751 EmitRemainderOperation(assembler); | 728 EmitRemainderOperation(assembler); |
| 752 // Untagged remainder result in RAX. | 729 // Untagged remainder result in RAX. |
| 753 __ SmiTag(RAX); | 730 __ SmiTag(RAX); |
| 754 __ ret(); | 731 __ ret(); |
| 755 __ Bind(&fall_through); | 732 __ Bind(&fall_through); |
| 756 return false; | |
| 757 } | 733 } |
| 758 | 734 |
| 759 | 735 |
| 760 bool Intrinsifier::Integer_truncDivide(Assembler* assembler) { | 736 void Intrinsifier::Integer_truncDivide(Assembler* assembler) { |
| 761 Label fall_through, not_32bit; | 737 Label fall_through, not_32bit; |
| 762 TestBothArgumentsSmis(assembler, &fall_through); | 738 TestBothArgumentsSmis(assembler, &fall_through); |
| 763 // RAX: right argument (divisor) | 739 // RAX: right argument (divisor) |
| 764 __ cmpq(RAX, Immediate(0)); | 740 __ cmpq(RAX, Immediate(0)); |
| 765 __ j(EQUAL, &fall_through, Assembler::kNearJump); | 741 __ j(EQUAL, &fall_through, Assembler::kNearJump); |
| 766 __ movq(RCX, RAX); | 742 __ movq(RCX, RAX); |
| 767 __ movq(RAX, Address(RSP, + 2 * kWordSize)); // Left argument (dividend). | 743 __ movq(RAX, Address(RSP, + 2 * kWordSize)); // Left argument (dividend). |
| 768 | 744 |
| 769 // Check if both operands fit into 32bits as idiv with 64bit operands | 745 // Check if both operands fit into 32bits as idiv with 64bit operands |
| 770 // requires twice as many cycles and has much higher latency. We are checking | 746 // requires twice as many cycles and has much higher latency. We are checking |
| (...skipping 23 matching lines...) Expand all Loading... |
| 794 __ cqo(); | 770 __ cqo(); |
| 795 __ idivq(RCX); | 771 __ idivq(RCX); |
| 796 __ popq(RDX); | 772 __ popq(RDX); |
| 797 // Check the corner case of dividing the 'MIN_SMI' with -1, in which case we | 773 // Check the corner case of dividing the 'MIN_SMI' with -1, in which case we |
| 798 // cannot tag the result. | 774 // cannot tag the result. |
| 799 __ cmpq(RAX, Immediate(0x4000000000000000)); | 775 __ cmpq(RAX, Immediate(0x4000000000000000)); |
| 800 __ j(EQUAL, &fall_through); | 776 __ j(EQUAL, &fall_through); |
| 801 __ SmiTag(RAX); | 777 __ SmiTag(RAX); |
| 802 __ ret(); | 778 __ ret(); |
| 803 __ Bind(&fall_through); | 779 __ Bind(&fall_through); |
| 804 return false; | |
| 805 } | 780 } |
| 806 | 781 |
| 807 | 782 |
| 808 bool Intrinsifier::Integer_negate(Assembler* assembler) { | 783 void Intrinsifier::Integer_negate(Assembler* assembler) { |
| 809 Label fall_through; | 784 Label fall_through; |
| 810 __ movq(RAX, Address(RSP, + 1 * kWordSize)); | 785 __ movq(RAX, Address(RSP, + 1 * kWordSize)); |
| 811 __ testq(RAX, Immediate(kSmiTagMask)); | 786 __ testq(RAX, Immediate(kSmiTagMask)); |
| 812 __ j(NOT_ZERO, &fall_through, Assembler::kNearJump); // Non-smi value. | 787 __ j(NOT_ZERO, &fall_through, Assembler::kNearJump); // Non-smi value. |
| 813 __ negq(RAX); | 788 __ negq(RAX); |
| 814 __ j(OVERFLOW, &fall_through, Assembler::kNearJump); | 789 __ j(OVERFLOW, &fall_through, Assembler::kNearJump); |
| 815 // Result is in RAX. | 790 // Result is in RAX. |
| 816 __ ret(); | 791 __ ret(); |
| 817 __ Bind(&fall_through); | 792 __ Bind(&fall_through); |
| 818 return false; | |
| 819 } | 793 } |
| 820 | 794 |
| 821 | 795 |
| 822 bool Intrinsifier::Integer_bitAndFromInteger(Assembler* assembler) { | 796 void Intrinsifier::Integer_bitAndFromInteger(Assembler* assembler) { |
| 823 Label fall_through; | 797 Label fall_through; |
| 824 TestBothArgumentsSmis(assembler, &fall_through); | 798 TestBothArgumentsSmis(assembler, &fall_through); |
| 825 // RAX is the right argument. | 799 // RAX is the right argument. |
| 826 __ andq(RAX, Address(RSP, + 2 * kWordSize)); | 800 __ andq(RAX, Address(RSP, + 2 * kWordSize)); |
| 827 // Result is in RAX. | 801 // Result is in RAX. |
| 828 __ ret(); | 802 __ ret(); |
| 829 __ Bind(&fall_through); | 803 __ Bind(&fall_through); |
| 830 return false; | |
| 831 } | 804 } |
| 832 | 805 |
| 833 | 806 |
| 834 bool Intrinsifier::Integer_bitAnd(Assembler* assembler) { | 807 void Intrinsifier::Integer_bitAnd(Assembler* assembler) { |
| 835 return Integer_bitAndFromInteger(assembler); | 808 return Integer_bitAndFromInteger(assembler); |
| 836 } | 809 } |
| 837 | 810 |
| 838 | 811 |
| 839 bool Intrinsifier::Integer_bitOrFromInteger(Assembler* assembler) { | 812 void Intrinsifier::Integer_bitOrFromInteger(Assembler* assembler) { |
| 840 Label fall_through; | 813 Label fall_through; |
| 841 TestBothArgumentsSmis(assembler, &fall_through); | 814 TestBothArgumentsSmis(assembler, &fall_through); |
| 842 // RAX is the right argument. | 815 // RAX is the right argument. |
| 843 __ orq(RAX, Address(RSP, + 2 * kWordSize)); | 816 __ orq(RAX, Address(RSP, + 2 * kWordSize)); |
| 844 // Result is in RAX. | 817 // Result is in RAX. |
| 845 __ ret(); | 818 __ ret(); |
| 846 __ Bind(&fall_through); | 819 __ Bind(&fall_through); |
| 847 return false; | |
| 848 } | 820 } |
| 849 | 821 |
| 850 | 822 |
| 851 bool Intrinsifier::Integer_bitOr(Assembler* assembler) { | 823 void Intrinsifier::Integer_bitOr(Assembler* assembler) { |
| 852 return Integer_bitOrFromInteger(assembler); | 824 return Integer_bitOrFromInteger(assembler); |
| 853 } | 825 } |
| 854 | 826 |
| 855 | 827 |
| 856 bool Intrinsifier::Integer_bitXorFromInteger(Assembler* assembler) { | 828 void Intrinsifier::Integer_bitXorFromInteger(Assembler* assembler) { |
| 857 Label fall_through; | 829 Label fall_through; |
| 858 TestBothArgumentsSmis(assembler, &fall_through); | 830 TestBothArgumentsSmis(assembler, &fall_through); |
| 859 // RAX is the right argument. | 831 // RAX is the right argument. |
| 860 __ xorq(RAX, Address(RSP, + 2 * kWordSize)); | 832 __ xorq(RAX, Address(RSP, + 2 * kWordSize)); |
| 861 // Result is in RAX. | 833 // Result is in RAX. |
| 862 __ ret(); | 834 __ ret(); |
| 863 __ Bind(&fall_through); | 835 __ Bind(&fall_through); |
| 864 return false; | |
| 865 } | 836 } |
| 866 | 837 |
| 867 | 838 |
| 868 bool Intrinsifier::Integer_bitXor(Assembler* assembler) { | 839 void Intrinsifier::Integer_bitXor(Assembler* assembler) { |
| 869 return Integer_bitXorFromInteger(assembler); | 840 return Integer_bitXorFromInteger(assembler); |
| 870 } | 841 } |
| 871 | 842 |
| 872 | 843 |
| 873 bool Intrinsifier::Integer_shl(Assembler* assembler) { | 844 void Intrinsifier::Integer_shl(Assembler* assembler) { |
| 874 ASSERT(kSmiTagShift == 1); | 845 ASSERT(kSmiTagShift == 1); |
| 875 ASSERT(kSmiTag == 0); | 846 ASSERT(kSmiTag == 0); |
| 876 Label fall_through, overflow; | 847 Label fall_through, overflow; |
| 877 TestBothArgumentsSmis(assembler, &fall_through); | 848 TestBothArgumentsSmis(assembler, &fall_through); |
| 878 // Shift value is in RAX. Compare with tagged Smi. | 849 // Shift value is in RAX. Compare with tagged Smi. |
| 879 __ cmpq(RAX, Immediate(Smi::RawValue(Smi::kBits))); | 850 __ cmpq(RAX, Immediate(Smi::RawValue(Smi::kBits))); |
| 880 __ j(ABOVE_EQUAL, &fall_through, Assembler::kNearJump); | 851 __ j(ABOVE_EQUAL, &fall_through, Assembler::kNearJump); |
| 881 | 852 |
| 882 __ SmiUntag(RAX); | 853 __ SmiUntag(RAX); |
| 883 __ movq(RCX, RAX); // Shift amount must be in RCX. | 854 __ movq(RCX, RAX); // Shift amount must be in RCX. |
| 884 __ movq(RAX, Address(RSP, + 2 * kWordSize)); // Value. | 855 __ movq(RAX, Address(RSP, + 2 * kWordSize)); // Value. |
| 885 | 856 |
| 886 // Overflow test - all the shifted-out bits must be same as the sign bit. | 857 // Overflow test - all the shifted-out bits must be same as the sign bit. |
| 887 __ movq(RDI, RAX); | 858 __ movq(RDI, RAX); |
| 888 __ shlq(RAX, RCX); | 859 __ shlq(RAX, RCX); |
| 889 __ sarq(RAX, RCX); | 860 __ sarq(RAX, RCX); |
| 890 __ cmpq(RAX, RDI); | 861 __ cmpq(RAX, RDI); |
| 891 __ j(NOT_EQUAL, &overflow, Assembler::kNearJump); | 862 __ j(NOT_EQUAL, &overflow, Assembler::kNearJump); |
| 892 | 863 |
| 893 __ shlq(RAX, RCX); // Shift for result now we know there is no overflow. | 864 __ shlq(RAX, RCX); // Shift for result now we know there is no overflow. |
| 894 | 865 |
| 895 // RAX is a correctly tagged Smi. | 866 // RAX is a correctly tagged Smi. |
| 896 __ ret(); | 867 __ ret(); |
| 897 | 868 |
| 898 __ Bind(&overflow); | 869 __ Bind(&overflow); |
| 899 // Mint is rarely used on x64 (only for integers requiring 64 bit instead of | 870 // Mint is rarely used on x64 (only for integers requiring 64 bit instead of |
| 900 // 63 bits as represented by Smi). | 871 // 63 bits as represented by Smi). |
| 901 __ Bind(&fall_through); | 872 __ Bind(&fall_through); |
| 902 return false; | |
| 903 } | 873 } |
| 904 | 874 |
| 905 | 875 |
| 906 static bool CompareIntegers(Assembler* assembler, Condition true_condition) { | 876 static void CompareIntegers(Assembler* assembler, Condition true_condition) { |
| 907 Label fall_through, true_label; | 877 Label fall_through, true_label; |
| 908 TestBothArgumentsSmis(assembler, &fall_through); | 878 TestBothArgumentsSmis(assembler, &fall_through); |
| 909 // RAX contains the right argument. | 879 // RAX contains the right argument. |
| 910 __ cmpq(Address(RSP, + 2 * kWordSize), RAX); | 880 __ cmpq(Address(RSP, + 2 * kWordSize), RAX); |
| 911 __ j(true_condition, &true_label, Assembler::kNearJump); | 881 __ j(true_condition, &true_label, Assembler::kNearJump); |
| 912 __ LoadObject(RAX, Bool::False()); | 882 __ LoadObject(RAX, Bool::False()); |
| 913 __ ret(); | 883 __ ret(); |
| 914 __ Bind(&true_label); | 884 __ Bind(&true_label); |
| 915 __ LoadObject(RAX, Bool::True()); | 885 __ LoadObject(RAX, Bool::True()); |
| 916 __ ret(); | 886 __ ret(); |
| 917 __ Bind(&fall_through); | 887 __ Bind(&fall_through); |
| 918 return false; | |
| 919 } | 888 } |
| 920 | 889 |
| 921 | 890 |
| 922 | 891 |
| 923 bool Intrinsifier::Integer_lessThan(Assembler* assembler) { | 892 void Intrinsifier::Integer_lessThan(Assembler* assembler) { |
| 924 return CompareIntegers(assembler, LESS); | 893 return CompareIntegers(assembler, LESS); |
| 925 } | 894 } |
| 926 | 895 |
| 927 | 896 |
| 928 bool Intrinsifier::Integer_greaterThanFromInt(Assembler* assembler) { | 897 void Intrinsifier::Integer_greaterThanFromInt(Assembler* assembler) { |
| 929 return CompareIntegers(assembler, LESS); | 898 return CompareIntegers(assembler, LESS); |
| 930 } | 899 } |
| 931 | 900 |
| 932 | 901 |
| 933 bool Intrinsifier::Integer_greaterThan(Assembler* assembler) { | 902 void Intrinsifier::Integer_greaterThan(Assembler* assembler) { |
| 934 return CompareIntegers(assembler, GREATER); | 903 return CompareIntegers(assembler, GREATER); |
| 935 } | 904 } |
| 936 | 905 |
| 937 | 906 |
| 938 bool Intrinsifier::Integer_lessEqualThan(Assembler* assembler) { | 907 void Intrinsifier::Integer_lessEqualThan(Assembler* assembler) { |
| 939 return CompareIntegers(assembler, LESS_EQUAL); | 908 return CompareIntegers(assembler, LESS_EQUAL); |
| 940 } | 909 } |
| 941 | 910 |
| 942 | 911 |
| 943 bool Intrinsifier::Integer_greaterEqualThan(Assembler* assembler) { | 912 void Intrinsifier::Integer_greaterEqualThan(Assembler* assembler) { |
| 944 return CompareIntegers(assembler, GREATER_EQUAL); | 913 return CompareIntegers(assembler, GREATER_EQUAL); |
| 945 } | 914 } |
| 946 | 915 |
| 947 | 916 |
| 948 // This is called for Smi, Mint and Bigint receivers. The right argument | 917 // This is called for Smi, Mint and Bigint receivers. The right argument |
| 949 // can be Smi, Mint, Bigint or double. | 918 // can be Smi, Mint, Bigint or double. |
| 950 bool Intrinsifier::Integer_equalToInteger(Assembler* assembler) { | 919 void Intrinsifier::Integer_equalToInteger(Assembler* assembler) { |
| 951 Label fall_through, true_label, check_for_mint; | 920 Label fall_through, true_label, check_for_mint; |
| 952 // For integer receiver '===' check first. | 921 // For integer receiver '===' check first. |
| 953 __ movq(RAX, Address(RSP, + 1 * kWordSize)); | 922 __ movq(RAX, Address(RSP, + 1 * kWordSize)); |
| 954 __ movq(RCX, Address(RSP, + 2 * kWordSize)); | 923 __ movq(RCX, Address(RSP, + 2 * kWordSize)); |
| 955 __ cmpq(RAX, RCX); | 924 __ cmpq(RAX, RCX); |
| 956 __ j(EQUAL, &true_label, Assembler::kNearJump); | 925 __ j(EQUAL, &true_label, Assembler::kNearJump); |
| 957 __ orq(RAX, RCX); | 926 __ orq(RAX, RCX); |
| 958 __ testq(RAX, Immediate(kSmiTagMask)); | 927 __ testq(RAX, Immediate(kSmiTagMask)); |
| 959 __ j(NOT_ZERO, &check_for_mint, Assembler::kNearJump); | 928 __ j(NOT_ZERO, &check_for_mint, Assembler::kNearJump); |
| 960 // Both arguments are smi, '===' is good enough. | 929 // Both arguments are smi, '===' is good enough. |
| (...skipping 25 matching lines...) Expand all Loading... |
| 986 __ j(NOT_EQUAL, &fall_through); | 955 __ j(NOT_EQUAL, &fall_through); |
| 987 // Receiver is Mint, return false if right is Smi. | 956 // Receiver is Mint, return false if right is Smi. |
| 988 __ movq(RAX, Address(RSP, + 1 * kWordSize)); // Right argument. | 957 __ movq(RAX, Address(RSP, + 1 * kWordSize)); // Right argument. |
| 989 __ testq(RAX, Immediate(kSmiTagMask)); | 958 __ testq(RAX, Immediate(kSmiTagMask)); |
| 990 __ j(NOT_ZERO, &fall_through); | 959 __ j(NOT_ZERO, &fall_through); |
| 991 __ LoadObject(RAX, Bool::False()); // Smi == Mint -> false. | 960 __ LoadObject(RAX, Bool::False()); // Smi == Mint -> false. |
| 992 __ ret(); | 961 __ ret(); |
| 993 // TODO(srdjan): Implement Mint == Mint comparison. | 962 // TODO(srdjan): Implement Mint == Mint comparison. |
| 994 | 963 |
| 995 __ Bind(&fall_through); | 964 __ Bind(&fall_through); |
| 996 return false; | |
| 997 } | 965 } |
| 998 | 966 |
| 999 | 967 |
| 1000 bool Intrinsifier::Integer_equal(Assembler* assembler) { | 968 void Intrinsifier::Integer_equal(Assembler* assembler) { |
| 1001 return Integer_equalToInteger(assembler); | 969 return Integer_equalToInteger(assembler); |
| 1002 } | 970 } |
| 1003 | 971 |
| 1004 | 972 |
| 1005 bool Intrinsifier::Integer_sar(Assembler* assembler) { | 973 void Intrinsifier::Integer_sar(Assembler* assembler) { |
| 1006 Label fall_through, shift_count_ok; | 974 Label fall_through, shift_count_ok; |
| 1007 TestBothArgumentsSmis(assembler, &fall_through); | 975 TestBothArgumentsSmis(assembler, &fall_through); |
| 1008 const Immediate& count_limit = Immediate(0x3F); | 976 const Immediate& count_limit = Immediate(0x3F); |
| 1009 // Check that the count is not larger than what the hardware can handle. | 977 // Check that the count is not larger than what the hardware can handle. |
| 1010 // For shifting right a Smi the result is the same for all numbers | 978 // For shifting right a Smi the result is the same for all numbers |
| 1011 // >= count_limit. | 979 // >= count_limit. |
| 1012 __ SmiUntag(RAX); | 980 __ SmiUntag(RAX); |
| 1013 // Negative counts throw exception. | 981 // Negative counts throw exception. |
| 1014 __ cmpq(RAX, Immediate(0)); | 982 __ cmpq(RAX, Immediate(0)); |
| 1015 __ j(LESS, &fall_through, Assembler::kNearJump); | 983 __ j(LESS, &fall_through, Assembler::kNearJump); |
| 1016 __ cmpq(RAX, count_limit); | 984 __ cmpq(RAX, count_limit); |
| 1017 __ j(LESS_EQUAL, &shift_count_ok, Assembler::kNearJump); | 985 __ j(LESS_EQUAL, &shift_count_ok, Assembler::kNearJump); |
| 1018 __ movq(RAX, count_limit); | 986 __ movq(RAX, count_limit); |
| 1019 __ Bind(&shift_count_ok); | 987 __ Bind(&shift_count_ok); |
| 1020 __ movq(RCX, RAX); // Shift amount must be in RCX. | 988 __ movq(RCX, RAX); // Shift amount must be in RCX. |
| 1021 __ movq(RAX, Address(RSP, + 2 * kWordSize)); // Value. | 989 __ movq(RAX, Address(RSP, + 2 * kWordSize)); // Value. |
| 1022 __ SmiUntag(RAX); // Value. | 990 __ SmiUntag(RAX); // Value. |
| 1023 __ sarq(RAX, RCX); | 991 __ sarq(RAX, RCX); |
| 1024 __ SmiTag(RAX); | 992 __ SmiTag(RAX); |
| 1025 __ ret(); | 993 __ ret(); |
| 1026 __ Bind(&fall_through); | 994 __ Bind(&fall_through); |
| 1027 return false; | |
| 1028 } | 995 } |
| 1029 | 996 |
| 1030 | 997 |
| 1031 // Argument is Smi (receiver). | 998 // Argument is Smi (receiver). |
| 1032 bool Intrinsifier::Smi_bitNegate(Assembler* assembler) { | 999 void Intrinsifier::Smi_bitNegate(Assembler* assembler) { |
| 1033 __ movq(RAX, Address(RSP, + 1 * kWordSize)); // Index. | 1000 __ movq(RAX, Address(RSP, + 1 * kWordSize)); // Index. |
| 1034 __ notq(RAX); | 1001 __ notq(RAX); |
| 1035 __ andq(RAX, Immediate(~kSmiTagMask)); // Remove inverted smi-tag. | 1002 __ andq(RAX, Immediate(~kSmiTagMask)); // Remove inverted smi-tag. |
| 1036 __ ret(); | 1003 __ ret(); |
| 1037 return true; | |
| 1038 } | 1004 } |
| 1039 | 1005 |
| 1040 | 1006 |
| 1041 // Check if the last argument is a double, jump to label 'is_smi' if smi | 1007 // Check if the last argument is a double, jump to label 'is_smi' if smi |
| 1042 // (easy to convert to double), otherwise jump to label 'not_double_smi', | 1008 // (easy to convert to double), otherwise jump to label 'not_double_smi', |
| 1043 // Returns the last argument in RAX. | 1009 // Returns the last argument in RAX. |
| 1044 static void TestLastArgumentIsDouble(Assembler* assembler, | 1010 static void TestLastArgumentIsDouble(Assembler* assembler, |
| 1045 Label* is_smi, | 1011 Label* is_smi, |
| 1046 Label* not_double_smi) { | 1012 Label* not_double_smi) { |
| 1047 __ movq(RAX, Address(RSP, + 1 * kWordSize)); | 1013 __ movq(RAX, Address(RSP, + 1 * kWordSize)); |
| 1048 __ testq(RAX, Immediate(kSmiTagMask)); | 1014 __ testq(RAX, Immediate(kSmiTagMask)); |
| 1049 __ j(ZERO, is_smi, Assembler::kNearJump); // Jump if Smi. | 1015 __ j(ZERO, is_smi, Assembler::kNearJump); // Jump if Smi. |
| 1050 __ CompareClassId(RAX, kDoubleCid); | 1016 __ CompareClassId(RAX, kDoubleCid); |
| 1051 __ j(NOT_EQUAL, not_double_smi, Assembler::kNearJump); | 1017 __ j(NOT_EQUAL, not_double_smi, Assembler::kNearJump); |
| 1052 // Fall through if double. | 1018 // Fall through if double. |
| 1053 } | 1019 } |
| 1054 | 1020 |
| 1055 | 1021 |
| 1056 // Both arguments on stack, left argument is a double, right argument is of | 1022 // Both arguments on stack, left argument is a double, right argument is of |
| 1057 // unknown type. Return true or false object in RAX. Any NaN argument | 1023 // unknown type. Return true or false object in RAX. Any NaN argument |
| 1058 // returns false. Any non-double argument causes control flow to fall through | 1024 // returns false. Any non-double argument causes control flow to fall through |
| 1059 // to the slow case (compiled method body). | 1025 // to the slow case (compiled method body). |
| 1060 static bool CompareDoubles(Assembler* assembler, Condition true_condition) { | 1026 static void CompareDoubles(Assembler* assembler, Condition true_condition) { |
| 1061 Label fall_through, is_false, is_true, is_smi, double_op; | 1027 Label fall_through, is_false, is_true, is_smi, double_op; |
| 1062 TestLastArgumentIsDouble(assembler, &is_smi, &fall_through); | 1028 TestLastArgumentIsDouble(assembler, &is_smi, &fall_through); |
| 1063 // Both arguments are double, right operand is in RAX. | 1029 // Both arguments are double, right operand is in RAX. |
| 1064 __ movsd(XMM1, FieldAddress(RAX, Double::value_offset())); | 1030 __ movsd(XMM1, FieldAddress(RAX, Double::value_offset())); |
| 1065 __ Bind(&double_op); | 1031 __ Bind(&double_op); |
| 1066 __ movq(RAX, Address(RSP, + 2 * kWordSize)); // Left argument. | 1032 __ movq(RAX, Address(RSP, + 2 * kWordSize)); // Left argument. |
| 1067 __ movsd(XMM0, FieldAddress(RAX, Double::value_offset())); | 1033 __ movsd(XMM0, FieldAddress(RAX, Double::value_offset())); |
| 1068 __ comisd(XMM0, XMM1); | 1034 __ comisd(XMM0, XMM1); |
| 1069 __ j(PARITY_EVEN, &is_false, Assembler::kNearJump); // NaN -> false; | 1035 __ j(PARITY_EVEN, &is_false, Assembler::kNearJump); // NaN -> false; |
| 1070 __ j(true_condition, &is_true, Assembler::kNearJump); | 1036 __ j(true_condition, &is_true, Assembler::kNearJump); |
| 1071 // Fall through false. | 1037 // Fall through false. |
| 1072 __ Bind(&is_false); | 1038 __ Bind(&is_false); |
| 1073 __ LoadObject(RAX, Bool::False()); | 1039 __ LoadObject(RAX, Bool::False()); |
| 1074 __ ret(); | 1040 __ ret(); |
| 1075 __ Bind(&is_true); | 1041 __ Bind(&is_true); |
| 1076 __ LoadObject(RAX, Bool::True()); | 1042 __ LoadObject(RAX, Bool::True()); |
| 1077 __ ret(); | 1043 __ ret(); |
| 1078 __ Bind(&is_smi); | 1044 __ Bind(&is_smi); |
| 1079 __ SmiUntag(RAX); | 1045 __ SmiUntag(RAX); |
| 1080 __ cvtsi2sd(XMM1, RAX); | 1046 __ cvtsi2sd(XMM1, RAX); |
| 1081 __ jmp(&double_op); | 1047 __ jmp(&double_op); |
| 1082 __ Bind(&fall_through); | 1048 __ Bind(&fall_through); |
| 1083 return false; | |
| 1084 } | 1049 } |
| 1085 | 1050 |
| 1086 | 1051 |
| 1087 bool Intrinsifier::Double_greaterThan(Assembler* assembler) { | 1052 void Intrinsifier::Double_greaterThan(Assembler* assembler) { |
| 1088 return CompareDoubles(assembler, ABOVE); | 1053 return CompareDoubles(assembler, ABOVE); |
| 1089 } | 1054 } |
| 1090 | 1055 |
| 1091 | 1056 |
| 1092 bool Intrinsifier::Double_greaterEqualThan(Assembler* assembler) { | 1057 void Intrinsifier::Double_greaterEqualThan(Assembler* assembler) { |
| 1093 return CompareDoubles(assembler, ABOVE_EQUAL); | 1058 return CompareDoubles(assembler, ABOVE_EQUAL); |
| 1094 } | 1059 } |
| 1095 | 1060 |
| 1096 | 1061 |
| 1097 bool Intrinsifier::Double_lessThan(Assembler* assembler) { | 1062 void Intrinsifier::Double_lessThan(Assembler* assembler) { |
| 1098 return CompareDoubles(assembler, BELOW); | 1063 return CompareDoubles(assembler, BELOW); |
| 1099 } | 1064 } |
| 1100 | 1065 |
| 1101 | 1066 |
| 1102 bool Intrinsifier::Double_equal(Assembler* assembler) { | 1067 void Intrinsifier::Double_equal(Assembler* assembler) { |
| 1103 return CompareDoubles(assembler, EQUAL); | 1068 return CompareDoubles(assembler, EQUAL); |
| 1104 } | 1069 } |
| 1105 | 1070 |
| 1106 | 1071 |
| 1107 bool Intrinsifier::Double_lessEqualThan(Assembler* assembler) { | 1072 void Intrinsifier::Double_lessEqualThan(Assembler* assembler) { |
| 1108 return CompareDoubles(assembler, BELOW_EQUAL); | 1073 return CompareDoubles(assembler, BELOW_EQUAL); |
| 1109 } | 1074 } |
| 1110 | 1075 |
| 1111 | 1076 |
| 1112 // Expects left argument to be double (receiver). Right argument is unknown. | 1077 // Expects left argument to be double (receiver). Right argument is unknown. |
| 1113 // Both arguments are on stack. | 1078 // Both arguments are on stack. |
| 1114 static bool DoubleArithmeticOperations(Assembler* assembler, Token::Kind kind) { | 1079 static void DoubleArithmeticOperations(Assembler* assembler, Token::Kind kind) { |
| 1115 Label fall_through; | 1080 Label fall_through; |
| 1116 TestLastArgumentIsDouble(assembler, &fall_through, &fall_through); | 1081 TestLastArgumentIsDouble(assembler, &fall_through, &fall_through); |
| 1117 // Both arguments are double, right operand is in RAX. | 1082 // Both arguments are double, right operand is in RAX. |
| 1118 __ movsd(XMM1, FieldAddress(RAX, Double::value_offset())); | 1083 __ movsd(XMM1, FieldAddress(RAX, Double::value_offset())); |
| 1119 __ movq(RAX, Address(RSP, + 2 * kWordSize)); // Left argument. | 1084 __ movq(RAX, Address(RSP, + 2 * kWordSize)); // Left argument. |
| 1120 __ movsd(XMM0, FieldAddress(RAX, Double::value_offset())); | 1085 __ movsd(XMM0, FieldAddress(RAX, Double::value_offset())); |
| 1121 switch (kind) { | 1086 switch (kind) { |
| 1122 case Token::kADD: __ addsd(XMM0, XMM1); break; | 1087 case Token::kADD: __ addsd(XMM0, XMM1); break; |
| 1123 case Token::kSUB: __ subsd(XMM0, XMM1); break; | 1088 case Token::kSUB: __ subsd(XMM0, XMM1); break; |
| 1124 case Token::kMUL: __ mulsd(XMM0, XMM1); break; | 1089 case Token::kMUL: __ mulsd(XMM0, XMM1); break; |
| 1125 case Token::kDIV: __ divsd(XMM0, XMM1); break; | 1090 case Token::kDIV: __ divsd(XMM0, XMM1); break; |
| 1126 default: UNREACHABLE(); | 1091 default: UNREACHABLE(); |
| 1127 } | 1092 } |
| 1128 const Class& double_class = Class::Handle( | 1093 const Class& double_class = Class::Handle( |
| 1129 Isolate::Current()->object_store()->double_class()); | 1094 Isolate::Current()->object_store()->double_class()); |
| 1130 __ TryAllocate(double_class, | 1095 __ TryAllocate(double_class, |
| 1131 &fall_through, | 1096 &fall_through, |
| 1132 Assembler::kNearJump, | 1097 Assembler::kNearJump, |
| 1133 RAX); // Result register. | 1098 RAX); // Result register. |
| 1134 __ movsd(FieldAddress(RAX, Double::value_offset()), XMM0); | 1099 __ movsd(FieldAddress(RAX, Double::value_offset()), XMM0); |
| 1135 __ ret(); | 1100 __ ret(); |
| 1136 __ Bind(&fall_through); | 1101 __ Bind(&fall_through); |
| 1137 return false; | |
| 1138 } | 1102 } |
| 1139 | 1103 |
| 1140 | 1104 |
| 1141 bool Intrinsifier::Double_add(Assembler* assembler) { | 1105 void Intrinsifier::Double_add(Assembler* assembler) { |
| 1142 return DoubleArithmeticOperations(assembler, Token::kADD); | 1106 return DoubleArithmeticOperations(assembler, Token::kADD); |
| 1143 } | 1107 } |
| 1144 | 1108 |
| 1145 | 1109 |
| 1146 bool Intrinsifier::Double_mul(Assembler* assembler) { | 1110 void Intrinsifier::Double_mul(Assembler* assembler) { |
| 1147 return DoubleArithmeticOperations(assembler, Token::kMUL); | 1111 return DoubleArithmeticOperations(assembler, Token::kMUL); |
| 1148 } | 1112 } |
| 1149 | 1113 |
| 1150 | 1114 |
| 1151 bool Intrinsifier::Double_sub(Assembler* assembler) { | 1115 void Intrinsifier::Double_sub(Assembler* assembler) { |
| 1152 return DoubleArithmeticOperations(assembler, Token::kSUB); | 1116 return DoubleArithmeticOperations(assembler, Token::kSUB); |
| 1153 } | 1117 } |
| 1154 | 1118 |
| 1155 | 1119 |
| 1156 bool Intrinsifier::Double_div(Assembler* assembler) { | 1120 void Intrinsifier::Double_div(Assembler* assembler) { |
| 1157 return DoubleArithmeticOperations(assembler, Token::kDIV); | 1121 return DoubleArithmeticOperations(assembler, Token::kDIV); |
| 1158 } | 1122 } |
| 1159 | 1123 |
| 1160 | 1124 |
| 1161 bool Intrinsifier::Double_mulFromInteger(Assembler* assembler) { | 1125 void Intrinsifier::Double_mulFromInteger(Assembler* assembler) { |
| 1162 Label fall_through; | 1126 Label fall_through; |
| 1163 // Only Smi-s allowed. | 1127 // Only Smi-s allowed. |
| 1164 __ movq(RAX, Address(RSP, + 1 * kWordSize)); | 1128 __ movq(RAX, Address(RSP, + 1 * kWordSize)); |
| 1165 __ testq(RAX, Immediate(kSmiTagMask)); | 1129 __ testq(RAX, Immediate(kSmiTagMask)); |
| 1166 __ j(NOT_ZERO, &fall_through, Assembler::kNearJump); | 1130 __ j(NOT_ZERO, &fall_through, Assembler::kNearJump); |
| 1167 // Is Smi. | 1131 // Is Smi. |
| 1168 __ SmiUntag(RAX); | 1132 __ SmiUntag(RAX); |
| 1169 __ cvtsi2sd(XMM1, RAX); | 1133 __ cvtsi2sd(XMM1, RAX); |
| 1170 __ movq(RAX, Address(RSP, + 2 * kWordSize)); | 1134 __ movq(RAX, Address(RSP, + 2 * kWordSize)); |
| 1171 __ movsd(XMM0, FieldAddress(RAX, Double::value_offset())); | 1135 __ movsd(XMM0, FieldAddress(RAX, Double::value_offset())); |
| 1172 __ mulsd(XMM0, XMM1); | 1136 __ mulsd(XMM0, XMM1); |
| 1173 const Class& double_class = Class::Handle( | 1137 const Class& double_class = Class::Handle( |
| 1174 Isolate::Current()->object_store()->double_class()); | 1138 Isolate::Current()->object_store()->double_class()); |
| 1175 __ TryAllocate(double_class, | 1139 __ TryAllocate(double_class, |
| 1176 &fall_through, | 1140 &fall_through, |
| 1177 Assembler::kNearJump, | 1141 Assembler::kNearJump, |
| 1178 RAX); // Result register. | 1142 RAX); // Result register. |
| 1179 __ movsd(FieldAddress(RAX, Double::value_offset()), XMM0); | 1143 __ movsd(FieldAddress(RAX, Double::value_offset()), XMM0); |
| 1180 __ ret(); | 1144 __ ret(); |
| 1181 __ Bind(&fall_through); | 1145 __ Bind(&fall_through); |
| 1182 return false; | |
| 1183 } | 1146 } |
| 1184 | 1147 |
| 1185 | 1148 |
| 1186 // Left is double right is integer (Bigint, Mint or Smi) | 1149 // Left is double right is integer (Bigint, Mint or Smi) |
| 1187 bool Intrinsifier::Double_fromInteger(Assembler* assembler) { | 1150 void Intrinsifier::Double_fromInteger(Assembler* assembler) { |
| 1188 Label fall_through; | 1151 Label fall_through; |
| 1189 __ movq(RAX, Address(RSP, +1 * kWordSize)); | 1152 __ movq(RAX, Address(RSP, +1 * kWordSize)); |
| 1190 __ testq(RAX, Immediate(kSmiTagMask)); | 1153 __ testq(RAX, Immediate(kSmiTagMask)); |
| 1191 __ j(NOT_ZERO, &fall_through, Assembler::kNearJump); | 1154 __ j(NOT_ZERO, &fall_through, Assembler::kNearJump); |
| 1192 // Is Smi. | 1155 // Is Smi. |
| 1193 __ SmiUntag(RAX); | 1156 __ SmiUntag(RAX); |
| 1194 __ cvtsi2sd(XMM0, RAX); | 1157 __ cvtsi2sd(XMM0, RAX); |
| 1195 const Class& double_class = Class::Handle( | 1158 const Class& double_class = Class::Handle( |
| 1196 Isolate::Current()->object_store()->double_class()); | 1159 Isolate::Current()->object_store()->double_class()); |
| 1197 __ TryAllocate(double_class, | 1160 __ TryAllocate(double_class, |
| 1198 &fall_through, | 1161 &fall_through, |
| 1199 Assembler::kNearJump, | 1162 Assembler::kNearJump, |
| 1200 RAX); // Result register. | 1163 RAX); // Result register. |
| 1201 __ movsd(FieldAddress(RAX, Double::value_offset()), XMM0); | 1164 __ movsd(FieldAddress(RAX, Double::value_offset()), XMM0); |
| 1202 __ ret(); | 1165 __ ret(); |
| 1203 __ Bind(&fall_through); | 1166 __ Bind(&fall_through); |
| 1204 return false; | |
| 1205 } | 1167 } |
| 1206 | 1168 |
| 1207 | 1169 |
| 1208 bool Intrinsifier::Double_getIsNaN(Assembler* assembler) { | 1170 void Intrinsifier::Double_getIsNaN(Assembler* assembler) { |
| 1209 Label is_true; | 1171 Label is_true; |
| 1210 __ movq(RAX, Address(RSP, +1 * kWordSize)); | 1172 __ movq(RAX, Address(RSP, +1 * kWordSize)); |
| 1211 __ movsd(XMM0, FieldAddress(RAX, Double::value_offset())); | 1173 __ movsd(XMM0, FieldAddress(RAX, Double::value_offset())); |
| 1212 __ comisd(XMM0, XMM0); | 1174 __ comisd(XMM0, XMM0); |
| 1213 __ j(PARITY_EVEN, &is_true, Assembler::kNearJump); // NaN -> true; | 1175 __ j(PARITY_EVEN, &is_true, Assembler::kNearJump); // NaN -> true; |
| 1214 __ LoadObject(RAX, Bool::False()); | 1176 __ LoadObject(RAX, Bool::False()); |
| 1215 __ ret(); | 1177 __ ret(); |
| 1216 __ Bind(&is_true); | 1178 __ Bind(&is_true); |
| 1217 __ LoadObject(RAX, Bool::True()); | 1179 __ LoadObject(RAX, Bool::True()); |
| 1218 __ ret(); | 1180 __ ret(); |
| 1219 return true; // Method is complete, no slow case. | |
| 1220 } | 1181 } |
| 1221 | 1182 |
| 1222 | 1183 |
| 1223 bool Intrinsifier::Double_getIsNegative(Assembler* assembler) { | 1184 void Intrinsifier::Double_getIsNegative(Assembler* assembler) { |
| 1224 Label is_false, is_true, is_zero; | 1185 Label is_false, is_true, is_zero; |
| 1225 __ movq(RAX, Address(RSP, +1 * kWordSize)); | 1186 __ movq(RAX, Address(RSP, +1 * kWordSize)); |
| 1226 __ movsd(XMM0, FieldAddress(RAX, Double::value_offset())); | 1187 __ movsd(XMM0, FieldAddress(RAX, Double::value_offset())); |
| 1227 __ xorpd(XMM1, XMM1); // 0.0 -> XMM1. | 1188 __ xorpd(XMM1, XMM1); // 0.0 -> XMM1. |
| 1228 __ comisd(XMM0, XMM1); | 1189 __ comisd(XMM0, XMM1); |
| 1229 __ j(PARITY_EVEN, &is_false, Assembler::kNearJump); // NaN -> false. | 1190 __ j(PARITY_EVEN, &is_false, Assembler::kNearJump); // NaN -> false. |
| 1230 __ j(EQUAL, &is_zero, Assembler::kNearJump); // Check for negative zero. | 1191 __ j(EQUAL, &is_zero, Assembler::kNearJump); // Check for negative zero. |
| 1231 __ j(ABOVE_EQUAL, &is_false, Assembler::kNearJump); // >= 0 -> false. | 1192 __ j(ABOVE_EQUAL, &is_false, Assembler::kNearJump); // >= 0 -> false. |
| 1232 __ Bind(&is_true); | 1193 __ Bind(&is_true); |
| 1233 __ LoadObject(RAX, Bool::True()); | 1194 __ LoadObject(RAX, Bool::True()); |
| 1234 __ ret(); | 1195 __ ret(); |
| 1235 __ Bind(&is_false); | 1196 __ Bind(&is_false); |
| 1236 __ LoadObject(RAX, Bool::False()); | 1197 __ LoadObject(RAX, Bool::False()); |
| 1237 __ ret(); | 1198 __ ret(); |
| 1238 __ Bind(&is_zero); | 1199 __ Bind(&is_zero); |
| 1239 // Check for negative zero (get the sign bit). | 1200 // Check for negative zero (get the sign bit). |
| 1240 __ movmskpd(RAX, XMM0); | 1201 __ movmskpd(RAX, XMM0); |
| 1241 __ testq(RAX, Immediate(1)); | 1202 __ testq(RAX, Immediate(1)); |
| 1242 __ j(NOT_ZERO, &is_true, Assembler::kNearJump); | 1203 __ j(NOT_ZERO, &is_true, Assembler::kNearJump); |
| 1243 __ jmp(&is_false, Assembler::kNearJump); | 1204 __ jmp(&is_false, Assembler::kNearJump); |
| 1244 return true; // Method is complete, no slow case. | |
| 1245 } | 1205 } |
| 1246 | 1206 |
| 1247 | 1207 |
| 1248 enum TrigonometricFunctions { | 1208 enum TrigonometricFunctions { |
| 1249 kSine, | 1209 kSine, |
| 1250 kCosine, | 1210 kCosine, |
| 1251 }; | 1211 }; |
| 1252 | 1212 |
| 1253 | 1213 |
| 1254 static void EmitTrigonometric(Assembler* assembler, | 1214 static void EmitTrigonometric(Assembler* assembler, |
| (...skipping 27 matching lines...) Expand all Loading... |
| 1282 __ jmp(&double_op); | 1242 __ jmp(&double_op); |
| 1283 | 1243 |
| 1284 __ Bind(&alloc_failed); | 1244 __ Bind(&alloc_failed); |
| 1285 __ ffree(0); | 1245 __ ffree(0); |
| 1286 __ fincstp(); | 1246 __ fincstp(); |
| 1287 | 1247 |
| 1288 __ Bind(&fall_through); | 1248 __ Bind(&fall_through); |
| 1289 } | 1249 } |
| 1290 | 1250 |
| 1291 | 1251 |
| 1292 bool Intrinsifier::Double_toInt(Assembler* assembler) { | 1252 void Intrinsifier::Double_toInt(Assembler* assembler) { |
| 1293 __ movq(RAX, Address(RSP, +1 * kWordSize)); | 1253 __ movq(RAX, Address(RSP, +1 * kWordSize)); |
| 1294 __ movsd(XMM0, FieldAddress(RAX, Double::value_offset())); | 1254 __ movsd(XMM0, FieldAddress(RAX, Double::value_offset())); |
| 1295 __ cvttsd2siq(RAX, XMM0); | 1255 __ cvttsd2siq(RAX, XMM0); |
| 1296 // Overflow is signalled with minint. | 1256 // Overflow is signalled with minint. |
| 1297 Label fall_through; | 1257 Label fall_through; |
| 1298 // Check for overflow and that it fits into Smi. | 1258 // Check for overflow and that it fits into Smi. |
| 1299 __ movq(RCX, RAX); | 1259 __ movq(RCX, RAX); |
| 1300 __ shlq(RCX, Immediate(1)); | 1260 __ shlq(RCX, Immediate(1)); |
| 1301 __ j(OVERFLOW, &fall_through, Assembler::kNearJump); | 1261 __ j(OVERFLOW, &fall_through, Assembler::kNearJump); |
| 1302 __ SmiTag(RAX); | 1262 __ SmiTag(RAX); |
| 1303 __ ret(); | 1263 __ ret(); |
| 1304 __ Bind(&fall_through); | 1264 __ Bind(&fall_through); |
| 1305 return false; | |
| 1306 } | 1265 } |
| 1307 | 1266 |
| 1308 | 1267 |
| 1309 bool Intrinsifier::Math_sqrt(Assembler* assembler) { | 1268 void Intrinsifier::Math_sqrt(Assembler* assembler) { |
| 1310 Label fall_through, is_smi, double_op; | 1269 Label fall_through, is_smi, double_op; |
| 1311 TestLastArgumentIsDouble(assembler, &is_smi, &fall_through); | 1270 TestLastArgumentIsDouble(assembler, &is_smi, &fall_through); |
| 1312 // Argument is double and is in RAX. | 1271 // Argument is double and is in RAX. |
| 1313 __ movsd(XMM1, FieldAddress(RAX, Double::value_offset())); | 1272 __ movsd(XMM1, FieldAddress(RAX, Double::value_offset())); |
| 1314 __ Bind(&double_op); | 1273 __ Bind(&double_op); |
| 1315 __ sqrtsd(XMM0, XMM1); | 1274 __ sqrtsd(XMM0, XMM1); |
| 1316 const Class& double_class = Class::Handle( | 1275 const Class& double_class = Class::Handle( |
| 1317 Isolate::Current()->object_store()->double_class()); | 1276 Isolate::Current()->object_store()->double_class()); |
| 1318 __ TryAllocate(double_class, | 1277 __ TryAllocate(double_class, |
| 1319 &fall_through, | 1278 &fall_through, |
| 1320 Assembler::kNearJump, | 1279 Assembler::kNearJump, |
| 1321 RAX); // Result register. | 1280 RAX); // Result register. |
| 1322 __ movsd(FieldAddress(RAX, Double::value_offset()), XMM0); | 1281 __ movsd(FieldAddress(RAX, Double::value_offset()), XMM0); |
| 1323 __ ret(); | 1282 __ ret(); |
| 1324 __ Bind(&is_smi); | 1283 __ Bind(&is_smi); |
| 1325 __ SmiUntag(RAX); | 1284 __ SmiUntag(RAX); |
| 1326 __ cvtsi2sd(XMM1, RAX); | 1285 __ cvtsi2sd(XMM1, RAX); |
| 1327 __ jmp(&double_op); | 1286 __ jmp(&double_op); |
| 1328 __ Bind(&fall_through); | 1287 __ Bind(&fall_through); |
| 1329 return false; | |
| 1330 } | 1288 } |
| 1331 | 1289 |
| 1332 | 1290 |
| 1333 bool Intrinsifier::Math_sin(Assembler* assembler) { | 1291 void Intrinsifier::Math_sin(Assembler* assembler) { |
| 1334 EmitTrigonometric(assembler, kSine); | 1292 EmitTrigonometric(assembler, kSine); |
| 1335 return false; // Compile method for slow case. | |
| 1336 } | 1293 } |
| 1337 | 1294 |
| 1338 | 1295 |
| 1339 bool Intrinsifier::Math_cos(Assembler* assembler) { | 1296 void Intrinsifier::Math_cos(Assembler* assembler) { |
| 1340 EmitTrigonometric(assembler, kCosine); | 1297 EmitTrigonometric(assembler, kCosine); |
| 1341 return false; // Compile method for slow case. | |
| 1342 } | 1298 } |
| 1343 | 1299 |
| 1344 | 1300 |
| 1345 // var state = ((_A * (_state[kSTATE_LO])) + _state[kSTATE_HI]) & _MASK_64; | 1301 // var state = ((_A * (_state[kSTATE_LO])) + _state[kSTATE_HI]) & _MASK_64; |
| 1346 // _state[kSTATE_LO] = state & _MASK_32; | 1302 // _state[kSTATE_LO] = state & _MASK_32; |
| 1347 // _state[kSTATE_HI] = state >> 32; | 1303 // _state[kSTATE_HI] = state >> 32; |
| 1348 bool Intrinsifier::Random_nextState(Assembler* assembler) { | 1304 void Intrinsifier::Random_nextState(Assembler* assembler) { |
| 1349 const Library& math_lib = Library::Handle(Library::MathLibrary()); | 1305 const Library& math_lib = Library::Handle(Library::MathLibrary()); |
| 1350 ASSERT(!math_lib.IsNull()); | 1306 ASSERT(!math_lib.IsNull()); |
| 1351 const Class& random_class = Class::Handle( | 1307 const Class& random_class = Class::Handle( |
| 1352 math_lib.LookupClassAllowPrivate(Symbols::_Random(), NULL)); | 1308 math_lib.LookupClassAllowPrivate(Symbols::_Random(), NULL)); |
| 1353 ASSERT(!random_class.IsNull()); | 1309 ASSERT(!random_class.IsNull()); |
| 1354 const Field& state_field = Field::ZoneHandle( | 1310 const Field& state_field = Field::ZoneHandle( |
| 1355 random_class.LookupInstanceField(Symbols::_state())); | 1311 random_class.LookupInstanceField(Symbols::_state())); |
| 1356 ASSERT(!state_field.IsNull()); | 1312 ASSERT(!state_field.IsNull()); |
| 1357 const Field& random_A_field = Field::ZoneHandle( | 1313 const Field& random_A_field = Field::ZoneHandle( |
| 1358 random_class.LookupStaticField(Symbols::_A())); | 1314 random_class.LookupStaticField(Symbols::_A())); |
| (...skipping 17 matching lines...) Expand all Loading... |
| 1376 | 1332 |
| 1377 __ movq(RAX, Immediate(a_int_value)); | 1333 __ movq(RAX, Immediate(a_int_value)); |
| 1378 __ movl(RCX, addr_0); | 1334 __ movl(RCX, addr_0); |
| 1379 __ imulq(RCX, RAX); | 1335 __ imulq(RCX, RAX); |
| 1380 __ movl(RDX, addr_1); | 1336 __ movl(RDX, addr_1); |
| 1381 __ addq(RDX, RCX); | 1337 __ addq(RDX, RCX); |
| 1382 __ movl(addr_0, RDX); | 1338 __ movl(addr_0, RDX); |
| 1383 __ shrq(RDX, Immediate(32)); | 1339 __ shrq(RDX, Immediate(32)); |
| 1384 __ movl(addr_1, RDX); | 1340 __ movl(addr_1, RDX); |
| 1385 __ ret(); | 1341 __ ret(); |
| 1386 return true; | |
| 1387 } | 1342 } |
| 1388 | 1343 |
| 1389 | 1344 |
| 1390 | 1345 |
| 1391 // Identity comparison. | 1346 // Identity comparison. |
| 1392 bool Intrinsifier::Object_equal(Assembler* assembler) { | 1347 void Intrinsifier::Object_equal(Assembler* assembler) { |
| 1393 Label is_true; | 1348 Label is_true; |
| 1394 __ movq(RAX, Address(RSP, + 1 * kWordSize)); | 1349 __ movq(RAX, Address(RSP, + 1 * kWordSize)); |
| 1395 __ cmpq(RAX, Address(RSP, + 2 * kWordSize)); | 1350 __ cmpq(RAX, Address(RSP, + 2 * kWordSize)); |
| 1396 __ j(EQUAL, &is_true, Assembler::kNearJump); | 1351 __ j(EQUAL, &is_true, Assembler::kNearJump); |
| 1397 __ LoadObject(RAX, Bool::False()); | 1352 __ LoadObject(RAX, Bool::False()); |
| 1398 __ ret(); | 1353 __ ret(); |
| 1399 __ Bind(&is_true); | 1354 __ Bind(&is_true); |
| 1400 __ LoadObject(RAX, Bool::True()); | 1355 __ LoadObject(RAX, Bool::True()); |
| 1401 __ ret(); | 1356 __ ret(); |
| 1402 return true; | |
| 1403 } | 1357 } |
| 1404 | 1358 |
| 1405 | 1359 |
| 1406 bool Intrinsifier::String_getHashCode(Assembler* assembler) { | 1360 void Intrinsifier::String_getHashCode(Assembler* assembler) { |
| 1407 Label fall_through; | 1361 Label fall_through; |
| 1408 __ movq(RAX, Address(RSP, + 1 * kWordSize)); // String object. | 1362 __ movq(RAX, Address(RSP, + 1 * kWordSize)); // String object. |
| 1409 __ movq(RAX, FieldAddress(RAX, String::hash_offset())); | 1363 __ movq(RAX, FieldAddress(RAX, String::hash_offset())); |
| 1410 __ cmpq(RAX, Immediate(0)); | 1364 __ cmpq(RAX, Immediate(0)); |
| 1411 __ j(EQUAL, &fall_through, Assembler::kNearJump); | 1365 __ j(EQUAL, &fall_through, Assembler::kNearJump); |
| 1412 __ ret(); | 1366 __ ret(); |
| 1413 __ Bind(&fall_through); | 1367 __ Bind(&fall_through); |
| 1414 // Hash not yet computed. | 1368 // Hash not yet computed. |
| 1415 return false; | |
| 1416 } | 1369 } |
| 1417 | 1370 |
| 1418 | 1371 |
| 1419 bool Intrinsifier::String_getLength(Assembler* assembler) { | 1372 void Intrinsifier::String_getLength(Assembler* assembler) { |
| 1420 __ movq(RAX, Address(RSP, + 1 * kWordSize)); // String object. | 1373 __ movq(RAX, Address(RSP, + 1 * kWordSize)); // String object. |
| 1421 __ movq(RAX, FieldAddress(RAX, String::length_offset())); | 1374 __ movq(RAX, FieldAddress(RAX, String::length_offset())); |
| 1422 __ ret(); | 1375 __ ret(); |
| 1423 return true; | |
| 1424 } | 1376 } |
| 1425 | 1377 |
| 1426 | 1378 |
| 1427 bool Intrinsifier::String_codeUnitAt(Assembler* assembler) { | 1379 void Intrinsifier::String_codeUnitAt(Assembler* assembler) { |
| 1428 Label fall_through, try_two_byte_string; | 1380 Label fall_through, try_two_byte_string; |
| 1429 __ movq(RCX, Address(RSP, + 1 * kWordSize)); // Index. | 1381 __ movq(RCX, Address(RSP, + 1 * kWordSize)); // Index. |
| 1430 __ movq(RAX, Address(RSP, + 2 * kWordSize)); // String. | 1382 __ movq(RAX, Address(RSP, + 2 * kWordSize)); // String. |
| 1431 __ testq(RCX, Immediate(kSmiTagMask)); | 1383 __ testq(RCX, Immediate(kSmiTagMask)); |
| 1432 __ j(NOT_ZERO, &fall_through, Assembler::kNearJump); // Non-smi index. | 1384 __ j(NOT_ZERO, &fall_through, Assembler::kNearJump); // Non-smi index. |
| 1433 // Range check. | 1385 // Range check. |
| 1434 __ cmpq(RCX, FieldAddress(RAX, String::length_offset())); | 1386 __ cmpq(RCX, FieldAddress(RAX, String::length_offset())); |
| 1435 // Runtime throws exception. | 1387 // Runtime throws exception. |
| 1436 __ j(ABOVE_EQUAL, &fall_through, Assembler::kNearJump); | 1388 __ j(ABOVE_EQUAL, &fall_through, Assembler::kNearJump); |
| 1437 __ CompareClassId(RAX, kOneByteStringCid); | 1389 __ CompareClassId(RAX, kOneByteStringCid); |
| 1438 __ j(NOT_EQUAL, &try_two_byte_string, Assembler::kNearJump); | 1390 __ j(NOT_EQUAL, &try_two_byte_string, Assembler::kNearJump); |
| 1439 __ SmiUntag(RCX); | 1391 __ SmiUntag(RCX); |
| 1440 __ movzxb(RAX, FieldAddress(RAX, RCX, TIMES_1, OneByteString::data_offset())); | 1392 __ movzxb(RAX, FieldAddress(RAX, RCX, TIMES_1, OneByteString::data_offset())); |
| 1441 __ SmiTag(RAX); | 1393 __ SmiTag(RAX); |
| 1442 __ ret(); | 1394 __ ret(); |
| 1443 | 1395 |
| 1444 __ Bind(&try_two_byte_string); | 1396 __ Bind(&try_two_byte_string); |
| 1445 __ CompareClassId(RAX, kTwoByteStringCid); | 1397 __ CompareClassId(RAX, kTwoByteStringCid); |
| 1446 __ j(NOT_EQUAL, &fall_through, Assembler::kNearJump); | 1398 __ j(NOT_EQUAL, &fall_through, Assembler::kNearJump); |
| 1447 ASSERT(kSmiTagShift == 1); | 1399 ASSERT(kSmiTagShift == 1); |
| 1448 __ movzxw(RAX, FieldAddress(RAX, RCX, TIMES_1, OneByteString::data_offset())); | 1400 __ movzxw(RAX, FieldAddress(RAX, RCX, TIMES_1, OneByteString::data_offset())); |
| 1449 __ SmiTag(RAX); | 1401 __ SmiTag(RAX); |
| 1450 __ ret(); | 1402 __ ret(); |
| 1451 | 1403 |
| 1452 __ Bind(&fall_through); | 1404 __ Bind(&fall_through); |
| 1453 return false; | |
| 1454 } | 1405 } |
| 1455 | 1406 |
| 1456 | 1407 |
| 1457 bool Intrinsifier::String_getIsEmpty(Assembler* assembler) { | 1408 void Intrinsifier::String_getIsEmpty(Assembler* assembler) { |
| 1458 Label is_true; | 1409 Label is_true; |
| 1459 // Get length. | 1410 // Get length. |
| 1460 __ movq(RAX, Address(RSP, + 1 * kWordSize)); // String object. | 1411 __ movq(RAX, Address(RSP, + 1 * kWordSize)); // String object. |
| 1461 __ movq(RAX, FieldAddress(RAX, String::length_offset())); | 1412 __ movq(RAX, FieldAddress(RAX, String::length_offset())); |
| 1462 __ cmpq(RAX, Immediate(Smi::RawValue(0))); | 1413 __ cmpq(RAX, Immediate(Smi::RawValue(0))); |
| 1463 __ j(EQUAL, &is_true, Assembler::kNearJump); | 1414 __ j(EQUAL, &is_true, Assembler::kNearJump); |
| 1464 __ LoadObject(RAX, Bool::False()); | 1415 __ LoadObject(RAX, Bool::False()); |
| 1465 __ ret(); | 1416 __ ret(); |
| 1466 __ Bind(&is_true); | 1417 __ Bind(&is_true); |
| 1467 __ LoadObject(RAX, Bool::True()); | 1418 __ LoadObject(RAX, Bool::True()); |
| 1468 __ ret(); | 1419 __ ret(); |
| 1469 return false; | |
| 1470 } | 1420 } |
| 1471 | 1421 |
| 1472 | 1422 |
| 1473 bool Intrinsifier::OneByteString_getHashCode(Assembler* assembler) { | 1423 void Intrinsifier::OneByteString_getHashCode(Assembler* assembler) { |
| 1474 Label compute_hash; | 1424 Label compute_hash; |
| 1475 __ movq(RBX, Address(RSP, + 1 * kWordSize)); // OneByteString object. | 1425 __ movq(RBX, Address(RSP, + 1 * kWordSize)); // OneByteString object. |
| 1476 __ movq(RAX, FieldAddress(RBX, String::hash_offset())); | 1426 __ movq(RAX, FieldAddress(RBX, String::hash_offset())); |
| 1477 __ cmpq(RAX, Immediate(0)); | 1427 __ cmpq(RAX, Immediate(0)); |
| 1478 __ j(EQUAL, &compute_hash, Assembler::kNearJump); | 1428 __ j(EQUAL, &compute_hash, Assembler::kNearJump); |
| 1479 __ ret(); | 1429 __ ret(); |
| 1480 | 1430 |
| 1481 __ Bind(&compute_hash); | 1431 __ Bind(&compute_hash); |
| 1482 // Hash not yet computed, use algorithm of class StringHasher. | 1432 // Hash not yet computed, use algorithm of class StringHasher. |
| 1483 __ movq(RCX, FieldAddress(RBX, String::length_offset())); | 1433 __ movq(RCX, FieldAddress(RBX, String::length_offset())); |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1529 Immediate(((static_cast<intptr_t>(1) << String::kHashBits) - 1))); | 1479 Immediate(((static_cast<intptr_t>(1) << String::kHashBits) - 1))); |
| 1530 | 1480 |
| 1531 // return hash_ == 0 ? 1 : hash_; | 1481 // return hash_ == 0 ? 1 : hash_; |
| 1532 __ cmpq(RAX, Immediate(0)); | 1482 __ cmpq(RAX, Immediate(0)); |
| 1533 __ j(NOT_EQUAL, &set_hash_code, Assembler::kNearJump); | 1483 __ j(NOT_EQUAL, &set_hash_code, Assembler::kNearJump); |
| 1534 __ incq(RAX); | 1484 __ incq(RAX); |
| 1535 __ Bind(&set_hash_code); | 1485 __ Bind(&set_hash_code); |
| 1536 __ SmiTag(RAX); | 1486 __ SmiTag(RAX); |
| 1537 __ movq(FieldAddress(RBX, String::hash_offset()), RAX); | 1487 __ movq(FieldAddress(RBX, String::hash_offset()), RAX); |
| 1538 __ ret(); | 1488 __ ret(); |
| 1539 return true; | |
| 1540 } | 1489 } |
| 1541 | 1490 |
| 1542 | 1491 |
| 1543 // Allocates one-byte string of length 'end - start'. The content is not | 1492 // Allocates one-byte string of length 'end - start'. The content is not |
| 1544 // initialized. 'length-reg' contains tagged length. | 1493 // initialized. 'length-reg' contains tagged length. |
| 1545 // Returns new string as tagged pointer in EAX. | 1494 // Returns new string as tagged pointer in EAX. |
| 1546 static void TryAllocateOnebyteString(Assembler* assembler, | 1495 static void TryAllocateOnebyteString(Assembler* assembler, |
| 1547 Label* ok, | 1496 Label* ok, |
| 1548 Label* failure, | 1497 Label* failure, |
| 1549 Register length_reg) { | 1498 Register length_reg) { |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1615 __ Bind(&pop_and_fail); | 1564 __ Bind(&pop_and_fail); |
| 1616 __ popq(RDI); | 1565 __ popq(RDI); |
| 1617 __ jmp(failure); | 1566 __ jmp(failure); |
| 1618 } | 1567 } |
| 1619 | 1568 |
| 1620 | 1569 |
| 1621 // Arg0: Onebyte String | 1570 // Arg0: Onebyte String |
| 1622 // Arg1: Start index as Smi. | 1571 // Arg1: Start index as Smi. |
| 1623 // Arg2: End index as Smi. | 1572 // Arg2: End index as Smi. |
| 1624 // The indexes must be valid. | 1573 // The indexes must be valid. |
| 1625 bool Intrinsifier::OneByteString_substringUnchecked(Assembler* assembler) { | 1574 void Intrinsifier::OneByteString_substringUnchecked(Assembler* assembler) { |
| 1626 const intptr_t kStringOffset = 3 * kWordSize; | 1575 const intptr_t kStringOffset = 3 * kWordSize; |
| 1627 const intptr_t kStartIndexOffset = 2 * kWordSize; | 1576 const intptr_t kStartIndexOffset = 2 * kWordSize; |
| 1628 const intptr_t kEndIndexOffset = 1 * kWordSize; | 1577 const intptr_t kEndIndexOffset = 1 * kWordSize; |
| 1629 Label fall_through, ok; | 1578 Label fall_through, ok; |
| 1630 __ movq(RDI, Address(RSP, + kEndIndexOffset)); | 1579 __ movq(RDI, Address(RSP, + kEndIndexOffset)); |
| 1631 __ subq(RDI, Address(RSP, + kStartIndexOffset)); | 1580 __ subq(RDI, Address(RSP, + kStartIndexOffset)); |
| 1632 TryAllocateOnebyteString(assembler, &ok, &fall_through, RDI); | 1581 TryAllocateOnebyteString(assembler, &ok, &fall_through, RDI); |
| 1633 __ Bind(&ok); | 1582 __ Bind(&ok); |
| 1634 // RAX: new string as tagged pointer. | 1583 // RAX: new string as tagged pointer. |
| 1635 // Copy string. | 1584 // Copy string. |
| (...skipping 16 matching lines...) Expand all Loading... |
| 1652 __ jmp(&check, Assembler::kNearJump); | 1601 __ jmp(&check, Assembler::kNearJump); |
| 1653 __ Bind(&loop); | 1602 __ Bind(&loop); |
| 1654 __ movzxb(RBX, Address(RSI, RDX, TIMES_1, 0)); | 1603 __ movzxb(RBX, Address(RSI, RDX, TIMES_1, 0)); |
| 1655 __ movb(FieldAddress(RAX, RDX, TIMES_1, OneByteString::data_offset()), RBX); | 1604 __ movb(FieldAddress(RAX, RDX, TIMES_1, OneByteString::data_offset()), RBX); |
| 1656 __ incq(RDX); | 1605 __ incq(RDX); |
| 1657 __ Bind(&check); | 1606 __ Bind(&check); |
| 1658 __ cmpq(RDX, RCX); | 1607 __ cmpq(RDX, RCX); |
| 1659 __ j(LESS, &loop, Assembler::kNearJump); | 1608 __ j(LESS, &loop, Assembler::kNearJump); |
| 1660 __ ret(); | 1609 __ ret(); |
| 1661 __ Bind(&fall_through); | 1610 __ Bind(&fall_through); |
| 1662 return false; | |
| 1663 } | 1611 } |
| 1664 | 1612 |
| 1665 | 1613 |
| 1666 bool Intrinsifier::OneByteString_setAt(Assembler* assembler) { | 1614 void Intrinsifier::OneByteString_setAt(Assembler* assembler) { |
| 1667 __ movq(RCX, Address(RSP, + 1 * kWordSize)); // Value. | 1615 __ movq(RCX, Address(RSP, + 1 * kWordSize)); // Value. |
| 1668 __ movq(RBX, Address(RSP, + 2 * kWordSize)); // Index. | 1616 __ movq(RBX, Address(RSP, + 2 * kWordSize)); // Index. |
| 1669 __ movq(RAX, Address(RSP, + 3 * kWordSize)); // OneByteString. | 1617 __ movq(RAX, Address(RSP, + 3 * kWordSize)); // OneByteString. |
| 1670 __ SmiUntag(RBX); | 1618 __ SmiUntag(RBX); |
| 1671 __ SmiUntag(RCX); | 1619 __ SmiUntag(RCX); |
| 1672 __ movb(FieldAddress(RAX, RBX, TIMES_1, OneByteString::data_offset()), RCX); | 1620 __ movb(FieldAddress(RAX, RBX, TIMES_1, OneByteString::data_offset()), RCX); |
| 1673 __ ret(); | 1621 __ ret(); |
| 1674 return true; | |
| 1675 } | 1622 } |
| 1676 | 1623 |
| 1677 | 1624 |
| 1678 bool Intrinsifier::OneByteString_allocate(Assembler* assembler) { | 1625 void Intrinsifier::OneByteString_allocate(Assembler* assembler) { |
| 1679 __ movq(RDI, Address(RSP, + 1 * kWordSize)); // Length.v= | 1626 __ movq(RDI, Address(RSP, + 1 * kWordSize)); // Length.v= |
| 1680 Label fall_through, ok; | 1627 Label fall_through, ok; |
| 1681 TryAllocateOnebyteString(assembler, &ok, &fall_through, RDI); | 1628 TryAllocateOnebyteString(assembler, &ok, &fall_through, RDI); |
| 1682 // EDI: Start address to copy from (untagged). | 1629 // EDI: Start address to copy from (untagged). |
| 1683 | 1630 |
| 1684 __ Bind(&ok); | 1631 __ Bind(&ok); |
| 1685 __ ret(); | 1632 __ ret(); |
| 1686 | 1633 |
| 1687 __ Bind(&fall_through); | 1634 __ Bind(&fall_through); |
| 1688 return false; | |
| 1689 } | 1635 } |
| 1690 | 1636 |
| 1691 | 1637 |
| 1692 #undef __ | 1638 #undef __ |
| 1693 | 1639 |
| 1694 } // namespace dart | 1640 } // namespace dart |
| 1695 | 1641 |
| 1696 #endif // defined TARGET_ARCH_X64 | 1642 #endif // defined TARGET_ARCH_X64 |
| OLD | NEW |