| 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 // The intrinsic code below is executed before a method has built its frame. | 5 // The intrinsic code below is executed before a method has built its frame. |
| 6 // The return address is on the stack and the arguments below it. | 6 // The return address is on the stack and the arguments below it. |
| 7 // Registers EDX (arguments descriptor) and ECX (function) must be preserved. | 7 // Registers EDX (arguments descriptor) and ECX (function) must be preserved. |
| 8 // Each intrinsification method returns true if the corresponding | 8 // Each intrinsification method returns true if the corresponding |
| 9 // Dart method was intrinsified. | 9 // Dart method was intrinsified. |
| 10 | 10 |
| (...skipping 10 matching lines...) Expand all Loading... |
| 21 #include "vm/stub_code.h" | 21 #include "vm/stub_code.h" |
| 22 #include "vm/symbols.h" | 22 #include "vm/symbols.h" |
| 23 | 23 |
| 24 namespace dart { | 24 namespace dart { |
| 25 | 25 |
| 26 DECLARE_FLAG(bool, enable_type_checks); | 26 DECLARE_FLAG(bool, enable_type_checks); |
| 27 | 27 |
| 28 | 28 |
| 29 #define __ assembler-> | 29 #define __ assembler-> |
| 30 | 30 |
| 31 void Intrinsifier::ObjectArray_Allocate(Assembler* assembler) { | 31 void Intrinsifier::List_Allocate(Assembler* assembler) { |
| 32 // This snippet of inlined code uses the following registers: | 32 // This snippet of inlined code uses the following registers: |
| 33 // EAX, EBX, EDI | 33 // EAX, EBX, EDI |
| 34 // and the newly allocated object is returned in EAX. | 34 // and the newly allocated object is returned in EAX. |
| 35 const intptr_t kTypeArgumentsOffset = 2 * kWordSize; | 35 const intptr_t kTypeArgumentsOffset = 2 * kWordSize; |
| 36 const intptr_t kArrayLengthOffset = 1 * kWordSize; | 36 const intptr_t kArrayLengthOffset = 1 * kWordSize; |
| 37 Label fall_through; | 37 Label fall_through; |
| 38 | 38 |
| 39 // Compute the size to be allocated, it is based on the array length | 39 // Compute the size to be allocated, it is based on the array length |
| 40 // and is computed as: | 40 // and is computed as: |
| 41 // RoundedAllocationSize((array_length * kwordSize) + sizeof(RawArray)). | 41 // RoundedAllocationSize((array_length * kwordSize) + sizeof(RawArray)). |
| (...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 135 } | 135 } |
| 136 | 136 |
| 137 | 137 |
| 138 void Intrinsifier::Array_getLength(Assembler* assembler) { | 138 void Intrinsifier::Array_getLength(Assembler* assembler) { |
| 139 __ movl(EAX, Address(ESP, + 1 * kWordSize)); | 139 __ movl(EAX, Address(ESP, + 1 * kWordSize)); |
| 140 __ movl(EAX, FieldAddress(EAX, Array::length_offset())); | 140 __ movl(EAX, FieldAddress(EAX, Array::length_offset())); |
| 141 __ ret(); | 141 __ ret(); |
| 142 } | 142 } |
| 143 | 143 |
| 144 | 144 |
| 145 void Intrinsifier::ImmutableArray_getLength(Assembler* assembler) { | 145 void Intrinsifier::ImmutableList_getLength(Assembler* assembler) { |
| 146 return Array_getLength(assembler); | 146 return Array_getLength(assembler); |
| 147 } | 147 } |
| 148 | 148 |
| 149 | 149 |
| 150 void Intrinsifier::Array_getIndexed(Assembler* assembler) { | 150 void Intrinsifier::Array_getIndexed(Assembler* assembler) { |
| 151 Label fall_through; | 151 Label fall_through; |
| 152 __ movl(EBX, Address(ESP, + 1 * kWordSize)); // Index. | 152 __ movl(EBX, Address(ESP, + 1 * kWordSize)); // Index. |
| 153 __ movl(EAX, Address(ESP, + 2 * kWordSize)); // Array. | 153 __ movl(EAX, Address(ESP, + 2 * kWordSize)); // Array. |
| 154 __ testl(EBX, Immediate(kSmiTagMask)); | 154 __ testl(EBX, Immediate(kSmiTagMask)); |
| 155 __ j(NOT_ZERO, &fall_through, Assembler::kNearJump); // Non-smi index. | 155 __ j(NOT_ZERO, &fall_through, Assembler::kNearJump); // Non-smi index. |
| 156 // Range check. | 156 // Range check. |
| 157 __ cmpl(EBX, FieldAddress(EAX, Array::length_offset())); | 157 __ cmpl(EBX, FieldAddress(EAX, Array::length_offset())); |
| 158 // Runtime throws exception. | 158 // Runtime throws exception. |
| 159 __ j(ABOVE_EQUAL, &fall_through, Assembler::kNearJump); | 159 __ j(ABOVE_EQUAL, &fall_through, Assembler::kNearJump); |
| 160 // Note that EBX is Smi, i.e, times 2. | 160 // Note that EBX is Smi, i.e, times 2. |
| 161 ASSERT(kSmiTagShift == 1); | 161 ASSERT(kSmiTagShift == 1); |
| 162 __ movl(EAX, FieldAddress(EAX, EBX, TIMES_2, Array::data_offset())); | 162 __ movl(EAX, FieldAddress(EAX, EBX, TIMES_2, Array::data_offset())); |
| 163 __ ret(); | 163 __ ret(); |
| 164 __ Bind(&fall_through); | 164 __ Bind(&fall_through); |
| 165 } | 165 } |
| 166 | 166 |
| 167 | 167 |
| 168 void Intrinsifier::ImmutableArray_getIndexed(Assembler* assembler) { | 168 void Intrinsifier::ImmutableList_getIndexed(Assembler* assembler) { |
| 169 return Array_getIndexed(assembler); | 169 return Array_getIndexed(assembler); |
| 170 } | 170 } |
| 171 | 171 |
| 172 | 172 |
| 173 static intptr_t ComputeObjectArrayTypeArgumentsOffset() { | 173 static intptr_t ComputeObjectArrayTypeArgumentsOffset() { |
| 174 const Library& core_lib = Library::Handle(Library::CoreLibrary()); | 174 const Library& core_lib = Library::Handle(Library::CoreLibrary()); |
| 175 const Class& cls = Class::Handle( | 175 const Class& cls = Class::Handle( |
| 176 core_lib.LookupClassAllowPrivate(Symbols::ObjectArray())); | 176 core_lib.LookupClassAllowPrivate(Symbols::_List())); |
| 177 ASSERT(!cls.IsNull()); | 177 ASSERT(!cls.IsNull()); |
| 178 ASSERT(cls.HasTypeArguments()); | 178 ASSERT(cls.HasTypeArguments()); |
| 179 ASSERT(cls.NumTypeArguments() == 1); | 179 ASSERT(cls.NumTypeArguments() == 1); |
| 180 const intptr_t field_offset = cls.type_arguments_field_offset(); | 180 const intptr_t field_offset = cls.type_arguments_field_offset(); |
| 181 ASSERT(field_offset != Class::kNoTypeArguments); | 181 ASSERT(field_offset != Class::kNoTypeArguments); |
| 182 return field_offset; | 182 return field_offset; |
| 183 } | 183 } |
| 184 | 184 |
| 185 | 185 |
| 186 // Intrinsify only for Smi value and index. Non-smi values need a store buffer | 186 // Intrinsify only for Smi value and index. Non-smi values need a store buffer |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 238 FieldAddress(EAX, EBX, TIMES_2, Array::data_offset()), | 238 FieldAddress(EAX, EBX, TIMES_2, Array::data_offset()), |
| 239 ECX); | 239 ECX); |
| 240 // Caller is responsible of preserving the value if necessary. | 240 // Caller is responsible of preserving the value if necessary. |
| 241 __ ret(); | 241 __ ret(); |
| 242 __ Bind(&fall_through); | 242 __ Bind(&fall_through); |
| 243 } | 243 } |
| 244 | 244 |
| 245 | 245 |
| 246 // Allocate a GrowableObjectArray using the backing array specified. | 246 // Allocate a GrowableObjectArray using the backing array specified. |
| 247 // On stack: type argument (+2), data (+1), return-address (+0). | 247 // On stack: type argument (+2), data (+1), return-address (+0). |
| 248 void Intrinsifier::GrowableArray_Allocate(Assembler* assembler) { | 248 void Intrinsifier::GrowableList_Allocate(Assembler* assembler) { |
| 249 // This snippet of inlined code uses the following registers: | 249 // This snippet of inlined code uses the following registers: |
| 250 // EAX, EBX | 250 // EAX, EBX |
| 251 // and the newly allocated object is returned in EAX. | 251 // and the newly allocated object is returned in EAX. |
| 252 const intptr_t kTypeArgumentsOffset = 2 * kWordSize; | 252 const intptr_t kTypeArgumentsOffset = 2 * kWordSize; |
| 253 const intptr_t kArrayOffset = 1 * kWordSize; | 253 const intptr_t kArrayOffset = 1 * kWordSize; |
| 254 Label fall_through; | 254 Label fall_through; |
| 255 | 255 |
| 256 // Compute the size to be allocated, it is based on the array length | 256 // Compute the size to be allocated, it is based on the array length |
| 257 // and is computed as: | 257 // and is computed as: |
| 258 // RoundedAllocationSize(sizeof(RawGrowableObjectArray)) + | 258 // RoundedAllocationSize(sizeof(RawGrowableObjectArray)) + |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 305 __ movl(FieldAddress(EAX, GrowableObjectArray::length_offset()), | 305 __ movl(FieldAddress(EAX, GrowableObjectArray::length_offset()), |
| 306 Immediate(0)); | 306 Immediate(0)); |
| 307 __ ret(); // returns the newly allocated object in EAX. | 307 __ ret(); // returns the newly allocated object in EAX. |
| 308 | 308 |
| 309 __ Bind(&fall_through); | 309 __ Bind(&fall_through); |
| 310 } | 310 } |
| 311 | 311 |
| 312 | 312 |
| 313 // Get length of growable object array. | 313 // Get length of growable object array. |
| 314 // On stack: growable array (+1), return-address (+0). | 314 // On stack: growable array (+1), return-address (+0). |
| 315 void Intrinsifier::GrowableArray_getLength(Assembler* assembler) { | 315 void Intrinsifier::GrowableList_getLength(Assembler* assembler) { |
| 316 __ movl(EAX, Address(ESP, + 1 * kWordSize)); | 316 __ movl(EAX, Address(ESP, + 1 * kWordSize)); |
| 317 __ movl(EAX, FieldAddress(EAX, GrowableObjectArray::length_offset())); | 317 __ movl(EAX, FieldAddress(EAX, GrowableObjectArray::length_offset())); |
| 318 __ ret(); | 318 __ ret(); |
| 319 } | 319 } |
| 320 | 320 |
| 321 | 321 |
| 322 // Get capacity of growable object array. | 322 // Get capacity of growable object array. |
| 323 // On stack: growable array (+1), return-address (+0). | 323 // On stack: growable array (+1), return-address (+0). |
| 324 void Intrinsifier::GrowableArray_getCapacity(Assembler* assembler) { | 324 void Intrinsifier::GrowableList_getCapacity(Assembler* assembler) { |
| 325 __ movl(EAX, Address(ESP, + 1 * kWordSize)); | 325 __ movl(EAX, Address(ESP, + 1 * kWordSize)); |
| 326 __ movl(EAX, FieldAddress(EAX, GrowableObjectArray::data_offset())); | 326 __ movl(EAX, FieldAddress(EAX, GrowableObjectArray::data_offset())); |
| 327 __ movl(EAX, FieldAddress(EAX, Array::length_offset())); | 327 __ movl(EAX, FieldAddress(EAX, Array::length_offset())); |
| 328 __ ret(); | 328 __ ret(); |
| 329 } | 329 } |
| 330 | 330 |
| 331 | 331 |
| 332 // Access growable object array at specified index. | 332 // Access growable object array at specified index. |
| 333 // On stack: growable array (+2), index (+1), return-address (+0). | 333 // On stack: growable array (+2), index (+1), return-address (+0). |
| 334 void Intrinsifier::GrowableArray_getIndexed(Assembler* assembler) { | 334 void Intrinsifier::GrowableList_getIndexed(Assembler* assembler) { |
| 335 Label fall_through; | 335 Label fall_through; |
| 336 __ movl(EBX, Address(ESP, + 1 * kWordSize)); // Index. | 336 __ movl(EBX, Address(ESP, + 1 * kWordSize)); // Index. |
| 337 __ movl(EAX, Address(ESP, + 2 * kWordSize)); // GrowableArray. | 337 __ movl(EAX, Address(ESP, + 2 * kWordSize)); // GrowableArray. |
| 338 __ testl(EBX, Immediate(kSmiTagMask)); | 338 __ testl(EBX, Immediate(kSmiTagMask)); |
| 339 __ j(NOT_ZERO, &fall_through, Assembler::kNearJump); // Non-smi index. | 339 __ j(NOT_ZERO, &fall_through, Assembler::kNearJump); // Non-smi index. |
| 340 // Range check using _length field. | 340 // Range check using _length field. |
| 341 __ cmpl(EBX, FieldAddress(EAX, GrowableObjectArray::length_offset())); | 341 __ cmpl(EBX, FieldAddress(EAX, GrowableObjectArray::length_offset())); |
| 342 // Runtime throws exception. | 342 // Runtime throws exception. |
| 343 __ j(ABOVE_EQUAL, &fall_through, Assembler::kNearJump); | 343 __ j(ABOVE_EQUAL, &fall_through, Assembler::kNearJump); |
| 344 __ movl(EAX, FieldAddress(EAX, GrowableObjectArray::data_offset())); // data. | 344 __ movl(EAX, FieldAddress(EAX, GrowableObjectArray::data_offset())); // data. |
| 345 | 345 |
| 346 // Note that EBX is Smi, i.e, times 2. | 346 // Note that EBX is Smi, i.e, times 2. |
| 347 ASSERT(kSmiTagShift == 1); | 347 ASSERT(kSmiTagShift == 1); |
| 348 __ movl(EAX, FieldAddress(EAX, EBX, TIMES_2, Array::data_offset())); | 348 __ movl(EAX, FieldAddress(EAX, EBX, TIMES_2, Array::data_offset())); |
| 349 __ ret(); | 349 __ ret(); |
| 350 __ Bind(&fall_through); | 350 __ Bind(&fall_through); |
| 351 } | 351 } |
| 352 | 352 |
| 353 | 353 |
| 354 // Set value into growable object array at specified index. | 354 // Set value into growable object array at specified index. |
| 355 // On stack: growable array (+3), index (+2), value (+1), return-address (+0). | 355 // On stack: growable array (+3), index (+2), value (+1), return-address (+0). |
| 356 void Intrinsifier::GrowableArray_setIndexed(Assembler* assembler) { | 356 void Intrinsifier::GrowableList_setIndexed(Assembler* assembler) { |
| 357 if (FLAG_enable_type_checks) { | 357 if (FLAG_enable_type_checks) { |
| 358 return; | 358 return; |
| 359 } | 359 } |
| 360 Label fall_through; | 360 Label fall_through; |
| 361 __ movl(EBX, Address(ESP, + 2 * kWordSize)); // Index. | 361 __ movl(EBX, Address(ESP, + 2 * kWordSize)); // Index. |
| 362 __ movl(EAX, Address(ESP, + 3 * kWordSize)); // GrowableArray. | 362 __ movl(EAX, Address(ESP, + 3 * kWordSize)); // GrowableArray. |
| 363 __ testl(EBX, Immediate(kSmiTagMask)); | 363 __ testl(EBX, Immediate(kSmiTagMask)); |
| 364 __ j(NOT_ZERO, &fall_through); // Non-smi index. | 364 __ j(NOT_ZERO, &fall_through); // Non-smi index. |
| 365 // Range check using _length field. | 365 // Range check using _length field. |
| 366 __ cmpl(EBX, FieldAddress(EAX, GrowableObjectArray::length_offset())); | 366 __ cmpl(EBX, FieldAddress(EAX, GrowableObjectArray::length_offset())); |
| 367 // Runtime throws exception. | 367 // Runtime throws exception. |
| 368 __ j(ABOVE_EQUAL, &fall_through); | 368 __ j(ABOVE_EQUAL, &fall_through); |
| 369 __ movl(EAX, FieldAddress(EAX, GrowableObjectArray::data_offset())); // data. | 369 __ movl(EAX, FieldAddress(EAX, GrowableObjectArray::data_offset())); // data. |
| 370 __ movl(EDI, Address(ESP, + 1 * kWordSize)); // Value. | 370 __ movl(EDI, Address(ESP, + 1 * kWordSize)); // Value. |
| 371 // Note that EBX is Smi, i.e, times 2. | 371 // Note that EBX is Smi, i.e, times 2. |
| 372 ASSERT(kSmiTagShift == 1); | 372 ASSERT(kSmiTagShift == 1); |
| 373 __ StoreIntoObject(EAX, | 373 __ StoreIntoObject(EAX, |
| 374 FieldAddress(EAX, EBX, TIMES_2, Array::data_offset()), | 374 FieldAddress(EAX, EBX, TIMES_2, Array::data_offset()), |
| 375 EDI); | 375 EDI); |
| 376 __ ret(); | 376 __ ret(); |
| 377 __ Bind(&fall_through); | 377 __ Bind(&fall_through); |
| 378 } | 378 } |
| 379 | 379 |
| 380 | 380 |
| 381 // Set length of growable object array. The length cannot | 381 // Set length of growable object array. The length cannot |
| 382 // be greater than the length of the data container. | 382 // be greater than the length of the data container. |
| 383 // On stack: growable array (+2), length (+1), return-address (+0). | 383 // On stack: growable array (+2), length (+1), return-address (+0). |
| 384 void Intrinsifier::GrowableArray_setLength(Assembler* assembler) { | 384 void Intrinsifier::GrowableList_setLength(Assembler* assembler) { |
| 385 Label fall_through; | 385 Label fall_through; |
| 386 __ movl(EAX, Address(ESP, + 2 * kWordSize)); // Growable array. | 386 __ movl(EAX, Address(ESP, + 2 * kWordSize)); // Growable array. |
| 387 __ movl(EBX, Address(ESP, + 1 * kWordSize)); // Length value. | 387 __ movl(EBX, Address(ESP, + 1 * kWordSize)); // Length value. |
| 388 __ testl(EBX, Immediate(kSmiTagMask)); | 388 __ testl(EBX, Immediate(kSmiTagMask)); |
| 389 __ j(NOT_ZERO, &fall_through, Assembler::kNearJump); // Non-smi length. | 389 __ j(NOT_ZERO, &fall_through, Assembler::kNearJump); // Non-smi length. |
| 390 __ movl(FieldAddress(EAX, GrowableObjectArray::length_offset()), EBX); | 390 __ movl(FieldAddress(EAX, GrowableObjectArray::length_offset()), EBX); |
| 391 __ ret(); | 391 __ ret(); |
| 392 __ Bind(&fall_through); | 392 __ Bind(&fall_through); |
| 393 } | 393 } |
| 394 | 394 |
| 395 | 395 |
| 396 // Set data of growable object array. | 396 // Set data of growable object array. |
| 397 // On stack: growable array (+2), data (+1), return-address (+0). | 397 // On stack: growable array (+2), data (+1), return-address (+0). |
| 398 void Intrinsifier::GrowableArray_setData(Assembler* assembler) { | 398 void Intrinsifier::GrowableList_setData(Assembler* assembler) { |
| 399 if (FLAG_enable_type_checks) { | 399 if (FLAG_enable_type_checks) { |
| 400 return; | 400 return; |
| 401 } | 401 } |
| 402 Label fall_through; | 402 Label fall_through; |
| 403 __ movl(EBX, Address(ESP, + 1 * kWordSize)); // Data. | 403 __ movl(EBX, Address(ESP, + 1 * kWordSize)); // Data. |
| 404 // Check that data is an ObjectArray. | 404 // Check that data is an ObjectArray. |
| 405 __ testl(EBX, Immediate(kSmiTagMask)); | 405 __ testl(EBX, Immediate(kSmiTagMask)); |
| 406 __ j(ZERO, &fall_through); // Data is Smi. | 406 __ j(ZERO, &fall_through); // Data is Smi. |
| 407 __ CompareClassId(EBX, kArrayCid, EAX); | 407 __ CompareClassId(EBX, kArrayCid, EAX); |
| 408 __ j(NOT_EQUAL, &fall_through); | 408 __ j(NOT_EQUAL, &fall_through); |
| 409 __ movl(EAX, Address(ESP, + 2 * kWordSize)); // Growable array. | 409 __ movl(EAX, Address(ESP, + 2 * kWordSize)); // Growable array. |
| 410 __ StoreIntoObject(EAX, | 410 __ StoreIntoObject(EAX, |
| 411 FieldAddress(EAX, GrowableObjectArray::data_offset()), | 411 FieldAddress(EAX, GrowableObjectArray::data_offset()), |
| 412 EBX); | 412 EBX); |
| 413 __ ret(); | 413 __ ret(); |
| 414 __ Bind(&fall_through); | 414 __ Bind(&fall_through); |
| 415 } | 415 } |
| 416 | 416 |
| 417 | 417 |
| 418 // Add an element to growable array if it doesn't need to grow, otherwise | 418 // Add an element to growable array if it doesn't need to grow, otherwise |
| 419 // call into regular code. | 419 // call into regular code. |
| 420 // On stack: growable array (+2), value (+1), return-address (+0). | 420 // On stack: growable array (+2), value (+1), return-address (+0). |
| 421 void Intrinsifier::GrowableArray_add(Assembler* assembler) { | 421 void Intrinsifier::GrowableList_add(Assembler* assembler) { |
| 422 // In checked mode we need to type-check the incoming argument. | 422 // In checked mode we need to type-check the incoming argument. |
| 423 if (FLAG_enable_type_checks) return; | 423 if (FLAG_enable_type_checks) return; |
| 424 | 424 |
| 425 Label fall_through; | 425 Label fall_through; |
| 426 __ movl(EAX, Address(ESP, + 2 * kWordSize)); // Array. | 426 __ movl(EAX, Address(ESP, + 2 * kWordSize)); // Array. |
| 427 __ movl(EBX, FieldAddress(EAX, GrowableObjectArray::length_offset())); | 427 __ movl(EBX, FieldAddress(EAX, GrowableObjectArray::length_offset())); |
| 428 // EBX: length. | 428 // EBX: length. |
| 429 __ movl(EDI, FieldAddress(EAX, GrowableObjectArray::data_offset())); | 429 __ movl(EDI, FieldAddress(EAX, GrowableObjectArray::data_offset())); |
| 430 // EDI: data. | 430 // EDI: data. |
| 431 // Compare length with capacity. | 431 // Compare length with capacity. |
| (...skipping 1301 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1733 __ Bind(&ok); | 1733 __ Bind(&ok); |
| 1734 __ ret(); | 1734 __ ret(); |
| 1735 | 1735 |
| 1736 __ Bind(&fall_through); | 1736 __ Bind(&fall_through); |
| 1737 } | 1737 } |
| 1738 | 1738 |
| 1739 #undef __ | 1739 #undef __ |
| 1740 } // namespace dart | 1740 } // namespace dart |
| 1741 | 1741 |
| 1742 #endif // defined TARGET_ARCH_IA32 | 1742 #endif // defined TARGET_ARCH_IA32 |
| OLD | NEW |