| 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 | 
|---|