| OLD | NEW |
| 1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, 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 |
| 11 #include "vm/globals.h" // Needed here to get TARGET_ARCH_IA32. | 11 #include "vm/globals.h" // Needed here to get TARGET_ARCH_IA32. |
| 12 #if defined(TARGET_ARCH_IA32) | 12 #if defined(TARGET_ARCH_IA32) |
| 13 | 13 |
| 14 #include "vm/intrinsifier.h" | 14 #include "vm/intrinsifier.h" |
| 15 | 15 |
| 16 #include "vm/assembler.h" | 16 #include "vm/assembler.h" |
| 17 #include "vm/assembler_macros.h" | 17 #include "vm/assembler_macros.h" |
| 18 #include "vm/object.h" | 18 #include "vm/object.h" |
| 19 #include "vm/object_store.h" | 19 #include "vm/object_store.h" |
| 20 #include "vm/os.h" | 20 #include "vm/os.h" |
| 21 #include "vm/stub_code.h" | 21 #include "vm/stub_code.h" |
| 22 | 22 |
| 23 namespace dart { | 23 namespace dart { |
| 24 | 24 |
| 25 DEFINE_FLAG(bool, intrinsify, true, "Instrinsify when possible"); | |
| 26 DECLARE_FLAG(bool, enable_type_checks); | 25 DECLARE_FLAG(bool, enable_type_checks); |
| 27 | 26 |
| 28 // List of intrinsics: (class-name, function-name, intrinsification method). | |
| 29 #define INTRINSIC_LIST(V) \ | |
| 30 V(IntegerImplementation, addFromInteger, Integer_addFromInteger) \ | |
| 31 V(IntegerImplementation, +, Integer_addFromInteger) \ | |
| 32 V(IntegerImplementation, subFromInteger, Integer_subFromInteger) \ | |
| 33 V(IntegerImplementation, -, Integer_sub) \ | |
| 34 V(IntegerImplementation, mulFromInteger, Integer_mulFromInteger) \ | |
| 35 V(IntegerImplementation, *, Integer_mulFromInteger) \ | |
| 36 V(IntegerImplementation, %, Integer_modulo) \ | |
| 37 V(IntegerImplementation, ~/, Integer_truncDivide) \ | |
| 38 V(IntegerImplementation, negate, Integer_negate) \ | |
| 39 V(IntegerImplementation, bitAndFromInteger, Integer_bitAndFromInteger) \ | |
| 40 V(IntegerImplementation, &, Integer_bitAndFromInteger) \ | |
| 41 V(IntegerImplementation, bitOrFromInteger, Integer_bitOrFromInteger) \ | |
| 42 V(IntegerImplementation, |, Integer_bitOrFromInteger) \ | |
| 43 V(IntegerImplementation, bitXorFromInteger, Integer_bitXorFromInteger) \ | |
| 44 V(IntegerImplementation, ^, Integer_bitXorFromInteger) \ | |
| 45 V(IntegerImplementation, greaterThanFromInteger, Integer_lessThan) \ | |
| 46 V(IntegerImplementation, >, Integer_greaterThan) \ | |
| 47 V(IntegerImplementation, ==, Integer_equalToInteger) \ | |
| 48 V(IntegerImplementation, equalToInteger, Integer_equalToInteger) \ | |
| 49 V(IntegerImplementation, <, Integer_lessThan) \ | |
| 50 V(IntegerImplementation, <=, Integer_lessEqualThan) \ | |
| 51 V(IntegerImplementation, >=, Integer_greaterEqualThan) \ | |
| 52 V(IntegerImplementation, <<, Integer_shl) \ | |
| 53 V(IntegerImplementation, >>, Integer_sar) \ | |
| 54 V(Smi, ~, Smi_bitNegate) \ | |
| 55 V(Double, >, Double_greaterThan) \ | |
| 56 V(Double, >=, Double_greaterEqualThan) \ | |
| 57 V(Double, <, Double_lessThan) \ | |
| 58 V(Double, <=, Double_lessEqualThan) \ | |
| 59 V(Double, ==, Double_equal) \ | |
| 60 V(Double, +, Double_add) \ | |
| 61 V(Double, -, Double_sub) \ | |
| 62 V(Double, *, Double_mul) \ | |
| 63 V(Double, /, Double_div) \ | |
| 64 V(Double, toDouble, Double_toDouble) \ | |
| 65 V(Double, mulFromInteger, Double_mulFromInteger) \ | |
| 66 V(Double, Double.fromInteger, Double_fromInteger) \ | |
| 67 V(Double, isNaN, Double_isNaN) \ | |
| 68 V(Double, isNegative, Double_isNegative) \ | |
| 69 V(ObjectArray, ObjectArray., ObjectArray_Allocate) \ | |
| 70 V(ObjectArray, get:length, Array_getLength) \ | |
| 71 V(ObjectArray, [], Array_getIndexed) \ | |
| 72 V(ObjectArray, []=, Array_setIndexed) \ | |
| 73 V(GrowableObjectArray, GrowableObjectArray.fromObjectArray, GArray_Allocate) \ | |
| 74 V(GrowableObjectArray, get:length, GrowableArray_getLength) \ | |
| 75 V(GrowableObjectArray, get:capacity, GrowableArray_getCapacity) \ | |
| 76 V(GrowableObjectArray, [], GrowableArray_getIndexed) \ | |
| 77 V(GrowableObjectArray, []=, GrowableArray_setIndexed) \ | |
| 78 V(GrowableObjectArray, _setLength, GrowableArray_setLength) \ | |
| 79 V(GrowableObjectArray, set:data, GrowableArray_setData) \ | |
| 80 V(_ByteArrayBase, get:length, ByteArrayBase_getLength) \ | |
| 81 V(_ByteArrayBase, [], ByteArrayBase_getIndexed) \ | |
| 82 V(ImmutableArray, [], Array_getIndexed) \ | |
| 83 V(ImmutableArray, get:length, Array_getLength) \ | |
| 84 V(Math, sqrt, Math_sqrt) \ | |
| 85 V(Math, sin, Math_sin) \ | |
| 86 V(Math, cos, Math_cos) \ | |
| 87 V(Object, ==, Object_equal) \ | |
| 88 V(FixedSizeArrayIterator, next, FixedSizeArrayIterator_next) \ | |
| 89 V(FixedSizeArrayIterator, hasNext, FixedSizeArrayIterator_hasNext) \ | |
| 90 V(StringBase, get:length, String_getLength) \ | |
| 91 V(StringBase, charCodeAt, String_charCodeAt) \ | |
| 92 V(StringBase, hashCode, String_hashCode) \ | |
| 93 V(StringBase, isEmpty, String_isEmpty) \ | |
| 94 | 27 |
| 95 #define __ assembler-> | 28 #define __ assembler-> |
| 96 | 29 |
| 97 static bool ObjectArray_Allocate(Assembler* assembler) { | 30 bool Intrinsifier::ObjectArray_Allocate(Assembler* assembler) { |
| 98 // This snippet of inlined code uses the following registers: | 31 // This snippet of inlined code uses the following registers: |
| 99 // EAX, EBX, EDI | 32 // EAX, EBX, EDI |
| 100 // and the newly allocated object is returned in EAX. | 33 // and the newly allocated object is returned in EAX. |
| 101 const intptr_t kTypeArgumentsOffset = 2 * kWordSize; | 34 const intptr_t kTypeArgumentsOffset = 2 * kWordSize; |
| 102 const intptr_t kArrayLengthOffset = 1 * kWordSize; | 35 const intptr_t kArrayLengthOffset = 1 * kWordSize; |
| 103 Label fall_through; | 36 Label fall_through; |
| 104 | 37 |
| 105 // Compute the size to be allocated, it is based on the array length | 38 // Compute the size to be allocated, it is based on the array length |
| 106 // and it computed as: | 39 // and it computed as: |
| 107 // RoundedAllocationSize((array_length * kwordSize) + sizeof(RawArray)). | 40 // RoundedAllocationSize((array_length * kwordSize) + sizeof(RawArray)). |
| (...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 186 __ addl(EDI, Immediate(kWordSize)); | 119 __ addl(EDI, Immediate(kWordSize)); |
| 187 __ jmp(&init_loop, Assembler::kNearJump); | 120 __ jmp(&init_loop, Assembler::kNearJump); |
| 188 __ Bind(&done); | 121 __ Bind(&done); |
| 189 __ ret(); // returns the newly allocated object in EAX. | 122 __ ret(); // returns the newly allocated object in EAX. |
| 190 | 123 |
| 191 __ Bind(&fall_through); | 124 __ Bind(&fall_through); |
| 192 return false; | 125 return false; |
| 193 } | 126 } |
| 194 | 127 |
| 195 | 128 |
| 196 static bool Array_getLength(Assembler* assembler) { | 129 bool Intrinsifier::Array_getLength(Assembler* assembler) { |
| 197 __ movl(EAX, Address(ESP, + 1 * kWordSize)); | 130 __ movl(EAX, Address(ESP, + 1 * kWordSize)); |
| 198 __ movl(EAX, FieldAddress(EAX, Array::length_offset())); | 131 __ movl(EAX, FieldAddress(EAX, Array::length_offset())); |
| 199 __ ret(); | 132 __ ret(); |
| 200 return true; | 133 return true; |
| 201 } | 134 } |
| 202 | 135 |
| 203 | 136 |
| 204 static bool Array_getIndexed(Assembler* assembler) { | 137 bool Intrinsifier::ImmutableArray_getLength(Assembler* assembler) { |
| 138 return Array_getLength(assembler); |
| 139 } |
| 140 |
| 141 |
| 142 bool Intrinsifier::Array_getIndexed(Assembler* assembler) { |
| 205 Label fall_through; | 143 Label fall_through; |
| 206 __ movl(EBX, Address(ESP, + 1 * kWordSize)); // Index. | 144 __ movl(EBX, Address(ESP, + 1 * kWordSize)); // Index. |
| 207 __ movl(EAX, Address(ESP, + 2 * kWordSize)); // Array. | 145 __ movl(EAX, Address(ESP, + 2 * kWordSize)); // Array. |
| 208 __ testl(EBX, Immediate(kSmiTagMask)); | 146 __ testl(EBX, Immediate(kSmiTagMask)); |
| 209 __ j(NOT_ZERO, &fall_through, Assembler::kNearJump); // Non-smi index. | 147 __ j(NOT_ZERO, &fall_through, Assembler::kNearJump); // Non-smi index. |
| 210 // Range check. | 148 // Range check. |
| 211 __ cmpl(EBX, FieldAddress(EAX, Array::length_offset())); | 149 __ cmpl(EBX, FieldAddress(EAX, Array::length_offset())); |
| 212 // Runtime throws exception. | 150 // Runtime throws exception. |
| 213 __ j(ABOVE_EQUAL, &fall_through, Assembler::kNearJump); | 151 __ j(ABOVE_EQUAL, &fall_through, Assembler::kNearJump); |
| 214 // Note that EBX is Smi, i.e, times 2. | 152 // Note that EBX is Smi, i.e, times 2. |
| 215 ASSERT(kSmiTagShift == 1); | 153 ASSERT(kSmiTagShift == 1); |
| 216 __ movl(EAX, FieldAddress(EAX, EBX, TIMES_2, sizeof(RawArray))); | 154 __ movl(EAX, FieldAddress(EAX, EBX, TIMES_2, sizeof(RawArray))); |
| 217 __ ret(); | 155 __ ret(); |
| 218 __ Bind(&fall_through); | 156 __ Bind(&fall_through); |
| 219 return false; | 157 return false; |
| 220 } | 158 } |
| 221 | 159 |
| 222 | 160 |
| 161 bool Intrinsifier::ImmutableArray_getIndexed(Assembler* assembler) { |
| 162 return Array_getIndexed(assembler); |
| 163 } |
| 164 |
| 165 |
| 223 static intptr_t ComputeObjectArrayTypeArgumentsOffset() { | 166 static intptr_t ComputeObjectArrayTypeArgumentsOffset() { |
| 224 const String& class_name = String::Handle(String::NewSymbol("ObjectArray")); | 167 const String& class_name = String::Handle(String::NewSymbol("ObjectArray")); |
| 225 const Class& cls = Class::Handle( | 168 const Class& cls = Class::Handle( |
| 226 Library::Handle(Library::CoreImplLibrary()).LookupClass(class_name)); | 169 Library::Handle(Library::CoreImplLibrary()).LookupClass(class_name)); |
| 227 ASSERT(!cls.IsNull()); | 170 ASSERT(!cls.IsNull()); |
| 228 ASSERT(cls.HasTypeArguments()); | 171 ASSERT(cls.HasTypeArguments()); |
| 229 ASSERT(cls.NumTypeArguments() == 1); | 172 ASSERT(cls.NumTypeArguments() == 1); |
| 230 const intptr_t field_offset = cls.type_arguments_instance_field_offset(); | 173 const intptr_t field_offset = cls.type_arguments_instance_field_offset(); |
| 231 ASSERT(field_offset != Class::kNoTypeArguments); | 174 ASSERT(field_offset != Class::kNoTypeArguments); |
| 232 return field_offset; | 175 return field_offset; |
| 233 } | 176 } |
| 234 | 177 |
| 235 | 178 |
| 236 // Intrinsify only for Smi value and index. Non-smi values need a store buffer | 179 // Intrinsify only for Smi value and index. Non-smi values need a store buffer |
| 237 // update. Array length is always a Smi. | 180 // update. Array length is always a Smi. |
| 238 static bool Array_setIndexed(Assembler* assembler) { | 181 bool Intrinsifier::Array_setIndexed(Assembler* assembler) { |
| 239 Label fall_through; | 182 Label fall_through; |
| 240 if (FLAG_enable_type_checks) { | 183 if (FLAG_enable_type_checks) { |
| 241 const intptr_t type_args_field_offset = | 184 const intptr_t type_args_field_offset = |
| 242 ComputeObjectArrayTypeArgumentsOffset(); | 185 ComputeObjectArrayTypeArgumentsOffset(); |
| 243 // Inline simple tests (Smi, null), fallthrough if not positive. | 186 // Inline simple tests (Smi, null), fallthrough if not positive. |
| 244 const Immediate raw_null = | 187 const Immediate raw_null = |
| 245 Immediate(reinterpret_cast<intptr_t>(Object::null())); | 188 Immediate(reinterpret_cast<intptr_t>(Object::null())); |
| 246 Label checked_ok; | 189 Label checked_ok; |
| 247 __ movl(EDI, Address(ESP, + 1 * kWordSize)); // Value. | 190 __ movl(EDI, Address(ESP, + 1 * kWordSize)); // Value. |
| 248 // Null value is valid for any type. | 191 // Null value is valid for any type. |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 303 Library::CoreImplLibrary()).LookupClass(class_name)); | 246 Library::CoreImplLibrary()).LookupClass(class_name)); |
| 304 ASSERT(!cls.IsNull()); | 247 ASSERT(!cls.IsNull()); |
| 305 const Field& field = Field::ZoneHandle(cls.LookupInstanceField(field_name)); | 248 const Field& field = Field::ZoneHandle(cls.LookupInstanceField(field_name)); |
| 306 ASSERT(!field.IsNull()); | 249 ASSERT(!field.IsNull()); |
| 307 return field.Offset(); | 250 return field.Offset(); |
| 308 } | 251 } |
| 309 | 252 |
| 310 | 253 |
| 311 // Allocate a GrowableObjectArray using the backing array specified. | 254 // Allocate a GrowableObjectArray using the backing array specified. |
| 312 // On stack: type argument (+2), data (+1), return-address (+0). | 255 // On stack: type argument (+2), data (+1), return-address (+0). |
| 313 static bool GArray_Allocate(Assembler* assembler) { | 256 bool Intrinsifier::GArray_Allocate(Assembler* assembler) { |
| 314 // This snippet of inlined code uses the following registers: | 257 // This snippet of inlined code uses the following registers: |
| 315 // EAX, EBX | 258 // EAX, EBX |
| 316 // and the newly allocated object is returned in EAX. | 259 // and the newly allocated object is returned in EAX. |
| 317 const intptr_t kTypeArgumentsOffset = 2 * kWordSize; | 260 const intptr_t kTypeArgumentsOffset = 2 * kWordSize; |
| 318 const intptr_t kArrayOffset = 1 * kWordSize; | 261 const intptr_t kArrayOffset = 1 * kWordSize; |
| 319 Label fall_through; | 262 Label fall_through; |
| 320 | 263 |
| 321 // Compute the size to be allocated, it is based on the array length | 264 // Compute the size to be allocated, it is based on the array length |
| 322 // and it computed as: | 265 // and it computed as: |
| 323 // RoundedAllocationSize(sizeof(RawGrowableObjectArray)) + | 266 // RoundedAllocationSize(sizeof(RawGrowableObjectArray)) + |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 371 Immediate(0)); | 314 Immediate(0)); |
| 372 __ ret(); // returns the newly allocated object in EAX. | 315 __ ret(); // returns the newly allocated object in EAX. |
| 373 | 316 |
| 374 __ Bind(&fall_through); | 317 __ Bind(&fall_through); |
| 375 return false; | 318 return false; |
| 376 } | 319 } |
| 377 | 320 |
| 378 | 321 |
| 379 // Get length of growable object array. | 322 // Get length of growable object array. |
| 380 // On stack: growable array (+1), return-address (+0). | 323 // On stack: growable array (+1), return-address (+0). |
| 381 static bool GrowableArray_getLength(Assembler* assembler) { | 324 bool Intrinsifier::GrowableArray_getLength(Assembler* assembler) { |
| 382 __ movl(EAX, Address(ESP, + 1 * kWordSize)); | 325 __ movl(EAX, Address(ESP, + 1 * kWordSize)); |
| 383 __ movl(EAX, FieldAddress(EAX, GrowableObjectArray::length_offset())); | 326 __ movl(EAX, FieldAddress(EAX, GrowableObjectArray::length_offset())); |
| 384 __ ret(); | 327 __ ret(); |
| 385 return true; | 328 return true; |
| 386 } | 329 } |
| 387 | 330 |
| 388 | 331 |
| 389 // Get capacity of growable object array. | 332 // Get capacity of growable object array. |
| 390 // On stack: growable array (+1), return-address (+0). | 333 // On stack: growable array (+1), return-address (+0). |
| 391 static bool GrowableArray_getCapacity(Assembler* assembler) { | 334 bool Intrinsifier::GrowableArray_getCapacity(Assembler* assembler) { |
| 392 __ movl(EAX, Address(ESP, + 1 * kWordSize)); | 335 __ movl(EAX, Address(ESP, + 1 * kWordSize)); |
| 393 __ movl(EAX, FieldAddress(EAX, GrowableObjectArray::data_offset())); | 336 __ movl(EAX, FieldAddress(EAX, GrowableObjectArray::data_offset())); |
| 394 __ movl(EAX, FieldAddress(EAX, Array::length_offset())); | 337 __ movl(EAX, FieldAddress(EAX, Array::length_offset())); |
| 395 __ ret(); | 338 __ ret(); |
| 396 return true; | 339 return true; |
| 397 } | 340 } |
| 398 | 341 |
| 399 | 342 |
| 400 // Access growable object array at specified index. | 343 // Access growable object array at specified index. |
| 401 // On stack: growable array (+2), index (+1), return-address (+0). | 344 // On stack: growable array (+2), index (+1), return-address (+0). |
| 402 static bool GrowableArray_getIndexed(Assembler* assembler) { | 345 bool Intrinsifier::GrowableArray_getIndexed(Assembler* assembler) { |
| 403 Label fall_through; | 346 Label fall_through; |
| 404 __ movl(EBX, Address(ESP, + 1 * kWordSize)); // Index. | 347 __ movl(EBX, Address(ESP, + 1 * kWordSize)); // Index. |
| 405 __ movl(EAX, Address(ESP, + 2 * kWordSize)); // GrowableArray. | 348 __ movl(EAX, Address(ESP, + 2 * kWordSize)); // GrowableArray. |
| 406 __ testl(EBX, Immediate(kSmiTagMask)); | 349 __ testl(EBX, Immediate(kSmiTagMask)); |
| 407 __ j(NOT_ZERO, &fall_through, Assembler::kNearJump); // Non-smi index. | 350 __ j(NOT_ZERO, &fall_through, Assembler::kNearJump); // Non-smi index. |
| 408 // Range check using _length field. | 351 // Range check using _length field. |
| 409 __ cmpl(EBX, FieldAddress(EAX, GrowableObjectArray::length_offset())); | 352 __ cmpl(EBX, FieldAddress(EAX, GrowableObjectArray::length_offset())); |
| 410 // Runtime throws exception. | 353 // Runtime throws exception. |
| 411 __ j(ABOVE_EQUAL, &fall_through, Assembler::kNearJump); | 354 __ j(ABOVE_EQUAL, &fall_through, Assembler::kNearJump); |
| 412 __ movl(EAX, FieldAddress(EAX, GrowableObjectArray::data_offset())); // data. | 355 __ movl(EAX, FieldAddress(EAX, GrowableObjectArray::data_offset())); // data. |
| 413 | 356 |
| 414 // Note that EBX is Smi, i.e, times 2. | 357 // Note that EBX is Smi, i.e, times 2. |
| 415 ASSERT(kSmiTagShift == 1); | 358 ASSERT(kSmiTagShift == 1); |
| 416 __ movl(EAX, FieldAddress(EAX, EBX, TIMES_2, sizeof(RawArray))); | 359 __ movl(EAX, FieldAddress(EAX, EBX, TIMES_2, sizeof(RawArray))); |
| 417 __ ret(); | 360 __ ret(); |
| 418 __ Bind(&fall_through); | 361 __ Bind(&fall_through); |
| 419 return false; | 362 return false; |
| 420 } | 363 } |
| 421 | 364 |
| 422 | 365 |
| 423 // Set value into growable object array at specified index. | 366 // Set value into growable object array at specified index. |
| 424 // On stack: growable array (+3), index (+2), value (+1), return-address (+0). | 367 // On stack: growable array (+3), index (+2), value (+1), return-address (+0). |
| 425 static bool GrowableArray_setIndexed(Assembler* assembler) { | 368 bool Intrinsifier::GrowableArray_setIndexed(Assembler* assembler) { |
| 426 if (FLAG_enable_type_checks) { | 369 if (FLAG_enable_type_checks) { |
| 427 return false; | 370 return false; |
| 428 } | 371 } |
| 429 Label fall_through; | 372 Label fall_through; |
| 430 __ movl(EBX, Address(ESP, + 2 * kWordSize)); // Index. | 373 __ movl(EBX, Address(ESP, + 2 * kWordSize)); // Index. |
| 431 __ movl(EAX, Address(ESP, + 3 * kWordSize)); // GrowableArray. | 374 __ movl(EAX, Address(ESP, + 3 * kWordSize)); // GrowableArray. |
| 432 __ testl(EBX, Immediate(kSmiTagMask)); | 375 __ testl(EBX, Immediate(kSmiTagMask)); |
| 433 __ j(NOT_ZERO, &fall_through, Assembler::kNearJump); // Non-smi index. | 376 __ j(NOT_ZERO, &fall_through, Assembler::kNearJump); // Non-smi index. |
| 434 // Range check using _length field. | 377 // Range check using _length field. |
| 435 __ cmpl(EBX, FieldAddress(EAX, GrowableObjectArray::length_offset())); | 378 __ cmpl(EBX, FieldAddress(EAX, GrowableObjectArray::length_offset())); |
| 436 // Runtime throws exception. | 379 // Runtime throws exception. |
| 437 __ j(ABOVE_EQUAL, &fall_through, Assembler::kNearJump); | 380 __ j(ABOVE_EQUAL, &fall_through, Assembler::kNearJump); |
| 438 __ movl(EAX, FieldAddress(EAX, GrowableObjectArray::data_offset())); // data. | 381 __ movl(EAX, FieldAddress(EAX, GrowableObjectArray::data_offset())); // data. |
| 439 __ movl(EDI, Address(ESP, + 1 * kWordSize)); // Value. | 382 __ movl(EDI, Address(ESP, + 1 * kWordSize)); // Value. |
| 440 // Note that EBX is Smi, i.e, times 2. | 383 // Note that EBX is Smi, i.e, times 2. |
| 441 ASSERT(kSmiTagShift == 1); | 384 ASSERT(kSmiTagShift == 1); |
| 442 __ StoreIntoObject(EAX, | 385 __ StoreIntoObject(EAX, |
| 443 FieldAddress(EAX, EBX, TIMES_2, sizeof(RawArray)), | 386 FieldAddress(EAX, EBX, TIMES_2, sizeof(RawArray)), |
| 444 EDI); | 387 EDI); |
| 445 __ ret(); | 388 __ ret(); |
| 446 __ Bind(&fall_through); | 389 __ Bind(&fall_through); |
| 447 return false; | 390 return false; |
| 448 } | 391 } |
| 449 | 392 |
| 450 | 393 |
| 451 // Set length of growable object array. | 394 // Set length of growable object array. |
| 452 // On stack: growable array (+2), length (+1), return-address (+0). | 395 // On stack: growable array (+2), length (+1), return-address (+0). |
| 453 static bool GrowableArray_setLength(Assembler* assembler) { | 396 bool Intrinsifier::GrowableArray_setLength(Assembler* assembler) { |
| 454 Label fall_through; | 397 Label fall_through; |
| 455 __ movl(EAX, Address(ESP, + 2 * kWordSize)); | 398 __ movl(EAX, Address(ESP, + 2 * kWordSize)); |
| 456 __ movl(EBX, Address(ESP, + 1 * kWordSize)); | 399 __ movl(EBX, Address(ESP, + 1 * kWordSize)); |
| 457 __ movl(EDI, FieldAddress(EAX, GrowableObjectArray::data_offset())); | 400 __ movl(EDI, FieldAddress(EAX, GrowableObjectArray::data_offset())); |
| 458 __ cmpl(EBX, FieldAddress(EDI, Array::length_offset())); | 401 __ cmpl(EBX, FieldAddress(EDI, Array::length_offset())); |
| 459 __ j(ABOVE, &fall_through, Assembler::kNearJump); | 402 __ j(ABOVE, &fall_through, Assembler::kNearJump); |
| 460 __ movl(FieldAddress(EAX, GrowableObjectArray::length_offset()), EBX); | 403 __ movl(FieldAddress(EAX, GrowableObjectArray::length_offset()), EBX); |
| 461 __ ret(); | 404 __ ret(); |
| 462 __ Bind(&fall_through); | 405 __ Bind(&fall_through); |
| 463 return true; | 406 return true; |
| 464 } | 407 } |
| 465 | 408 |
| 466 | 409 |
| 467 // Set data of growable object array. | 410 // Set data of growable object array. |
| 468 // On stack: growable array (+2), data (+1), return-address (+0). | 411 // On stack: growable array (+2), data (+1), return-address (+0). |
| 469 static bool GrowableArray_setData(Assembler* assembler) { | 412 bool Intrinsifier::GrowableArray_setData(Assembler* assembler) { |
| 470 if (FLAG_enable_type_checks) { | 413 if (FLAG_enable_type_checks) { |
| 471 return false; | 414 return false; |
| 472 } | 415 } |
| 473 __ movl(EAX, Address(ESP, + 2 * kWordSize)); | 416 __ movl(EAX, Address(ESP, + 2 * kWordSize)); |
| 474 __ movl(EBX, Address(ESP, + 1 * kWordSize)); | 417 __ movl(EBX, Address(ESP, + 1 * kWordSize)); |
| 475 __ movl(FieldAddress(EAX, GrowableObjectArray::data_offset()), EBX); | 418 __ movl(FieldAddress(EAX, GrowableObjectArray::data_offset()), EBX); |
| 476 __ ret(); | 419 __ ret(); |
| 477 return true; | 420 return true; |
| 478 } | 421 } |
| 479 | 422 |
| 480 | 423 |
| 481 // Handles only class InternalByteArray. | 424 // Handles only class InternalByteArray. |
| 482 static bool ByteArrayBase_getLength(Assembler* assembler) { | 425 bool Intrinsifier::ByteArrayBase_getLength(Assembler* assembler) { |
| 483 ObjectStore* object_store = Isolate::Current()->object_store(); | 426 ObjectStore* object_store = Isolate::Current()->object_store(); |
| 484 Label fall_through; | 427 Label fall_through; |
| 485 __ movl(EAX, Address(ESP, + 1 * kWordSize)); | 428 __ movl(EAX, Address(ESP, + 1 * kWordSize)); |
| 486 __ movl(EBX, FieldAddress(EAX, Object::class_offset())); | 429 __ movl(EBX, FieldAddress(EAX, Object::class_offset())); |
| 487 __ CompareObject(EBX, | 430 __ CompareObject(EBX, |
| 488 Class::ZoneHandle(object_store->internal_byte_array_class())); | 431 Class::ZoneHandle(object_store->internal_byte_array_class())); |
| 489 __ j(NOT_EQUAL, &fall_through); | 432 __ j(NOT_EQUAL, &fall_through); |
| 490 __ movl(EAX, FieldAddress(EAX, InternalByteArray::length_offset())); | 433 __ movl(EAX, FieldAddress(EAX, InternalByteArray::length_offset())); |
| 491 __ ret(); | 434 __ ret(); |
| 492 __ Bind(&fall_through); | 435 __ Bind(&fall_through); |
| 493 return false; | 436 return false; |
| 494 } | 437 } |
| 495 | 438 |
| 496 | 439 |
| 497 // Handles only class InternalByteArray. | 440 // Handles only class InternalByteArray. |
| 498 static bool ByteArrayBase_getIndexed(Assembler* assembler) { | 441 bool Intrinsifier::ByteArrayBase_getIndexed(Assembler* assembler) { |
| 499 ObjectStore* object_store = Isolate::Current()->object_store(); | 442 ObjectStore* object_store = Isolate::Current()->object_store(); |
| 500 Label fall_through; | 443 Label fall_through; |
| 501 __ movl(EAX, Address(ESP, + 2 * kWordSize)); // Array. | 444 __ movl(EAX, Address(ESP, + 2 * kWordSize)); // Array. |
| 502 __ movl(EBX, FieldAddress(EAX, Object::class_offset())); | 445 __ movl(EBX, FieldAddress(EAX, Object::class_offset())); |
| 503 __ CompareObject(EBX, | 446 __ CompareObject(EBX, |
| 504 Class::ZoneHandle(object_store->internal_byte_array_class())); | 447 Class::ZoneHandle(object_store->internal_byte_array_class())); |
| 505 __ j(NOT_EQUAL, &fall_through); | 448 __ j(NOT_EQUAL, &fall_through); |
| 506 __ movl(EBX, Address(ESP, + 1 * kWordSize)); // Index. | 449 __ movl(EBX, Address(ESP, + 1 * kWordSize)); // Index. |
| 507 __ testl(EBX, Immediate(kSmiTagMask)); | 450 __ testl(EBX, Immediate(kSmiTagMask)); |
| 508 __ j(NOT_ZERO, &fall_through, Assembler::kNearJump); // Non-smi index. | 451 __ j(NOT_ZERO, &fall_through, Assembler::kNearJump); // Non-smi index. |
| (...skipping 17 matching lines...) Expand all Loading... |
| 526 // Topmost argument is in EAX. | 469 // Topmost argument is in EAX. |
| 527 static void TestBothArgumentsSmis(Assembler* assembler, Label* not_smi) { | 470 static void TestBothArgumentsSmis(Assembler* assembler, Label* not_smi) { |
| 528 __ movl(EAX, Address(ESP, + 1 * kWordSize)); | 471 __ movl(EAX, Address(ESP, + 1 * kWordSize)); |
| 529 __ movl(EBX, Address(ESP, + 2 * kWordSize)); | 472 __ movl(EBX, Address(ESP, + 2 * kWordSize)); |
| 530 __ orl(EBX, EAX); | 473 __ orl(EBX, EAX); |
| 531 __ testl(EBX, Immediate(kSmiTagMask)); | 474 __ testl(EBX, Immediate(kSmiTagMask)); |
| 532 __ j(NOT_ZERO, not_smi, Assembler::kNearJump); | 475 __ j(NOT_ZERO, not_smi, Assembler::kNearJump); |
| 533 } | 476 } |
| 534 | 477 |
| 535 | 478 |
| 536 static bool Integer_addFromInteger(Assembler* assembler) { | 479 bool Intrinsifier::Integer_addFromInteger(Assembler* assembler) { |
| 537 Label fall_through; | 480 Label fall_through; |
| 538 TestBothArgumentsSmis(assembler, &fall_through); | 481 TestBothArgumentsSmis(assembler, &fall_through); |
| 539 __ addl(EAX, Address(ESP, + 2 * kWordSize)); | 482 __ addl(EAX, Address(ESP, + 2 * kWordSize)); |
| 540 __ j(OVERFLOW, &fall_through, Assembler::kNearJump); | 483 __ j(OVERFLOW, &fall_through, Assembler::kNearJump); |
| 541 // Result is in EAX. | 484 // Result is in EAX. |
| 542 __ ret(); | 485 __ ret(); |
| 543 __ Bind(&fall_through); | 486 __ Bind(&fall_through); |
| 544 return false; | 487 return false; |
| 545 } | 488 } |
| 546 | 489 |
| 547 | 490 |
| 548 static bool Integer_subFromInteger(Assembler* assembler) { | 491 bool Intrinsifier::Integer_add(Assembler* assembler) { |
| 492 return Integer_addFromInteger(assembler); |
| 493 } |
| 494 |
| 495 |
| 496 bool Intrinsifier::Integer_subFromInteger(Assembler* assembler) { |
| 549 Label fall_through; | 497 Label fall_through; |
| 550 TestBothArgumentsSmis(assembler, &fall_through); | 498 TestBothArgumentsSmis(assembler, &fall_through); |
| 551 __ subl(EAX, Address(ESP, + 2 * kWordSize)); | 499 __ subl(EAX, Address(ESP, + 2 * kWordSize)); |
| 552 __ j(OVERFLOW, &fall_through, Assembler::kNearJump); | 500 __ j(OVERFLOW, &fall_through, Assembler::kNearJump); |
| 553 // Result is in EAX. | 501 // Result is in EAX. |
| 554 __ ret(); | 502 __ ret(); |
| 555 __ Bind(&fall_through); | 503 __ Bind(&fall_through); |
| 556 return false; | 504 return false; |
| 557 } | 505 } |
| 558 | 506 |
| 559 | 507 |
| 560 static bool Integer_sub(Assembler* assembler) { | 508 bool Intrinsifier::Integer_sub(Assembler* assembler) { |
| 561 Label fall_through; | 509 Label fall_through; |
| 562 TestBothArgumentsSmis(assembler, &fall_through); | 510 TestBothArgumentsSmis(assembler, &fall_through); |
| 563 __ movl(EBX, EAX); | 511 __ movl(EBX, EAX); |
| 564 __ movl(EAX, Address(ESP, + 2 * kWordSize)); | 512 __ movl(EAX, Address(ESP, + 2 * kWordSize)); |
| 565 __ subl(EAX, EBX); | 513 __ subl(EAX, EBX); |
| 566 __ j(OVERFLOW, &fall_through, Assembler::kNearJump); | 514 __ j(OVERFLOW, &fall_through, Assembler::kNearJump); |
| 567 // Result is in EAX. | 515 // Result is in EAX. |
| 568 __ ret(); | 516 __ ret(); |
| 569 __ Bind(&fall_through); | 517 __ Bind(&fall_through); |
| 570 return false; | 518 return false; |
| 571 } | 519 } |
| 572 | 520 |
| 573 | 521 |
| 574 | 522 |
| 575 static bool Integer_mulFromInteger(Assembler* assembler) { | 523 bool Intrinsifier::Integer_mulFromInteger(Assembler* assembler) { |
| 576 Label fall_through; | 524 Label fall_through; |
| 577 TestBothArgumentsSmis(assembler, &fall_through); | 525 TestBothArgumentsSmis(assembler, &fall_through); |
| 578 ASSERT(kSmiTag == 0); // Adjust code below if not the case. | 526 ASSERT(kSmiTag == 0); // Adjust code below if not the case. |
| 579 __ SmiUntag(EAX); | 527 __ SmiUntag(EAX); |
| 580 __ imull(EAX, Address(ESP, + 2 * kWordSize)); | 528 __ imull(EAX, Address(ESP, + 2 * kWordSize)); |
| 581 __ j(OVERFLOW, &fall_through, Assembler::kNearJump); | 529 __ j(OVERFLOW, &fall_through, Assembler::kNearJump); |
| 582 // Result is in EAX. | 530 // Result is in EAX. |
| 583 __ ret(); | 531 __ ret(); |
| 584 __ Bind(&fall_through); | 532 __ Bind(&fall_through); |
| 585 return false; | 533 return false; |
| 586 } | 534 } |
| 587 | 535 |
| 588 | 536 |
| 537 bool Intrinsifier::Integer_mul(Assembler* assembler) { |
| 538 return Integer_mulFromInteger(assembler); |
| 539 } |
| 540 |
| 541 |
| 589 // Simple implementation: for positive dividend values greater than divisor, | 542 // Simple implementation: for positive dividend values greater than divisor, |
| 590 // return dividend. | 543 // return dividend. |
| 591 static bool Integer_modulo(Assembler* assembler) { | 544 bool Intrinsifier::Integer_modulo(Assembler* assembler) { |
| 592 Label fall_through, return_zero; | 545 Label fall_through, return_zero; |
| 593 TestBothArgumentsSmis(assembler, &fall_through); | 546 TestBothArgumentsSmis(assembler, &fall_through); |
| 594 // EAX: right argument (divisor) | 547 // EAX: right argument (divisor) |
| 595 // Check if modulo by zero -> exception thrown in main function. | 548 // Check if modulo by zero -> exception thrown in main function. |
| 596 __ cmpl(EAX, Immediate(0)); | 549 __ cmpl(EAX, Immediate(0)); |
| 597 __ j(EQUAL, &fall_through, Assembler::kNearJump); | 550 __ j(EQUAL, &fall_through, Assembler::kNearJump); |
| 598 __ movl(EBX, Address(ESP, + 2 * kWordSize)); // Left argument (dividend). | 551 __ movl(EBX, Address(ESP, + 2 * kWordSize)); // Left argument (dividend). |
| 599 __ cmpl(EBX, Immediate(0)); | 552 __ cmpl(EBX, Immediate(0)); |
| 600 __ j(LESS, &fall_through, Assembler::kNearJump); | 553 __ j(LESS, &fall_through, Assembler::kNearJump); |
| 601 __ cmpl(EBX, EAX); | 554 __ cmpl(EBX, EAX); |
| 602 __ j(EQUAL, &return_zero, Assembler::kNearJump); | 555 __ j(EQUAL, &return_zero, Assembler::kNearJump); |
| 603 __ j(GREATER, &fall_through, Assembler::kNearJump); | 556 __ j(GREATER, &fall_through, Assembler::kNearJump); |
| 604 __ movl(EAX, EBX); // Return dividend. | 557 __ movl(EAX, EBX); // Return dividend. |
| 605 __ ret(); | 558 __ ret(); |
| 606 __ Bind(&return_zero); | 559 __ Bind(&return_zero); |
| 607 __ xorl(EAX, EAX); // Return zero. | 560 __ xorl(EAX, EAX); // Return zero. |
| 608 __ ret(); | 561 __ ret(); |
| 609 __ Bind(&fall_through); | 562 __ Bind(&fall_through); |
| 610 return false; | 563 return false; |
| 611 } | 564 } |
| 612 | 565 |
| 613 | 566 |
| 614 static bool Integer_truncDivide(Assembler* assembler) { | 567 bool Intrinsifier::Integer_truncDivide(Assembler* assembler) { |
| 615 Label fall_through; | 568 Label fall_through; |
| 616 TestBothArgumentsSmis(assembler, &fall_through); | 569 TestBothArgumentsSmis(assembler, &fall_through); |
| 617 // EAX: right argument (divisor) | 570 // EAX: right argument (divisor) |
| 618 __ cmpl(EAX, Immediate(0)); | 571 __ cmpl(EAX, Immediate(0)); |
| 619 __ j(EQUAL, &fall_through, Assembler::kNearJump); | 572 __ j(EQUAL, &fall_through, Assembler::kNearJump); |
| 620 __ movl(EBX, EAX); | 573 __ movl(EBX, EAX); |
| 621 __ SmiUntag(EBX); | 574 __ SmiUntag(EBX); |
| 622 __ movl(EAX, Address(ESP, + 2 * kWordSize)); // Left argument (dividend). | 575 __ movl(EAX, Address(ESP, + 2 * kWordSize)); // Left argument (dividend). |
| 623 __ SmiUntag(EAX); | 576 __ SmiUntag(EAX); |
| 624 __ pushl(EDX); // Preserve EDX in case of 'fall_through'. | 577 __ pushl(EDX); // Preserve EDX in case of 'fall_through'. |
| 625 __ cdq(); | 578 __ cdq(); |
| 626 __ idivl(EBX); | 579 __ idivl(EBX); |
| 627 __ popl(EDX); | 580 __ popl(EDX); |
| 628 // Check the corner case of dividing the 'MIN_SMI' with -1, in which case we | 581 // Check the corner case of dividing the 'MIN_SMI' with -1, in which case we |
| 629 // cannot tag the result. | 582 // cannot tag the result. |
| 630 __ cmpl(EAX, Immediate(0x40000000)); | 583 __ cmpl(EAX, Immediate(0x40000000)); |
| 631 __ j(EQUAL, &fall_through); | 584 __ j(EQUAL, &fall_through); |
| 632 __ SmiTag(EAX); | 585 __ SmiTag(EAX); |
| 633 __ ret(); | 586 __ ret(); |
| 634 __ Bind(&fall_through); | 587 __ Bind(&fall_through); |
| 635 return false; | 588 return false; |
| 636 } | 589 } |
| 637 | 590 |
| 638 | 591 |
| 639 static bool Integer_negate(Assembler* assembler) { | 592 bool Intrinsifier::Integer_negate(Assembler* assembler) { |
| 640 Label fall_through; | 593 Label fall_through; |
| 641 __ movl(EAX, Address(ESP, + 1 * kWordSize)); | 594 __ movl(EAX, Address(ESP, + 1 * kWordSize)); |
| 642 __ testl(EAX, Immediate(kSmiTagMask)); | 595 __ testl(EAX, Immediate(kSmiTagMask)); |
| 643 __ j(NOT_ZERO, &fall_through, Assembler::kNearJump); // Non-smi value. | 596 __ j(NOT_ZERO, &fall_through, Assembler::kNearJump); // Non-smi value. |
| 644 __ negl(EAX); | 597 __ negl(EAX); |
| 645 __ j(OVERFLOW, &fall_through, Assembler::kNearJump); | 598 __ j(OVERFLOW, &fall_through, Assembler::kNearJump); |
| 646 // Result is in EAX. | 599 // Result is in EAX. |
| 647 __ ret(); | 600 __ ret(); |
| 648 __ Bind(&fall_through); | 601 __ Bind(&fall_through); |
| 649 return false; | 602 return false; |
| 650 } | 603 } |
| 651 | 604 |
| 652 | 605 |
| 653 static bool Integer_bitAndFromInteger(Assembler* assembler) { | 606 bool Intrinsifier::Integer_bitAndFromInteger(Assembler* assembler) { |
| 654 Label fall_through; | 607 Label fall_through; |
| 655 TestBothArgumentsSmis(assembler, &fall_through); | 608 TestBothArgumentsSmis(assembler, &fall_through); |
| 656 __ movl(EBX, Address(ESP, + 2 * kWordSize)); | 609 __ movl(EBX, Address(ESP, + 2 * kWordSize)); |
| 657 __ andl(EAX, EBX); | 610 __ andl(EAX, EBX); |
| 658 // Result is in EAX. | 611 // Result is in EAX. |
| 659 __ ret(); | 612 __ ret(); |
| 660 __ Bind(&fall_through); | 613 __ Bind(&fall_through); |
| 661 return false; | 614 return false; |
| 662 } | 615 } |
| 663 | 616 |
| 664 | 617 |
| 665 static bool Integer_bitOrFromInteger(Assembler* assembler) { | 618 bool Intrinsifier::Integer_bitAnd(Assembler* assembler) { |
| 619 return Integer_bitAndFromInteger(assembler); |
| 620 } |
| 621 |
| 622 |
| 623 bool Intrinsifier::Integer_bitOrFromInteger(Assembler* assembler) { |
| 666 Label fall_through; | 624 Label fall_through; |
| 667 TestBothArgumentsSmis(assembler, &fall_through); | 625 TestBothArgumentsSmis(assembler, &fall_through); |
| 668 __ movl(EBX, Address(ESP, + 2 * kWordSize)); | 626 __ movl(EBX, Address(ESP, + 2 * kWordSize)); |
| 669 __ orl(EAX, EBX); | 627 __ orl(EAX, EBX); |
| 670 // Result is in EAX. | 628 // Result is in EAX. |
| 671 __ ret(); | 629 __ ret(); |
| 672 __ Bind(&fall_through); | 630 __ Bind(&fall_through); |
| 673 return false; | 631 return false; |
| 674 } | 632 } |
| 675 | 633 |
| 676 | 634 |
| 677 static bool Integer_bitXorFromInteger(Assembler* assembler) { | 635 bool Intrinsifier::Integer_bitOr(Assembler* assembler) { |
| 636 return Integer_bitOrFromInteger(assembler); |
| 637 } |
| 638 |
| 639 |
| 640 bool Intrinsifier::Integer_bitXorFromInteger(Assembler* assembler) { |
| 678 Label fall_through; | 641 Label fall_through; |
| 679 TestBothArgumentsSmis(assembler, &fall_through); | 642 TestBothArgumentsSmis(assembler, &fall_through); |
| 680 __ movl(EBX, Address(ESP, + 2 * kWordSize)); | 643 __ movl(EBX, Address(ESP, + 2 * kWordSize)); |
| 681 __ xorl(EAX, EBX); | 644 __ xorl(EAX, EBX); |
| 682 // Result is in EAX. | 645 // Result is in EAX. |
| 683 __ ret(); | 646 __ ret(); |
| 684 __ Bind(&fall_through); | 647 __ Bind(&fall_through); |
| 685 return false; | 648 return false; |
| 686 } | 649 } |
| 687 | 650 |
| 688 | 651 |
| 689 static bool Integer_shl(Assembler* assembler) { | 652 bool Intrinsifier::Integer_bitXor(Assembler* assembler) { |
| 653 return Integer_bitXorFromInteger(assembler); |
| 654 } |
| 655 |
| 656 |
| 657 bool Intrinsifier::Integer_shl(Assembler* assembler) { |
| 690 ASSERT(kSmiTagShift == 1); | 658 ASSERT(kSmiTagShift == 1); |
| 691 ASSERT(kSmiTag == 0); | 659 ASSERT(kSmiTag == 0); |
| 692 Label fall_through, overflow; | 660 Label fall_through, overflow; |
| 693 TestBothArgumentsSmis(assembler, &fall_through); | 661 TestBothArgumentsSmis(assembler, &fall_through); |
| 694 // Shift value is in EAX. Compare with tagged Smi. | 662 // Shift value is in EAX. Compare with tagged Smi. |
| 695 __ cmpl(EAX, Immediate(Smi::RawValue(Smi::kBits))); | 663 __ cmpl(EAX, Immediate(Smi::RawValue(Smi::kBits))); |
| 696 __ j(ABOVE_EQUAL, &fall_through, Assembler::kNearJump); | 664 __ j(ABOVE_EQUAL, &fall_through, Assembler::kNearJump); |
| 697 | 665 |
| 698 __ SmiUntag(EAX); | 666 __ SmiUntag(EAX); |
| 699 __ movl(ECX, EAX); // Shift amount must be in ECX. | 667 __ movl(ECX, EAX); // Shift amount must be in ECX. |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 750 __ LoadObject(EAX, bool_false); | 718 __ LoadObject(EAX, bool_false); |
| 751 __ ret(); | 719 __ ret(); |
| 752 __ Bind(&true_label); | 720 __ Bind(&true_label); |
| 753 __ LoadObject(EAX, bool_true); | 721 __ LoadObject(EAX, bool_true); |
| 754 __ ret(); | 722 __ ret(); |
| 755 __ Bind(&fall_through); | 723 __ Bind(&fall_through); |
| 756 return false; | 724 return false; |
| 757 } | 725 } |
| 758 | 726 |
| 759 | 727 |
| 760 static bool Integer_lessThan(Assembler* assembler) { | 728 bool Intrinsifier::Integer_lessThan(Assembler* assembler) { |
| 761 return CompareIntegers(assembler, LESS); | 729 return CompareIntegers(assembler, LESS); |
| 762 } | 730 } |
| 763 | 731 |
| 764 | 732 |
| 765 static bool Integer_greaterThan(Assembler* assembler) { | 733 bool Intrinsifier::Integer_greaterThanFromInt(Assembler* assembler) { |
| 734 return CompareIntegers(assembler, LESS); |
| 735 } |
| 736 |
| 737 |
| 738 bool Intrinsifier::Integer_greaterThan(Assembler* assembler) { |
| 766 return CompareIntegers(assembler, GREATER); | 739 return CompareIntegers(assembler, GREATER); |
| 767 } | 740 } |
| 768 | 741 |
| 769 | 742 |
| 770 static bool Integer_lessEqualThan(Assembler* assembler) { | 743 bool Intrinsifier::Integer_lessEqualThan(Assembler* assembler) { |
| 771 return CompareIntegers(assembler, LESS_EQUAL); | 744 return CompareIntegers(assembler, LESS_EQUAL); |
| 772 } | 745 } |
| 773 | 746 |
| 774 | 747 |
| 775 static bool Integer_greaterEqualThan(Assembler* assembler) { | 748 bool Intrinsifier::Integer_greaterEqualThan(Assembler* assembler) { |
| 776 return CompareIntegers(assembler, GREATER_EQUAL); | 749 return CompareIntegers(assembler, GREATER_EQUAL); |
| 777 } | 750 } |
| 778 | 751 |
| 779 | 752 |
| 780 // This is called for Smi, Mint and Bigint receivers. Bigints are not handled. | 753 // This is called for Smi, Mint and Bigint receivers. Bigints are not handled. |
| 781 static bool Integer_equalToInteger(Assembler* assembler) { | 754 bool Intrinsifier::Integer_equalToInteger(Assembler* assembler) { |
| 782 Label fall_through, true_label, check_for_mint; | 755 Label fall_through, true_label, check_for_mint; |
| 783 const Bool& bool_true = Bool::ZoneHandle(Bool::True()); | 756 const Bool& bool_true = Bool::ZoneHandle(Bool::True()); |
| 784 const Bool& bool_false = Bool::ZoneHandle(Bool::False()); | 757 const Bool& bool_false = Bool::ZoneHandle(Bool::False()); |
| 785 // For integer receiver '===' check first. | 758 // For integer receiver '===' check first. |
| 786 __ movl(EAX, Address(ESP, + 1 * kWordSize)); | 759 __ movl(EAX, Address(ESP, + 1 * kWordSize)); |
| 787 __ cmpl(EAX, Address(ESP, + 2 * kWordSize)); | 760 __ cmpl(EAX, Address(ESP, + 2 * kWordSize)); |
| 788 __ j(EQUAL, &true_label, Assembler::kNearJump); | 761 __ j(EQUAL, &true_label, Assembler::kNearJump); |
| 789 __ movl(EBX, Address(ESP, + 2 * kWordSize)); | 762 __ movl(EBX, Address(ESP, + 2 * kWordSize)); |
| 790 __ orl(EAX, EBX); | 763 __ orl(EAX, EBX); |
| 791 __ testl(EAX, Immediate(kSmiTagMask)); | 764 __ testl(EAX, Immediate(kSmiTagMask)); |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 827 __ j(NOT_ZERO, &fall_through); | 800 __ j(NOT_ZERO, &fall_through); |
| 828 __ LoadObject(EAX, bool_false); // Smi == Mint -> false. | 801 __ LoadObject(EAX, bool_false); // Smi == Mint -> false. |
| 829 __ ret(); | 802 __ ret(); |
| 830 // TODO(srdjan): Implement Mint == Mint comparison. | 803 // TODO(srdjan): Implement Mint == Mint comparison. |
| 831 | 804 |
| 832 __ Bind(&fall_through); | 805 __ Bind(&fall_through); |
| 833 return false; | 806 return false; |
| 834 } | 807 } |
| 835 | 808 |
| 836 | 809 |
| 837 static bool Integer_sar(Assembler* assembler) { | 810 bool Intrinsifier::Integer_equal(Assembler* assembler) { |
| 811 return Integer_equalToInteger(assembler); |
| 812 } |
| 813 |
| 814 |
| 815 bool Intrinsifier::Integer_sar(Assembler* assembler) { |
| 838 Label fall_through, shift_count_ok; | 816 Label fall_through, shift_count_ok; |
| 839 TestBothArgumentsSmis(assembler, &fall_through); | 817 TestBothArgumentsSmis(assembler, &fall_through); |
| 840 // Can destroy ECX since we are not falling through. | 818 // Can destroy ECX since we are not falling through. |
| 841 Immediate count_limit = Immediate(0x1F); | 819 Immediate count_limit = Immediate(0x1F); |
| 842 // Check that the count is not larger than what the hardware can handle. | 820 // Check that the count is not larger than what the hardware can handle. |
| 843 // For shifting right a Smi the result is the same for all numbers | 821 // For shifting right a Smi the result is the same for all numbers |
| 844 // >= count_limit. | 822 // >= count_limit. |
| 845 __ SmiUntag(EAX); | 823 __ SmiUntag(EAX); |
| 846 // Negative counts throw exception. | 824 // Negative counts throw exception. |
| 847 __ cmpl(EAX, Immediate(0)); | 825 __ cmpl(EAX, Immediate(0)); |
| 848 __ j(LESS, &fall_through, Assembler::kNearJump); | 826 __ j(LESS, &fall_through, Assembler::kNearJump); |
| 849 __ cmpl(EAX, count_limit); | 827 __ cmpl(EAX, count_limit); |
| 850 __ j(LESS_EQUAL, &shift_count_ok, Assembler::kNearJump); | 828 __ j(LESS_EQUAL, &shift_count_ok, Assembler::kNearJump); |
| 851 __ movl(EAX, count_limit); | 829 __ movl(EAX, count_limit); |
| 852 __ Bind(&shift_count_ok); | 830 __ Bind(&shift_count_ok); |
| 853 __ movl(ECX, EAX); // Shift amount must be in ECX. | 831 __ movl(ECX, EAX); // Shift amount must be in ECX. |
| 854 __ movl(EAX, Address(ESP, + 2 * kWordSize)); // Value. | 832 __ movl(EAX, Address(ESP, + 2 * kWordSize)); // Value. |
| 855 __ SmiUntag(EAX); // Value. | 833 __ SmiUntag(EAX); // Value. |
| 856 __ sarl(EAX, ECX); | 834 __ sarl(EAX, ECX); |
| 857 __ SmiTag(EAX); | 835 __ SmiTag(EAX); |
| 858 __ ret(); | 836 __ ret(); |
| 859 __ Bind(&fall_through); | 837 __ Bind(&fall_through); |
| 860 return false; | 838 return false; |
| 861 } | 839 } |
| 862 | 840 |
| 863 | 841 |
| 864 static bool Smi_bitNegate(Assembler* assembler) { | 842 bool Intrinsifier::Smi_bitNegate(Assembler* assembler) { |
| 865 Label fall_through; | 843 Label fall_through; |
| 866 __ movl(EAX, Address(ESP, + 1 * kWordSize)); // Index. | 844 __ movl(EAX, Address(ESP, + 1 * kWordSize)); // Index. |
| 867 __ testl(EAX, Immediate(kSmiTagMask)); | 845 __ testl(EAX, Immediate(kSmiTagMask)); |
| 868 __ j(NOT_ZERO, &fall_through, Assembler::kNearJump); // Non-smi. | 846 __ j(NOT_ZERO, &fall_through, Assembler::kNearJump); // Non-smi. |
| 869 __ notl(EAX); | 847 __ notl(EAX); |
| 870 __ andl(EAX, Immediate(~kSmiTagMask)); // Remove inverted smi-tag. | 848 __ andl(EAX, Immediate(~kSmiTagMask)); // Remove inverted smi-tag. |
| 871 __ ret(); | 849 __ ret(); |
| 872 __ Bind(&fall_through); | 850 __ Bind(&fall_through); |
| 873 return false; | 851 return false; |
| 874 } | 852 } |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 918 __ Bind(&is_smi); | 896 __ Bind(&is_smi); |
| 919 __ SmiUntag(EAX); | 897 __ SmiUntag(EAX); |
| 920 __ cvtsi2sd(XMM1, EAX); | 898 __ cvtsi2sd(XMM1, EAX); |
| 921 __ jmp(&double_op); | 899 __ jmp(&double_op); |
| 922 __ Bind(&fall_through); | 900 __ Bind(&fall_through); |
| 923 return false; | 901 return false; |
| 924 } | 902 } |
| 925 | 903 |
| 926 | 904 |
| 927 // arg0 is Double, arg1 is unknown. | 905 // arg0 is Double, arg1 is unknown. |
| 928 static bool Double_greaterThan(Assembler* assembler) { | 906 bool Intrinsifier::Double_greaterThan(Assembler* assembler) { |
| 929 return CompareDoubles(assembler, ABOVE); | 907 return CompareDoubles(assembler, ABOVE); |
| 930 } | 908 } |
| 931 | 909 |
| 932 | 910 |
| 933 // arg0 is Double, arg1 is unknown. | 911 // arg0 is Double, arg1 is unknown. |
| 934 static bool Double_greaterEqualThan(Assembler* assembler) { | 912 bool Intrinsifier::Double_greaterEqualThan(Assembler* assembler) { |
| 935 return CompareDoubles(assembler, ABOVE_EQUAL); | 913 return CompareDoubles(assembler, ABOVE_EQUAL); |
| 936 } | 914 } |
| 937 | 915 |
| 938 | 916 |
| 939 // arg0 is Double, arg1 is unknown. | 917 // arg0 is Double, arg1 is unknown. |
| 940 static bool Double_lessThan(Assembler* assembler) { | 918 bool Intrinsifier::Double_lessThan(Assembler* assembler) { |
| 941 return CompareDoubles(assembler, BELOW); | 919 return CompareDoubles(assembler, BELOW); |
| 942 } | 920 } |
| 943 | 921 |
| 944 | 922 |
| 945 // arg0 is Double, arg1 is unknown. | 923 // arg0 is Double, arg1 is unknown. |
| 946 static bool Double_equal(Assembler* assembler) { | 924 bool Intrinsifier::Double_equal(Assembler* assembler) { |
| 947 return CompareDoubles(assembler, EQUAL); | 925 return CompareDoubles(assembler, EQUAL); |
| 948 } | 926 } |
| 949 | 927 |
| 950 | 928 |
| 951 // arg0 is Double, arg1 is unknown. | 929 // arg0 is Double, arg1 is unknown. |
| 952 static bool Double_lessEqualThan(Assembler* assembler) { | 930 bool Intrinsifier::Double_lessEqualThan(Assembler* assembler) { |
| 953 return CompareDoubles(assembler, BELOW_EQUAL); | 931 return CompareDoubles(assembler, BELOW_EQUAL); |
| 954 } | 932 } |
| 955 | 933 |
| 956 | 934 |
| 957 static bool Double_toDouble(Assembler* assembler) { | 935 bool Intrinsifier::Double_toDouble(Assembler* assembler) { |
| 958 __ movl(EAX, Address(ESP, + 1 * kWordSize)); | 936 __ movl(EAX, Address(ESP, + 1 * kWordSize)); |
| 959 __ ret(); | 937 __ ret(); |
| 960 return true; | 938 return true; |
| 961 } | 939 } |
| 962 | 940 |
| 963 | 941 |
| 964 // Expects EAX to contain right argument, left argument is on stack. Left | 942 // Expects EAX to contain right argument, left argument is on stack. Left |
| 965 // argument is double, right argument is of unknown type. | 943 // argument is double, right argument is of unknown type. |
| 966 static bool DoubleArithmeticOperations(Assembler* assembler, Token::Kind kind) { | 944 static bool DoubleArithmeticOperations(Assembler* assembler, Token::Kind kind) { |
| 967 Label fall_through; | 945 Label fall_through; |
| (...skipping 17 matching lines...) Expand all Loading... |
| 985 EBX, // Class register. | 963 EBX, // Class register. |
| 986 &fall_through, | 964 &fall_through, |
| 987 EAX); // Result register. | 965 EAX); // Result register. |
| 988 __ movsd(FieldAddress(EAX, Double::value_offset()), XMM0); | 966 __ movsd(FieldAddress(EAX, Double::value_offset()), XMM0); |
| 989 __ ret(); | 967 __ ret(); |
| 990 __ Bind(&fall_through); | 968 __ Bind(&fall_through); |
| 991 return false; | 969 return false; |
| 992 } | 970 } |
| 993 | 971 |
| 994 | 972 |
| 995 static bool Double_add(Assembler* assembler) { | 973 bool Intrinsifier::Double_add(Assembler* assembler) { |
| 996 return DoubleArithmeticOperations(assembler, Token::kADD); | 974 return DoubleArithmeticOperations(assembler, Token::kADD); |
| 997 } | 975 } |
| 998 | 976 |
| 999 | 977 |
| 1000 static bool Double_mul(Assembler* assembler) { | 978 bool Intrinsifier::Double_mul(Assembler* assembler) { |
| 1001 return DoubleArithmeticOperations(assembler, Token::kMUL); | 979 return DoubleArithmeticOperations(assembler, Token::kMUL); |
| 1002 } | 980 } |
| 1003 | 981 |
| 1004 | 982 |
| 1005 static bool Double_sub(Assembler* assembler) { | 983 bool Intrinsifier::Double_sub(Assembler* assembler) { |
| 1006 return DoubleArithmeticOperations(assembler, Token::kSUB); | 984 return DoubleArithmeticOperations(assembler, Token::kSUB); |
| 1007 } | 985 } |
| 1008 | 986 |
| 1009 | 987 |
| 1010 static bool Double_div(Assembler* assembler) { | 988 bool Intrinsifier::Double_div(Assembler* assembler) { |
| 1011 return DoubleArithmeticOperations(assembler, Token::kDIV); | 989 return DoubleArithmeticOperations(assembler, Token::kDIV); |
| 1012 } | 990 } |
| 1013 | 991 |
| 1014 | 992 |
| 1015 // Left is double right is integer (bigint or Smi) | 993 // Left is double right is integer (bigint or Smi) |
| 1016 static bool Double_mulFromInteger(Assembler* assembler) { | 994 bool Intrinsifier::Double_mulFromInteger(Assembler* assembler) { |
| 1017 Label fall_through; | 995 Label fall_through; |
| 1018 // Only Smi-s allowed. | 996 // Only Smi-s allowed. |
| 1019 __ movl(EAX, Address(ESP, + 1 * kWordSize)); | 997 __ movl(EAX, Address(ESP, + 1 * kWordSize)); |
| 1020 __ testl(EAX, Immediate(kSmiTagMask)); | 998 __ testl(EAX, Immediate(kSmiTagMask)); |
| 1021 __ j(NOT_ZERO, &fall_through, Assembler::kNearJump); | 999 __ j(NOT_ZERO, &fall_through, Assembler::kNearJump); |
| 1022 // Is Smi. | 1000 // Is Smi. |
| 1023 __ SmiUntag(EAX); | 1001 __ SmiUntag(EAX); |
| 1024 __ cvtsi2sd(XMM1, EAX); | 1002 __ cvtsi2sd(XMM1, EAX); |
| 1025 __ movl(EAX, Address(ESP, + 2 * kWordSize)); | 1003 __ movl(EAX, Address(ESP, + 2 * kWordSize)); |
| 1026 __ movsd(XMM0, FieldAddress(EAX, Double::value_offset())); | 1004 __ movsd(XMM0, FieldAddress(EAX, Double::value_offset())); |
| 1027 __ mulsd(XMM0, XMM1); | 1005 __ mulsd(XMM0, XMM1); |
| 1028 const Class& double_class = Class::ZoneHandle( | 1006 const Class& double_class = Class::ZoneHandle( |
| 1029 Isolate::Current()->object_store()->double_class()); | 1007 Isolate::Current()->object_store()->double_class()); |
| 1030 __ LoadObject(EBX, double_class); | 1008 __ LoadObject(EBX, double_class); |
| 1031 AssemblerMacros::TryAllocate(assembler, | 1009 AssemblerMacros::TryAllocate(assembler, |
| 1032 double_class, | 1010 double_class, |
| 1033 EBX, // Class register. | 1011 EBX, // Class register. |
| 1034 &fall_through, | 1012 &fall_through, |
| 1035 EAX); // Result register. | 1013 EAX); // Result register. |
| 1036 __ movsd(FieldAddress(EAX, Double::value_offset()), XMM0); | 1014 __ movsd(FieldAddress(EAX, Double::value_offset()), XMM0); |
| 1037 __ ret(); | 1015 __ ret(); |
| 1038 __ Bind(&fall_through); | 1016 __ Bind(&fall_through); |
| 1039 return false; | 1017 return false; |
| 1040 } | 1018 } |
| 1041 | 1019 |
| 1042 | 1020 |
| 1043 static bool Double_fromInteger(Assembler* assembler) { | 1021 bool Intrinsifier::Double_fromInteger(Assembler* assembler) { |
| 1044 Label fall_through; | 1022 Label fall_through; |
| 1045 __ movl(EAX, Address(ESP, +1 * kWordSize)); | 1023 __ movl(EAX, Address(ESP, +1 * kWordSize)); |
| 1046 __ testl(EAX, Immediate(kSmiTagMask)); | 1024 __ testl(EAX, Immediate(kSmiTagMask)); |
| 1047 __ j(NOT_ZERO, &fall_through, Assembler::kNearJump); | 1025 __ j(NOT_ZERO, &fall_through, Assembler::kNearJump); |
| 1048 // Is Smi. | 1026 // Is Smi. |
| 1049 __ SmiUntag(EAX); | 1027 __ SmiUntag(EAX); |
| 1050 __ cvtsi2sd(XMM0, EAX); | 1028 __ cvtsi2sd(XMM0, EAX); |
| 1051 const Class& double_class = Class::ZoneHandle( | 1029 const Class& double_class = Class::ZoneHandle( |
| 1052 Isolate::Current()->object_store()->double_class()); | 1030 Isolate::Current()->object_store()->double_class()); |
| 1053 __ LoadObject(EBX, double_class); | 1031 __ LoadObject(EBX, double_class); |
| 1054 AssemblerMacros::TryAllocate(assembler, | 1032 AssemblerMacros::TryAllocate(assembler, |
| 1055 double_class, | 1033 double_class, |
| 1056 EBX, // Class register. | 1034 EBX, // Class register. |
| 1057 &fall_through, | 1035 &fall_through, |
| 1058 EAX); // Result register. | 1036 EAX); // Result register. |
| 1059 __ movsd(FieldAddress(EAX, Double::value_offset()), XMM0); | 1037 __ movsd(FieldAddress(EAX, Double::value_offset()), XMM0); |
| 1060 __ ret(); | 1038 __ ret(); |
| 1061 __ Bind(&fall_through); | 1039 __ Bind(&fall_through); |
| 1062 return false; | 1040 return false; |
| 1063 } | 1041 } |
| 1064 | 1042 |
| 1065 | 1043 |
| 1066 static bool Double_isNaN(Assembler* assembler) { | 1044 bool Intrinsifier::Double_isNaN(Assembler* assembler) { |
| 1067 const Bool& bool_true = Bool::ZoneHandle(Bool::True()); | 1045 const Bool& bool_true = Bool::ZoneHandle(Bool::True()); |
| 1068 const Bool& bool_false = Bool::ZoneHandle(Bool::False()); | 1046 const Bool& bool_false = Bool::ZoneHandle(Bool::False()); |
| 1069 Label is_true; | 1047 Label is_true; |
| 1070 __ movl(EAX, Address(ESP, +1 * kWordSize)); | 1048 __ movl(EAX, Address(ESP, +1 * kWordSize)); |
| 1071 __ movsd(XMM0, FieldAddress(EAX, Double::value_offset())); | 1049 __ movsd(XMM0, FieldAddress(EAX, Double::value_offset())); |
| 1072 __ comisd(XMM0, XMM0); | 1050 __ comisd(XMM0, XMM0); |
| 1073 __ j(PARITY_EVEN, &is_true, Assembler::kNearJump); // NaN -> true; | 1051 __ j(PARITY_EVEN, &is_true, Assembler::kNearJump); // NaN -> true; |
| 1074 __ LoadObject(EAX, bool_false); | 1052 __ LoadObject(EAX, bool_false); |
| 1075 __ ret(); | 1053 __ ret(); |
| 1076 __ Bind(&is_true); | 1054 __ Bind(&is_true); |
| 1077 __ LoadObject(EAX, bool_true); | 1055 __ LoadObject(EAX, bool_true); |
| 1078 __ ret(); | 1056 __ ret(); |
| 1079 return true; // Method is complete, no slow case. | 1057 return true; // Method is complete, no slow case. |
| 1080 } | 1058 } |
| 1081 | 1059 |
| 1082 | 1060 |
| 1083 static bool Double_isNegative(Assembler* assembler) { | 1061 bool Intrinsifier::Double_isNegative(Assembler* assembler) { |
| 1084 const Bool& bool_true = Bool::ZoneHandle(Bool::True()); | 1062 const Bool& bool_true = Bool::ZoneHandle(Bool::True()); |
| 1085 const Bool& bool_false = Bool::ZoneHandle(Bool::False()); | 1063 const Bool& bool_false = Bool::ZoneHandle(Bool::False()); |
| 1086 Label is_false, is_true, is_zero; | 1064 Label is_false, is_true, is_zero; |
| 1087 __ movl(EAX, Address(ESP, +1 * kWordSize)); | 1065 __ movl(EAX, Address(ESP, +1 * kWordSize)); |
| 1088 __ movsd(XMM0, FieldAddress(EAX, Double::value_offset())); | 1066 __ movsd(XMM0, FieldAddress(EAX, Double::value_offset())); |
| 1089 __ xorpd(XMM1, XMM1); // 0.0 -> XMM1. | 1067 __ xorpd(XMM1, XMM1); // 0.0 -> XMM1. |
| 1090 __ comisd(XMM0, XMM1); | 1068 __ comisd(XMM0, XMM1); |
| 1091 __ j(PARITY_EVEN, &is_false, Assembler::kNearJump); // NaN -> false. | 1069 __ j(PARITY_EVEN, &is_false, Assembler::kNearJump); // NaN -> false. |
| 1092 __ j(EQUAL, &is_zero, Assembler::kNearJump); // Check for negative zero. | 1070 __ j(EQUAL, &is_zero, Assembler::kNearJump); // Check for negative zero. |
| 1093 __ j(ABOVE_EQUAL, &is_false, Assembler::kNearJump); // >= 0 -> false. | 1071 __ j(ABOVE_EQUAL, &is_false, Assembler::kNearJump); // >= 0 -> false. |
| 1094 __ Bind(&is_true); | 1072 __ Bind(&is_true); |
| 1095 __ LoadObject(EAX, bool_true); | 1073 __ LoadObject(EAX, bool_true); |
| 1096 __ ret(); | 1074 __ ret(); |
| 1097 __ Bind(&is_false); | 1075 __ Bind(&is_false); |
| 1098 __ LoadObject(EAX, bool_false); | 1076 __ LoadObject(EAX, bool_false); |
| 1099 __ ret(); | 1077 __ ret(); |
| 1100 __ Bind(&is_zero); | 1078 __ Bind(&is_zero); |
| 1101 // Check for negative zero (get the sign bit). | 1079 // Check for negative zero (get the sign bit). |
| 1102 __ movmskpd(EAX, XMM0); | 1080 __ movmskpd(EAX, XMM0); |
| 1103 __ testl(EAX, Immediate(1)); | 1081 __ testl(EAX, Immediate(1)); |
| 1104 __ j(NOT_ZERO, &is_true, Assembler::kNearJump); | 1082 __ j(NOT_ZERO, &is_true, Assembler::kNearJump); |
| 1105 __ jmp(&is_false, Assembler::kNearJump); | 1083 __ jmp(&is_false, Assembler::kNearJump); |
| 1106 return true; // Method is complete, no slow case. | 1084 return true; // Method is complete, no slow case. |
| 1107 } | 1085 } |
| 1108 | 1086 |
| 1109 | 1087 |
| 1110 // Argument type is not known | 1088 // Argument type is not known |
| 1111 static bool Math_sqrt(Assembler* assembler) { | 1089 bool Intrinsifier::Math_sqrt(Assembler* assembler) { |
| 1112 Label fall_through, is_smi, double_op; | 1090 Label fall_through, is_smi, double_op; |
| 1113 TestLastArgumentIsDouble(assembler, &is_smi, &fall_through); | 1091 TestLastArgumentIsDouble(assembler, &is_smi, &fall_through); |
| 1114 // Argument is double and is in EAX, class in EBX. | 1092 // Argument is double and is in EAX, class in EBX. |
| 1115 __ movsd(XMM1, FieldAddress(EAX, Double::value_offset())); | 1093 __ movsd(XMM1, FieldAddress(EAX, Double::value_offset())); |
| 1116 __ Bind(&double_op); | 1094 __ Bind(&double_op); |
| 1117 __ sqrtsd(XMM0, XMM1); | 1095 __ sqrtsd(XMM0, XMM1); |
| 1118 const Class& double_class = Class::ZoneHandle( | 1096 const Class& double_class = Class::ZoneHandle( |
| 1119 Isolate::Current()->object_store()->double_class()); | 1097 Isolate::Current()->object_store()->double_class()); |
| 1120 __ LoadObject(EBX, double_class); | 1098 __ LoadObject(EBX, double_class); |
| 1121 AssemblerMacros::TryAllocate(assembler, | 1099 AssemblerMacros::TryAllocate(assembler, |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1173 __ jmp(&double_op); | 1151 __ jmp(&double_op); |
| 1174 | 1152 |
| 1175 __ Bind(&alloc_failed); | 1153 __ Bind(&alloc_failed); |
| 1176 __ ffree(0); | 1154 __ ffree(0); |
| 1177 __ fincstp(); | 1155 __ fincstp(); |
| 1178 | 1156 |
| 1179 __ Bind(&fall_through); | 1157 __ Bind(&fall_through); |
| 1180 } | 1158 } |
| 1181 | 1159 |
| 1182 | 1160 |
| 1183 static bool Math_sin(Assembler* assembler) { | 1161 bool Intrinsifier::Math_sin(Assembler* assembler) { |
| 1184 EmitTrigonometric(assembler, kSine); | 1162 EmitTrigonometric(assembler, kSine); |
| 1185 return false; // Compile method for slow case. | 1163 return false; // Compile method for slow case. |
| 1186 } | 1164 } |
| 1187 | 1165 |
| 1188 | 1166 |
| 1189 static bool Math_cos(Assembler* assembler) { | 1167 bool Intrinsifier::Math_cos(Assembler* assembler) { |
| 1190 EmitTrigonometric(assembler, kCosine); | 1168 EmitTrigonometric(assembler, kCosine); |
| 1191 return false; // Compile method for slow case. | 1169 return false; // Compile method for slow case. |
| 1192 } | 1170 } |
| 1193 | 1171 |
| 1194 | 1172 |
| 1195 // Identity comparison. | 1173 // Identity comparison. |
| 1196 static bool Object_equal(Assembler* assembler) { | 1174 bool Intrinsifier::Object_equal(Assembler* assembler) { |
| 1197 Label is_true; | 1175 Label is_true; |
| 1198 const Bool& bool_true = Bool::ZoneHandle(Bool::True()); | 1176 const Bool& bool_true = Bool::ZoneHandle(Bool::True()); |
| 1199 const Bool& bool_false = Bool::ZoneHandle(Bool::False()); | 1177 const Bool& bool_false = Bool::ZoneHandle(Bool::False()); |
| 1200 __ movl(EAX, Address(ESP, + 1 * kWordSize)); | 1178 __ movl(EAX, Address(ESP, + 1 * kWordSize)); |
| 1201 __ cmpl(EAX, Address(ESP, + 2 * kWordSize)); | 1179 __ cmpl(EAX, Address(ESP, + 2 * kWordSize)); |
| 1202 __ j(EQUAL, &is_true, Assembler::kNearJump); | 1180 __ j(EQUAL, &is_true, Assembler::kNearJump); |
| 1203 __ LoadObject(EAX, bool_false); | 1181 __ LoadObject(EAX, bool_false); |
| 1204 __ ret(); | 1182 __ ret(); |
| 1205 __ Bind(&is_true); | 1183 __ Bind(&is_true); |
| 1206 __ LoadObject(EAX, bool_true); | 1184 __ LoadObject(EAX, bool_true); |
| 1207 __ ret(); | 1185 __ ret(); |
| 1208 return true; | 1186 return true; |
| 1209 } | 1187 } |
| 1210 | 1188 |
| 1211 | 1189 |
| 1212 static const char* kFixedSizeArrayIteratorClassName = "FixedSizeArrayIterator"; | 1190 static const char* kFixedSizeArrayIteratorClassName = "FixedSizeArrayIterator"; |
| 1213 | 1191 |
| 1214 | 1192 |
| 1215 // Class 'FixedSizeArrayIterator': | 1193 // Class 'FixedSizeArrayIterator': |
| 1216 // T next() { | 1194 // T next() { |
| 1217 // return _array[_pos++]; | 1195 // return _array[_pos++]; |
| 1218 // } | 1196 // } |
| 1219 // Intrinsify: return _array[_pos++]; | 1197 // Intrinsify: return _array[_pos++]; |
| 1220 // TODO(srdjan): Throw a 'NoMoreElementsException' exception if the iterator | 1198 // TODO(srdjan): Throw a 'NoMoreElementsException' exception if the iterator |
| 1221 // has no more elements. | 1199 // has no more elements. |
| 1222 static bool FixedSizeArrayIterator_next(Assembler* assembler) { | 1200 bool Intrinsifier::FixedSizeArrayIterator_next(Assembler* assembler) { |
| 1223 Label fall_through; | 1201 Label fall_through; |
| 1224 intptr_t array_offset = | 1202 intptr_t array_offset = |
| 1225 GetOffsetForField(kFixedSizeArrayIteratorClassName, "_array"); | 1203 GetOffsetForField(kFixedSizeArrayIteratorClassName, "_array"); |
| 1226 intptr_t pos_offset = | 1204 intptr_t pos_offset = |
| 1227 GetOffsetForField(kFixedSizeArrayIteratorClassName, "_pos"); | 1205 GetOffsetForField(kFixedSizeArrayIteratorClassName, "_pos"); |
| 1228 ASSERT(array_offset >= 0 && pos_offset >= 0); | 1206 ASSERT(array_offset >= 0 && pos_offset >= 0); |
| 1229 // Receiver is not NULL. | 1207 // Receiver is not NULL. |
| 1230 __ movl(EAX, Address(ESP, + 1 * kWordSize)); // Receiver. | 1208 __ movl(EAX, Address(ESP, + 1 * kWordSize)); // Receiver. |
| 1231 __ movl(EBX, FieldAddress(EAX, pos_offset)); // Field _pos. | 1209 __ movl(EBX, FieldAddress(EAX, pos_offset)); // Field _pos. |
| 1232 // '_pos' cannot be greater than array length and therefore is always Smi. | 1210 // '_pos' cannot be greater than array length and therefore is always Smi. |
| (...skipping 21 matching lines...) Expand all Loading... |
| 1254 __ ret(); | 1232 __ ret(); |
| 1255 __ Bind(&fall_through); | 1233 __ Bind(&fall_through); |
| 1256 return false; | 1234 return false; |
| 1257 } | 1235 } |
| 1258 | 1236 |
| 1259 | 1237 |
| 1260 // Class 'FixedSizeArrayIterator': | 1238 // Class 'FixedSizeArrayIterator': |
| 1261 // bool hasNext() { | 1239 // bool hasNext() { |
| 1262 // return _length > _pos; | 1240 // return _length > _pos; |
| 1263 // } | 1241 // } |
| 1264 static bool FixedSizeArrayIterator_hasNext(Assembler* assembler) { | 1242 bool Intrinsifier::FixedSizeArrayIterator_hasNext(Assembler* assembler) { |
| 1265 Label fall_through, is_true; | 1243 Label fall_through, is_true; |
| 1266 const Bool& bool_true = Bool::ZoneHandle(Bool::True()); | 1244 const Bool& bool_true = Bool::ZoneHandle(Bool::True()); |
| 1267 const Bool& bool_false = Bool::ZoneHandle(Bool::False()); | 1245 const Bool& bool_false = Bool::ZoneHandle(Bool::False()); |
| 1268 intptr_t length_offset = | 1246 intptr_t length_offset = |
| 1269 GetOffsetForField(kFixedSizeArrayIteratorClassName, "_length"); | 1247 GetOffsetForField(kFixedSizeArrayIteratorClassName, "_length"); |
| 1270 intptr_t pos_offset = | 1248 intptr_t pos_offset = |
| 1271 GetOffsetForField(kFixedSizeArrayIteratorClassName, "_pos"); | 1249 GetOffsetForField(kFixedSizeArrayIteratorClassName, "_pos"); |
| 1272 __ movl(EAX, Address(ESP, + 1 * kWordSize)); // Receiver. | 1250 __ movl(EAX, Address(ESP, + 1 * kWordSize)); // Receiver. |
| 1273 __ movl(EBX, FieldAddress(EAX, length_offset)); // Field _length. | 1251 __ movl(EBX, FieldAddress(EAX, length_offset)); // Field _length. |
| 1274 __ movl(EAX, FieldAddress(EAX, pos_offset)); // Field _pos. | 1252 __ movl(EAX, FieldAddress(EAX, pos_offset)); // Field _pos. |
| 1275 __ movl(EDI, EAX); | 1253 __ movl(EDI, EAX); |
| 1276 __ orl(EDI, EBX); | 1254 __ orl(EDI, EBX); |
| 1277 __ testl(EDI, Immediate(kSmiTagMask)); | 1255 __ testl(EDI, Immediate(kSmiTagMask)); |
| 1278 __ j(NOT_ZERO, &fall_through, Assembler::kNearJump); // Non-smi _length. | 1256 __ j(NOT_ZERO, &fall_through, Assembler::kNearJump); // Non-smi _length. |
| 1279 __ cmpl(EBX, EAX); // _length > _pos. | 1257 __ cmpl(EBX, EAX); // _length > _pos. |
| 1280 __ j(GREATER, &is_true, Assembler::kNearJump); | 1258 __ j(GREATER, &is_true, Assembler::kNearJump); |
| 1281 __ LoadObject(EAX, bool_false); | 1259 __ LoadObject(EAX, bool_false); |
| 1282 __ ret(); | 1260 __ ret(); |
| 1283 __ Bind(&is_true); | 1261 __ Bind(&is_true); |
| 1284 __ LoadObject(EAX, bool_true); | 1262 __ LoadObject(EAX, bool_true); |
| 1285 __ ret(); | 1263 __ ret(); |
| 1286 __ Bind(&fall_through); | 1264 __ Bind(&fall_through); |
| 1287 return false; | 1265 return false; |
| 1288 } | 1266 } |
| 1289 | 1267 |
| 1290 | 1268 |
| 1291 static bool String_getLength(Assembler* assembler) { | 1269 bool Intrinsifier::String_getLength(Assembler* assembler) { |
| 1292 __ movl(EAX, Address(ESP, + 1 * kWordSize)); // String object. | 1270 __ movl(EAX, Address(ESP, + 1 * kWordSize)); // String object. |
| 1293 __ movl(EAX, FieldAddress(EAX, String::length_offset())); | 1271 __ movl(EAX, FieldAddress(EAX, String::length_offset())); |
| 1294 __ ret(); | 1272 __ ret(); |
| 1295 return true; | 1273 return true; |
| 1296 } | 1274 } |
| 1297 | 1275 |
| 1298 | 1276 |
| 1299 // TODO(srdjan): Implement for two and four byte strings as well. | 1277 // TODO(srdjan): Implement for two and four byte strings as well. |
| 1300 static bool String_charCodeAt(Assembler* assembler) { | 1278 bool Intrinsifier::String_charCodeAt(Assembler* assembler) { |
| 1301 ObjectStore* object_store = Isolate::Current()->object_store(); | 1279 ObjectStore* object_store = Isolate::Current()->object_store(); |
| 1302 Label fall_through; | 1280 Label fall_through; |
| 1303 __ movl(EBX, Address(ESP, + 1 * kWordSize)); // Index. | 1281 __ movl(EBX, Address(ESP, + 1 * kWordSize)); // Index. |
| 1304 __ movl(EAX, Address(ESP, + 2 * kWordSize)); // String. | 1282 __ movl(EAX, Address(ESP, + 2 * kWordSize)); // String. |
| 1305 __ testl(EBX, Immediate(kSmiTagMask)); | 1283 __ testl(EBX, Immediate(kSmiTagMask)); |
| 1306 __ j(NOT_ZERO, &fall_through, Assembler::kNearJump); // Non-smi index. | 1284 __ j(NOT_ZERO, &fall_through, Assembler::kNearJump); // Non-smi index. |
| 1307 // Range check. | 1285 // Range check. |
| 1308 __ cmpl(EBX, FieldAddress(EAX, String::length_offset())); | 1286 __ cmpl(EBX, FieldAddress(EAX, String::length_offset())); |
| 1309 // Runtime throws exception. | 1287 // Runtime throws exception. |
| 1310 __ j(ABOVE_EQUAL, &fall_through, Assembler::kNearJump); | 1288 __ j(ABOVE_EQUAL, &fall_through, Assembler::kNearJump); |
| 1311 __ movl(EDI, FieldAddress(EAX, Instance::class_offset())); | 1289 __ movl(EDI, FieldAddress(EAX, Instance::class_offset())); |
| 1312 __ CompareObject(EDI, | 1290 __ CompareObject(EDI, |
| 1313 Class::ZoneHandle(object_store->one_byte_string_class())); | 1291 Class::ZoneHandle(object_store->one_byte_string_class())); |
| 1314 __ j(NOT_EQUAL, &fall_through); | 1292 __ j(NOT_EQUAL, &fall_through); |
| 1315 __ SmiUntag(EBX); | 1293 __ SmiUntag(EBX); |
| 1316 __ movzxb(EAX, FieldAddress(EAX, EBX, TIMES_1, OneByteString::data_offset())); | 1294 __ movzxb(EAX, FieldAddress(EAX, EBX, TIMES_1, OneByteString::data_offset())); |
| 1317 __ SmiTag(EAX); | 1295 __ SmiTag(EAX); |
| 1318 __ ret(); | 1296 __ ret(); |
| 1319 __ Bind(&fall_through); | 1297 __ Bind(&fall_through); |
| 1320 return false; | 1298 return false; |
| 1321 } | 1299 } |
| 1322 | 1300 |
| 1323 | 1301 |
| 1324 static bool String_hashCode(Assembler* assembler) { | 1302 bool Intrinsifier::String_hashCode(Assembler* assembler) { |
| 1325 Label fall_through; | 1303 Label fall_through; |
| 1326 __ movl(EAX, Address(ESP, + 1 * kWordSize)); // String object. | 1304 __ movl(EAX, Address(ESP, + 1 * kWordSize)); // String object. |
| 1327 __ movl(EAX, FieldAddress(EAX, String::hash_offset())); | 1305 __ movl(EAX, FieldAddress(EAX, String::hash_offset())); |
| 1328 __ cmpl(EAX, Immediate(0)); | 1306 __ cmpl(EAX, Immediate(0)); |
| 1329 __ j(EQUAL, &fall_through, Assembler::kNearJump); | 1307 __ j(EQUAL, &fall_through, Assembler::kNearJump); |
| 1330 __ ret(); | 1308 __ ret(); |
| 1331 __ Bind(&fall_through); | 1309 __ Bind(&fall_through); |
| 1332 // Hash not yet computed. | 1310 // Hash not yet computed. |
| 1333 return false; | 1311 return false; |
| 1334 } | 1312 } |
| 1335 | 1313 |
| 1336 | 1314 |
| 1337 static bool String_isEmpty(Assembler* assembler) { | 1315 bool Intrinsifier::String_isEmpty(Assembler* assembler) { |
| 1338 Label is_true; | 1316 Label is_true; |
| 1339 const Bool& bool_true = Bool::ZoneHandle(Bool::True()); | 1317 const Bool& bool_true = Bool::ZoneHandle(Bool::True()); |
| 1340 const Bool& bool_false = Bool::ZoneHandle(Bool::False()); | 1318 const Bool& bool_false = Bool::ZoneHandle(Bool::False()); |
| 1341 // Get length. | 1319 // Get length. |
| 1342 __ movl(EAX, Address(ESP, + 1 * kWordSize)); // String object. | 1320 __ movl(EAX, Address(ESP, + 1 * kWordSize)); // String object. |
| 1343 __ movl(EAX, FieldAddress(EAX, String::length_offset())); | 1321 __ movl(EAX, FieldAddress(EAX, String::length_offset())); |
| 1344 __ cmpl(EAX, Immediate(Smi::RawValue(0))); | 1322 __ cmpl(EAX, Immediate(Smi::RawValue(0))); |
| 1345 __ j(EQUAL, &is_true, Assembler::kNearJump); | 1323 __ j(EQUAL, &is_true, Assembler::kNearJump); |
| 1346 __ LoadObject(EAX, bool_false); | 1324 __ LoadObject(EAX, bool_false); |
| 1347 __ ret(); | 1325 __ ret(); |
| 1348 __ Bind(&is_true); | 1326 __ Bind(&is_true); |
| 1349 __ LoadObject(EAX, bool_true); | 1327 __ LoadObject(EAX, bool_true); |
| 1350 __ ret(); | 1328 __ ret(); |
| 1351 return true; | 1329 return true; |
| 1352 } | 1330 } |
| 1353 | 1331 |
| 1354 #undef __ | 1332 #undef __ |
| 1355 | |
| 1356 | |
| 1357 static bool CompareNames(const char* test_name, const char* name) { | |
| 1358 if (strcmp(test_name, name) == 0) { | |
| 1359 return true; | |
| 1360 } | |
| 1361 if ((name[0] == '_') && (test_name[0] == '_')) { | |
| 1362 // Check if the private class is member of corelib and matches the | |
| 1363 // test_class_name. | |
| 1364 const Library& core_lib = Library::Handle(Library::CoreLibrary()); | |
| 1365 const Library& core_impl_lib = Library::Handle(Library::CoreImplLibrary()); | |
| 1366 String& test_str = String::Handle(String::New(test_name)); | |
| 1367 String& test_str_with_key = String::Handle(); | |
| 1368 test_str_with_key = | |
| 1369 String::Concat(test_str, String::Handle(core_lib.private_key())); | |
| 1370 if (strcmp(test_str_with_key.ToCString(), name) == 0) { | |
| 1371 return true; | |
| 1372 } | |
| 1373 test_str_with_key = | |
| 1374 String::Concat(test_str, String::Handle(core_impl_lib.private_key())); | |
| 1375 if (strcmp(test_str_with_key.ToCString(), name) == 0) { | |
| 1376 return true; | |
| 1377 } | |
| 1378 } | |
| 1379 return false; | |
| 1380 } | |
| 1381 | |
| 1382 | |
| 1383 // Returns true if the function matches function_name and class_name, with | |
| 1384 // special recognition of corelib private classes | |
| 1385 static bool TestFunction(const Function& function, | |
| 1386 const char* function_class_name, | |
| 1387 const char* function_name, | |
| 1388 const char* test_class_name, | |
| 1389 const char* test_function_name) { | |
| 1390 return CompareNames(test_class_name, function_class_name) && | |
| 1391 CompareNames(test_function_name, function_name); | |
| 1392 } | |
| 1393 | |
| 1394 | |
| 1395 bool Intrinsifier::Intrinsify(const Function& function, Assembler* assembler) { | |
| 1396 if (!FLAG_intrinsify) return false; | |
| 1397 const char* function_name = String::Handle(function.name()).ToCString(); | |
| 1398 const Class& function_class = Class::Handle(function.owner()); | |
| 1399 const char* class_name = String::Handle(function_class.Name()).ToCString(); | |
| 1400 // Only core library methods can be intrinsified. | |
| 1401 const Library& core_lib = Library::Handle(Library::CoreLibrary()); | |
| 1402 const Library& core_impl_lib = Library::Handle(Library::CoreImplLibrary()); | |
| 1403 if ((function_class.library() != core_lib.raw()) && | |
| 1404 (function_class.library() != core_impl_lib.raw())) { | |
| 1405 return false; | |
| 1406 } | |
| 1407 #define FIND_INTRINSICS(test_class_name, test_function_name, destination) \ | |
| 1408 if (TestFunction(function, \ | |
| 1409 class_name, function_name, \ | |
| 1410 #test_class_name, #test_function_name)) { \ | |
| 1411 return destination(assembler); \ | |
| 1412 } \ | |
| 1413 | |
| 1414 INTRINSIC_LIST(FIND_INTRINSICS); | |
| 1415 #undef FIND_INTRINSICS | |
| 1416 return false; | |
| 1417 } | |
| 1418 | |
| 1419 } // namespace dart | 1333 } // namespace dart |
| 1420 | 1334 |
| 1421 #endif // defined TARGET_ARCH_IA32 | 1335 #endif // defined TARGET_ARCH_IA32 |
| OLD | NEW |