| 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 bool Intrinsifier::ObjectArray_Allocate(Assembler* assembler) { | 31 void Intrinsifier::ObjectArray_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 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 125 __ Bind(&init_loop); | 125 __ Bind(&init_loop); |
| 126 __ cmpl(EDI, EBX); | 126 __ cmpl(EDI, EBX); |
| 127 __ j(ABOVE_EQUAL, &done, Assembler::kNearJump); | 127 __ j(ABOVE_EQUAL, &done, Assembler::kNearJump); |
| 128 __ movl(Address(EDI, 0), raw_null); | 128 __ movl(Address(EDI, 0), raw_null); |
| 129 __ addl(EDI, Immediate(kWordSize)); | 129 __ addl(EDI, 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 EAX. | 132 __ ret(); // returns the newly allocated object in EAX. |
| 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 __ movl(EAX, Address(ESP, + 1 * kWordSize)); | 139 __ movl(EAX, Address(ESP, + 1 * kWordSize)); |
| 141 __ movl(EAX, FieldAddress(EAX, Array::length_offset())); | 140 __ movl(EAX, FieldAddress(EAX, 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 __ movl(EBX, Address(ESP, + 1 * kWordSize)); // Index. | 152 __ movl(EBX, Address(ESP, + 1 * kWordSize)); // Index. |
| 155 __ movl(EAX, Address(ESP, + 2 * kWordSize)); // Array. | 153 __ movl(EAX, Address(ESP, + 2 * kWordSize)); // Array. |
| 156 __ testl(EBX, Immediate(kSmiTagMask)); | 154 __ testl(EBX, 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 __ cmpl(EBX, FieldAddress(EAX, Array::length_offset())); | 157 __ cmpl(EBX, FieldAddress(EAX, 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 EBX is Smi, i.e, times 2. | 160 // Note that EBX is Smi, i.e, times 2. |
| 163 ASSERT(kSmiTagShift == 1); | 161 ASSERT(kSmiTagShift == 1); |
| 164 __ movl(EAX, FieldAddress(EAX, EBX, TIMES_2, Array::data_offset())); | 162 __ movl(EAX, FieldAddress(EAX, EBX, TIMES_2, 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 static intptr_t ComputeObjectArrayTypeArgumentsOffset() { | 173 static intptr_t ComputeObjectArrayTypeArgumentsOffset() { |
| 177 const Library& core_lib = Library::Handle(Library::CoreLibrary()); | 174 const Library& core_lib = Library::Handle(Library::CoreLibrary()); |
| 178 const Class& cls = Class::Handle( | 175 const Class& cls = Class::Handle( |
| 179 core_lib.LookupClassAllowPrivate(Symbols::ObjectArray(), NULL)); | 176 core_lib.LookupClassAllowPrivate(Symbols::ObjectArray(), NULL)); |
| 180 ASSERT(!cls.IsNull()); | 177 ASSERT(!cls.IsNull()); |
| 181 ASSERT(cls.HasTypeArguments()); | 178 ASSERT(cls.HasTypeArguments()); |
| 182 ASSERT(cls.NumTypeArguments() == 1); | 179 ASSERT(cls.NumTypeArguments() == 1); |
| 183 const intptr_t field_offset = cls.type_arguments_field_offset(); | 180 const intptr_t field_offset = cls.type_arguments_field_offset(); |
| 184 ASSERT(field_offset != Class::kNoTypeArguments); | 181 ASSERT(field_offset != Class::kNoTypeArguments); |
| 185 return field_offset; | 182 return field_offset; |
| 186 } | 183 } |
| 187 | 184 |
| 188 | 185 |
| 189 // 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 |
| 190 // update. Array length is always a Smi. | 187 // update. Array length is always a Smi. |
| 191 bool Intrinsifier::Array_setIndexed(Assembler* assembler) { | 188 void Intrinsifier::Array_setIndexed(Assembler* assembler) { |
| 192 Label fall_through; | 189 Label fall_through; |
| 193 if (FLAG_enable_type_checks) { | 190 if (FLAG_enable_type_checks) { |
| 194 const intptr_t type_args_field_offset = | 191 const intptr_t type_args_field_offset = |
| 195 ComputeObjectArrayTypeArgumentsOffset(); | 192 ComputeObjectArrayTypeArgumentsOffset(); |
| 196 // Inline simple tests (Smi, null), fallthrough if not positive. | 193 // Inline simple tests (Smi, null), fallthrough if not positive. |
| 197 const Immediate& raw_null = | 194 const Immediate& raw_null = |
| 198 Immediate(reinterpret_cast<intptr_t>(Object::null())); | 195 Immediate(reinterpret_cast<intptr_t>(Object::null())); |
| 199 Label checked_ok; | 196 Label checked_ok; |
| 200 __ movl(EDI, Address(ESP, + 1 * kWordSize)); // Value. | 197 __ movl(EDI, Address(ESP, + 1 * kWordSize)); // Value. |
| 201 // Null value is valid for any type. | 198 // Null value is valid for any type. |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 236 // Note that EBX is Smi, i.e, times 2. | 233 // Note that EBX is Smi, i.e, times 2. |
| 237 ASSERT(kSmiTagShift == 1); | 234 ASSERT(kSmiTagShift == 1); |
| 238 // Destroy ECX (ic data) as we will not continue in the function. | 235 // Destroy ECX (ic data) as we will not continue in the function. |
| 239 __ movl(ECX, Address(ESP, + 1 * kWordSize)); // Value. | 236 __ movl(ECX, Address(ESP, + 1 * kWordSize)); // Value. |
| 240 __ StoreIntoObject(EAX, | 237 __ StoreIntoObject(EAX, |
| 241 FieldAddress(EAX, EBX, TIMES_2, Array::data_offset()), | 238 FieldAddress(EAX, EBX, TIMES_2, Array::data_offset()), |
| 242 ECX); | 239 ECX); |
| 243 // Caller is responsible of preserving the value if necessary. | 240 // Caller is responsible of preserving the value if necessary. |
| 244 __ ret(); | 241 __ ret(); |
| 245 __ Bind(&fall_through); | 242 __ Bind(&fall_through); |
| 246 return false; | |
| 247 } | 243 } |
| 248 | 244 |
| 249 | 245 |
| 250 // Allocate a GrowableObjectArray using the backing array specified. | 246 // Allocate a GrowableObjectArray using the backing array specified. |
| 251 // On stack: type argument (+2), data (+1), return-address (+0). | 247 // On stack: type argument (+2), data (+1), return-address (+0). |
| 252 bool Intrinsifier::GrowableArray_Allocate(Assembler* assembler) { | 248 void Intrinsifier::GrowableArray_Allocate(Assembler* assembler) { |
| 253 // This snippet of inlined code uses the following registers: | 249 // This snippet of inlined code uses the following registers: |
| 254 // EAX, EBX | 250 // EAX, EBX |
| 255 // and the newly allocated object is returned in EAX. | 251 // and the newly allocated object is returned in EAX. |
| 256 const intptr_t kTypeArgumentsOffset = 2 * kWordSize; | 252 const intptr_t kTypeArgumentsOffset = 2 * kWordSize; |
| 257 const intptr_t kArrayOffset = 1 * kWordSize; | 253 const intptr_t kArrayOffset = 1 * kWordSize; |
| 258 Label fall_through; | 254 Label fall_through; |
| 259 | 255 |
| 260 // 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 |
| 261 // and is computed as: | 257 // and is computed as: |
| 262 // RoundedAllocationSize(sizeof(RawGrowableObjectArray)) + | 258 // RoundedAllocationSize(sizeof(RawGrowableObjectArray)) + |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 304 EAX, | 300 EAX, |
| 305 FieldAddress(EAX, GrowableObjectArray::type_arguments_offset()), | 301 FieldAddress(EAX, GrowableObjectArray::type_arguments_offset()), |
| 306 EBX); | 302 EBX); |
| 307 | 303 |
| 308 // Set the length field in the growable array object to 0. | 304 // Set the length field in the growable array object to 0. |
| 309 __ movl(FieldAddress(EAX, GrowableObjectArray::length_offset()), | 305 __ movl(FieldAddress(EAX, GrowableObjectArray::length_offset()), |
| 310 Immediate(0)); | 306 Immediate(0)); |
| 311 __ ret(); // returns the newly allocated object in EAX. | 307 __ ret(); // returns the newly allocated object in EAX. |
| 312 | 308 |
| 313 __ Bind(&fall_through); | 309 __ Bind(&fall_through); |
| 314 return false; | |
| 315 } | 310 } |
| 316 | 311 |
| 317 | 312 |
| 318 // Get length of growable object array. | 313 // Get length of growable object array. |
| 319 // On stack: growable array (+1), return-address (+0). | 314 // On stack: growable array (+1), return-address (+0). |
| 320 bool Intrinsifier::GrowableArray_getLength(Assembler* assembler) { | 315 void Intrinsifier::GrowableArray_getLength(Assembler* assembler) { |
| 321 __ movl(EAX, Address(ESP, + 1 * kWordSize)); | 316 __ movl(EAX, Address(ESP, + 1 * kWordSize)); |
| 322 __ movl(EAX, FieldAddress(EAX, GrowableObjectArray::length_offset())); | 317 __ movl(EAX, FieldAddress(EAX, GrowableObjectArray::length_offset())); |
| 323 __ ret(); | 318 __ ret(); |
| 324 return true; | |
| 325 } | 319 } |
| 326 | 320 |
| 327 | 321 |
| 328 // Get capacity of growable object array. | 322 // Get capacity of growable object array. |
| 329 // On stack: growable array (+1), return-address (+0). | 323 // On stack: growable array (+1), return-address (+0). |
| 330 bool Intrinsifier::GrowableArray_getCapacity(Assembler* assembler) { | 324 void Intrinsifier::GrowableArray_getCapacity(Assembler* assembler) { |
| 331 __ movl(EAX, Address(ESP, + 1 * kWordSize)); | 325 __ movl(EAX, Address(ESP, + 1 * kWordSize)); |
| 332 __ movl(EAX, FieldAddress(EAX, GrowableObjectArray::data_offset())); | 326 __ movl(EAX, FieldAddress(EAX, GrowableObjectArray::data_offset())); |
| 333 __ movl(EAX, FieldAddress(EAX, Array::length_offset())); | 327 __ movl(EAX, FieldAddress(EAX, Array::length_offset())); |
| 334 __ ret(); | 328 __ ret(); |
| 335 return true; | |
| 336 } | 329 } |
| 337 | 330 |
| 338 | 331 |
| 339 // Access growable object array at specified index. | 332 // Access growable object array at specified index. |
| 340 // On stack: growable array (+2), index (+1), return-address (+0). | 333 // On stack: growable array (+2), index (+1), return-address (+0). |
| 341 bool Intrinsifier::GrowableArray_getIndexed(Assembler* assembler) { | 334 void Intrinsifier::GrowableArray_getIndexed(Assembler* assembler) { |
| 342 Label fall_through; | 335 Label fall_through; |
| 343 __ movl(EBX, Address(ESP, + 1 * kWordSize)); // Index. | 336 __ movl(EBX, Address(ESP, + 1 * kWordSize)); // Index. |
| 344 __ movl(EAX, Address(ESP, + 2 * kWordSize)); // GrowableArray. | 337 __ movl(EAX, Address(ESP, + 2 * kWordSize)); // GrowableArray. |
| 345 __ testl(EBX, Immediate(kSmiTagMask)); | 338 __ testl(EBX, Immediate(kSmiTagMask)); |
| 346 __ j(NOT_ZERO, &fall_through, Assembler::kNearJump); // Non-smi index. | 339 __ j(NOT_ZERO, &fall_through, Assembler::kNearJump); // Non-smi index. |
| 347 // Range check using _length field. | 340 // Range check using _length field. |
| 348 __ cmpl(EBX, FieldAddress(EAX, GrowableObjectArray::length_offset())); | 341 __ cmpl(EBX, FieldAddress(EAX, GrowableObjectArray::length_offset())); |
| 349 // Runtime throws exception. | 342 // Runtime throws exception. |
| 350 __ j(ABOVE_EQUAL, &fall_through, Assembler::kNearJump); | 343 __ j(ABOVE_EQUAL, &fall_through, Assembler::kNearJump); |
| 351 __ movl(EAX, FieldAddress(EAX, GrowableObjectArray::data_offset())); // data. | 344 __ movl(EAX, FieldAddress(EAX, GrowableObjectArray::data_offset())); // data. |
| 352 | 345 |
| 353 // Note that EBX is Smi, i.e, times 2. | 346 // Note that EBX is Smi, i.e, times 2. |
| 354 ASSERT(kSmiTagShift == 1); | 347 ASSERT(kSmiTagShift == 1); |
| 355 __ movl(EAX, FieldAddress(EAX, EBX, TIMES_2, Array::data_offset())); | 348 __ movl(EAX, FieldAddress(EAX, EBX, TIMES_2, Array::data_offset())); |
| 356 __ ret(); | 349 __ ret(); |
| 357 __ Bind(&fall_through); | 350 __ Bind(&fall_through); |
| 358 return false; | |
| 359 } | 351 } |
| 360 | 352 |
| 361 | 353 |
| 362 // Set value into growable object array at specified index. | 354 // Set value into growable object array at specified index. |
| 363 // 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). |
| 364 bool Intrinsifier::GrowableArray_setIndexed(Assembler* assembler) { | 356 void Intrinsifier::GrowableArray_setIndexed(Assembler* assembler) { |
| 365 if (FLAG_enable_type_checks) { | 357 if (FLAG_enable_type_checks) { |
| 366 return false; | 358 return; |
| 367 } | 359 } |
| 368 Label fall_through; | 360 Label fall_through; |
| 369 __ movl(EBX, Address(ESP, + 2 * kWordSize)); // Index. | 361 __ movl(EBX, Address(ESP, + 2 * kWordSize)); // Index. |
| 370 __ movl(EAX, Address(ESP, + 3 * kWordSize)); // GrowableArray. | 362 __ movl(EAX, Address(ESP, + 3 * kWordSize)); // GrowableArray. |
| 371 __ testl(EBX, Immediate(kSmiTagMask)); | 363 __ testl(EBX, Immediate(kSmiTagMask)); |
| 372 __ j(NOT_ZERO, &fall_through); // Non-smi index. | 364 __ j(NOT_ZERO, &fall_through); // Non-smi index. |
| 373 // Range check using _length field. | 365 // Range check using _length field. |
| 374 __ cmpl(EBX, FieldAddress(EAX, GrowableObjectArray::length_offset())); | 366 __ cmpl(EBX, FieldAddress(EAX, GrowableObjectArray::length_offset())); |
| 375 // Runtime throws exception. | 367 // Runtime throws exception. |
| 376 __ j(ABOVE_EQUAL, &fall_through); | 368 __ j(ABOVE_EQUAL, &fall_through); |
| 377 __ movl(EAX, FieldAddress(EAX, GrowableObjectArray::data_offset())); // data. | 369 __ movl(EAX, FieldAddress(EAX, GrowableObjectArray::data_offset())); // data. |
| 378 __ movl(EDI, Address(ESP, + 1 * kWordSize)); // Value. | 370 __ movl(EDI, Address(ESP, + 1 * kWordSize)); // Value. |
| 379 // Note that EBX is Smi, i.e, times 2. | 371 // Note that EBX is Smi, i.e, times 2. |
| 380 ASSERT(kSmiTagShift == 1); | 372 ASSERT(kSmiTagShift == 1); |
| 381 __ StoreIntoObject(EAX, | 373 __ StoreIntoObject(EAX, |
| 382 FieldAddress(EAX, EBX, TIMES_2, Array::data_offset()), | 374 FieldAddress(EAX, EBX, TIMES_2, Array::data_offset()), |
| 383 EDI); | 375 EDI); |
| 384 __ ret(); | 376 __ ret(); |
| 385 __ Bind(&fall_through); | 377 __ Bind(&fall_through); |
| 386 return false; | |
| 387 } | 378 } |
| 388 | 379 |
| 389 | 380 |
| 390 // Set length of growable object array. The length cannot | 381 // Set length of growable object array. The length cannot |
| 391 // be greater than the length of the data container. | 382 // be greater than the length of the data container. |
| 392 // On stack: growable array (+2), length (+1), return-address (+0). | 383 // On stack: growable array (+2), length (+1), return-address (+0). |
| 393 bool Intrinsifier::GrowableArray_setLength(Assembler* assembler) { | 384 void Intrinsifier::GrowableArray_setLength(Assembler* assembler) { |
| 394 Label fall_through; | 385 Label fall_through; |
| 395 __ movl(EAX, Address(ESP, + 2 * kWordSize)); // Growable array. | 386 __ movl(EAX, Address(ESP, + 2 * kWordSize)); // Growable array. |
| 396 __ movl(EBX, Address(ESP, + 1 * kWordSize)); // Length value. | 387 __ movl(EBX, Address(ESP, + 1 * kWordSize)); // Length value. |
| 397 __ testl(EBX, Immediate(kSmiTagMask)); | 388 __ testl(EBX, Immediate(kSmiTagMask)); |
| 398 __ j(NOT_ZERO, &fall_through, Assembler::kNearJump); // Non-smi length. | 389 __ j(NOT_ZERO, &fall_through, Assembler::kNearJump); // Non-smi length. |
| 399 __ movl(FieldAddress(EAX, GrowableObjectArray::length_offset()), EBX); | 390 __ movl(FieldAddress(EAX, GrowableObjectArray::length_offset()), EBX); |
| 400 __ ret(); | 391 __ ret(); |
| 401 __ Bind(&fall_through); | 392 __ Bind(&fall_through); |
| 402 return false; | |
| 403 } | 393 } |
| 404 | 394 |
| 405 | 395 |
| 406 // Set data of growable object array. | 396 // Set data of growable object array. |
| 407 // On stack: growable array (+2), data (+1), return-address (+0). | 397 // On stack: growable array (+2), data (+1), return-address (+0). |
| 408 bool Intrinsifier::GrowableArray_setData(Assembler* assembler) { | 398 void Intrinsifier::GrowableArray_setData(Assembler* assembler) { |
| 409 if (FLAG_enable_type_checks) { | 399 if (FLAG_enable_type_checks) { |
| 410 return false; | 400 return; |
| 411 } | 401 } |
| 412 Label fall_through; | 402 Label fall_through; |
| 413 __ movl(EBX, Address(ESP, + 1 * kWordSize)); // Data. | 403 __ movl(EBX, Address(ESP, + 1 * kWordSize)); // Data. |
| 414 // Check that data is an ObjectArray. | 404 // Check that data is an ObjectArray. |
| 415 __ testl(EBX, Immediate(kSmiTagMask)); | 405 __ testl(EBX, Immediate(kSmiTagMask)); |
| 416 __ j(ZERO, &fall_through); // Data is Smi. | 406 __ j(ZERO, &fall_through); // Data is Smi. |
| 417 __ CompareClassId(EBX, kArrayCid, EAX); | 407 __ CompareClassId(EBX, kArrayCid, EAX); |
| 418 __ j(NOT_EQUAL, &fall_through); | 408 __ j(NOT_EQUAL, &fall_through); |
| 419 __ movl(EAX, Address(ESP, + 2 * kWordSize)); // Growable array. | 409 __ movl(EAX, Address(ESP, + 2 * kWordSize)); // Growable array. |
| 420 __ StoreIntoObject(EAX, | 410 __ StoreIntoObject(EAX, |
| 421 FieldAddress(EAX, GrowableObjectArray::data_offset()), | 411 FieldAddress(EAX, GrowableObjectArray::data_offset()), |
| 422 EBX); | 412 EBX); |
| 423 __ ret(); | 413 __ ret(); |
| 424 __ Bind(&fall_through); | 414 __ Bind(&fall_through); |
| 425 return false; | |
| 426 } | 415 } |
| 427 | 416 |
| 428 | 417 |
| 429 // 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 |
| 430 // call into regular code. | 419 // call into regular code. |
| 431 // On stack: growable array (+2), value (+1), return-address (+0). | 420 // On stack: growable array (+2), value (+1), return-address (+0). |
| 432 bool Intrinsifier::GrowableArray_add(Assembler* assembler) { | 421 void Intrinsifier::GrowableArray_add(Assembler* assembler) { |
| 433 // In checked mode we need to type-check the incoming argument. | 422 // In checked mode we need to type-check the incoming argument. |
| 434 if (FLAG_enable_type_checks) return false; | 423 if (FLAG_enable_type_checks) return; |
| 424 |
| 435 Label fall_through; | 425 Label fall_through; |
| 436 __ movl(EAX, Address(ESP, + 2 * kWordSize)); // Array. | 426 __ movl(EAX, Address(ESP, + 2 * kWordSize)); // Array. |
| 437 __ movl(EBX, FieldAddress(EAX, GrowableObjectArray::length_offset())); | 427 __ movl(EBX, FieldAddress(EAX, GrowableObjectArray::length_offset())); |
| 438 // EBX: length. | 428 // EBX: length. |
| 439 __ movl(EDI, FieldAddress(EAX, GrowableObjectArray::data_offset())); | 429 __ movl(EDI, FieldAddress(EAX, GrowableObjectArray::data_offset())); |
| 440 // EDI: data. | 430 // EDI: data. |
| 441 // Compare length with capacity. | 431 // Compare length with capacity. |
| 442 __ cmpl(EBX, FieldAddress(EDI, Array::length_offset())); | 432 __ cmpl(EBX, FieldAddress(EDI, Array::length_offset())); |
| 443 __ j(EQUAL, &fall_through); // Must grow data. | 433 __ j(EQUAL, &fall_through); // Must grow data. |
| 444 const Immediate& value_one = | 434 const Immediate& value_one = |
| 445 Immediate(reinterpret_cast<int32_t>(Smi::New(1))); | 435 Immediate(reinterpret_cast<int32_t>(Smi::New(1))); |
| 446 // len = len + 1; | 436 // len = len + 1; |
| 447 __ addl(FieldAddress(EAX, GrowableObjectArray::length_offset()), value_one); | 437 __ addl(FieldAddress(EAX, GrowableObjectArray::length_offset()), value_one); |
| 448 __ movl(EAX, Address(ESP, + 1 * kWordSize)); // Value | 438 __ movl(EAX, Address(ESP, + 1 * kWordSize)); // Value |
| 449 ASSERT(kSmiTagShift == 1); | 439 ASSERT(kSmiTagShift == 1); |
| 450 __ StoreIntoObject(EDI, | 440 __ StoreIntoObject(EDI, |
| 451 FieldAddress(EDI, EBX, TIMES_2, Array::data_offset()), | 441 FieldAddress(EDI, EBX, TIMES_2, Array::data_offset()), |
| 452 EAX); | 442 EAX); |
| 453 const Immediate& raw_null = | 443 const Immediate& raw_null = |
| 454 Immediate(reinterpret_cast<int32_t>(Object::null())); | 444 Immediate(reinterpret_cast<int32_t>(Object::null())); |
| 455 __ movl(EAX, raw_null); | 445 __ movl(EAX, raw_null); |
| 456 __ ret(); | 446 __ ret(); |
| 457 __ Bind(&fall_through); | 447 __ Bind(&fall_through); |
| 458 return false; | |
| 459 } | 448 } |
| 460 | 449 |
| 461 | 450 |
| 462 #define TYPED_ARRAY_ALLOCATION(type_name, cid, max_len, scale_factor) \ | 451 #define TYPED_ARRAY_ALLOCATION(type_name, cid, max_len, scale_factor) \ |
| 463 Label fall_through; \ | 452 Label fall_through; \ |
| 464 const intptr_t kArrayLengthStackOffset = 1 * kWordSize; \ | 453 const intptr_t kArrayLengthStackOffset = 1 * kWordSize; \ |
| 465 __ movl(EDI, Address(ESP, kArrayLengthStackOffset)); /* Array length. */ \ | 454 __ movl(EDI, Address(ESP, kArrayLengthStackOffset)); /* Array length. */ \ |
| 466 /* Check that length is a positive Smi. */ \ | 455 /* Check that length is a positive Smi. */ \ |
| 467 /* EDI: requested array length argument. */ \ | 456 /* EDI: requested array length argument. */ \ |
| 468 __ testl(EDI, Immediate(kSmiTagMask)); \ | 457 __ testl(EDI, Immediate(kSmiTagMask)); \ |
| (...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 547 __ addl(EDI, Immediate(kWordSize)); \ | 536 __ addl(EDI, Immediate(kWordSize)); \ |
| 548 __ jmp(&init_loop, Assembler::kNearJump); \ | 537 __ jmp(&init_loop, Assembler::kNearJump); \ |
| 549 __ Bind(&done); \ | 538 __ Bind(&done); \ |
| 550 \ | 539 \ |
| 551 __ ret(); \ | 540 __ ret(); \ |
| 552 __ Bind(&fall_through); \ | 541 __ Bind(&fall_through); \ |
| 553 | 542 |
| 554 | 543 |
| 555 | 544 |
| 556 // Gets the length of a TypedData. | 545 // Gets the length of a TypedData. |
| 557 bool Intrinsifier::TypedData_getLength(Assembler* assembler) { | 546 void Intrinsifier::TypedData_getLength(Assembler* assembler) { |
| 558 __ movl(EAX, Address(ESP, + 1 * kWordSize)); | 547 __ movl(EAX, Address(ESP, + 1 * kWordSize)); |
| 559 __ movl(EAX, FieldAddress(EAX, TypedData::length_offset())); | 548 __ movl(EAX, FieldAddress(EAX, TypedData::length_offset())); |
| 560 __ ret(); | 549 __ ret(); |
| 561 return true; | |
| 562 } | 550 } |
| 563 | 551 |
| 564 | 552 |
| 565 static ScaleFactor GetScaleFactor(intptr_t size) { | 553 static ScaleFactor GetScaleFactor(intptr_t size) { |
| 566 switch (size) { | 554 switch (size) { |
| 567 case 1: return TIMES_1; | 555 case 1: return TIMES_1; |
| 568 case 2: return TIMES_2; | 556 case 2: return TIMES_2; |
| 569 case 4: return TIMES_4; | 557 case 4: return TIMES_4; |
| 570 case 8: return TIMES_8; | 558 case 8: return TIMES_8; |
| 571 case 16: return TIMES_16; | 559 case 16: return TIMES_16; |
| 572 } | 560 } |
| 573 UNREACHABLE(); | 561 UNREACHABLE(); |
| 574 return static_cast<ScaleFactor>(0); | 562 return static_cast<ScaleFactor>(0); |
| 575 }; | 563 }; |
| 576 | 564 |
| 577 | 565 |
| 578 #define TYPED_DATA_ALLOCATOR(clazz) \ | 566 #define TYPED_DATA_ALLOCATOR(clazz) \ |
| 579 bool Intrinsifier::TypedData_##clazz##_new(Assembler* assembler) { \ | 567 void Intrinsifier::TypedData_##clazz##_new(Assembler* assembler) { \ |
| 580 intptr_t size = TypedData::ElementSizeInBytes(kTypedData##clazz##Cid); \ | 568 intptr_t size = TypedData::ElementSizeInBytes(kTypedData##clazz##Cid); \ |
| 581 intptr_t max_len = TypedData::MaxElements(kTypedData##clazz##Cid); \ | 569 intptr_t max_len = TypedData::MaxElements(kTypedData##clazz##Cid); \ |
| 582 ScaleFactor scale = GetScaleFactor(size); \ | 570 ScaleFactor scale = GetScaleFactor(size); \ |
| 583 TYPED_ARRAY_ALLOCATION(TypedData, kTypedData##clazz##Cid, max_len, scale); \ | 571 TYPED_ARRAY_ALLOCATION(TypedData, kTypedData##clazz##Cid, max_len, scale); \ |
| 584 return false; \ | |
| 585 } \ | 572 } \ |
| 586 bool Intrinsifier::TypedData_##clazz##_factory(Assembler* assembler) { \ | 573 void Intrinsifier::TypedData_##clazz##_factory(Assembler* assembler) { \ |
| 587 intptr_t size = TypedData::ElementSizeInBytes(kTypedData##clazz##Cid); \ | 574 intptr_t size = TypedData::ElementSizeInBytes(kTypedData##clazz##Cid); \ |
| 588 intptr_t max_len = TypedData::MaxElements(kTypedData##clazz##Cid); \ | 575 intptr_t max_len = TypedData::MaxElements(kTypedData##clazz##Cid); \ |
| 589 ScaleFactor scale = GetScaleFactor(size); \ | 576 ScaleFactor scale = GetScaleFactor(size); \ |
| 590 TYPED_ARRAY_ALLOCATION(TypedData, kTypedData##clazz##Cid, max_len, scale); \ | 577 TYPED_ARRAY_ALLOCATION(TypedData, kTypedData##clazz##Cid, max_len, scale); \ |
| 591 return false; \ | |
| 592 } | 578 } |
| 593 CLASS_LIST_TYPED_DATA(TYPED_DATA_ALLOCATOR) | 579 CLASS_LIST_TYPED_DATA(TYPED_DATA_ALLOCATOR) |
| 594 #undef TYPED_DATA_ALLOCATOR | 580 #undef TYPED_DATA_ALLOCATOR |
| 595 | 581 |
| 596 | 582 |
| 597 // Tests if two top most arguments are smis, jumps to label not_smi if not. | 583 // Tests if two top most arguments are smis, jumps to label not_smi if not. |
| 598 // Topmost argument is in EAX. | 584 // Topmost argument is in EAX. |
| 599 static void TestBothArgumentsSmis(Assembler* assembler, Label* not_smi) { | 585 static void TestBothArgumentsSmis(Assembler* assembler, Label* not_smi) { |
| 600 __ movl(EAX, Address(ESP, + 1 * kWordSize)); | 586 __ movl(EAX, Address(ESP, + 1 * kWordSize)); |
| 601 __ movl(EBX, Address(ESP, + 2 * kWordSize)); | 587 __ movl(EBX, Address(ESP, + 2 * kWordSize)); |
| 602 __ orl(EBX, EAX); | 588 __ orl(EBX, EAX); |
| 603 __ testl(EBX, Immediate(kSmiTagMask)); | 589 __ testl(EBX, Immediate(kSmiTagMask)); |
| 604 __ j(NOT_ZERO, not_smi, Assembler::kNearJump); | 590 __ j(NOT_ZERO, not_smi, Assembler::kNearJump); |
| 605 } | 591 } |
| 606 | 592 |
| 607 | 593 |
| 608 bool Intrinsifier::Integer_addFromInteger(Assembler* assembler) { | 594 void Intrinsifier::Integer_addFromInteger(Assembler* assembler) { |
| 609 Label fall_through; | 595 Label fall_through; |
| 610 TestBothArgumentsSmis(assembler, &fall_through); | 596 TestBothArgumentsSmis(assembler, &fall_through); |
| 611 __ addl(EAX, Address(ESP, + 2 * kWordSize)); | 597 __ addl(EAX, Address(ESP, + 2 * kWordSize)); |
| 612 __ j(OVERFLOW, &fall_through, Assembler::kNearJump); | 598 __ j(OVERFLOW, &fall_through, Assembler::kNearJump); |
| 613 // Result is in EAX. | 599 // Result is in EAX. |
| 614 __ ret(); | 600 __ ret(); |
| 615 __ Bind(&fall_through); | 601 __ Bind(&fall_through); |
| 616 return false; | |
| 617 } | 602 } |
| 618 | 603 |
| 619 | 604 |
| 620 bool Intrinsifier::Integer_add(Assembler* assembler) { | 605 void Intrinsifier::Integer_add(Assembler* assembler) { |
| 621 return Integer_addFromInteger(assembler); | 606 return Integer_addFromInteger(assembler); |
| 622 } | 607 } |
| 623 | 608 |
| 624 | 609 |
| 625 bool Intrinsifier::Integer_subFromInteger(Assembler* assembler) { | 610 void Intrinsifier::Integer_subFromInteger(Assembler* assembler) { |
| 626 Label fall_through; | 611 Label fall_through; |
| 627 TestBothArgumentsSmis(assembler, &fall_through); | 612 TestBothArgumentsSmis(assembler, &fall_through); |
| 628 __ subl(EAX, Address(ESP, + 2 * kWordSize)); | 613 __ subl(EAX, Address(ESP, + 2 * kWordSize)); |
| 629 __ j(OVERFLOW, &fall_through, Assembler::kNearJump); | 614 __ j(OVERFLOW, &fall_through, Assembler::kNearJump); |
| 630 // Result is in EAX. | 615 // Result is in EAX. |
| 631 __ ret(); | 616 __ ret(); |
| 632 __ Bind(&fall_through); | 617 __ Bind(&fall_through); |
| 633 return false; | |
| 634 } | 618 } |
| 635 | 619 |
| 636 | 620 |
| 637 bool Intrinsifier::Integer_sub(Assembler* assembler) { | 621 void Intrinsifier::Integer_sub(Assembler* assembler) { |
| 638 Label fall_through; | 622 Label fall_through; |
| 639 TestBothArgumentsSmis(assembler, &fall_through); | 623 TestBothArgumentsSmis(assembler, &fall_through); |
| 640 __ movl(EBX, EAX); | 624 __ movl(EBX, EAX); |
| 641 __ movl(EAX, Address(ESP, + 2 * kWordSize)); | 625 __ movl(EAX, Address(ESP, + 2 * kWordSize)); |
| 642 __ subl(EAX, EBX); | 626 __ subl(EAX, EBX); |
| 643 __ j(OVERFLOW, &fall_through, Assembler::kNearJump); | 627 __ j(OVERFLOW, &fall_through, Assembler::kNearJump); |
| 644 // Result is in EAX. | 628 // Result is in EAX. |
| 645 __ ret(); | 629 __ ret(); |
| 646 __ Bind(&fall_through); | 630 __ Bind(&fall_through); |
| 647 return false; | |
| 648 } | 631 } |
| 649 | 632 |
| 650 | 633 |
| 651 | 634 |
| 652 bool Intrinsifier::Integer_mulFromInteger(Assembler* assembler) { | 635 void Intrinsifier::Integer_mulFromInteger(Assembler* assembler) { |
| 653 Label fall_through; | 636 Label fall_through; |
| 654 TestBothArgumentsSmis(assembler, &fall_through); | 637 TestBothArgumentsSmis(assembler, &fall_through); |
| 655 ASSERT(kSmiTag == 0); // Adjust code below if not the case. | 638 ASSERT(kSmiTag == 0); // Adjust code below if not the case. |
| 656 __ SmiUntag(EAX); | 639 __ SmiUntag(EAX); |
| 657 __ imull(EAX, Address(ESP, + 2 * kWordSize)); | 640 __ imull(EAX, Address(ESP, + 2 * kWordSize)); |
| 658 __ j(OVERFLOW, &fall_through, Assembler::kNearJump); | 641 __ j(OVERFLOW, &fall_through, Assembler::kNearJump); |
| 659 // Result is in EAX. | 642 // Result is in EAX. |
| 660 __ ret(); | 643 __ ret(); |
| 661 __ Bind(&fall_through); | 644 __ Bind(&fall_through); |
| 662 return false; | |
| 663 } | 645 } |
| 664 | 646 |
| 665 | 647 |
| 666 bool Intrinsifier::Integer_mul(Assembler* assembler) { | 648 void Intrinsifier::Integer_mul(Assembler* assembler) { |
| 667 return Integer_mulFromInteger(assembler); | 649 return Integer_mulFromInteger(assembler); |
| 668 } | 650 } |
| 669 | 651 |
| 670 | 652 |
| 671 // Optimizations: | 653 // Optimizations: |
| 672 // - result is 0 if: | 654 // - result is 0 if: |
| 673 // - left is 0 | 655 // - left is 0 |
| 674 // - left equals right | 656 // - left equals right |
| 675 // - result is left if | 657 // - result is left if |
| 676 // - left > 0 && left < right | 658 // - left > 0 && left < right |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 708 | 690 |
| 709 // Implementation: | 691 // Implementation: |
| 710 // res = left % right; | 692 // res = left % right; |
| 711 // if (res < 0) { | 693 // if (res < 0) { |
| 712 // if (right < 0) { | 694 // if (right < 0) { |
| 713 // res = res - right; | 695 // res = res - right; |
| 714 // } else { | 696 // } else { |
| 715 // res = res + right; | 697 // res = res + right; |
| 716 // } | 698 // } |
| 717 // } | 699 // } |
| 718 bool Intrinsifier::Integer_moduloFromInteger(Assembler* assembler) { | 700 void Intrinsifier::Integer_moduloFromInteger(Assembler* assembler) { |
| 719 Label fall_through, subtract; | 701 Label fall_through, subtract; |
| 720 TestBothArgumentsSmis(assembler, &fall_through); | 702 TestBothArgumentsSmis(assembler, &fall_through); |
| 721 __ movl(EBX, Address(ESP, + 2 * kWordSize)); | 703 __ movl(EBX, Address(ESP, + 2 * kWordSize)); |
| 722 // EAX: Tagged left (dividend). | 704 // EAX: Tagged left (dividend). |
| 723 // EBX: Tagged right (divisor). | 705 // EBX: Tagged right (divisor). |
| 724 // Check if modulo by zero -> exception thrown in main function. | 706 // Check if modulo by zero -> exception thrown in main function. |
| 725 __ cmpl(EBX, Immediate(0)); | 707 __ cmpl(EBX, Immediate(0)); |
| 726 __ j(EQUAL, &fall_through, Assembler::kNearJump); | 708 __ j(EQUAL, &fall_through, Assembler::kNearJump); |
| 727 EmitRemainderOperation(assembler); | 709 EmitRemainderOperation(assembler); |
| 728 // Untagged remainder result in EDX. | 710 // Untagged remainder result in EDX. |
| (...skipping 10 matching lines...) Expand all Loading... |
| 739 | 721 |
| 740 __ Bind(&subtract); | 722 __ Bind(&subtract); |
| 741 __ subl(EAX, EBX); | 723 __ subl(EAX, EBX); |
| 742 | 724 |
| 743 __ Bind(&done); | 725 __ Bind(&done); |
| 744 // The remainder of two Smi-s is always a Smi, no overflow check needed. | 726 // The remainder of two Smi-s is always a Smi, no overflow check needed. |
| 745 __ SmiTag(EAX); | 727 __ SmiTag(EAX); |
| 746 __ ret(); | 728 __ ret(); |
| 747 | 729 |
| 748 __ Bind(&fall_through); | 730 __ Bind(&fall_through); |
| 749 return false; | |
| 750 } | 731 } |
| 751 | 732 |
| 752 | 733 |
| 753 bool Intrinsifier::Integer_remainder(Assembler* assembler) { | 734 void Intrinsifier::Integer_remainder(Assembler* assembler) { |
| 754 Label fall_through; | 735 Label fall_through; |
| 755 TestBothArgumentsSmis(assembler, &fall_through); | 736 TestBothArgumentsSmis(assembler, &fall_through); |
| 756 // EAX: right argument (divisor) | 737 // EAX: right argument (divisor) |
| 757 __ movl(EBX, EAX); | 738 __ movl(EBX, EAX); |
| 758 __ movl(EAX, Address(ESP, + 2 * kWordSize)); // Left argument (dividend). | 739 __ movl(EAX, Address(ESP, + 2 * kWordSize)); // Left argument (dividend). |
| 759 // EAX: Tagged left (dividend). | 740 // EAX: Tagged left (dividend). |
| 760 // EBX: Tagged right (divisor). | 741 // EBX: Tagged right (divisor). |
| 761 // Check if modulo by zero -> exception thrown in main function. | 742 // Check if modulo by zero -> exception thrown in main function. |
| 762 __ cmpl(EBX, Immediate(0)); | 743 __ cmpl(EBX, Immediate(0)); |
| 763 __ j(EQUAL, &fall_through, Assembler::kNearJump); | 744 __ j(EQUAL, &fall_through, Assembler::kNearJump); |
| 764 EmitRemainderOperation(assembler); | 745 EmitRemainderOperation(assembler); |
| 765 // Untagged remainder result in EDX. | 746 // Untagged remainder result in EDX. |
| 766 __ movl(EAX, EDX); | 747 __ movl(EAX, EDX); |
| 767 __ SmiTag(EAX); | 748 __ SmiTag(EAX); |
| 768 __ ret(); | 749 __ ret(); |
| 769 | 750 |
| 770 __ Bind(&fall_through); | 751 __ Bind(&fall_through); |
| 771 return false; | |
| 772 } | 752 } |
| 773 | 753 |
| 774 | 754 |
| 775 bool Intrinsifier::Integer_truncDivide(Assembler* assembler) { | 755 void Intrinsifier::Integer_truncDivide(Assembler* assembler) { |
| 776 Label fall_through; | 756 Label fall_through; |
| 777 TestBothArgumentsSmis(assembler, &fall_through); | 757 TestBothArgumentsSmis(assembler, &fall_through); |
| 778 // EAX: right argument (divisor) | 758 // EAX: right argument (divisor) |
| 779 __ cmpl(EAX, Immediate(0)); | 759 __ cmpl(EAX, Immediate(0)); |
| 780 __ j(EQUAL, &fall_through, Assembler::kNearJump); | 760 __ j(EQUAL, &fall_through, Assembler::kNearJump); |
| 781 __ movl(EBX, EAX); | 761 __ movl(EBX, EAX); |
| 782 __ SmiUntag(EBX); | 762 __ SmiUntag(EBX); |
| 783 __ movl(EAX, Address(ESP, + 2 * kWordSize)); // Left argument (dividend). | 763 __ movl(EAX, Address(ESP, + 2 * kWordSize)); // Left argument (dividend). |
| 784 __ SmiUntag(EAX); | 764 __ SmiUntag(EAX); |
| 785 __ pushl(EDX); // Preserve EDX in case of 'fall_through'. | 765 __ pushl(EDX); // Preserve EDX in case of 'fall_through'. |
| 786 __ cdq(); | 766 __ cdq(); |
| 787 __ idivl(EBX); | 767 __ idivl(EBX); |
| 788 __ popl(EDX); | 768 __ popl(EDX); |
| 789 // Check the corner case of dividing the 'MIN_SMI' with -1, in which case we | 769 // Check the corner case of dividing the 'MIN_SMI' with -1, in which case we |
| 790 // cannot tag the result. | 770 // cannot tag the result. |
| 791 __ cmpl(EAX, Immediate(0x40000000)); | 771 __ cmpl(EAX, Immediate(0x40000000)); |
| 792 __ j(EQUAL, &fall_through); | 772 __ j(EQUAL, &fall_through); |
| 793 __ SmiTag(EAX); | 773 __ SmiTag(EAX); |
| 794 __ ret(); | 774 __ ret(); |
| 795 __ Bind(&fall_through); | 775 __ Bind(&fall_through); |
| 796 return false; | |
| 797 } | 776 } |
| 798 | 777 |
| 799 | 778 |
| 800 bool Intrinsifier::Integer_negate(Assembler* assembler) { | 779 void Intrinsifier::Integer_negate(Assembler* assembler) { |
| 801 Label fall_through; | 780 Label fall_through; |
| 802 __ movl(EAX, Address(ESP, + 1 * kWordSize)); | 781 __ movl(EAX, Address(ESP, + 1 * kWordSize)); |
| 803 __ testl(EAX, Immediate(kSmiTagMask)); | 782 __ testl(EAX, Immediate(kSmiTagMask)); |
| 804 __ j(NOT_ZERO, &fall_through, Assembler::kNearJump); // Non-smi value. | 783 __ j(NOT_ZERO, &fall_through, Assembler::kNearJump); // Non-smi value. |
| 805 __ negl(EAX); | 784 __ negl(EAX); |
| 806 __ j(OVERFLOW, &fall_through, Assembler::kNearJump); | 785 __ j(OVERFLOW, &fall_through, Assembler::kNearJump); |
| 807 // Result is in EAX. | 786 // Result is in EAX. |
| 808 __ ret(); | 787 __ ret(); |
| 809 __ Bind(&fall_through); | 788 __ Bind(&fall_through); |
| 810 return false; | |
| 811 } | 789 } |
| 812 | 790 |
| 813 | 791 |
| 814 bool Intrinsifier::Integer_bitAndFromInteger(Assembler* assembler) { | 792 void Intrinsifier::Integer_bitAndFromInteger(Assembler* assembler) { |
| 815 Label fall_through; | 793 Label fall_through; |
| 816 TestBothArgumentsSmis(assembler, &fall_through); | 794 TestBothArgumentsSmis(assembler, &fall_through); |
| 817 __ movl(EBX, Address(ESP, + 2 * kWordSize)); | 795 __ movl(EBX, Address(ESP, + 2 * kWordSize)); |
| 818 __ andl(EAX, EBX); | 796 __ andl(EAX, EBX); |
| 819 // Result is in EAX. | 797 // Result is in EAX. |
| 820 __ ret(); | 798 __ ret(); |
| 821 __ Bind(&fall_through); | 799 __ Bind(&fall_through); |
| 822 return false; | |
| 823 } | 800 } |
| 824 | 801 |
| 825 | 802 |
| 826 bool Intrinsifier::Integer_bitAnd(Assembler* assembler) { | 803 void Intrinsifier::Integer_bitAnd(Assembler* assembler) { |
| 827 return Integer_bitAndFromInteger(assembler); | 804 return Integer_bitAndFromInteger(assembler); |
| 828 } | 805 } |
| 829 | 806 |
| 830 | 807 |
| 831 bool Intrinsifier::Integer_bitOrFromInteger(Assembler* assembler) { | 808 void Intrinsifier::Integer_bitOrFromInteger(Assembler* assembler) { |
| 832 Label fall_through; | 809 Label fall_through; |
| 833 TestBothArgumentsSmis(assembler, &fall_through); | 810 TestBothArgumentsSmis(assembler, &fall_through); |
| 834 __ movl(EBX, Address(ESP, + 2 * kWordSize)); | 811 __ movl(EBX, Address(ESP, + 2 * kWordSize)); |
| 835 __ orl(EAX, EBX); | 812 __ orl(EAX, EBX); |
| 836 // Result is in EAX. | 813 // Result is in EAX. |
| 837 __ ret(); | 814 __ ret(); |
| 838 __ Bind(&fall_through); | 815 __ Bind(&fall_through); |
| 839 return false; | |
| 840 } | 816 } |
| 841 | 817 |
| 842 | 818 |
| 843 bool Intrinsifier::Integer_bitOr(Assembler* assembler) { | 819 void Intrinsifier::Integer_bitOr(Assembler* assembler) { |
| 844 return Integer_bitOrFromInteger(assembler); | 820 return Integer_bitOrFromInteger(assembler); |
| 845 } | 821 } |
| 846 | 822 |
| 847 | 823 |
| 848 bool Intrinsifier::Integer_bitXorFromInteger(Assembler* assembler) { | 824 void Intrinsifier::Integer_bitXorFromInteger(Assembler* assembler) { |
| 849 Label fall_through; | 825 Label fall_through; |
| 850 TestBothArgumentsSmis(assembler, &fall_through); | 826 TestBothArgumentsSmis(assembler, &fall_through); |
| 851 __ movl(EBX, Address(ESP, + 2 * kWordSize)); | 827 __ movl(EBX, Address(ESP, + 2 * kWordSize)); |
| 852 __ xorl(EAX, EBX); | 828 __ xorl(EAX, EBX); |
| 853 // Result is in EAX. | 829 // Result is in EAX. |
| 854 __ ret(); | 830 __ ret(); |
| 855 __ Bind(&fall_through); | 831 __ Bind(&fall_through); |
| 856 return false; | |
| 857 } | 832 } |
| 858 | 833 |
| 859 | 834 |
| 860 bool Intrinsifier::Integer_bitXor(Assembler* assembler) { | 835 void Intrinsifier::Integer_bitXor(Assembler* assembler) { |
| 861 return Integer_bitXorFromInteger(assembler); | 836 return Integer_bitXorFromInteger(assembler); |
| 862 } | 837 } |
| 863 | 838 |
| 864 | 839 |
| 865 bool Intrinsifier::Integer_shl(Assembler* assembler) { | 840 void Intrinsifier::Integer_shl(Assembler* assembler) { |
| 866 ASSERT(kSmiTagShift == 1); | 841 ASSERT(kSmiTagShift == 1); |
| 867 ASSERT(kSmiTag == 0); | 842 ASSERT(kSmiTag == 0); |
| 868 Label fall_through, overflow; | 843 Label fall_through, overflow; |
| 869 TestBothArgumentsSmis(assembler, &fall_through); | 844 TestBothArgumentsSmis(assembler, &fall_through); |
| 870 // Shift value is in EAX. Compare with tagged Smi. | 845 // Shift value is in EAX. Compare with tagged Smi. |
| 871 __ cmpl(EAX, Immediate(Smi::RawValue(Smi::kBits))); | 846 __ cmpl(EAX, Immediate(Smi::RawValue(Smi::kBits))); |
| 872 __ j(ABOVE_EQUAL, &fall_through, Assembler::kNearJump); | 847 __ j(ABOVE_EQUAL, &fall_through, Assembler::kNearJump); |
| 873 | 848 |
| 874 __ SmiUntag(EAX); | 849 __ SmiUntag(EAX); |
| 875 __ movl(ECX, EAX); // Shift amount must be in ECX. | 850 __ movl(ECX, EAX); // Shift amount must be in ECX. |
| (...skipping 26 matching lines...) Expand all Loading... |
| 902 Isolate::Current()->object_store()->mint_class()); | 877 Isolate::Current()->object_store()->mint_class()); |
| 903 __ TryAllocate(mint_class, | 878 __ TryAllocate(mint_class, |
| 904 &fall_through, | 879 &fall_through, |
| 905 Assembler::kNearJump, | 880 Assembler::kNearJump, |
| 906 EAX); // Result register. | 881 EAX); // Result register. |
| 907 // EBX and EDI are not objects but integer values. | 882 // EBX and EDI are not objects but integer values. |
| 908 __ movl(FieldAddress(EAX, Mint::value_offset()), EBX); | 883 __ movl(FieldAddress(EAX, Mint::value_offset()), EBX); |
| 909 __ movl(FieldAddress(EAX, Mint::value_offset() + kWordSize), EDI); | 884 __ movl(FieldAddress(EAX, Mint::value_offset() + kWordSize), EDI); |
| 910 __ ret(); | 885 __ ret(); |
| 911 __ Bind(&fall_through); | 886 __ Bind(&fall_through); |
| 912 return false; | |
| 913 } | 887 } |
| 914 | 888 |
| 915 | 889 |
| 916 static void Push64SmiOrMint(Assembler* assembler, | 890 static void Push64SmiOrMint(Assembler* assembler, |
| 917 Register reg, | 891 Register reg, |
| 918 Register tmp, | 892 Register tmp, |
| 919 Label* not_smi_or_mint) { | 893 Label* not_smi_or_mint) { |
| 920 Label not_smi, done; | 894 Label not_smi, done; |
| 921 __ testl(reg, Immediate(kSmiTagMask)); | 895 __ testl(reg, Immediate(kSmiTagMask)); |
| 922 __ j(NOT_ZERO, ¬_smi, Assembler::kNearJump); | 896 __ j(NOT_ZERO, ¬_smi, Assembler::kNearJump); |
| 923 __ SmiUntag(reg); | 897 __ SmiUntag(reg); |
| 924 // Sign extend to 64 bit | 898 // Sign extend to 64 bit |
| 925 __ movl(tmp, reg); | 899 __ movl(tmp, reg); |
| 926 __ sarl(tmp, Immediate(31)); | 900 __ sarl(tmp, Immediate(31)); |
| 927 __ pushl(tmp); | 901 __ pushl(tmp); |
| 928 __ pushl(reg); | 902 __ pushl(reg); |
| 929 __ jmp(&done); | 903 __ jmp(&done); |
| 930 __ Bind(¬_smi); | 904 __ Bind(¬_smi); |
| 931 __ CompareClassId(reg, kMintCid, tmp); | 905 __ CompareClassId(reg, kMintCid, tmp); |
| 932 __ j(NOT_EQUAL, not_smi_or_mint); | 906 __ j(NOT_EQUAL, not_smi_or_mint); |
| 933 // Mint. | 907 // Mint. |
| 934 __ pushl(FieldAddress(reg, Mint::value_offset() + kWordSize)); | 908 __ pushl(FieldAddress(reg, Mint::value_offset() + kWordSize)); |
| 935 __ pushl(FieldAddress(reg, Mint::value_offset())); | 909 __ pushl(FieldAddress(reg, Mint::value_offset())); |
| 936 __ Bind(&done); | 910 __ Bind(&done); |
| 937 } | 911 } |
| 938 | 912 |
| 939 | 913 |
| 940 static bool CompareIntegers(Assembler* assembler, Condition true_condition) { | 914 static void CompareIntegers(Assembler* assembler, Condition true_condition) { |
| 941 Label try_mint_smi, is_true, is_false, drop_two_fall_through, fall_through; | 915 Label try_mint_smi, is_true, is_false, drop_two_fall_through, fall_through; |
| 942 TestBothArgumentsSmis(assembler, &try_mint_smi); | 916 TestBothArgumentsSmis(assembler, &try_mint_smi); |
| 943 // EAX contains the right argument. | 917 // EAX contains the right argument. |
| 944 __ cmpl(Address(ESP, + 2 * kWordSize), EAX); | 918 __ cmpl(Address(ESP, + 2 * kWordSize), EAX); |
| 945 __ j(true_condition, &is_true, Assembler::kNearJump); | 919 __ j(true_condition, &is_true, Assembler::kNearJump); |
| 946 __ Bind(&is_false); | 920 __ Bind(&is_false); |
| 947 __ LoadObject(EAX, Bool::False()); | 921 __ LoadObject(EAX, Bool::False()); |
| 948 __ ret(); | 922 __ ret(); |
| 949 __ Bind(&is_true); | 923 __ Bind(&is_true); |
| 950 __ LoadObject(EAX, Bool::True()); | 924 __ LoadObject(EAX, Bool::True()); |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 986 __ j(hi_false_cond, &is_false, Assembler::kNearJump); | 960 __ j(hi_false_cond, &is_false, Assembler::kNearJump); |
| 987 __ j(hi_true_cond, &is_true, Assembler::kNearJump); | 961 __ j(hi_true_cond, &is_true, Assembler::kNearJump); |
| 988 __ cmpl(EAX, EBX); // cmpl left.LO, right.LO. | 962 __ cmpl(EAX, EBX); // cmpl left.LO, right.LO. |
| 989 __ j(lo_false_cond, &is_false, Assembler::kNearJump); | 963 __ j(lo_false_cond, &is_false, Assembler::kNearJump); |
| 990 // Else is true. | 964 // Else is true. |
| 991 __ jmp(&is_true); | 965 __ jmp(&is_true); |
| 992 | 966 |
| 993 __ Bind(&drop_two_fall_through); | 967 __ Bind(&drop_two_fall_through); |
| 994 __ Drop(2); | 968 __ Drop(2); |
| 995 __ Bind(&fall_through); | 969 __ Bind(&fall_through); |
| 996 return false; | |
| 997 } | 970 } |
| 998 | 971 |
| 999 | 972 |
| 1000 | 973 |
| 1001 bool Intrinsifier::Integer_greaterThanFromInt(Assembler* assembler) { | 974 void Intrinsifier::Integer_greaterThanFromInt(Assembler* assembler) { |
| 1002 return CompareIntegers(assembler, LESS); | 975 return CompareIntegers(assembler, LESS); |
| 1003 } | 976 } |
| 1004 | 977 |
| 1005 | 978 |
| 1006 bool Intrinsifier::Integer_lessThan(Assembler* assembler) { | 979 void Intrinsifier::Integer_lessThan(Assembler* assembler) { |
| 1007 return Integer_greaterThanFromInt(assembler); | 980 return Integer_greaterThanFromInt(assembler); |
| 1008 } | 981 } |
| 1009 | 982 |
| 1010 | 983 |
| 1011 bool Intrinsifier::Integer_greaterThan(Assembler* assembler) { | 984 void Intrinsifier::Integer_greaterThan(Assembler* assembler) { |
| 1012 return CompareIntegers(assembler, GREATER); | 985 return CompareIntegers(assembler, GREATER); |
| 1013 } | 986 } |
| 1014 | 987 |
| 1015 | 988 |
| 1016 bool Intrinsifier::Integer_lessEqualThan(Assembler* assembler) { | 989 void Intrinsifier::Integer_lessEqualThan(Assembler* assembler) { |
| 1017 return CompareIntegers(assembler, LESS_EQUAL); | 990 return CompareIntegers(assembler, LESS_EQUAL); |
| 1018 } | 991 } |
| 1019 | 992 |
| 1020 | 993 |
| 1021 bool Intrinsifier::Integer_greaterEqualThan(Assembler* assembler) { | 994 void Intrinsifier::Integer_greaterEqualThan(Assembler* assembler) { |
| 1022 return CompareIntegers(assembler, GREATER_EQUAL); | 995 return CompareIntegers(assembler, GREATER_EQUAL); |
| 1023 } | 996 } |
| 1024 | 997 |
| 1025 | 998 |
| 1026 // This is called for Smi, Mint and Bigint receivers. The right argument | 999 // This is called for Smi, Mint and Bigint receivers. The right argument |
| 1027 // can be Smi, Mint, Bigint or double. | 1000 // can be Smi, Mint, Bigint or double. |
| 1028 bool Intrinsifier::Integer_equalToInteger(Assembler* assembler) { | 1001 void Intrinsifier::Integer_equalToInteger(Assembler* assembler) { |
| 1029 Label fall_through, true_label, check_for_mint; | 1002 Label fall_through, true_label, check_for_mint; |
| 1030 // For integer receiver '===' check first. | 1003 // For integer receiver '===' check first. |
| 1031 __ movl(EAX, Address(ESP, + 1 * kWordSize)); | 1004 __ movl(EAX, Address(ESP, + 1 * kWordSize)); |
| 1032 __ cmpl(EAX, Address(ESP, + 2 * kWordSize)); | 1005 __ cmpl(EAX, Address(ESP, + 2 * kWordSize)); |
| 1033 __ j(EQUAL, &true_label, Assembler::kNearJump); | 1006 __ j(EQUAL, &true_label, Assembler::kNearJump); |
| 1034 __ movl(EBX, Address(ESP, + 2 * kWordSize)); | 1007 __ movl(EBX, Address(ESP, + 2 * kWordSize)); |
| 1035 __ orl(EAX, EBX); | 1008 __ orl(EAX, EBX); |
| 1036 __ testl(EAX, Immediate(kSmiTagMask)); | 1009 __ testl(EAX, Immediate(kSmiTagMask)); |
| 1037 __ j(NOT_ZERO, &check_for_mint, Assembler::kNearJump); | 1010 __ j(NOT_ZERO, &check_for_mint, Assembler::kNearJump); |
| 1038 // Both arguments are smi, '===' is good enough. | 1011 // Both arguments are smi, '===' is good enough. |
| (...skipping 25 matching lines...) Expand all Loading... |
| 1064 __ j(NOT_EQUAL, &fall_through); | 1037 __ j(NOT_EQUAL, &fall_through); |
| 1065 // Receiver is Mint, return false if right is Smi. | 1038 // Receiver is Mint, return false if right is Smi. |
| 1066 __ movl(EAX, Address(ESP, + 1 * kWordSize)); // Right argument. | 1039 __ movl(EAX, Address(ESP, + 1 * kWordSize)); // Right argument. |
| 1067 __ testl(EAX, Immediate(kSmiTagMask)); | 1040 __ testl(EAX, Immediate(kSmiTagMask)); |
| 1068 __ j(NOT_ZERO, &fall_through); | 1041 __ j(NOT_ZERO, &fall_through); |
| 1069 __ LoadObject(EAX, Bool::False()); | 1042 __ LoadObject(EAX, Bool::False()); |
| 1070 __ ret(); | 1043 __ ret(); |
| 1071 // TODO(srdjan): Implement Mint == Mint comparison. | 1044 // TODO(srdjan): Implement Mint == Mint comparison. |
| 1072 | 1045 |
| 1073 __ Bind(&fall_through); | 1046 __ Bind(&fall_through); |
| 1074 return false; | |
| 1075 } | 1047 } |
| 1076 | 1048 |
| 1077 | 1049 |
| 1078 bool Intrinsifier::Integer_equal(Assembler* assembler) { | 1050 void Intrinsifier::Integer_equal(Assembler* assembler) { |
| 1079 return Integer_equalToInteger(assembler); | 1051 return Integer_equalToInteger(assembler); |
| 1080 } | 1052 } |
| 1081 | 1053 |
| 1082 | 1054 |
| 1083 bool Intrinsifier::Integer_sar(Assembler* assembler) { | 1055 void Intrinsifier::Integer_sar(Assembler* assembler) { |
| 1084 Label fall_through, shift_count_ok; | 1056 Label fall_through, shift_count_ok; |
| 1085 TestBothArgumentsSmis(assembler, &fall_through); | 1057 TestBothArgumentsSmis(assembler, &fall_through); |
| 1086 // Can destroy ECX since we are not falling through. | 1058 // Can destroy ECX since we are not falling through. |
| 1087 const Immediate& count_limit = Immediate(0x1F); | 1059 const Immediate& count_limit = Immediate(0x1F); |
| 1088 // Check that the count is not larger than what the hardware can handle. | 1060 // Check that the count is not larger than what the hardware can handle. |
| 1089 // For shifting right a Smi the result is the same for all numbers | 1061 // For shifting right a Smi the result is the same for all numbers |
| 1090 // >= count_limit. | 1062 // >= count_limit. |
| 1091 __ SmiUntag(EAX); | 1063 __ SmiUntag(EAX); |
| 1092 // Negative counts throw exception. | 1064 // Negative counts throw exception. |
| 1093 __ cmpl(EAX, Immediate(0)); | 1065 __ cmpl(EAX, Immediate(0)); |
| 1094 __ j(LESS, &fall_through, Assembler::kNearJump); | 1066 __ j(LESS, &fall_through, Assembler::kNearJump); |
| 1095 __ cmpl(EAX, count_limit); | 1067 __ cmpl(EAX, count_limit); |
| 1096 __ j(LESS_EQUAL, &shift_count_ok, Assembler::kNearJump); | 1068 __ j(LESS_EQUAL, &shift_count_ok, Assembler::kNearJump); |
| 1097 __ movl(EAX, count_limit); | 1069 __ movl(EAX, count_limit); |
| 1098 __ Bind(&shift_count_ok); | 1070 __ Bind(&shift_count_ok); |
| 1099 __ movl(ECX, EAX); // Shift amount must be in ECX. | 1071 __ movl(ECX, EAX); // Shift amount must be in ECX. |
| 1100 __ movl(EAX, Address(ESP, + 2 * kWordSize)); // Value. | 1072 __ movl(EAX, Address(ESP, + 2 * kWordSize)); // Value. |
| 1101 __ SmiUntag(EAX); // Value. | 1073 __ SmiUntag(EAX); // Value. |
| 1102 __ sarl(EAX, ECX); | 1074 __ sarl(EAX, ECX); |
| 1103 __ SmiTag(EAX); | 1075 __ SmiTag(EAX); |
| 1104 __ ret(); | 1076 __ ret(); |
| 1105 __ Bind(&fall_through); | 1077 __ Bind(&fall_through); |
| 1106 return false; | |
| 1107 } | 1078 } |
| 1108 | 1079 |
| 1109 | 1080 |
| 1110 // Argument is Smi (receiver). | 1081 // Argument is Smi (receiver). |
| 1111 bool Intrinsifier::Smi_bitNegate(Assembler* assembler) { | 1082 void Intrinsifier::Smi_bitNegate(Assembler* assembler) { |
| 1112 __ movl(EAX, Address(ESP, + 1 * kWordSize)); // Index. | 1083 __ movl(EAX, Address(ESP, + 1 * kWordSize)); // Index. |
| 1113 __ notl(EAX); | 1084 __ notl(EAX); |
| 1114 __ andl(EAX, Immediate(~kSmiTagMask)); // Remove inverted smi-tag. | 1085 __ andl(EAX, Immediate(~kSmiTagMask)); // Remove inverted smi-tag. |
| 1115 __ ret(); | 1086 __ ret(); |
| 1116 return true; | |
| 1117 } | 1087 } |
| 1118 | 1088 |
| 1119 | 1089 |
| 1120 // Check if the last argument is a double, jump to label 'is_smi' if smi | 1090 // Check if the last argument is a double, jump to label 'is_smi' if smi |
| 1121 // (easy to convert to double), otherwise jump to label 'not_double_smi', | 1091 // (easy to convert to double), otherwise jump to label 'not_double_smi', |
| 1122 // Returns the last argument in EAX. | 1092 // Returns the last argument in EAX. |
| 1123 static void TestLastArgumentIsDouble(Assembler* assembler, | 1093 static void TestLastArgumentIsDouble(Assembler* assembler, |
| 1124 Label* is_smi, | 1094 Label* is_smi, |
| 1125 Label* not_double_smi) { | 1095 Label* not_double_smi) { |
| 1126 __ movl(EAX, Address(ESP, + 1 * kWordSize)); | 1096 __ movl(EAX, Address(ESP, + 1 * kWordSize)); |
| 1127 __ testl(EAX, Immediate(kSmiTagMask)); | 1097 __ testl(EAX, Immediate(kSmiTagMask)); |
| 1128 __ j(ZERO, is_smi, Assembler::kNearJump); // Jump if Smi. | 1098 __ j(ZERO, is_smi, Assembler::kNearJump); // Jump if Smi. |
| 1129 __ CompareClassId(EAX, kDoubleCid, EBX); | 1099 __ CompareClassId(EAX, kDoubleCid, EBX); |
| 1130 __ j(NOT_EQUAL, not_double_smi, Assembler::kNearJump); | 1100 __ j(NOT_EQUAL, not_double_smi, Assembler::kNearJump); |
| 1131 // Fall through if double. | 1101 // Fall through if double. |
| 1132 } | 1102 } |
| 1133 | 1103 |
| 1134 | 1104 |
| 1135 // Both arguments on stack, arg0 (left) is a double, arg1 (right) is of unknown | 1105 // Both arguments on stack, arg0 (left) is a double, arg1 (right) is of unknown |
| 1136 // type. Return true or false object in the register EAX. Any NaN argument | 1106 // type. Return true or false object in the register EAX. Any NaN argument |
| 1137 // returns false. Any non-double arg1 causes control flow to fall through to the | 1107 // returns false. Any non-double arg1 causes control flow to fall through to the |
| 1138 // slow case (compiled method body). | 1108 // slow case (compiled method body). |
| 1139 static bool CompareDoubles(Assembler* assembler, Condition true_condition) { | 1109 static void CompareDoubles(Assembler* assembler, Condition true_condition) { |
| 1140 Label fall_through, is_false, is_true, is_smi, double_op; | 1110 Label fall_through, is_false, is_true, is_smi, double_op; |
| 1141 TestLastArgumentIsDouble(assembler, &is_smi, &fall_through); | 1111 TestLastArgumentIsDouble(assembler, &is_smi, &fall_through); |
| 1142 // Both arguments are double, right operand is in EAX. | 1112 // Both arguments are double, right operand is in EAX. |
| 1143 __ movsd(XMM1, FieldAddress(EAX, Double::value_offset())); | 1113 __ movsd(XMM1, FieldAddress(EAX, Double::value_offset())); |
| 1144 __ Bind(&double_op); | 1114 __ Bind(&double_op); |
| 1145 __ movl(EAX, Address(ESP, + 2 * kWordSize)); // Left argument. | 1115 __ movl(EAX, Address(ESP, + 2 * kWordSize)); // Left argument. |
| 1146 __ movsd(XMM0, FieldAddress(EAX, Double::value_offset())); | 1116 __ movsd(XMM0, FieldAddress(EAX, Double::value_offset())); |
| 1147 __ comisd(XMM0, XMM1); | 1117 __ comisd(XMM0, XMM1); |
| 1148 __ j(PARITY_EVEN, &is_false, Assembler::kNearJump); // NaN -> false; | 1118 __ j(PARITY_EVEN, &is_false, Assembler::kNearJump); // NaN -> false; |
| 1149 __ j(true_condition, &is_true, Assembler::kNearJump); | 1119 __ j(true_condition, &is_true, Assembler::kNearJump); |
| 1150 // Fall through false. | 1120 // Fall through false. |
| 1151 __ Bind(&is_false); | 1121 __ Bind(&is_false); |
| 1152 __ LoadObject(EAX, Bool::False()); | 1122 __ LoadObject(EAX, Bool::False()); |
| 1153 __ ret(); | 1123 __ ret(); |
| 1154 __ Bind(&is_true); | 1124 __ Bind(&is_true); |
| 1155 __ LoadObject(EAX, Bool::True()); | 1125 __ LoadObject(EAX, Bool::True()); |
| 1156 __ ret(); | 1126 __ ret(); |
| 1157 __ Bind(&is_smi); | 1127 __ Bind(&is_smi); |
| 1158 __ SmiUntag(EAX); | 1128 __ SmiUntag(EAX); |
| 1159 __ cvtsi2sd(XMM1, EAX); | 1129 __ cvtsi2sd(XMM1, EAX); |
| 1160 __ jmp(&double_op); | 1130 __ jmp(&double_op); |
| 1161 __ Bind(&fall_through); | 1131 __ Bind(&fall_through); |
| 1162 return false; | |
| 1163 } | 1132 } |
| 1164 | 1133 |
| 1165 | 1134 |
| 1166 // arg0 is Double, arg1 is unknown. | 1135 // arg0 is Double, arg1 is unknown. |
| 1167 bool Intrinsifier::Double_greaterThan(Assembler* assembler) { | 1136 void Intrinsifier::Double_greaterThan(Assembler* assembler) { |
| 1168 return CompareDoubles(assembler, ABOVE); | 1137 return CompareDoubles(assembler, ABOVE); |
| 1169 } | 1138 } |
| 1170 | 1139 |
| 1171 | 1140 |
| 1172 // arg0 is Double, arg1 is unknown. | 1141 // arg0 is Double, arg1 is unknown. |
| 1173 bool Intrinsifier::Double_greaterEqualThan(Assembler* assembler) { | 1142 void Intrinsifier::Double_greaterEqualThan(Assembler* assembler) { |
| 1174 return CompareDoubles(assembler, ABOVE_EQUAL); | 1143 return CompareDoubles(assembler, ABOVE_EQUAL); |
| 1175 } | 1144 } |
| 1176 | 1145 |
| 1177 | 1146 |
| 1178 // arg0 is Double, arg1 is unknown. | 1147 // arg0 is Double, arg1 is unknown. |
| 1179 bool Intrinsifier::Double_lessThan(Assembler* assembler) { | 1148 void Intrinsifier::Double_lessThan(Assembler* assembler) { |
| 1180 return CompareDoubles(assembler, BELOW); | 1149 return CompareDoubles(assembler, BELOW); |
| 1181 } | 1150 } |
| 1182 | 1151 |
| 1183 | 1152 |
| 1184 // arg0 is Double, arg1 is unknown. | 1153 // arg0 is Double, arg1 is unknown. |
| 1185 bool Intrinsifier::Double_equal(Assembler* assembler) { | 1154 void Intrinsifier::Double_equal(Assembler* assembler) { |
| 1186 return CompareDoubles(assembler, EQUAL); | 1155 return CompareDoubles(assembler, EQUAL); |
| 1187 } | 1156 } |
| 1188 | 1157 |
| 1189 | 1158 |
| 1190 // arg0 is Double, arg1 is unknown. | 1159 // arg0 is Double, arg1 is unknown. |
| 1191 bool Intrinsifier::Double_lessEqualThan(Assembler* assembler) { | 1160 void Intrinsifier::Double_lessEqualThan(Assembler* assembler) { |
| 1192 return CompareDoubles(assembler, BELOW_EQUAL); | 1161 return CompareDoubles(assembler, BELOW_EQUAL); |
| 1193 } | 1162 } |
| 1194 | 1163 |
| 1195 | 1164 |
| 1196 // Expects left argument to be double (receiver). Right argument is unknown. | 1165 // Expects left argument to be double (receiver). Right argument is unknown. |
| 1197 // Both arguments are on stack. | 1166 // Both arguments are on stack. |
| 1198 static bool DoubleArithmeticOperations(Assembler* assembler, Token::Kind kind) { | 1167 static void DoubleArithmeticOperations(Assembler* assembler, Token::Kind kind) { |
| 1199 Label fall_through; | 1168 Label fall_through; |
| 1200 TestLastArgumentIsDouble(assembler, &fall_through, &fall_through); | 1169 TestLastArgumentIsDouble(assembler, &fall_through, &fall_through); |
| 1201 // Both arguments are double, right operand is in EAX. | 1170 // Both arguments are double, right operand is in EAX. |
| 1202 __ movsd(XMM1, FieldAddress(EAX, Double::value_offset())); | 1171 __ movsd(XMM1, FieldAddress(EAX, Double::value_offset())); |
| 1203 __ movl(EAX, Address(ESP, + 2 * kWordSize)); // Left argument. | 1172 __ movl(EAX, Address(ESP, + 2 * kWordSize)); // Left argument. |
| 1204 __ movsd(XMM0, FieldAddress(EAX, Double::value_offset())); | 1173 __ movsd(XMM0, FieldAddress(EAX, Double::value_offset())); |
| 1205 switch (kind) { | 1174 switch (kind) { |
| 1206 case Token::kADD: __ addsd(XMM0, XMM1); break; | 1175 case Token::kADD: __ addsd(XMM0, XMM1); break; |
| 1207 case Token::kSUB: __ subsd(XMM0, XMM1); break; | 1176 case Token::kSUB: __ subsd(XMM0, XMM1); break; |
| 1208 case Token::kMUL: __ mulsd(XMM0, XMM1); break; | 1177 case Token::kMUL: __ mulsd(XMM0, XMM1); break; |
| 1209 case Token::kDIV: __ divsd(XMM0, XMM1); break; | 1178 case Token::kDIV: __ divsd(XMM0, XMM1); break; |
| 1210 default: UNREACHABLE(); | 1179 default: UNREACHABLE(); |
| 1211 } | 1180 } |
| 1212 const Class& double_class = Class::Handle( | 1181 const Class& double_class = Class::Handle( |
| 1213 Isolate::Current()->object_store()->double_class()); | 1182 Isolate::Current()->object_store()->double_class()); |
| 1214 __ TryAllocate(double_class, | 1183 __ TryAllocate(double_class, |
| 1215 &fall_through, | 1184 &fall_through, |
| 1216 Assembler::kNearJump, | 1185 Assembler::kNearJump, |
| 1217 EAX); // Result register. | 1186 EAX); // Result register. |
| 1218 __ movsd(FieldAddress(EAX, Double::value_offset()), XMM0); | 1187 __ movsd(FieldAddress(EAX, Double::value_offset()), XMM0); |
| 1219 __ ret(); | 1188 __ ret(); |
| 1220 __ Bind(&fall_through); | 1189 __ Bind(&fall_through); |
| 1221 return false; | |
| 1222 } | 1190 } |
| 1223 | 1191 |
| 1224 | 1192 |
| 1225 bool Intrinsifier::Double_add(Assembler* assembler) { | 1193 void Intrinsifier::Double_add(Assembler* assembler) { |
| 1226 return DoubleArithmeticOperations(assembler, Token::kADD); | 1194 return DoubleArithmeticOperations(assembler, Token::kADD); |
| 1227 } | 1195 } |
| 1228 | 1196 |
| 1229 | 1197 |
| 1230 bool Intrinsifier::Double_mul(Assembler* assembler) { | 1198 void Intrinsifier::Double_mul(Assembler* assembler) { |
| 1231 return DoubleArithmeticOperations(assembler, Token::kMUL); | 1199 return DoubleArithmeticOperations(assembler, Token::kMUL); |
| 1232 } | 1200 } |
| 1233 | 1201 |
| 1234 | 1202 |
| 1235 bool Intrinsifier::Double_sub(Assembler* assembler) { | 1203 void Intrinsifier::Double_sub(Assembler* assembler) { |
| 1236 return DoubleArithmeticOperations(assembler, Token::kSUB); | 1204 return DoubleArithmeticOperations(assembler, Token::kSUB); |
| 1237 } | 1205 } |
| 1238 | 1206 |
| 1239 | 1207 |
| 1240 bool Intrinsifier::Double_div(Assembler* assembler) { | 1208 void Intrinsifier::Double_div(Assembler* assembler) { |
| 1241 return DoubleArithmeticOperations(assembler, Token::kDIV); | 1209 return DoubleArithmeticOperations(assembler, Token::kDIV); |
| 1242 } | 1210 } |
| 1243 | 1211 |
| 1244 | 1212 |
| 1245 // Left is double right is integer (Bigint, Mint or Smi) | 1213 // Left is double right is integer (Bigint, Mint or Smi) |
| 1246 bool Intrinsifier::Double_mulFromInteger(Assembler* assembler) { | 1214 void Intrinsifier::Double_mulFromInteger(Assembler* assembler) { |
| 1247 Label fall_through; | 1215 Label fall_through; |
| 1248 // Only Smi-s allowed. | 1216 // Only Smi-s allowed. |
| 1249 __ movl(EAX, Address(ESP, + 1 * kWordSize)); | 1217 __ movl(EAX, Address(ESP, + 1 * kWordSize)); |
| 1250 __ testl(EAX, Immediate(kSmiTagMask)); | 1218 __ testl(EAX, Immediate(kSmiTagMask)); |
| 1251 __ j(NOT_ZERO, &fall_through, Assembler::kNearJump); | 1219 __ j(NOT_ZERO, &fall_through, Assembler::kNearJump); |
| 1252 // Is Smi. | 1220 // Is Smi. |
| 1253 __ SmiUntag(EAX); | 1221 __ SmiUntag(EAX); |
| 1254 __ cvtsi2sd(XMM1, EAX); | 1222 __ cvtsi2sd(XMM1, EAX); |
| 1255 __ movl(EAX, Address(ESP, + 2 * kWordSize)); | 1223 __ movl(EAX, Address(ESP, + 2 * kWordSize)); |
| 1256 __ movsd(XMM0, FieldAddress(EAX, Double::value_offset())); | 1224 __ movsd(XMM0, FieldAddress(EAX, Double::value_offset())); |
| 1257 __ mulsd(XMM0, XMM1); | 1225 __ mulsd(XMM0, XMM1); |
| 1258 const Class& double_class = Class::Handle( | 1226 const Class& double_class = Class::Handle( |
| 1259 Isolate::Current()->object_store()->double_class()); | 1227 Isolate::Current()->object_store()->double_class()); |
| 1260 __ TryAllocate(double_class, | 1228 __ TryAllocate(double_class, |
| 1261 &fall_through, | 1229 &fall_through, |
| 1262 Assembler::kNearJump, | 1230 Assembler::kNearJump, |
| 1263 EAX); // Result register. | 1231 EAX); // Result register. |
| 1264 __ movsd(FieldAddress(EAX, Double::value_offset()), XMM0); | 1232 __ movsd(FieldAddress(EAX, Double::value_offset()), XMM0); |
| 1265 __ ret(); | 1233 __ ret(); |
| 1266 __ Bind(&fall_through); | 1234 __ Bind(&fall_through); |
| 1267 return false; | |
| 1268 } | 1235 } |
| 1269 | 1236 |
| 1270 | 1237 |
| 1271 bool Intrinsifier::Double_fromInteger(Assembler* assembler) { | 1238 void Intrinsifier::Double_fromInteger(Assembler* assembler) { |
| 1272 Label fall_through; | 1239 Label fall_through; |
| 1273 __ movl(EAX, Address(ESP, +1 * kWordSize)); | 1240 __ movl(EAX, Address(ESP, +1 * kWordSize)); |
| 1274 __ testl(EAX, Immediate(kSmiTagMask)); | 1241 __ testl(EAX, Immediate(kSmiTagMask)); |
| 1275 __ j(NOT_ZERO, &fall_through, Assembler::kNearJump); | 1242 __ j(NOT_ZERO, &fall_through, Assembler::kNearJump); |
| 1276 // Is Smi. | 1243 // Is Smi. |
| 1277 __ SmiUntag(EAX); | 1244 __ SmiUntag(EAX); |
| 1278 __ cvtsi2sd(XMM0, EAX); | 1245 __ cvtsi2sd(XMM0, EAX); |
| 1279 const Class& double_class = Class::Handle( | 1246 const Class& double_class = Class::Handle( |
| 1280 Isolate::Current()->object_store()->double_class()); | 1247 Isolate::Current()->object_store()->double_class()); |
| 1281 __ TryAllocate(double_class, | 1248 __ TryAllocate(double_class, |
| 1282 &fall_through, | 1249 &fall_through, |
| 1283 Assembler::kNearJump, | 1250 Assembler::kNearJump, |
| 1284 EAX); // Result register. | 1251 EAX); // Result register. |
| 1285 __ movsd(FieldAddress(EAX, Double::value_offset()), XMM0); | 1252 __ movsd(FieldAddress(EAX, Double::value_offset()), XMM0); |
| 1286 __ ret(); | 1253 __ ret(); |
| 1287 __ Bind(&fall_through); | 1254 __ Bind(&fall_through); |
| 1288 return false; | |
| 1289 } | 1255 } |
| 1290 | 1256 |
| 1291 | 1257 |
| 1292 bool Intrinsifier::Double_getIsNaN(Assembler* assembler) { | 1258 void Intrinsifier::Double_getIsNaN(Assembler* assembler) { |
| 1293 Label is_true; | 1259 Label is_true; |
| 1294 __ movl(EAX, Address(ESP, +1 * kWordSize)); | 1260 __ movl(EAX, Address(ESP, +1 * kWordSize)); |
| 1295 __ movsd(XMM0, FieldAddress(EAX, Double::value_offset())); | 1261 __ movsd(XMM0, FieldAddress(EAX, Double::value_offset())); |
| 1296 __ comisd(XMM0, XMM0); | 1262 __ comisd(XMM0, XMM0); |
| 1297 __ j(PARITY_EVEN, &is_true, Assembler::kNearJump); // NaN -> true; | 1263 __ j(PARITY_EVEN, &is_true, Assembler::kNearJump); // NaN -> true; |
| 1298 __ LoadObject(EAX, Bool::False()); | 1264 __ LoadObject(EAX, Bool::False()); |
| 1299 __ ret(); | 1265 __ ret(); |
| 1300 __ Bind(&is_true); | 1266 __ Bind(&is_true); |
| 1301 __ LoadObject(EAX, Bool::True()); | 1267 __ LoadObject(EAX, Bool::True()); |
| 1302 __ ret(); | 1268 __ ret(); |
| 1303 return true; // Method is complete, no slow case. | |
| 1304 } | 1269 } |
| 1305 | 1270 |
| 1306 | 1271 |
| 1307 bool Intrinsifier::Double_getIsNegative(Assembler* assembler) { | 1272 void Intrinsifier::Double_getIsNegative(Assembler* assembler) { |
| 1308 Label is_false, is_true, is_zero; | 1273 Label is_false, is_true, is_zero; |
| 1309 __ movl(EAX, Address(ESP, +1 * kWordSize)); | 1274 __ movl(EAX, Address(ESP, +1 * kWordSize)); |
| 1310 __ movsd(XMM0, FieldAddress(EAX, Double::value_offset())); | 1275 __ movsd(XMM0, FieldAddress(EAX, Double::value_offset())); |
| 1311 __ xorpd(XMM1, XMM1); // 0.0 -> XMM1. | 1276 __ xorpd(XMM1, XMM1); // 0.0 -> XMM1. |
| 1312 __ comisd(XMM0, XMM1); | 1277 __ comisd(XMM0, XMM1); |
| 1313 __ j(PARITY_EVEN, &is_false, Assembler::kNearJump); // NaN -> false. | 1278 __ j(PARITY_EVEN, &is_false, Assembler::kNearJump); // NaN -> false. |
| 1314 __ j(EQUAL, &is_zero, Assembler::kNearJump); // Check for negative zero. | 1279 __ j(EQUAL, &is_zero, Assembler::kNearJump); // Check for negative zero. |
| 1315 __ j(ABOVE_EQUAL, &is_false, Assembler::kNearJump); // >= 0 -> false. | 1280 __ j(ABOVE_EQUAL, &is_false, Assembler::kNearJump); // >= 0 -> false. |
| 1316 __ Bind(&is_true); | 1281 __ Bind(&is_true); |
| 1317 __ LoadObject(EAX, Bool::True()); | 1282 __ LoadObject(EAX, Bool::True()); |
| 1318 __ ret(); | 1283 __ ret(); |
| 1319 __ Bind(&is_false); | 1284 __ Bind(&is_false); |
| 1320 __ LoadObject(EAX, Bool::False()); | 1285 __ LoadObject(EAX, Bool::False()); |
| 1321 __ ret(); | 1286 __ ret(); |
| 1322 __ Bind(&is_zero); | 1287 __ Bind(&is_zero); |
| 1323 // Check for negative zero (get the sign bit). | 1288 // Check for negative zero (get the sign bit). |
| 1324 __ movmskpd(EAX, XMM0); | 1289 __ movmskpd(EAX, XMM0); |
| 1325 __ testl(EAX, Immediate(1)); | 1290 __ testl(EAX, Immediate(1)); |
| 1326 __ j(NOT_ZERO, &is_true, Assembler::kNearJump); | 1291 __ j(NOT_ZERO, &is_true, Assembler::kNearJump); |
| 1327 __ jmp(&is_false, Assembler::kNearJump); | 1292 __ jmp(&is_false, Assembler::kNearJump); |
| 1328 return true; // Method is complete, no slow case. | |
| 1329 } | 1293 } |
| 1330 | 1294 |
| 1331 | 1295 |
| 1332 bool Intrinsifier::Double_toInt(Assembler* assembler) { | 1296 void Intrinsifier::Double_toInt(Assembler* assembler) { |
| 1333 __ movl(EAX, Address(ESP, +1 * kWordSize)); | 1297 __ movl(EAX, Address(ESP, +1 * kWordSize)); |
| 1334 __ movsd(XMM0, FieldAddress(EAX, Double::value_offset())); | 1298 __ movsd(XMM0, FieldAddress(EAX, Double::value_offset())); |
| 1335 __ cvttsd2si(EAX, XMM0); | 1299 __ cvttsd2si(EAX, XMM0); |
| 1336 // Overflow is signalled with minint. | 1300 // Overflow is signalled with minint. |
| 1337 Label fall_through; | 1301 Label fall_through; |
| 1338 // Check for overflow and that it fits into Smi. | 1302 // Check for overflow and that it fits into Smi. |
| 1339 __ cmpl(EAX, Immediate(0xC0000000)); | 1303 __ cmpl(EAX, Immediate(0xC0000000)); |
| 1340 __ j(NEGATIVE, &fall_through, Assembler::kNearJump); | 1304 __ j(NEGATIVE, &fall_through, Assembler::kNearJump); |
| 1341 __ SmiTag(EAX); | 1305 __ SmiTag(EAX); |
| 1342 __ ret(); | 1306 __ ret(); |
| 1343 __ Bind(&fall_through); | 1307 __ Bind(&fall_through); |
| 1344 return false; | |
| 1345 } | 1308 } |
| 1346 | 1309 |
| 1347 | 1310 |
| 1348 // Argument type is not known | 1311 // Argument type is not known |
| 1349 bool Intrinsifier::Math_sqrt(Assembler* assembler) { | 1312 void Intrinsifier::Math_sqrt(Assembler* assembler) { |
| 1350 Label fall_through, is_smi, double_op; | 1313 Label fall_through, is_smi, double_op; |
| 1351 TestLastArgumentIsDouble(assembler, &is_smi, &fall_through); | 1314 TestLastArgumentIsDouble(assembler, &is_smi, &fall_through); |
| 1352 // Argument is double and is in EAX. | 1315 // Argument is double and is in EAX. |
| 1353 __ movsd(XMM1, FieldAddress(EAX, Double::value_offset())); | 1316 __ movsd(XMM1, FieldAddress(EAX, Double::value_offset())); |
| 1354 __ Bind(&double_op); | 1317 __ Bind(&double_op); |
| 1355 __ sqrtsd(XMM0, XMM1); | 1318 __ sqrtsd(XMM0, XMM1); |
| 1356 const Class& double_class = Class::Handle( | 1319 const Class& double_class = Class::Handle( |
| 1357 Isolate::Current()->object_store()->double_class()); | 1320 Isolate::Current()->object_store()->double_class()); |
| 1358 __ TryAllocate(double_class, | 1321 __ TryAllocate(double_class, |
| 1359 &fall_through, | 1322 &fall_through, |
| 1360 Assembler::kNearJump, | 1323 Assembler::kNearJump, |
| 1361 EAX); // Result register. | 1324 EAX); // Result register. |
| 1362 __ movsd(FieldAddress(EAX, Double::value_offset()), XMM0); | 1325 __ movsd(FieldAddress(EAX, Double::value_offset()), XMM0); |
| 1363 __ ret(); | 1326 __ ret(); |
| 1364 __ Bind(&is_smi); | 1327 __ Bind(&is_smi); |
| 1365 __ SmiUntag(EAX); | 1328 __ SmiUntag(EAX); |
| 1366 __ cvtsi2sd(XMM1, EAX); | 1329 __ cvtsi2sd(XMM1, EAX); |
| 1367 __ jmp(&double_op); | 1330 __ jmp(&double_op); |
| 1368 __ Bind(&fall_through); | 1331 __ Bind(&fall_through); |
| 1369 return false; | |
| 1370 } | 1332 } |
| 1371 | 1333 |
| 1372 | 1334 |
| 1373 enum TrigonometricFunctions { | 1335 enum TrigonometricFunctions { |
| 1374 kSine, | 1336 kSine, |
| 1375 kCosine, | 1337 kCosine, |
| 1376 }; | 1338 }; |
| 1377 | 1339 |
| 1378 | 1340 |
| 1379 static void EmitTrigonometric(Assembler* assembler, | 1341 static void EmitTrigonometric(Assembler* assembler, |
| (...skipping 27 matching lines...) Expand all Loading... |
| 1407 __ jmp(&double_op); | 1369 __ jmp(&double_op); |
| 1408 | 1370 |
| 1409 __ Bind(&alloc_failed); | 1371 __ Bind(&alloc_failed); |
| 1410 __ ffree(0); | 1372 __ ffree(0); |
| 1411 __ fincstp(); | 1373 __ fincstp(); |
| 1412 | 1374 |
| 1413 __ Bind(&fall_through); | 1375 __ Bind(&fall_through); |
| 1414 } | 1376 } |
| 1415 | 1377 |
| 1416 | 1378 |
| 1417 bool Intrinsifier::Math_sin(Assembler* assembler) { | 1379 void Intrinsifier::Math_sin(Assembler* assembler) { |
| 1418 EmitTrigonometric(assembler, kSine); | 1380 EmitTrigonometric(assembler, kSine); |
| 1419 return false; // Compile method for slow case. | |
| 1420 } | 1381 } |
| 1421 | 1382 |
| 1422 | 1383 |
| 1423 bool Intrinsifier::Math_cos(Assembler* assembler) { | 1384 void Intrinsifier::Math_cos(Assembler* assembler) { |
| 1424 EmitTrigonometric(assembler, kCosine); | 1385 EmitTrigonometric(assembler, kCosine); |
| 1425 return false; // Compile method for slow case. | |
| 1426 } | 1386 } |
| 1427 | 1387 |
| 1428 | 1388 |
| 1429 // var state = ((_A * (_state[kSTATE_LO])) + _state[kSTATE_HI]) & _MASK_64; | 1389 // var state = ((_A * (_state[kSTATE_LO])) + _state[kSTATE_HI]) & _MASK_64; |
| 1430 // _state[kSTATE_LO] = state & _MASK_32; | 1390 // _state[kSTATE_LO] = state & _MASK_32; |
| 1431 // _state[kSTATE_HI] = state >> 32; | 1391 // _state[kSTATE_HI] = state >> 32; |
| 1432 bool Intrinsifier::Random_nextState(Assembler* assembler) { | 1392 void Intrinsifier::Random_nextState(Assembler* assembler) { |
| 1433 const Library& math_lib = Library::Handle(Library::MathLibrary()); | 1393 const Library& math_lib = Library::Handle(Library::MathLibrary()); |
| 1434 ASSERT(!math_lib.IsNull()); | 1394 ASSERT(!math_lib.IsNull()); |
| 1435 const Class& random_class = Class::Handle( | 1395 const Class& random_class = Class::Handle( |
| 1436 math_lib.LookupClassAllowPrivate(Symbols::_Random(), NULL)); | 1396 math_lib.LookupClassAllowPrivate(Symbols::_Random(), NULL)); |
| 1437 ASSERT(!random_class.IsNull()); | 1397 ASSERT(!random_class.IsNull()); |
| 1438 const Field& state_field = Field::ZoneHandle( | 1398 const Field& state_field = Field::ZoneHandle( |
| 1439 random_class.LookupInstanceField(Symbols::_state())); | 1399 random_class.LookupInstanceField(Symbols::_state())); |
| 1440 ASSERT(!state_field.IsNull()); | 1400 ASSERT(!state_field.IsNull()); |
| 1441 const Field& random_A_field = Field::ZoneHandle( | 1401 const Field& random_A_field = Field::ZoneHandle( |
| 1442 random_class.LookupStaticField(Symbols::_A())); | 1402 random_class.LookupStaticField(Symbols::_A())); |
| (...skipping 18 matching lines...) Expand all Loading... |
| 1461 EBX, | 1421 EBX, |
| 1462 1); | 1422 1); |
| 1463 __ movl(EAX, Immediate(a_int32_value)); | 1423 __ movl(EAX, Immediate(a_int32_value)); |
| 1464 // 64-bit multiply EAX * value -> EDX:EAX. | 1424 // 64-bit multiply EAX * value -> EDX:EAX. |
| 1465 __ mull(addr_0); | 1425 __ mull(addr_0); |
| 1466 __ addl(EAX, addr_1); | 1426 __ addl(EAX, addr_1); |
| 1467 __ adcl(EDX, Immediate(0)); | 1427 __ adcl(EDX, Immediate(0)); |
| 1468 __ movl(addr_1, EDX); | 1428 __ movl(addr_1, EDX); |
| 1469 __ movl(addr_0, EAX); | 1429 __ movl(addr_0, EAX); |
| 1470 __ ret(); | 1430 __ ret(); |
| 1471 return true; | |
| 1472 } | 1431 } |
| 1473 | 1432 |
| 1474 | 1433 |
| 1475 // Identity comparison. | 1434 // Identity comparison. |
| 1476 bool Intrinsifier::Object_equal(Assembler* assembler) { | 1435 void Intrinsifier::Object_equal(Assembler* assembler) { |
| 1477 Label is_true; | 1436 Label is_true; |
| 1478 __ movl(EAX, Address(ESP, + 1 * kWordSize)); | 1437 __ movl(EAX, Address(ESP, + 1 * kWordSize)); |
| 1479 __ cmpl(EAX, Address(ESP, + 2 * kWordSize)); | 1438 __ cmpl(EAX, Address(ESP, + 2 * kWordSize)); |
| 1480 __ j(EQUAL, &is_true, Assembler::kNearJump); | 1439 __ j(EQUAL, &is_true, Assembler::kNearJump); |
| 1481 __ LoadObject(EAX, Bool::False()); | 1440 __ LoadObject(EAX, Bool::False()); |
| 1482 __ ret(); | 1441 __ ret(); |
| 1483 __ Bind(&is_true); | 1442 __ Bind(&is_true); |
| 1484 __ LoadObject(EAX, Bool::True()); | 1443 __ LoadObject(EAX, Bool::True()); |
| 1485 __ ret(); | 1444 __ ret(); |
| 1486 return true; | |
| 1487 } | 1445 } |
| 1488 | 1446 |
| 1489 | 1447 |
| 1490 bool Intrinsifier::String_getHashCode(Assembler* assembler) { | 1448 void Intrinsifier::String_getHashCode(Assembler* assembler) { |
| 1491 Label fall_through; | 1449 Label fall_through; |
| 1492 __ movl(EAX, Address(ESP, + 1 * kWordSize)); // String object. | 1450 __ movl(EAX, Address(ESP, + 1 * kWordSize)); // String object. |
| 1493 __ movl(EAX, FieldAddress(EAX, String::hash_offset())); | 1451 __ movl(EAX, FieldAddress(EAX, String::hash_offset())); |
| 1494 __ cmpl(EAX, Immediate(0)); | 1452 __ cmpl(EAX, Immediate(0)); |
| 1495 __ j(EQUAL, &fall_through, Assembler::kNearJump); | 1453 __ j(EQUAL, &fall_through, Assembler::kNearJump); |
| 1496 __ ret(); | 1454 __ ret(); |
| 1497 __ Bind(&fall_through); | 1455 __ Bind(&fall_through); |
| 1498 // Hash not yet computed. | 1456 // Hash not yet computed. |
| 1499 return false; | |
| 1500 } | 1457 } |
| 1501 | 1458 |
| 1502 | 1459 |
| 1503 bool Intrinsifier::String_getLength(Assembler* assembler) { | 1460 void Intrinsifier::String_getLength(Assembler* assembler) { |
| 1504 __ movl(EAX, Address(ESP, + 1 * kWordSize)); // String object. | 1461 __ movl(EAX, Address(ESP, + 1 * kWordSize)); // String object. |
| 1505 __ movl(EAX, FieldAddress(EAX, String::length_offset())); | 1462 __ movl(EAX, FieldAddress(EAX, String::length_offset())); |
| 1506 __ ret(); | 1463 __ ret(); |
| 1507 return true; | |
| 1508 } | 1464 } |
| 1509 | 1465 |
| 1510 | 1466 |
| 1511 bool Intrinsifier::String_codeUnitAt(Assembler* assembler) { | 1467 void Intrinsifier::String_codeUnitAt(Assembler* assembler) { |
| 1512 Label fall_through, try_two_byte_string; | 1468 Label fall_through, try_two_byte_string; |
| 1513 __ movl(EBX, Address(ESP, + 1 * kWordSize)); // Index. | 1469 __ movl(EBX, Address(ESP, + 1 * kWordSize)); // Index. |
| 1514 __ movl(EAX, Address(ESP, + 2 * kWordSize)); // String. | 1470 __ movl(EAX, Address(ESP, + 2 * kWordSize)); // String. |
| 1515 __ testl(EBX, Immediate(kSmiTagMask)); | 1471 __ testl(EBX, Immediate(kSmiTagMask)); |
| 1516 __ j(NOT_ZERO, &fall_through, Assembler::kNearJump); // Non-smi index. | 1472 __ j(NOT_ZERO, &fall_through, Assembler::kNearJump); // Non-smi index. |
| 1517 // Range check. | 1473 // Range check. |
| 1518 __ cmpl(EBX, FieldAddress(EAX, String::length_offset())); | 1474 __ cmpl(EBX, FieldAddress(EAX, String::length_offset())); |
| 1519 // Runtime throws exception. | 1475 // Runtime throws exception. |
| 1520 __ j(ABOVE_EQUAL, &fall_through, Assembler::kNearJump); | 1476 __ j(ABOVE_EQUAL, &fall_through, Assembler::kNearJump); |
| 1521 __ CompareClassId(EAX, kOneByteStringCid, EDI); | 1477 __ CompareClassId(EAX, kOneByteStringCid, EDI); |
| 1522 __ j(NOT_EQUAL, &try_two_byte_string, Assembler::kNearJump); | 1478 __ j(NOT_EQUAL, &try_two_byte_string, Assembler::kNearJump); |
| 1523 __ SmiUntag(EBX); | 1479 __ SmiUntag(EBX); |
| 1524 __ movzxb(EAX, FieldAddress(EAX, EBX, TIMES_1, OneByteString::data_offset())); | 1480 __ movzxb(EAX, FieldAddress(EAX, EBX, TIMES_1, OneByteString::data_offset())); |
| 1525 __ SmiTag(EAX); | 1481 __ SmiTag(EAX); |
| 1526 __ ret(); | 1482 __ ret(); |
| 1527 | 1483 |
| 1528 __ Bind(&try_two_byte_string); | 1484 __ Bind(&try_two_byte_string); |
| 1529 __ CompareClassId(EAX, kTwoByteStringCid, EDI); | 1485 __ CompareClassId(EAX, kTwoByteStringCid, EDI); |
| 1530 __ j(NOT_EQUAL, &fall_through, Assembler::kNearJump); | 1486 __ j(NOT_EQUAL, &fall_through, Assembler::kNearJump); |
| 1531 ASSERT(kSmiTagShift == 1); | 1487 ASSERT(kSmiTagShift == 1); |
| 1532 __ movzxw(EAX, FieldAddress(EAX, EBX, TIMES_1, OneByteString::data_offset())); | 1488 __ movzxw(EAX, FieldAddress(EAX, EBX, TIMES_1, OneByteString::data_offset())); |
| 1533 __ SmiTag(EAX); | 1489 __ SmiTag(EAX); |
| 1534 __ ret(); | 1490 __ ret(); |
| 1535 | 1491 |
| 1536 __ Bind(&fall_through); | 1492 __ Bind(&fall_through); |
| 1537 return false; | |
| 1538 } | 1493 } |
| 1539 | 1494 |
| 1540 | 1495 |
| 1541 bool Intrinsifier::String_getIsEmpty(Assembler* assembler) { | 1496 void Intrinsifier::String_getIsEmpty(Assembler* assembler) { |
| 1542 Label is_true; | 1497 Label is_true; |
| 1543 // Get length. | 1498 // Get length. |
| 1544 __ movl(EAX, Address(ESP, + 1 * kWordSize)); // String object. | 1499 __ movl(EAX, Address(ESP, + 1 * kWordSize)); // String object. |
| 1545 __ movl(EAX, FieldAddress(EAX, String::length_offset())); | 1500 __ movl(EAX, FieldAddress(EAX, String::length_offset())); |
| 1546 __ cmpl(EAX, Immediate(Smi::RawValue(0))); | 1501 __ cmpl(EAX, Immediate(Smi::RawValue(0))); |
| 1547 __ j(EQUAL, &is_true, Assembler::kNearJump); | 1502 __ j(EQUAL, &is_true, Assembler::kNearJump); |
| 1548 __ LoadObject(EAX, Bool::False()); | 1503 __ LoadObject(EAX, Bool::False()); |
| 1549 __ ret(); | 1504 __ ret(); |
| 1550 __ Bind(&is_true); | 1505 __ Bind(&is_true); |
| 1551 __ LoadObject(EAX, Bool::True()); | 1506 __ LoadObject(EAX, Bool::True()); |
| 1552 __ ret(); | 1507 __ ret(); |
| 1553 return false; | |
| 1554 } | 1508 } |
| 1555 | 1509 |
| 1556 | 1510 |
| 1557 bool Intrinsifier::OneByteString_getHashCode(Assembler* assembler) { | 1511 void Intrinsifier::OneByteString_getHashCode(Assembler* assembler) { |
| 1558 Label compute_hash; | 1512 Label compute_hash; |
| 1559 __ movl(EBX, Address(ESP, + 1 * kWordSize)); // OneByteString object. | 1513 __ movl(EBX, Address(ESP, + 1 * kWordSize)); // OneByteString object. |
| 1560 __ movl(EAX, FieldAddress(EBX, String::hash_offset())); | 1514 __ movl(EAX, FieldAddress(EBX, String::hash_offset())); |
| 1561 __ cmpl(EAX, Immediate(0)); | 1515 __ cmpl(EAX, Immediate(0)); |
| 1562 __ j(EQUAL, &compute_hash, Assembler::kNearJump); | 1516 __ j(EQUAL, &compute_hash, Assembler::kNearJump); |
| 1563 __ ret(); | 1517 __ ret(); |
| 1564 | 1518 |
| 1565 __ Bind(&compute_hash); | 1519 __ Bind(&compute_hash); |
| 1566 // Hash not yet computed, use algorithm of class StringHasher. | 1520 // Hash not yet computed, use algorithm of class StringHasher. |
| 1567 __ movl(ECX, FieldAddress(EBX, String::length_offset())); | 1521 __ movl(ECX, FieldAddress(EBX, String::length_offset())); |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1613 Immediate(((static_cast<intptr_t>(1) << String::kHashBits) - 1))); | 1567 Immediate(((static_cast<intptr_t>(1) << String::kHashBits) - 1))); |
| 1614 | 1568 |
| 1615 // return hash_ == 0 ? 1 : hash_; | 1569 // return hash_ == 0 ? 1 : hash_; |
| 1616 __ cmpl(EAX, Immediate(0)); | 1570 __ cmpl(EAX, Immediate(0)); |
| 1617 __ j(NOT_EQUAL, &set_hash_code, Assembler::kNearJump); | 1571 __ j(NOT_EQUAL, &set_hash_code, Assembler::kNearJump); |
| 1618 __ incl(EAX); | 1572 __ incl(EAX); |
| 1619 __ Bind(&set_hash_code); | 1573 __ Bind(&set_hash_code); |
| 1620 __ SmiTag(EAX); | 1574 __ SmiTag(EAX); |
| 1621 __ movl(FieldAddress(EBX, String::hash_offset()), EAX); | 1575 __ movl(FieldAddress(EBX, String::hash_offset()), EAX); |
| 1622 __ ret(); | 1576 __ ret(); |
| 1623 return true; | |
| 1624 } | 1577 } |
| 1625 | 1578 |
| 1626 | 1579 |
| 1627 // Allocates one-byte string of length 'end - start'. The content is not | 1580 // Allocates one-byte string of length 'end - start'. The content is not |
| 1628 // initialized. 'length-reg' contains tagged length. | 1581 // initialized. 'length-reg' contains tagged length. |
| 1629 // Returns new string as tagged pointer in EAX. | 1582 // Returns new string as tagged pointer in EAX. |
| 1630 static void TryAllocateOnebyteString(Assembler* assembler, | 1583 static void TryAllocateOnebyteString(Assembler* assembler, |
| 1631 Label* ok, | 1584 Label* ok, |
| 1632 Label* failure, | 1585 Label* failure, |
| 1633 Register length_reg) { | 1586 Register length_reg) { |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1697 __ Bind(&pop_and_fail); | 1650 __ Bind(&pop_and_fail); |
| 1698 __ popl(EDI); | 1651 __ popl(EDI); |
| 1699 __ jmp(failure); | 1652 __ jmp(failure); |
| 1700 } | 1653 } |
| 1701 | 1654 |
| 1702 | 1655 |
| 1703 // Arg0: Onebyte String | 1656 // Arg0: Onebyte String |
| 1704 // Arg1: Start index as Smi. | 1657 // Arg1: Start index as Smi. |
| 1705 // Arg2: End index as Smi. | 1658 // Arg2: End index as Smi. |
| 1706 // The indexes must be valid. | 1659 // The indexes must be valid. |
| 1707 bool Intrinsifier::OneByteString_substringUnchecked(Assembler* assembler) { | 1660 void Intrinsifier::OneByteString_substringUnchecked(Assembler* assembler) { |
| 1708 const intptr_t kStringOffset = 3 * kWordSize; | 1661 const intptr_t kStringOffset = 3 * kWordSize; |
| 1709 const intptr_t kStartIndexOffset = 2 * kWordSize; | 1662 const intptr_t kStartIndexOffset = 2 * kWordSize; |
| 1710 const intptr_t kEndIndexOffset = 1 * kWordSize; | 1663 const intptr_t kEndIndexOffset = 1 * kWordSize; |
| 1711 Label fall_through, ok; | 1664 Label fall_through, ok; |
| 1712 __ movl(EDI, Address(ESP, + kEndIndexOffset)); | 1665 __ movl(EDI, Address(ESP, + kEndIndexOffset)); |
| 1713 __ subl(EDI, Address(ESP, + kStartIndexOffset)); | 1666 __ subl(EDI, Address(ESP, + kStartIndexOffset)); |
| 1714 TryAllocateOnebyteString(assembler, &ok, &fall_through, EDI); | 1667 TryAllocateOnebyteString(assembler, &ok, &fall_through, EDI); |
| 1715 __ Bind(&ok); | 1668 __ Bind(&ok); |
| 1716 // EAX: new string as tagged pointer. | 1669 // EAX: new string as tagged pointer. |
| 1717 // Copy string. | 1670 // Copy string. |
| (...skipping 16 matching lines...) Expand all Loading... |
| 1734 __ jmp(&check, Assembler::kNearJump); | 1687 __ jmp(&check, Assembler::kNearJump); |
| 1735 __ Bind(&loop); | 1688 __ Bind(&loop); |
| 1736 __ movzxb(EBX, Address(EDI, EDX, TIMES_1, 0)); | 1689 __ movzxb(EBX, Address(EDI, EDX, TIMES_1, 0)); |
| 1737 __ movb(FieldAddress(EAX, EDX, TIMES_1, OneByteString::data_offset()), BL); | 1690 __ movb(FieldAddress(EAX, EDX, TIMES_1, OneByteString::data_offset()), BL); |
| 1738 __ incl(EDX); | 1691 __ incl(EDX); |
| 1739 __ Bind(&check); | 1692 __ Bind(&check); |
| 1740 __ cmpl(EDX, ECX); | 1693 __ cmpl(EDX, ECX); |
| 1741 __ j(LESS, &loop, Assembler::kNearJump); | 1694 __ j(LESS, &loop, Assembler::kNearJump); |
| 1742 __ ret(); | 1695 __ ret(); |
| 1743 __ Bind(&fall_through); | 1696 __ Bind(&fall_through); |
| 1744 return false; | |
| 1745 } | 1697 } |
| 1746 | 1698 |
| 1747 | 1699 |
| 1748 bool Intrinsifier::OneByteString_setAt(Assembler* assembler) { | 1700 void Intrinsifier::OneByteString_setAt(Assembler* assembler) { |
| 1749 __ movl(ECX, Address(ESP, + 1 * kWordSize)); // Value. | 1701 __ movl(ECX, Address(ESP, + 1 * kWordSize)); // Value. |
| 1750 __ movl(EBX, Address(ESP, + 2 * kWordSize)); // Index. | 1702 __ movl(EBX, Address(ESP, + 2 * kWordSize)); // Index. |
| 1751 __ movl(EAX, Address(ESP, + 3 * kWordSize)); // OneByteString. | 1703 __ movl(EAX, Address(ESP, + 3 * kWordSize)); // OneByteString. |
| 1752 __ SmiUntag(EBX); | 1704 __ SmiUntag(EBX); |
| 1753 __ SmiUntag(ECX); | 1705 __ SmiUntag(ECX); |
| 1754 __ movb(FieldAddress(EAX, EBX, TIMES_1, OneByteString::data_offset()), CL); | 1706 __ movb(FieldAddress(EAX, EBX, TIMES_1, OneByteString::data_offset()), CL); |
| 1755 __ ret(); | 1707 __ ret(); |
| 1756 return true; | |
| 1757 } | 1708 } |
| 1758 | 1709 |
| 1759 | 1710 |
| 1760 bool Intrinsifier::OneByteString_allocate(Assembler* assembler) { | 1711 void Intrinsifier::OneByteString_allocate(Assembler* assembler) { |
| 1761 __ movl(EDI, Address(ESP, + 1 * kWordSize)); // Length. | 1712 __ movl(EDI, Address(ESP, + 1 * kWordSize)); // Length. |
| 1762 Label fall_through, ok; | 1713 Label fall_through, ok; |
| 1763 TryAllocateOnebyteString(assembler, &ok, &fall_through, EDI); | 1714 TryAllocateOnebyteString(assembler, &ok, &fall_through, EDI); |
| 1764 // EDI: Start address to copy from (untagged). | 1715 // EDI: Start address to copy from (untagged). |
| 1765 | 1716 |
| 1766 __ Bind(&ok); | 1717 __ Bind(&ok); |
| 1767 __ ret(); | 1718 __ ret(); |
| 1768 | 1719 |
| 1769 __ Bind(&fall_through); | 1720 __ Bind(&fall_through); |
| 1770 return false; | |
| 1771 } | 1721 } |
| 1772 | 1722 |
| 1773 #undef __ | 1723 #undef __ |
| 1774 } // namespace dart | 1724 } // namespace dart |
| 1775 | 1725 |
| 1776 #endif // defined TARGET_ARCH_IA32 | 1726 #endif // defined TARGET_ARCH_IA32 |
| OLD | NEW |