Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(151)

Side by Side Diff: runtime/vm/intrinsifier_arm.cc

Issue 22866025: Always generate full unoptimized code for intrinsified methods. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 7 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « runtime/vm/intrinsifier.cc ('k') | runtime/vm/intrinsifier_ia32.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_ARM. 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_ARM.
6 #if defined(TARGET_ARCH_ARM) 6 #if defined(TARGET_ARCH_ARM)
7 7
8 #include "vm/intrinsifier.h" 8 #include "vm/intrinsifier.h"
9 9
10 #include "vm/assembler.h" 10 #include "vm/assembler.h"
11 #include "vm/flow_graph_compiler.h" 11 #include "vm/flow_graph_compiler.h"
12 #include "vm/object.h" 12 #include "vm/object.h"
13 #include "vm/object_store.h" 13 #include "vm/object_store.h"
14 #include "vm/symbols.h" 14 #include "vm/symbols.h"
15 15
16 namespace dart { 16 namespace dart {
17 17
18 DECLARE_FLAG(bool, enable_type_checks); 18 DECLARE_FLAG(bool, enable_type_checks);
19 19
20 20
21 #define __ assembler-> 21 #define __ assembler->
22 22
23 bool Intrinsifier::ObjectArray_Allocate(Assembler* assembler) { 23 void Intrinsifier::ObjectArray_Allocate(Assembler* assembler) {
24 const intptr_t kTypeArgumentsOffset = 1 * kWordSize; 24 const intptr_t kTypeArgumentsOffset = 1 * kWordSize;
25 const intptr_t kArrayLengthOffset = 0 * kWordSize; 25 const intptr_t kArrayLengthOffset = 0 * kWordSize;
26 Label fall_through; 26 Label fall_through;
27 27
28 // Compute the size to be allocated, it is based on the array length 28 // Compute the size to be allocated, it is based on the array length
29 // and is computed as: 29 // and is computed as:
30 // RoundedAllocationSize((array_length * kwordSize) + sizeof(RawArray)). 30 // RoundedAllocationSize((array_length * kwordSize) + sizeof(RawArray)).
31 __ ldr(R3, Address(SP, kArrayLengthOffset)); // Array length. 31 __ ldr(R3, Address(SP, kArrayLengthOffset)); // Array length.
32 32
33 // Check that length is a positive Smi. 33 // Check that length is a positive Smi.
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after
116 116
117 Label init_loop; 117 Label init_loop;
118 __ Bind(&init_loop); 118 __ Bind(&init_loop);
119 __ cmp(R2, ShifterOperand(R1)); 119 __ cmp(R2, ShifterOperand(R1));
120 __ str(R3, Address(R2, 0), CC); 120 __ str(R3, Address(R2, 0), CC);
121 __ AddImmediate(R2, kWordSize, CC); 121 __ AddImmediate(R2, kWordSize, CC);
122 __ b(&init_loop, CC); 122 __ b(&init_loop, CC);
123 123
124 __ Ret(); // Returns the newly allocated object in R0. 124 __ Ret(); // Returns the newly allocated object in R0.
125 __ Bind(&fall_through); 125 __ Bind(&fall_through);
126 return false;
127 } 126 }
128 127
129 128
130 bool Intrinsifier::Array_getLength(Assembler* assembler) { 129 void Intrinsifier::Array_getLength(Assembler* assembler) {
131 __ ldr(R0, Address(SP, 0 * kWordSize)); 130 __ ldr(R0, Address(SP, 0 * kWordSize));
132 __ ldr(R0, FieldAddress(R0, Array::length_offset())); 131 __ ldr(R0, FieldAddress(R0, Array::length_offset()));
133 __ Ret(); 132 __ Ret();
134 return true;
135 } 133 }
136 134
137 135
138 bool Intrinsifier::ImmutableArray_getLength(Assembler* assembler) { 136 void Intrinsifier::ImmutableArray_getLength(Assembler* assembler) {
139 return Array_getLength(assembler); 137 return Array_getLength(assembler);
140 } 138 }
141 139
142 140
143 bool Intrinsifier::Array_getIndexed(Assembler* assembler) { 141 void Intrinsifier::Array_getIndexed(Assembler* assembler) {
144 Label fall_through; 142 Label fall_through;
145 143
146 __ ldr(R0, Address(SP, + 0 * kWordSize)); // Index 144 __ ldr(R0, Address(SP, + 0 * kWordSize)); // Index
147 __ ldr(R1, Address(SP, + 1 * kWordSize)); // Array 145 __ ldr(R1, Address(SP, + 1 * kWordSize)); // Array
148 146
149 __ tst(R0, ShifterOperand(kSmiTagMask)); 147 __ tst(R0, ShifterOperand(kSmiTagMask));
150 __ b(&fall_through, NE); // Index is not an smi, fall through 148 __ b(&fall_through, NE); // Index is not an smi, fall through
151 149
152 // range check 150 // range check
153 __ ldr(R6, FieldAddress(R1, Array::length_offset())); 151 __ ldr(R6, FieldAddress(R1, Array::length_offset()));
154 __ cmp(R0, ShifterOperand(R6)); 152 __ cmp(R0, ShifterOperand(R6));
155 153
156 ASSERT(kSmiTagShift == 1); 154 ASSERT(kSmiTagShift == 1);
157 // array element at R1 + R0*2 + Array::data_offset - 1 155 // array element at R1 + R0*2 + Array::data_offset - 1
158 __ add(R6, R1, ShifterOperand(R0, LSL, 1), CC); 156 __ add(R6, R1, ShifterOperand(R0, LSL, 1), CC);
159 __ ldr(R0, FieldAddress(R6, Array::data_offset()), CC); 157 __ ldr(R0, FieldAddress(R6, Array::data_offset()), CC);
160 __ bx(LR, CC); 158 __ bx(LR, CC);
161 __ Bind(&fall_through); 159 __ Bind(&fall_through);
162 return false;
163 } 160 }
164 161
165 162
166 bool Intrinsifier::ImmutableArray_getIndexed(Assembler* assembler) { 163 void Intrinsifier::ImmutableArray_getIndexed(Assembler* assembler) {
167 return Array_getIndexed(assembler); 164 return Array_getIndexed(assembler);
168 } 165 }
169 166
170 167
171 static intptr_t ComputeObjectArrayTypeArgumentsOffset() { 168 static intptr_t ComputeObjectArrayTypeArgumentsOffset() {
172 const Library& core_lib = Library::Handle(Library::CoreLibrary()); 169 const Library& core_lib = Library::Handle(Library::CoreLibrary());
173 const Class& cls = Class::Handle( 170 const Class& cls = Class::Handle(
174 core_lib.LookupClassAllowPrivate(Symbols::ObjectArray(), NULL)); 171 core_lib.LookupClassAllowPrivate(Symbols::ObjectArray(), NULL));
175 ASSERT(!cls.IsNull()); 172 ASSERT(!cls.IsNull());
176 ASSERT(cls.HasTypeArguments()); 173 ASSERT(cls.HasTypeArguments());
177 ASSERT(cls.NumTypeArguments() == 1); 174 ASSERT(cls.NumTypeArguments() == 1);
178 const intptr_t field_offset = cls.type_arguments_field_offset(); 175 const intptr_t field_offset = cls.type_arguments_field_offset();
179 ASSERT(field_offset != Class::kNoTypeArguments); 176 ASSERT(field_offset != Class::kNoTypeArguments);
180 return field_offset; 177 return field_offset;
181 } 178 }
182 179
183 180
184 // Intrinsify only for Smi value and index. Non-smi values need a store buffer 181 // Intrinsify only for Smi value and index. Non-smi values need a store buffer
185 // update. Array length is always a Smi. 182 // update. Array length is always a Smi.
186 bool Intrinsifier::Array_setIndexed(Assembler* assembler) { 183 void Intrinsifier::Array_setIndexed(Assembler* assembler) {
187 Label fall_through; 184 Label fall_through;
188 185
189 if (FLAG_enable_type_checks) { 186 if (FLAG_enable_type_checks) {
190 const intptr_t type_args_field_offset = 187 const intptr_t type_args_field_offset =
191 ComputeObjectArrayTypeArgumentsOffset(); 188 ComputeObjectArrayTypeArgumentsOffset();
192 // Inline simple tests (Smi, null), fallthrough if not positive. 189 // Inline simple tests (Smi, null), fallthrough if not positive.
193 const int32_t raw_null = reinterpret_cast<intptr_t>(Object::null()); 190 const int32_t raw_null = reinterpret_cast<intptr_t>(Object::null());
194 Label checked_ok; 191 Label checked_ok;
195 __ ldr(R2, Address(SP, 0 * kWordSize)); // Value. 192 __ ldr(R2, Address(SP, 0 * kWordSize)); // Value.
196 193
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
238 // Note that R1 is Smi, i.e, times 2. 235 // Note that R1 is Smi, i.e, times 2.
239 ASSERT(kSmiTagShift == 1); 236 ASSERT(kSmiTagShift == 1);
240 __ ldr(R2, Address(SP, 0 * kWordSize)); // Value. 237 __ ldr(R2, Address(SP, 0 * kWordSize)); // Value.
241 __ add(R1, R0, ShifterOperand(R1, LSL, 1)); // R1 is Smi. 238 __ add(R1, R0, ShifterOperand(R1, LSL, 1)); // R1 is Smi.
242 __ StoreIntoObject(R0, 239 __ StoreIntoObject(R0,
243 FieldAddress(R1, Array::data_offset()), 240 FieldAddress(R1, Array::data_offset()),
244 R2); 241 R2);
245 // Caller is responsible for preserving the value if necessary. 242 // Caller is responsible for preserving the value if necessary.
246 __ Ret(); 243 __ Ret();
247 __ Bind(&fall_through); 244 __ Bind(&fall_through);
248 return false;
249 } 245 }
250 246
251 247
252 // Allocate a GrowableObjectArray using the backing array specified. 248 // Allocate a GrowableObjectArray using the backing array specified.
253 // On stack: type argument (+1), data (+0). 249 // On stack: type argument (+1), data (+0).
254 bool Intrinsifier::GrowableArray_Allocate(Assembler* assembler) { 250 void Intrinsifier::GrowableArray_Allocate(Assembler* assembler) {
255 // The newly allocated object is returned in R0. 251 // The newly allocated object is returned in R0.
256 const intptr_t kTypeArgumentsOffset = 1 * kWordSize; 252 const intptr_t kTypeArgumentsOffset = 1 * kWordSize;
257 const intptr_t kArrayOffset = 0 * kWordSize; 253 const intptr_t kArrayOffset = 0 * kWordSize;
258 Label fall_through; 254 Label fall_through;
259 255
260 // Compute the size to be allocated, it is based on the array length 256 // Compute the size to be allocated, it is based on the array length
261 // and is computed as: 257 // and is computed as:
262 // RoundedAllocationSize(sizeof(RawGrowableObjectArray)) + 258 // RoundedAllocationSize(sizeof(RawGrowableObjectArray)) +
263 intptr_t fixed_size = GrowableObjectArray::InstanceSize(); 259 intptr_t fixed_size = GrowableObjectArray::InstanceSize();
264 260
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
307 R0, 303 R0,
308 FieldAddress(R0, GrowableObjectArray::type_arguments_offset()), 304 FieldAddress(R0, GrowableObjectArray::type_arguments_offset()),
309 R1); 305 R1);
310 306
311 // Set the length field in the growable array object to 0. 307 // Set the length field in the growable array object to 0.
312 __ LoadImmediate(R1, 0); 308 __ LoadImmediate(R1, 0);
313 __ str(R1, FieldAddress(R0, GrowableObjectArray::length_offset())); 309 __ str(R1, FieldAddress(R0, GrowableObjectArray::length_offset()));
314 __ Ret(); // Returns the newly allocated object in R0. 310 __ Ret(); // Returns the newly allocated object in R0.
315 311
316 __ Bind(&fall_through); 312 __ Bind(&fall_through);
317 return false;
318 } 313 }
319 314
320 315
321 bool Intrinsifier::GrowableArray_getLength(Assembler* assembler) { 316 void Intrinsifier::GrowableArray_getLength(Assembler* assembler) {
322 __ ldr(R0, Address(SP, 0 * kWordSize)); 317 __ ldr(R0, Address(SP, 0 * kWordSize));
323 __ ldr(R0, FieldAddress(R0, GrowableObjectArray::length_offset())); 318 __ ldr(R0, FieldAddress(R0, GrowableObjectArray::length_offset()));
324 __ Ret(); 319 __ Ret();
325 return true;
326 } 320 }
327 321
328 322
329 bool Intrinsifier::GrowableArray_getCapacity(Assembler* assembler) { 323 void Intrinsifier::GrowableArray_getCapacity(Assembler* assembler) {
330 __ ldr(R0, Address(SP, 0 * kWordSize)); 324 __ ldr(R0, Address(SP, 0 * kWordSize));
331 __ ldr(R0, FieldAddress(R0, GrowableObjectArray::data_offset())); 325 __ ldr(R0, FieldAddress(R0, GrowableObjectArray::data_offset()));
332 __ ldr(R0, FieldAddress(R0, Array::length_offset())); 326 __ ldr(R0, FieldAddress(R0, Array::length_offset()));
333 __ Ret(); 327 __ Ret();
334 return true;
335 } 328 }
336 329
337 330
338 bool Intrinsifier::GrowableArray_getIndexed(Assembler* assembler) { 331 void Intrinsifier::GrowableArray_getIndexed(Assembler* assembler) {
339 Label fall_through; 332 Label fall_through;
340 333
341 __ ldr(R0, Address(SP, + 0 * kWordSize)); // Index 334 __ ldr(R0, Address(SP, + 0 * kWordSize)); // Index
342 __ ldr(R1, Address(SP, + 1 * kWordSize)); // Array 335 __ ldr(R1, Address(SP, + 1 * kWordSize)); // Array
343 336
344 __ tst(R0, ShifterOperand(kSmiTagMask)); 337 __ tst(R0, ShifterOperand(kSmiTagMask));
345 __ b(&fall_through, NE); // Index is not an smi, fall through 338 __ b(&fall_through, NE); // Index is not an smi, fall through
346 339
347 // range check 340 // range check
348 __ ldr(R6, FieldAddress(R1, GrowableObjectArray::length_offset())); 341 __ ldr(R6, FieldAddress(R1, GrowableObjectArray::length_offset()));
349 __ cmp(R0, ShifterOperand(R6)); 342 __ cmp(R0, ShifterOperand(R6));
350 343
351 ASSERT(kSmiTagShift == 1); 344 ASSERT(kSmiTagShift == 1);
352 // array element at R6 + R0 * 2 + Array::data_offset - 1 345 // array element at R6 + R0 * 2 + Array::data_offset - 1
353 __ ldr(R6, FieldAddress(R1, GrowableObjectArray::data_offset()), CC); // data 346 __ ldr(R6, FieldAddress(R1, GrowableObjectArray::data_offset()), CC); // data
354 __ add(R6, R6, ShifterOperand(R0, LSL, 1), CC); 347 __ add(R6, R6, ShifterOperand(R0, LSL, 1), CC);
355 __ ldr(R0, FieldAddress(R6, Array::data_offset()), CC); 348 __ ldr(R0, FieldAddress(R6, Array::data_offset()), CC);
356 __ bx(LR, CC); 349 __ bx(LR, CC);
357 __ Bind(&fall_through); 350 __ Bind(&fall_through);
358 return false;
359 } 351 }
360 352
361 353
362 // Set value into growable object array at specified index. 354 // Set value into growable object array at specified index.
363 // On stack: growable array (+2), index (+1), value (+0). 355 // On stack: growable array (+2), index (+1), value (+0).
364 bool Intrinsifier::GrowableArray_setIndexed(Assembler* assembler) { 356 void Intrinsifier::GrowableArray_setIndexed(Assembler* assembler) {
365 if (FLAG_enable_type_checks) { 357 if (FLAG_enable_type_checks) {
366 return false; 358 return;
367 } 359 }
368 Label fall_through; 360 Label fall_through;
369 __ ldr(R1, Address(SP, 1 * kWordSize)); // Index. 361 __ ldr(R1, Address(SP, 1 * kWordSize)); // Index.
370 __ ldr(R0, Address(SP, 2 * kWordSize)); // GrowableArray. 362 __ ldr(R0, Address(SP, 2 * kWordSize)); // GrowableArray.
371 __ tst(R1, ShifterOperand(kSmiTagMask)); 363 __ tst(R1, ShifterOperand(kSmiTagMask));
372 __ b(&fall_through, NE); // Non-smi index. 364 __ b(&fall_through, NE); // Non-smi index.
373 // Range check using _length field. 365 // Range check using _length field.
374 __ ldr(R2, FieldAddress(R0, GrowableObjectArray::length_offset())); 366 __ ldr(R2, FieldAddress(R0, GrowableObjectArray::length_offset()));
375 __ cmp(R1, ShifterOperand(R2)); 367 __ cmp(R1, ShifterOperand(R2));
376 // Runtime throws exception. 368 // Runtime throws exception.
377 __ b(&fall_through, CS); 369 __ b(&fall_through, CS);
378 __ ldr(R0, FieldAddress(R0, GrowableObjectArray::data_offset())); // data. 370 __ ldr(R0, FieldAddress(R0, GrowableObjectArray::data_offset())); // data.
379 __ ldr(R2, Address(SP, 0 * kWordSize)); // Value. 371 __ ldr(R2, Address(SP, 0 * kWordSize)); // Value.
380 // Note that R1 is Smi, i.e, times 2. 372 // Note that R1 is Smi, i.e, times 2.
381 ASSERT(kSmiTagShift == 1); 373 ASSERT(kSmiTagShift == 1);
382 __ add(R1, R0, ShifterOperand(R1, LSL, 1)); 374 __ add(R1, R0, ShifterOperand(R1, LSL, 1));
383 __ StoreIntoObject(R0, 375 __ StoreIntoObject(R0,
384 FieldAddress(R1, Array::data_offset()), 376 FieldAddress(R1, Array::data_offset()),
385 R2); 377 R2);
386 __ Ret(); 378 __ Ret();
387 __ Bind(&fall_through); 379 __ Bind(&fall_through);
388 return false;
389 } 380 }
390 381
391 382
392 // Set length of growable object array. The length cannot 383 // Set length of growable object array. The length cannot
393 // be greater than the length of the data container. 384 // be greater than the length of the data container.
394 // On stack: growable array (+1), length (+0). 385 // On stack: growable array (+1), length (+0).
395 bool Intrinsifier::GrowableArray_setLength(Assembler* assembler) { 386 void Intrinsifier::GrowableArray_setLength(Assembler* assembler) {
396 __ ldr(R0, Address(SP, 1 * kWordSize)); // Growable array. 387 __ ldr(R0, Address(SP, 1 * kWordSize)); // Growable array.
397 __ ldr(R1, Address(SP, 0 * kWordSize)); // Length value. 388 __ ldr(R1, Address(SP, 0 * kWordSize)); // Length value.
398 __ tst(R1, ShifterOperand(kSmiTagMask)); // Check for Smi. 389 __ tst(R1, ShifterOperand(kSmiTagMask)); // Check for Smi.
399 __ str(R1, FieldAddress(R0, GrowableObjectArray::length_offset()), EQ); 390 __ str(R1, FieldAddress(R0, GrowableObjectArray::length_offset()), EQ);
400 __ bx(LR, EQ); 391 __ bx(LR, EQ);
401 // Fall through on non-Smi. 392 // Fall through on non-Smi.
402 return false;
403 } 393 }
404 394
405 395
406 // Set data of growable object array. 396 // Set data of growable object array.
407 // On stack: growable array (+1), data (+0). 397 // On stack: growable array (+1), data (+0).
408 bool Intrinsifier::GrowableArray_setData(Assembler* assembler) { 398 void Intrinsifier::GrowableArray_setData(Assembler* assembler) {
409 if (FLAG_enable_type_checks) { 399 if (FLAG_enable_type_checks) {
410 return false; 400 return;
411 } 401 }
412 Label fall_through; 402 Label fall_through;
413 __ ldr(R1, Address(SP, 0 * kWordSize)); // Data. 403 __ ldr(R1, Address(SP, 0 * kWordSize)); // Data.
414 // Check that data is an ObjectArray. 404 // Check that data is an ObjectArray.
415 __ tst(R1, ShifterOperand(kSmiTagMask)); 405 __ tst(R1, ShifterOperand(kSmiTagMask));
416 __ b(&fall_through, EQ); // Data is Smi. 406 __ b(&fall_through, EQ); // Data is Smi.
417 __ CompareClassId(R1, kArrayCid, R0); 407 __ CompareClassId(R1, kArrayCid, R0);
418 __ b(&fall_through, NE); 408 __ b(&fall_through, NE);
419 __ ldr(R0, Address(SP, 1 * kWordSize)); // Growable array. 409 __ ldr(R0, Address(SP, 1 * kWordSize)); // Growable array.
420 __ StoreIntoObject(R0, 410 __ StoreIntoObject(R0,
421 FieldAddress(R0, GrowableObjectArray::data_offset()), 411 FieldAddress(R0, GrowableObjectArray::data_offset()),
422 R1); 412 R1);
423 __ Ret(); 413 __ Ret();
424 __ Bind(&fall_through); 414 __ Bind(&fall_through);
425 return false;
426 } 415 }
427 416
428 417
429 // Add an element to growable array if it doesn't need to grow, otherwise 418 // Add an element to growable array if it doesn't need to grow, otherwise
430 // call into regular code. 419 // call into regular code.
431 // On stack: growable array (+1), value (+0). 420 // On stack: growable array (+1), value (+0).
432 bool Intrinsifier::GrowableArray_add(Assembler* assembler) { 421 void Intrinsifier::GrowableArray_add(Assembler* assembler) {
433 // In checked mode we need to type-check the incoming argument. 422 // In checked mode we need to type-check the incoming argument.
434 if (FLAG_enable_type_checks) return false; 423 if (FLAG_enable_type_checks) return;
435 Label fall_through; 424 Label fall_through;
436 // R0: Array. 425 // R0: Array.
437 __ ldr(R0, Address(SP, 1 * kWordSize)); 426 __ ldr(R0, Address(SP, 1 * kWordSize));
438 // R1: length. 427 // R1: length.
439 __ ldr(R1, FieldAddress(R0, GrowableObjectArray::length_offset())); 428 __ ldr(R1, FieldAddress(R0, GrowableObjectArray::length_offset()));
440 // R2: data. 429 // R2: data.
441 __ ldr(R2, FieldAddress(R0, GrowableObjectArray::data_offset())); 430 __ ldr(R2, FieldAddress(R0, GrowableObjectArray::data_offset()));
442 // R3: capacity. 431 // R3: capacity.
443 __ ldr(R3, FieldAddress(R2, Array::length_offset())); 432 __ ldr(R3, FieldAddress(R2, Array::length_offset()));
444 // Compare length with capacity. 433 // Compare length with capacity.
445 __ cmp(R1, ShifterOperand(R3)); 434 __ cmp(R1, ShifterOperand(R3));
446 __ b(&fall_through, EQ); // Must grow data. 435 __ b(&fall_through, EQ); // Must grow data.
447 const int32_t value_one = reinterpret_cast<int32_t>(Smi::New(1)); 436 const int32_t value_one = reinterpret_cast<int32_t>(Smi::New(1));
448 // len = len + 1; 437 // len = len + 1;
449 __ add(R3, R1, ShifterOperand(value_one)); 438 __ add(R3, R1, ShifterOperand(value_one));
450 __ str(R3, FieldAddress(R0, GrowableObjectArray::length_offset())); 439 __ str(R3, FieldAddress(R0, GrowableObjectArray::length_offset()));
451 __ ldr(R0, Address(SP, 0 * kWordSize)); // Value. 440 __ ldr(R0, Address(SP, 0 * kWordSize)); // Value.
452 ASSERT(kSmiTagShift == 1); 441 ASSERT(kSmiTagShift == 1);
453 __ add(R1, R2, ShifterOperand(R1, LSL, 1)); 442 __ add(R1, R2, ShifterOperand(R1, LSL, 1));
454 __ StoreIntoObject(R2, 443 __ StoreIntoObject(R2,
455 FieldAddress(R1, Array::data_offset()), 444 FieldAddress(R1, Array::data_offset()),
456 R0); 445 R0);
457 const int32_t raw_null = reinterpret_cast<int32_t>(Object::null()); 446 const int32_t raw_null = reinterpret_cast<int32_t>(Object::null());
458 __ LoadImmediate(R0, raw_null); 447 __ LoadImmediate(R0, raw_null);
459 __ Ret(); 448 __ Ret();
460 __ Bind(&fall_through); 449 __ Bind(&fall_through);
461 return false;
462 } 450 }
463 451
464 452
465 #define TYPED_ARRAY_ALLOCATION(type_name, cid, max_len, scale_shift) \ 453 #define TYPED_ARRAY_ALLOCATION(type_name, cid, max_len, scale_shift) \
466 Label fall_through; \ 454 Label fall_through; \
467 const intptr_t kArrayLengthStackOffset = 0 * kWordSize; \ 455 const intptr_t kArrayLengthStackOffset = 0 * kWordSize; \
468 __ ldr(R2, Address(SP, kArrayLengthStackOffset)); /* Array length. */ \ 456 __ ldr(R2, Address(SP, kArrayLengthStackOffset)); /* Array length. */ \
469 /* Check that length is a positive Smi. */ \ 457 /* Check that length is a positive Smi. */ \
470 /* R2: requested array length argument. */ \ 458 /* R2: requested array length argument. */ \
471 __ tst(R2, ShifterOperand(kSmiTagMask)); \ 459 __ tst(R2, ShifterOperand(kSmiTagMask)); \
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after
540 __ cmp(R2, ShifterOperand(R1)); \ 528 __ cmp(R2, ShifterOperand(R1)); \
541 __ str(R3, Address(R2, 0), CC); \ 529 __ str(R3, Address(R2, 0), CC); \
542 __ add(R2, R2, ShifterOperand(kWordSize), CC); \ 530 __ add(R2, R2, ShifterOperand(kWordSize), CC); \
543 __ b(&init_loop, CC); \ 531 __ b(&init_loop, CC); \
544 \ 532 \
545 __ Ret(); \ 533 __ Ret(); \
546 __ Bind(&fall_through); \ 534 __ Bind(&fall_through); \
547 535
548 536
549 // Gets the length of a TypedData. 537 // Gets the length of a TypedData.
550 bool Intrinsifier::TypedData_getLength(Assembler* assembler) { 538 void Intrinsifier::TypedData_getLength(Assembler* assembler) {
551 __ ldr(R0, Address(SP, 0 * kWordSize)); 539 __ ldr(R0, Address(SP, 0 * kWordSize));
552 __ ldr(R0, FieldAddress(R0, TypedData::length_offset())); 540 __ ldr(R0, FieldAddress(R0, TypedData::length_offset()));
553 __ Ret(); 541 __ Ret();
554 return true;
555 } 542 }
556 543
557 544
558 static int GetScaleFactor(intptr_t size) { 545 static int GetScaleFactor(intptr_t size) {
559 switch (size) { 546 switch (size) {
560 case 1: return 0; 547 case 1: return 0;
561 case 2: return 1; 548 case 2: return 1;
562 case 4: return 2; 549 case 4: return 2;
563 case 8: return 3; 550 case 8: return 3;
564 case 16: return 4; 551 case 16: return 4;
565 } 552 }
566 UNREACHABLE(); 553 UNREACHABLE();
567 return -1; 554 return -1;
568 }; 555 };
569 556
570 557
571 #define TYPED_DATA_ALLOCATOR(clazz) \ 558 #define TYPED_DATA_ALLOCATOR(clazz) \
572 bool Intrinsifier::TypedData_##clazz##_new(Assembler* assembler) { \ 559 void Intrinsifier::TypedData_##clazz##_new(Assembler* assembler) { \
573 intptr_t size = TypedData::ElementSizeInBytes(kTypedData##clazz##Cid); \ 560 intptr_t size = TypedData::ElementSizeInBytes(kTypedData##clazz##Cid); \
574 intptr_t max_len = TypedData::MaxElements(kTypedData##clazz##Cid); \ 561 intptr_t max_len = TypedData::MaxElements(kTypedData##clazz##Cid); \
575 int shift = GetScaleFactor(size); \ 562 int shift = GetScaleFactor(size); \
576 TYPED_ARRAY_ALLOCATION(TypedData, kTypedData##clazz##Cid, max_len, shift); \ 563 TYPED_ARRAY_ALLOCATION(TypedData, kTypedData##clazz##Cid, max_len, shift); \
577 return false; \
578 } \ 564 } \
579 bool Intrinsifier::TypedData_##clazz##_factory(Assembler* assembler) { \ 565 void Intrinsifier::TypedData_##clazz##_factory(Assembler* assembler) { \
580 intptr_t size = TypedData::ElementSizeInBytes(kTypedData##clazz##Cid); \ 566 intptr_t size = TypedData::ElementSizeInBytes(kTypedData##clazz##Cid); \
581 intptr_t max_len = TypedData::MaxElements(kTypedData##clazz##Cid); \ 567 intptr_t max_len = TypedData::MaxElements(kTypedData##clazz##Cid); \
582 int shift = GetScaleFactor(size); \ 568 int shift = GetScaleFactor(size); \
583 TYPED_ARRAY_ALLOCATION(TypedData, kTypedData##clazz##Cid, max_len, shift); \ 569 TYPED_ARRAY_ALLOCATION(TypedData, kTypedData##clazz##Cid, max_len, shift); \
584 return false; \
585 } 570 }
586 CLASS_LIST_TYPED_DATA(TYPED_DATA_ALLOCATOR) 571 CLASS_LIST_TYPED_DATA(TYPED_DATA_ALLOCATOR)
587 #undef TYPED_DATA_ALLOCATOR 572 #undef TYPED_DATA_ALLOCATOR
588 573
589 574
590 // Loads args from stack into R0 and R1 575 // Loads args from stack into R0 and R1
591 // Tests if they are smis, jumps to label not_smi if not. 576 // Tests if they are smis, jumps to label not_smi if not.
592 static void TestBothArgumentsSmis(Assembler* assembler, Label* not_smi) { 577 static void TestBothArgumentsSmis(Assembler* assembler, Label* not_smi) {
593 __ ldr(R0, Address(SP, + 0 * kWordSize)); 578 __ ldr(R0, Address(SP, + 0 * kWordSize));
594 __ ldr(R1, Address(SP, + 1 * kWordSize)); 579 __ ldr(R1, Address(SP, + 1 * kWordSize));
595 __ orr(TMP, R0, ShifterOperand(R1)); 580 __ orr(TMP, R0, ShifterOperand(R1));
596 __ tst(TMP, ShifterOperand(kSmiTagMask)); 581 __ tst(TMP, ShifterOperand(kSmiTagMask));
597 __ b(not_smi, NE); 582 __ b(not_smi, NE);
598 return; 583 return;
599 } 584 }
600 585
601 586
602 bool Intrinsifier::Integer_addFromInteger(Assembler* assembler) { 587 void Intrinsifier::Integer_addFromInteger(Assembler* assembler) {
603 Label fall_through; 588 Label fall_through;
604 TestBothArgumentsSmis(assembler, &fall_through); // Checks two smis. 589 TestBothArgumentsSmis(assembler, &fall_through); // Checks two smis.
605 __ adds(R0, R0, ShifterOperand(R1)); // Adds. 590 __ adds(R0, R0, ShifterOperand(R1)); // Adds.
606 __ bx(LR, VC); // Return if no overflow. 591 __ bx(LR, VC); // Return if no overflow.
607 // Otherwise fall through. 592 // Otherwise fall through.
608 __ Bind(&fall_through); 593 __ Bind(&fall_through);
609 return false;
610 } 594 }
611 595
612 596
613 bool Intrinsifier::Integer_add(Assembler* assembler) { 597 void Intrinsifier::Integer_add(Assembler* assembler) {
614 return Integer_addFromInteger(assembler); 598 return Integer_addFromInteger(assembler);
615 } 599 }
616 600
617 601
618 bool Intrinsifier::Integer_subFromInteger(Assembler* assembler) { 602 void Intrinsifier::Integer_subFromInteger(Assembler* assembler) {
619 Label fall_through; 603 Label fall_through;
620 TestBothArgumentsSmis(assembler, &fall_through); 604 TestBothArgumentsSmis(assembler, &fall_through);
621 __ subs(R0, R0, ShifterOperand(R1)); // Subtract. 605 __ subs(R0, R0, ShifterOperand(R1)); // Subtract.
622 __ bx(LR, VC); // Return if no overflow. 606 __ bx(LR, VC); // Return if no overflow.
623 // Otherwise fall through. 607 // Otherwise fall through.
624 __ Bind(&fall_through); 608 __ Bind(&fall_through);
625 return false;
626 } 609 }
627 610
628 611
629 bool Intrinsifier::Integer_sub(Assembler* assembler) { 612 void Intrinsifier::Integer_sub(Assembler* assembler) {
630 Label fall_through; 613 Label fall_through;
631 TestBothArgumentsSmis(assembler, &fall_through); 614 TestBothArgumentsSmis(assembler, &fall_through);
632 __ subs(R0, R1, ShifterOperand(R0)); // Subtract. 615 __ subs(R0, R1, ShifterOperand(R0)); // Subtract.
633 __ bx(LR, VC); // Return if no overflow. 616 __ bx(LR, VC); // Return if no overflow.
634 // Otherwise fall through. 617 // Otherwise fall through.
635 __ Bind(&fall_through); 618 __ Bind(&fall_through);
636 return false;
637 } 619 }
638 620
639 621
640 bool Intrinsifier::Integer_mulFromInteger(Assembler* assembler) { 622 void Intrinsifier::Integer_mulFromInteger(Assembler* assembler) {
641 Label fall_through; 623 Label fall_through;
642 624
643 TestBothArgumentsSmis(assembler, &fall_through); // checks two smis 625 TestBothArgumentsSmis(assembler, &fall_through); // checks two smis
644 __ SmiUntag(R0); // untags R6. only want result shifted by one 626 __ SmiUntag(R0); // untags R6. only want result shifted by one
645 627
646 __ smull(R0, IP, R0, R1); // IP:R0 <- R0 * R1. 628 __ smull(R0, IP, R0, R1); // IP:R0 <- R0 * R1.
647 __ cmp(IP, ShifterOperand(R0, ASR, 31)); 629 __ cmp(IP, ShifterOperand(R0, ASR, 31));
648 __ bx(LR, EQ); 630 __ bx(LR, EQ);
649 __ Bind(&fall_through); // Fall through on overflow. 631 __ Bind(&fall_through); // Fall through on overflow.
650 return false;
651 } 632 }
652 633
653 634
654 bool Intrinsifier::Integer_mul(Assembler* assembler) { 635 void Intrinsifier::Integer_mul(Assembler* assembler) {
655 return Integer_mulFromInteger(assembler); 636 return Integer_mulFromInteger(assembler);
656 } 637 }
657 638
658 639
659 // Optimizations: 640 // Optimizations:
660 // - result is 0 if: 641 // - result is 0 if:
661 // - left is 0 642 // - left is 0
662 // - left equals right 643 // - left equals right
663 // - result is left if 644 // - result is left if
664 // - left > 0 && left < right 645 // - left > 0 && left < right
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
705 686
706 // Implementation: 687 // Implementation:
707 // res = left % right; 688 // res = left % right;
708 // if (res < 0) { 689 // if (res < 0) {
709 // if (right < 0) { 690 // if (right < 0) {
710 // res = res - right; 691 // res = res - right;
711 // } else { 692 // } else {
712 // res = res + right; 693 // res = res + right;
713 // } 694 // }
714 // } 695 // }
715 bool Intrinsifier::Integer_moduloFromInteger(Assembler* assembler) { 696 void Intrinsifier::Integer_moduloFromInteger(Assembler* assembler) {
716 // Check to see if we have integer division 697 // Check to see if we have integer division
717 Label fall_through, subtract; 698 Label fall_through, subtract;
718 __ ldr(R1, Address(SP, + 0 * kWordSize)); 699 __ ldr(R1, Address(SP, + 0 * kWordSize));
719 __ ldr(R0, Address(SP, + 1 * kWordSize)); 700 __ ldr(R0, Address(SP, + 1 * kWordSize));
720 __ orr(TMP, R0, ShifterOperand(R1)); 701 __ orr(TMP, R0, ShifterOperand(R1));
721 __ tst(TMP, ShifterOperand(kSmiTagMask)); 702 __ tst(TMP, ShifterOperand(kSmiTagMask));
722 __ b(&fall_through, NE); 703 __ b(&fall_through, NE);
723 // R1: Tagged left (dividend). 704 // R1: Tagged left (dividend).
724 // R0: Tagged right (divisor). 705 // R0: Tagged right (divisor).
725 // Check if modulo by zero -> exception thrown in main function. 706 // Check if modulo by zero -> exception thrown in main function.
726 __ cmp(R0, ShifterOperand(0)); 707 __ cmp(R0, ShifterOperand(0));
727 __ b(&fall_through, EQ); 708 __ b(&fall_through, EQ);
728 EmitRemainderOperation(assembler); 709 EmitRemainderOperation(assembler);
729 // Untagged right in R0. Untagged remainder result in R1. 710 // Untagged right in R0. Untagged remainder result in R1.
730 711
731 __ cmp(R1, ShifterOperand(0)); 712 __ cmp(R1, ShifterOperand(0));
732 __ mov(R0, ShifterOperand(R1, LSL, 1), GE); // Tag and move result to R0. 713 __ mov(R0, ShifterOperand(R1, LSL, 1), GE); // Tag and move result to R0.
733 __ bx(LR, GE); 714 __ bx(LR, GE);
734 715
735 // Result is negative, adjust it. 716 // Result is negative, adjust it.
736 __ cmp(R0, ShifterOperand(0)); 717 __ cmp(R0, ShifterOperand(0));
737 __ sub(R0, R1, ShifterOperand(R0), LT); 718 __ sub(R0, R1, ShifterOperand(R0), LT);
738 __ add(R0, R1, ShifterOperand(R0), GE); 719 __ add(R0, R1, ShifterOperand(R0), GE);
739 __ SmiTag(R0); 720 __ SmiTag(R0);
740 __ Ret(); 721 __ Ret();
741 722
742 __ Bind(&fall_through); 723 __ Bind(&fall_through);
743 return false;
744 } 724 }
745 725
746 726
747 bool Intrinsifier::Integer_remainder(Assembler* assembler) { 727 void Intrinsifier::Integer_remainder(Assembler* assembler) {
748 // Check to see if we have integer division 728 // Check to see if we have integer division
749 Label fall_through; 729 Label fall_through;
750 TestBothArgumentsSmis(assembler, &fall_through); 730 TestBothArgumentsSmis(assembler, &fall_through);
751 // R1: Tagged left (dividend). 731 // R1: Tagged left (dividend).
752 // R0: Tagged right (divisor). 732 // R0: Tagged right (divisor).
753 // Check if modulo by zero -> exception thrown in main function. 733 // Check if modulo by zero -> exception thrown in main function.
754 __ cmp(R0, ShifterOperand(0)); 734 __ cmp(R0, ShifterOperand(0));
755 __ b(&fall_through, EQ); 735 __ b(&fall_through, EQ);
756 EmitRemainderOperation(assembler); 736 EmitRemainderOperation(assembler);
757 // Untagged remainder result in R1. 737 // Untagged remainder result in R1.
758 __ mov(R0, ShifterOperand(R1, LSL, 1)); // Tag result and return. 738 __ mov(R0, ShifterOperand(R1, LSL, 1)); // Tag result and return.
759 __ Ret(); 739 __ Ret();
760 740
761 __ Bind(&fall_through); 741 __ Bind(&fall_through);
762 return false;
763 } 742 }
764 743
765 744
766 bool Intrinsifier::Integer_truncDivide(Assembler* assembler) { 745 void Intrinsifier::Integer_truncDivide(Assembler* assembler) {
767 // Check to see if we have integer division 746 // Check to see if we have integer division
768 Label fall_through; 747 Label fall_through;
769 748
770 TestBothArgumentsSmis(assembler, &fall_through); 749 TestBothArgumentsSmis(assembler, &fall_through);
771 __ cmp(R0, ShifterOperand(0)); 750 __ cmp(R0, ShifterOperand(0));
772 __ b(&fall_through, EQ); // If b is 0, fall through. 751 __ b(&fall_through, EQ); // If b is 0, fall through.
773 752
774 __ SmiUntag(R0); 753 __ SmiUntag(R0);
775 __ SmiUntag(R1); 754 __ SmiUntag(R1);
776 755
777 __ IntegerDivide(R0, R1, R0, D1, D0); 756 __ IntegerDivide(R0, R1, R0, D1, D0);
778 757
779 // Check the corner case of dividing the 'MIN_SMI' with -1, in which case we 758 // Check the corner case of dividing the 'MIN_SMI' with -1, in which case we
780 // cannot tag the result. 759 // cannot tag the result.
781 __ CompareImmediate(R0, 0x40000000); 760 __ CompareImmediate(R0, 0x40000000);
782 __ SmiTag(R0, NE); // Not equal. Okay to tag and return. 761 __ SmiTag(R0, NE); // Not equal. Okay to tag and return.
783 __ bx(LR, NE); // Return. 762 __ bx(LR, NE); // Return.
784 __ Bind(&fall_through); 763 __ Bind(&fall_through);
785 return false;
786 } 764 }
787 765
788 766
789 bool Intrinsifier::Integer_negate(Assembler* assembler) { 767 void Intrinsifier::Integer_negate(Assembler* assembler) {
790 Label fall_through; 768 Label fall_through;
791 __ ldr(R0, Address(SP, + 0 * kWordSize)); // Grab first argument. 769 __ ldr(R0, Address(SP, + 0 * kWordSize)); // Grab first argument.
792 __ tst(R0, ShifterOperand(kSmiTagMask)); // Test for Smi. 770 __ tst(R0, ShifterOperand(kSmiTagMask)); // Test for Smi.
793 __ b(&fall_through, NE); 771 __ b(&fall_through, NE);
794 __ rsbs(R0, R0, ShifterOperand(0)); // R0 is a Smi. R0 <- 0 - R0. 772 __ rsbs(R0, R0, ShifterOperand(0)); // R0 is a Smi. R0 <- 0 - R0.
795 __ bx(LR, VC); // Return if there wasn't overflow, fall through otherwise. 773 __ bx(LR, VC); // Return if there wasn't overflow, fall through otherwise.
796 // R0 is not a Smi. Fall through. 774 // R0 is not a Smi. Fall through.
797 __ Bind(&fall_through); 775 __ Bind(&fall_through);
798 return false;
799 } 776 }
800 777
801 778
802 bool Intrinsifier::Integer_bitAndFromInteger(Assembler* assembler) { 779 void Intrinsifier::Integer_bitAndFromInteger(Assembler* assembler) {
803 Label fall_through; 780 Label fall_through;
804 781
805 TestBothArgumentsSmis(assembler, &fall_through); // checks two smis 782 TestBothArgumentsSmis(assembler, &fall_through); // checks two smis
806 __ and_(R0, R0, ShifterOperand(R1)); 783 __ and_(R0, R0, ShifterOperand(R1));
807 784
808 __ Ret(); 785 __ Ret();
809 __ Bind(&fall_through); 786 __ Bind(&fall_through);
810 return false;
811 } 787 }
812 788
813 789
814 bool Intrinsifier::Integer_bitAnd(Assembler* assembler) { 790 void Intrinsifier::Integer_bitAnd(Assembler* assembler) {
815 return Integer_bitAndFromInteger(assembler); 791 return Integer_bitAndFromInteger(assembler);
816 } 792 }
817 793
818 794
819 bool Intrinsifier::Integer_bitOrFromInteger(Assembler* assembler) { 795 void Intrinsifier::Integer_bitOrFromInteger(Assembler* assembler) {
820 Label fall_through; 796 Label fall_through;
821 797
822 TestBothArgumentsSmis(assembler, &fall_through); // checks two smis 798 TestBothArgumentsSmis(assembler, &fall_through); // checks two smis
823 __ orr(R0, R0, ShifterOperand(R1)); 799 __ orr(R0, R0, ShifterOperand(R1));
824 800
825 __ Ret(); 801 __ Ret();
826 __ Bind(&fall_through); 802 __ Bind(&fall_through);
827 return false;
828 } 803 }
829 804
830 805
831 bool Intrinsifier::Integer_bitOr(Assembler* assembler) { 806 void Intrinsifier::Integer_bitOr(Assembler* assembler) {
832 return Integer_bitOrFromInteger(assembler); 807 return Integer_bitOrFromInteger(assembler);
833 } 808 }
834 809
835 810
836 bool Intrinsifier::Integer_bitXorFromInteger(Assembler* assembler) { 811 void Intrinsifier::Integer_bitXorFromInteger(Assembler* assembler) {
837 Label fall_through; 812 Label fall_through;
838 813
839 TestBothArgumentsSmis(assembler, &fall_through); // checks two smis 814 TestBothArgumentsSmis(assembler, &fall_through); // checks two smis
840 __ eor(R0, R0, ShifterOperand(R1)); 815 __ eor(R0, R0, ShifterOperand(R1));
841 816
842 __ Ret(); 817 __ Ret();
843 __ Bind(&fall_through); 818 __ Bind(&fall_through);
844 return false;
845 } 819 }
846 820
847 821
848 bool Intrinsifier::Integer_bitXor(Assembler* assembler) { 822 void Intrinsifier::Integer_bitXor(Assembler* assembler) {
849 return Integer_bitXorFromInteger(assembler); 823 return Integer_bitXorFromInteger(assembler);
850 } 824 }
851 825
852 826
853 bool Intrinsifier::Integer_shl(Assembler* assembler) { 827 void Intrinsifier::Integer_shl(Assembler* assembler) {
854 ASSERT(kSmiTagShift == 1); 828 ASSERT(kSmiTagShift == 1);
855 ASSERT(kSmiTag == 0); 829 ASSERT(kSmiTag == 0);
856 Label fall_through; 830 Label fall_through;
857 831
858 TestBothArgumentsSmis(assembler, &fall_through); 832 TestBothArgumentsSmis(assembler, &fall_through);
859 __ CompareImmediate(R0, Smi::RawValue(Smi::kBits)); 833 __ CompareImmediate(R0, Smi::RawValue(Smi::kBits));
860 __ b(&fall_through, HI); 834 __ b(&fall_through, HI);
861 835
862 __ SmiUntag(R0); 836 __ SmiUntag(R0);
863 837
(...skipping 27 matching lines...) Expand all
891 865
892 const Class& mint_class = Class::Handle( 866 const Class& mint_class = Class::Handle(
893 Isolate::Current()->object_store()->mint_class()); 867 Isolate::Current()->object_store()->mint_class());
894 __ TryAllocate(mint_class, &fall_through, R0); 868 __ TryAllocate(mint_class, &fall_through, R0);
895 869
896 870
897 __ str(R1, FieldAddress(R0, Mint::value_offset())); 871 __ str(R1, FieldAddress(R0, Mint::value_offset()));
898 __ str(R7, FieldAddress(R0, Mint::value_offset() + kWordSize)); 872 __ str(R7, FieldAddress(R0, Mint::value_offset() + kWordSize));
899 __ Ret(); 873 __ Ret();
900 __ Bind(&fall_through); 874 __ Bind(&fall_through);
901 return false;
902 } 875 }
903 876
904 877
905 static void Get64SmiOrMint(Assembler* assembler, 878 static void Get64SmiOrMint(Assembler* assembler,
906 Register res_hi, 879 Register res_hi,
907 Register res_lo, 880 Register res_lo,
908 Register reg, 881 Register reg,
909 Label* not_smi_or_mint) { 882 Label* not_smi_or_mint) {
910 Label not_smi, done; 883 Label not_smi, done;
911 __ tst(reg, ShifterOperand(kSmiTagMask)); 884 __ tst(reg, ShifterOperand(kSmiTagMask));
(...skipping 10 matching lines...) Expand all
922 __ b(not_smi_or_mint, NE); 895 __ b(not_smi_or_mint, NE);
923 896
924 // Mint. 897 // Mint.
925 __ ldr(res_lo, FieldAddress(reg, Mint::value_offset())); 898 __ ldr(res_lo, FieldAddress(reg, Mint::value_offset()));
926 __ ldr(res_hi, FieldAddress(reg, Mint::value_offset() + kWordSize)); 899 __ ldr(res_hi, FieldAddress(reg, Mint::value_offset() + kWordSize));
927 __ Bind(&done); 900 __ Bind(&done);
928 return; 901 return;
929 } 902 }
930 903
931 904
932 static bool CompareIntegers(Assembler* assembler, Condition true_condition) { 905 static void CompareIntegers(Assembler* assembler, Condition true_condition) {
933 Label try_mint_smi, is_true, is_false, drop_two_fall_through, fall_through; 906 Label try_mint_smi, is_true, is_false, drop_two_fall_through, fall_through;
934 TestBothArgumentsSmis(assembler, &try_mint_smi); 907 TestBothArgumentsSmis(assembler, &try_mint_smi);
935 // R0 contains the right argument. R1 contains left argument 908 // R0 contains the right argument. R1 contains left argument
936 909
937 __ cmp(R1, ShifterOperand(R0)); 910 __ cmp(R1, ShifterOperand(R0));
938 __ b(&is_true, true_condition); 911 __ b(&is_true, true_condition);
939 __ Bind(&is_false); 912 __ Bind(&is_false);
940 __ LoadObject(R0, Bool::False()); 913 __ LoadObject(R0, Bool::False());
941 __ Ret(); 914 __ Ret();
942 __ Bind(&is_true); 915 __ Bind(&is_true);
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
975 948
976 __ cmp(R3, ShifterOperand(R7)); // Compare left hi, right high. 949 __ cmp(R3, ShifterOperand(R7)); // Compare left hi, right high.
977 __ b(&is_false, hi_false_cond); 950 __ b(&is_false, hi_false_cond);
978 __ b(&is_true, hi_true_cond); 951 __ b(&is_true, hi_true_cond);
979 __ cmp(R2, ShifterOperand(R6)); // Compare left lo, right lo. 952 __ cmp(R2, ShifterOperand(R6)); // Compare left lo, right lo.
980 __ b(&is_false, lo_false_cond); 953 __ b(&is_false, lo_false_cond);
981 // Else is true. 954 // Else is true.
982 __ b(&is_true); 955 __ b(&is_true);
983 956
984 __ Bind(&fall_through); 957 __ Bind(&fall_through);
985 return false;
986 } 958 }
987 959
988 960
989 bool Intrinsifier::Integer_greaterThanFromInt(Assembler* assembler) { 961 void Intrinsifier::Integer_greaterThanFromInt(Assembler* assembler) {
990 return CompareIntegers(assembler, LT); 962 return CompareIntegers(assembler, LT);
991 } 963 }
992 964
993 965
994 bool Intrinsifier::Integer_lessThan(Assembler* assembler) { 966 void Intrinsifier::Integer_lessThan(Assembler* assembler) {
995 return Integer_greaterThanFromInt(assembler); 967 return Integer_greaterThanFromInt(assembler);
996 } 968 }
997 969
998 970
999 bool Intrinsifier::Integer_greaterThan(Assembler* assembler) { 971 void Intrinsifier::Integer_greaterThan(Assembler* assembler) {
1000 return CompareIntegers(assembler, GT); 972 return CompareIntegers(assembler, GT);
1001 } 973 }
1002 974
1003 975
1004 bool Intrinsifier::Integer_lessEqualThan(Assembler* assembler) { 976 void Intrinsifier::Integer_lessEqualThan(Assembler* assembler) {
1005 return CompareIntegers(assembler, LE); 977 return CompareIntegers(assembler, LE);
1006 } 978 }
1007 979
1008 980
1009 bool Intrinsifier::Integer_greaterEqualThan(Assembler* assembler) { 981 void Intrinsifier::Integer_greaterEqualThan(Assembler* assembler) {
1010 return CompareIntegers(assembler, GE); 982 return CompareIntegers(assembler, GE);
1011 } 983 }
1012 984
1013 985
1014 // This is called for Smi, Mint and Bigint receivers. The right argument 986 // This is called for Smi, Mint and Bigint receivers. The right argument
1015 // can be Smi, Mint, Bigint or double. 987 // can be Smi, Mint, Bigint or double.
1016 bool Intrinsifier::Integer_equalToInteger(Assembler* assembler) { 988 void Intrinsifier::Integer_equalToInteger(Assembler* assembler) {
1017 Label fall_through, true_label, check_for_mint; 989 Label fall_through, true_label, check_for_mint;
1018 // For integer receiver '===' check first. 990 // For integer receiver '===' check first.
1019 __ ldr(R0, Address(SP, 0 * kWordSize)); 991 __ ldr(R0, Address(SP, 0 * kWordSize));
1020 __ ldr(R1, Address(SP, 1 * kWordSize)); 992 __ ldr(R1, Address(SP, 1 * kWordSize));
1021 __ cmp(R0, ShifterOperand(R1)); 993 __ cmp(R0, ShifterOperand(R1));
1022 __ b(&true_label, EQ); 994 __ b(&true_label, EQ);
1023 995
1024 __ orr(R2, R0, ShifterOperand(R1)); 996 __ orr(R2, R0, ShifterOperand(R1));
1025 __ tst(R2, ShifterOperand(kSmiTagMask)); 997 __ tst(R2, ShifterOperand(kSmiTagMask));
1026 __ b(&check_for_mint, NE); // If R0 or R1 is not a smi do Mint checks. 998 __ b(&check_for_mint, NE); // If R0 or R1 is not a smi do Mint checks.
(...skipping 27 matching lines...) Expand all
1054 __ CompareClassId(R1, kMintCid, R2); 1026 __ CompareClassId(R1, kMintCid, R2);
1055 __ b(&fall_through, NE); 1027 __ b(&fall_through, NE);
1056 // Receiver is Mint, return false if right is Smi. 1028 // Receiver is Mint, return false if right is Smi.
1057 __ tst(R0, ShifterOperand(kSmiTagMask)); 1029 __ tst(R0, ShifterOperand(kSmiTagMask));
1058 __ b(&fall_through, NE); 1030 __ b(&fall_through, NE);
1059 __ LoadObject(R0, Bool::False()); 1031 __ LoadObject(R0, Bool::False());
1060 __ Ret(); 1032 __ Ret();
1061 // TODO(srdjan): Implement Mint == Mint comparison. 1033 // TODO(srdjan): Implement Mint == Mint comparison.
1062 1034
1063 __ Bind(&fall_through); 1035 __ Bind(&fall_through);
1064 return false;
1065 } 1036 }
1066 1037
1067 1038
1068 bool Intrinsifier::Integer_equal(Assembler* assembler) { 1039 void Intrinsifier::Integer_equal(Assembler* assembler) {
1069 return Integer_equalToInteger(assembler); 1040 return Integer_equalToInteger(assembler);
1070 } 1041 }
1071 1042
1072 1043
1073 bool Intrinsifier::Integer_sar(Assembler* assembler) { 1044 void Intrinsifier::Integer_sar(Assembler* assembler) {
1074 Label fall_through; 1045 Label fall_through;
1075 1046
1076 TestBothArgumentsSmis(assembler, &fall_through); 1047 TestBothArgumentsSmis(assembler, &fall_through);
1077 // Shift amount in R0. Value to shift in R1. 1048 // Shift amount in R0. Value to shift in R1.
1078 1049
1079 // Fall through if shift amount is negative. 1050 // Fall through if shift amount is negative.
1080 __ SmiUntag(R0); 1051 __ SmiUntag(R0);
1081 __ CompareImmediate(R0, 0); 1052 __ CompareImmediate(R0, 0);
1082 __ b(&fall_through, LT); 1053 __ b(&fall_through, LT);
1083 1054
1084 // If shift amount is bigger than 31, set to 31. 1055 // If shift amount is bigger than 31, set to 31.
1085 __ CompareImmediate(R0, 0x1F); 1056 __ CompareImmediate(R0, 0x1F);
1086 __ LoadImmediate(R0, 0x1F, GT); 1057 __ LoadImmediate(R0, 0x1F, GT);
1087 __ SmiUntag(R1); 1058 __ SmiUntag(R1);
1088 __ mov(R0, ShifterOperand(R1, ASR, R0)); 1059 __ mov(R0, ShifterOperand(R1, ASR, R0));
1089 __ SmiTag(R0); 1060 __ SmiTag(R0);
1090 __ Ret(); 1061 __ Ret();
1091 __ Bind(&fall_through); 1062 __ Bind(&fall_through);
1092 return false;
1093 } 1063 }
1094 1064
1095 1065
1096 bool Intrinsifier::Smi_bitNegate(Assembler* assembler) { 1066 void Intrinsifier::Smi_bitNegate(Assembler* assembler) {
1097 __ ldr(R0, Address(SP, 0 * kWordSize)); 1067 __ ldr(R0, Address(SP, 0 * kWordSize));
1098 __ mvn(R0, ShifterOperand(R0)); 1068 __ mvn(R0, ShifterOperand(R0));
1099 __ bic(R0, R0, ShifterOperand(kSmiTagMask)); // Remove inverted smi-tag. 1069 __ bic(R0, R0, ShifterOperand(kSmiTagMask)); // Remove inverted smi-tag.
1100 __ Ret(); 1070 __ Ret();
1101 return true;
1102 } 1071 }
1103 1072
1104 1073
1105 // Check if the last argument is a double, jump to label 'is_smi' if smi 1074 // Check if the last argument is a double, jump to label 'is_smi' if smi
1106 // (easy to convert to double), otherwise jump to label 'not_double_smi', 1075 // (easy to convert to double), otherwise jump to label 'not_double_smi',
1107 // Returns the last argument in R0. 1076 // Returns the last argument in R0.
1108 static void TestLastArgumentIsDouble(Assembler* assembler, 1077 static void TestLastArgumentIsDouble(Assembler* assembler,
1109 Label* is_smi, 1078 Label* is_smi,
1110 Label* not_double_smi) { 1079 Label* not_double_smi) {
1111 __ ldr(R0, Address(SP, 0 * kWordSize)); 1080 __ ldr(R0, Address(SP, 0 * kWordSize));
1112 __ tst(R0, ShifterOperand(kSmiTagMask)); 1081 __ tst(R0, ShifterOperand(kSmiTagMask));
1113 __ b(is_smi, EQ); 1082 __ b(is_smi, EQ);
1114 __ CompareClassId(R0, kDoubleCid, R1); 1083 __ CompareClassId(R0, kDoubleCid, R1);
1115 __ b(not_double_smi, NE); 1084 __ b(not_double_smi, NE);
1116 // Fall through with Double in R0. 1085 // Fall through with Double in R0.
1117 } 1086 }
1118 1087
1119 1088
1120 // Both arguments on stack, arg0 (left) is a double, arg1 (right) is of unknown 1089 // Both arguments on stack, arg0 (left) is a double, arg1 (right) is of unknown
1121 // type. Return true or false object in the register R0. Any NaN argument 1090 // type. Return true or false object in the register R0. Any NaN argument
1122 // returns false. Any non-double arg1 causes control flow to fall through to the 1091 // returns false. Any non-double arg1 causes control flow to fall through to the
1123 // slow case (compiled method body). 1092 // slow case (compiled method body).
1124 static bool CompareDoubles(Assembler* assembler, Condition true_condition) { 1093 static void CompareDoubles(Assembler* assembler, Condition true_condition) {
1125 Label fall_through, is_smi, double_op; 1094 Label fall_through, is_smi, double_op;
1126 1095
1127 TestLastArgumentIsDouble(assembler, &is_smi, &fall_through); 1096 TestLastArgumentIsDouble(assembler, &is_smi, &fall_through);
1128 // Both arguments are double, right operand is in R0. 1097 // Both arguments are double, right operand is in R0.
1129 1098
1130 __ LoadDFromOffset(D1, R0, Double::value_offset() - kHeapObjectTag); 1099 __ LoadDFromOffset(D1, R0, Double::value_offset() - kHeapObjectTag);
1131 __ Bind(&double_op); 1100 __ Bind(&double_op);
1132 __ ldr(R0, Address(SP, 1 * kWordSize)); // Left argument. 1101 __ ldr(R0, Address(SP, 1 * kWordSize)); // Left argument.
1133 __ LoadDFromOffset(D0, R0, Double::value_offset() - kHeapObjectTag); 1102 __ LoadDFromOffset(D0, R0, Double::value_offset() - kHeapObjectTag);
1134 1103
1135 __ vcmpd(D0, D1); 1104 __ vcmpd(D0, D1);
1136 __ vmstat(); 1105 __ vmstat();
1137 __ LoadObject(R0, Bool::False()); 1106 __ LoadObject(R0, Bool::False());
1138 // Return false if D0 or D1 was NaN before checking true condition. 1107 // Return false if D0 or D1 was NaN before checking true condition.
1139 __ bx(LR, VS); 1108 __ bx(LR, VS);
1140 __ LoadObject(R0, Bool::True(), true_condition); 1109 __ LoadObject(R0, Bool::True(), true_condition);
1141 __ Ret(); 1110 __ Ret();
1142 1111
1143 __ Bind(&is_smi); // Convert R0 to a double. 1112 __ Bind(&is_smi); // Convert R0 to a double.
1144 __ SmiUntag(R0); 1113 __ SmiUntag(R0);
1145 __ vmovsr(S0, R0); 1114 __ vmovsr(S0, R0);
1146 __ vcvtdi(D1, S0); 1115 __ vcvtdi(D1, S0);
1147 __ b(&double_op); // Then do the comparison. 1116 __ b(&double_op); // Then do the comparison.
1148 __ Bind(&fall_through); 1117 __ Bind(&fall_through);
1149 return false;
1150 } 1118 }
1151 1119
1152 1120
1153 bool Intrinsifier::Double_greaterThan(Assembler* assembler) { 1121 void Intrinsifier::Double_greaterThan(Assembler* assembler) {
1154 return CompareDoubles(assembler, HI); 1122 return CompareDoubles(assembler, HI);
1155 } 1123 }
1156 1124
1157 1125
1158 bool Intrinsifier::Double_greaterEqualThan(Assembler* assembler) { 1126 void Intrinsifier::Double_greaterEqualThan(Assembler* assembler) {
1159 return CompareDoubles(assembler, CS); 1127 return CompareDoubles(assembler, CS);
1160 } 1128 }
1161 1129
1162 1130
1163 bool Intrinsifier::Double_lessThan(Assembler* assembler) { 1131 void Intrinsifier::Double_lessThan(Assembler* assembler) {
1164 return CompareDoubles(assembler, CC); 1132 return CompareDoubles(assembler, CC);
1165 } 1133 }
1166 1134
1167 1135
1168 bool Intrinsifier::Double_equal(Assembler* assembler) { 1136 void Intrinsifier::Double_equal(Assembler* assembler) {
1169 return CompareDoubles(assembler, EQ); 1137 return CompareDoubles(assembler, EQ);
1170 } 1138 }
1171 1139
1172 1140
1173 bool Intrinsifier::Double_lessEqualThan(Assembler* assembler) { 1141 void Intrinsifier::Double_lessEqualThan(Assembler* assembler) {
1174 return CompareDoubles(assembler, LS); 1142 return CompareDoubles(assembler, LS);
1175 } 1143 }
1176 1144
1177 1145
1178 // Expects left argument to be double (receiver). Right argument is unknown. 1146 // Expects left argument to be double (receiver). Right argument is unknown.
1179 // Both arguments are on stack. 1147 // Both arguments are on stack.
1180 static bool DoubleArithmeticOperations(Assembler* assembler, Token::Kind kind) { 1148 static void DoubleArithmeticOperations(Assembler* assembler, Token::Kind kind) {
1181 Label fall_through; 1149 Label fall_through;
1182 1150
1183 TestLastArgumentIsDouble(assembler, &fall_through, &fall_through); 1151 TestLastArgumentIsDouble(assembler, &fall_through, &fall_through);
1184 // Both arguments are double, right operand is in R0. 1152 // Both arguments are double, right operand is in R0.
1185 __ LoadDFromOffset(D1, R0, Double::value_offset() - kHeapObjectTag); 1153 __ LoadDFromOffset(D1, R0, Double::value_offset() - kHeapObjectTag);
1186 __ ldr(R0, Address(SP, 1 * kWordSize)); // Left argument. 1154 __ ldr(R0, Address(SP, 1 * kWordSize)); // Left argument.
1187 __ LoadDFromOffset(D0, R0, Double::value_offset() - kHeapObjectTag); 1155 __ LoadDFromOffset(D0, R0, Double::value_offset() - kHeapObjectTag);
1188 switch (kind) { 1156 switch (kind) {
1189 case Token::kADD: __ vaddd(D0, D0, D1); break; 1157 case Token::kADD: __ vaddd(D0, D0, D1); break;
1190 case Token::kSUB: __ vsubd(D0, D0, D1); break; 1158 case Token::kSUB: __ vsubd(D0, D0, D1); break;
1191 case Token::kMUL: __ vmuld(D0, D0, D1); break; 1159 case Token::kMUL: __ vmuld(D0, D0, D1); break;
1192 case Token::kDIV: __ vdivd(D0, D0, D1); break; 1160 case Token::kDIV: __ vdivd(D0, D0, D1); break;
1193 default: UNREACHABLE(); 1161 default: UNREACHABLE();
1194 } 1162 }
1195 const Class& double_class = Class::Handle( 1163 const Class& double_class = Class::Handle(
1196 Isolate::Current()->object_store()->double_class()); 1164 Isolate::Current()->object_store()->double_class());
1197 __ TryAllocate(double_class, &fall_through, R0); // Result register. 1165 __ TryAllocate(double_class, &fall_through, R0); // Result register.
1198 __ StoreDToOffset(D0, R0, Double::value_offset() - kHeapObjectTag); 1166 __ StoreDToOffset(D0, R0, Double::value_offset() - kHeapObjectTag);
1199 __ Ret(); 1167 __ Ret();
1200 __ Bind(&fall_through); 1168 __ Bind(&fall_through);
1201 return false;
1202 } 1169 }
1203 1170
1204 1171
1205 bool Intrinsifier::Double_add(Assembler* assembler) { 1172 void Intrinsifier::Double_add(Assembler* assembler) {
1206 return DoubleArithmeticOperations(assembler, Token::kADD); 1173 return DoubleArithmeticOperations(assembler, Token::kADD);
1207 } 1174 }
1208 1175
1209 1176
1210 bool Intrinsifier::Double_mul(Assembler* assembler) { 1177 void Intrinsifier::Double_mul(Assembler* assembler) {
1211 return DoubleArithmeticOperations(assembler, Token::kMUL); 1178 return DoubleArithmeticOperations(assembler, Token::kMUL);
1212 } 1179 }
1213 1180
1214 1181
1215 bool Intrinsifier::Double_sub(Assembler* assembler) { 1182 void Intrinsifier::Double_sub(Assembler* assembler) {
1216 return DoubleArithmeticOperations(assembler, Token::kSUB); 1183 return DoubleArithmeticOperations(assembler, Token::kSUB);
1217 } 1184 }
1218 1185
1219 1186
1220 bool Intrinsifier::Double_div(Assembler* assembler) { 1187 void Intrinsifier::Double_div(Assembler* assembler) {
1221 return DoubleArithmeticOperations(assembler, Token::kDIV); 1188 return DoubleArithmeticOperations(assembler, Token::kDIV);
1222 } 1189 }
1223 1190
1224 1191
1225 // Left is double right is integer (Bigint, Mint or Smi) 1192 // Left is double right is integer (Bigint, Mint or Smi)
1226 bool Intrinsifier::Double_mulFromInteger(Assembler* assembler) { 1193 void Intrinsifier::Double_mulFromInteger(Assembler* assembler) {
1227 Label fall_through; 1194 Label fall_through;
1228 // Only Smi-s allowed. 1195 // Only Smi-s allowed.
1229 __ ldr(R0, Address(SP, 0 * kWordSize)); 1196 __ ldr(R0, Address(SP, 0 * kWordSize));
1230 __ tst(R0, ShifterOperand(kSmiTagMask)); 1197 __ tst(R0, ShifterOperand(kSmiTagMask));
1231 __ b(&fall_through, NE); 1198 __ b(&fall_through, NE);
1232 // Is Smi. 1199 // Is Smi.
1233 __ SmiUntag(R0); 1200 __ SmiUntag(R0);
1234 __ vmovsr(S0, R0); 1201 __ vmovsr(S0, R0);
1235 __ vcvtdi(D1, S0); 1202 __ vcvtdi(D1, S0);
1236 __ ldr(R0, Address(SP, 1 * kWordSize)); 1203 __ ldr(R0, Address(SP, 1 * kWordSize));
1237 __ LoadDFromOffset(D0, R0, Double::value_offset() - kHeapObjectTag); 1204 __ LoadDFromOffset(D0, R0, Double::value_offset() - kHeapObjectTag);
1238 __ vmuld(D0, D0, D1); 1205 __ vmuld(D0, D0, D1);
1239 const Class& double_class = Class::Handle( 1206 const Class& double_class = Class::Handle(
1240 Isolate::Current()->object_store()->double_class()); 1207 Isolate::Current()->object_store()->double_class());
1241 __ TryAllocate(double_class, &fall_through, R0); // Result register. 1208 __ TryAllocate(double_class, &fall_through, R0); // Result register.
1242 __ StoreDToOffset(D0, R0, Double::value_offset() - kHeapObjectTag); 1209 __ StoreDToOffset(D0, R0, Double::value_offset() - kHeapObjectTag);
1243 __ Ret(); 1210 __ Ret();
1244 __ Bind(&fall_through); 1211 __ Bind(&fall_through);
1245 return false;
1246 } 1212 }
1247 1213
1248 1214
1249 bool Intrinsifier::Double_fromInteger(Assembler* assembler) { 1215 void Intrinsifier::Double_fromInteger(Assembler* assembler) {
1250 Label fall_through; 1216 Label fall_through;
1251 1217
1252 __ ldr(R0, Address(SP, 0 * kWordSize)); 1218 __ ldr(R0, Address(SP, 0 * kWordSize));
1253 __ tst(R0, ShifterOperand(kSmiTagMask)); 1219 __ tst(R0, ShifterOperand(kSmiTagMask));
1254 __ b(&fall_through, NE); 1220 __ b(&fall_through, NE);
1255 // Is Smi. 1221 // Is Smi.
1256 __ SmiUntag(R0); 1222 __ SmiUntag(R0);
1257 __ vmovsr(S0, R0); 1223 __ vmovsr(S0, R0);
1258 __ vcvtdi(D0, S0); 1224 __ vcvtdi(D0, S0);
1259 const Class& double_class = Class::Handle( 1225 const Class& double_class = Class::Handle(
1260 Isolate::Current()->object_store()->double_class()); 1226 Isolate::Current()->object_store()->double_class());
1261 __ TryAllocate(double_class, &fall_through, R0); // Result register. 1227 __ TryAllocate(double_class, &fall_through, R0); // Result register.
1262 __ StoreDToOffset(D0, R0, Double::value_offset() - kHeapObjectTag); 1228 __ StoreDToOffset(D0, R0, Double::value_offset() - kHeapObjectTag);
1263 __ Ret(); 1229 __ Ret();
1264 __ Bind(&fall_through); 1230 __ Bind(&fall_through);
1265 return false;
1266 } 1231 }
1267 1232
1268 1233
1269 bool Intrinsifier::Double_getIsNaN(Assembler* assembler) { 1234 void Intrinsifier::Double_getIsNaN(Assembler* assembler) {
1270 Label is_true; 1235 Label is_true;
1271 __ ldr(R0, Address(SP, 0 * kWordSize)); 1236 __ ldr(R0, Address(SP, 0 * kWordSize));
1272 __ LoadDFromOffset(D0, R0, Double::value_offset() - kHeapObjectTag); 1237 __ LoadDFromOffset(D0, R0, Double::value_offset() - kHeapObjectTag);
1273 __ vcmpd(D0, D0); 1238 __ vcmpd(D0, D0);
1274 __ vmstat(); 1239 __ vmstat();
1275 __ LoadObject(R0, Bool::False(), VC); 1240 __ LoadObject(R0, Bool::False(), VC);
1276 __ LoadObject(R0, Bool::True(), VS); 1241 __ LoadObject(R0, Bool::True(), VS);
1277 __ Ret(); 1242 __ Ret();
1278 return true;
1279 } 1243 }
1280 1244
1281 1245
1282 bool Intrinsifier::Double_getIsNegative(Assembler* assembler) { 1246 void Intrinsifier::Double_getIsNegative(Assembler* assembler) {
1283 Label is_false, is_true, is_zero; 1247 Label is_false, is_true, is_zero;
1284 __ ldr(R0, Address(SP, 0 * kWordSize)); 1248 __ ldr(R0, Address(SP, 0 * kWordSize));
1285 __ LoadDFromOffset(D0, R0, Double::value_offset() - kHeapObjectTag); 1249 __ LoadDFromOffset(D0, R0, Double::value_offset() - kHeapObjectTag);
1286 __ LoadDImmediate(D1, 0.0, R1); 1250 __ LoadDImmediate(D1, 0.0, R1);
1287 __ vcmpd(D0, D1); 1251 __ vcmpd(D0, D1);
1288 __ vmstat(); 1252 __ vmstat();
1289 __ b(&is_false, VS); // NaN -> false. 1253 __ b(&is_false, VS); // NaN -> false.
1290 __ b(&is_zero, EQ); // Check for negative zero. 1254 __ b(&is_zero, EQ); // Check for negative zero.
1291 __ b(&is_false, CS); // >= 0 -> false. 1255 __ b(&is_false, CS); // >= 0 -> false.
1292 1256
1293 __ Bind(&is_true); 1257 __ Bind(&is_true);
1294 __ LoadObject(R0, Bool::True()); 1258 __ LoadObject(R0, Bool::True());
1295 __ Ret(); 1259 __ Ret();
1296 1260
1297 __ Bind(&is_false); 1261 __ Bind(&is_false);
1298 __ LoadObject(R0, Bool::False()); 1262 __ LoadObject(R0, Bool::False());
1299 __ Ret(); 1263 __ Ret();
1300 1264
1301 __ Bind(&is_zero); 1265 __ Bind(&is_zero);
1302 // Check for negative zero by looking at the sign bit. 1266 // Check for negative zero by looking at the sign bit.
1303 __ vmovrrd(R0, R1, D0); // R1:R0 <- D0, so sign bit is in bit 31 of R1. 1267 __ vmovrrd(R0, R1, D0); // R1:R0 <- D0, so sign bit is in bit 31 of R1.
1304 __ mov(R1, ShifterOperand(R1, LSR, 31)); 1268 __ mov(R1, ShifterOperand(R1, LSR, 31));
1305 __ tst(R1, ShifterOperand(1)); 1269 __ tst(R1, ShifterOperand(1));
1306 __ b(&is_true, NE); // Sign bit set. 1270 __ b(&is_true, NE); // Sign bit set.
1307 __ b(&is_false); 1271 __ b(&is_false);
1308 return true;
1309 } 1272 }
1310 1273
1311 1274
1312 bool Intrinsifier::Double_toInt(Assembler* assembler) { 1275 void Intrinsifier::Double_toInt(Assembler* assembler) {
1313 Label fall_through; 1276 Label fall_through;
1314 1277
1315 __ ldr(R0, Address(SP, 0 * kWordSize)); 1278 __ ldr(R0, Address(SP, 0 * kWordSize));
1316 __ LoadDFromOffset(D0, R0, Double::value_offset() - kHeapObjectTag); 1279 __ LoadDFromOffset(D0, R0, Double::value_offset() - kHeapObjectTag);
1317 1280
1318 // Explicit NaN check, since ARM gives an FPU exception if you try to 1281 // Explicit NaN check, since ARM gives an FPU exception if you try to
1319 // convert NaN to an int. 1282 // convert NaN to an int.
1320 __ vcmpd(D0, D0); 1283 __ vcmpd(D0, D0);
1321 __ vmstat(); 1284 __ vmstat();
1322 __ b(&fall_through, VS); 1285 __ b(&fall_through, VS);
1323 1286
1324 __ vcvtid(S0, D0); 1287 __ vcvtid(S0, D0);
1325 __ vmovrs(R0, S0); 1288 __ vmovrs(R0, S0);
1326 // Overflow is signaled with minint. 1289 // Overflow is signaled with minint.
1327 // Check for overflow and that it fits into Smi. 1290 // Check for overflow and that it fits into Smi.
1328 __ CompareImmediate(R0, 0xC0000000); 1291 __ CompareImmediate(R0, 0xC0000000);
1329 __ b(&fall_through, MI); 1292 __ b(&fall_through, MI);
1330 __ SmiTag(R0); 1293 __ SmiTag(R0);
1331 __ Ret(); 1294 __ Ret();
1332 __ Bind(&fall_through); 1295 __ Bind(&fall_through);
1333 return false;
1334 } 1296 }
1335 1297
1336 1298
1337 bool Intrinsifier::Math_sqrt(Assembler* assembler) { 1299 void Intrinsifier::Math_sqrt(Assembler* assembler) {
1338 Label fall_through, is_smi, double_op; 1300 Label fall_through, is_smi, double_op;
1339 TestLastArgumentIsDouble(assembler, &is_smi, &fall_through); 1301 TestLastArgumentIsDouble(assembler, &is_smi, &fall_through);
1340 // Argument is double and is in R0. 1302 // Argument is double and is in R0.
1341 __ LoadDFromOffset(D1, R0, Double::value_offset() - kHeapObjectTag); 1303 __ LoadDFromOffset(D1, R0, Double::value_offset() - kHeapObjectTag);
1342 __ Bind(&double_op); 1304 __ Bind(&double_op);
1343 __ vsqrtd(D0, D1); 1305 __ vsqrtd(D0, D1);
1344 const Class& double_class = Class::Handle( 1306 const Class& double_class = Class::Handle(
1345 Isolate::Current()->object_store()->double_class()); 1307 Isolate::Current()->object_store()->double_class());
1346 __ TryAllocate(double_class, &fall_through, R0); // Result register. 1308 __ TryAllocate(double_class, &fall_through, R0); // Result register.
1347 __ StoreDToOffset(D0, R0, Double::value_offset() - kHeapObjectTag); 1309 __ StoreDToOffset(D0, R0, Double::value_offset() - kHeapObjectTag);
1348 __ Ret(); 1310 __ Ret();
1349 __ Bind(&is_smi); 1311 __ Bind(&is_smi);
1350 __ SmiUntag(R0); 1312 __ SmiUntag(R0);
1351 __ vmovsr(S0, R0); 1313 __ vmovsr(S0, R0);
1352 __ vcvtdi(D1, S0); 1314 __ vcvtdi(D1, S0);
1353 __ b(&double_op); 1315 __ b(&double_op);
1354 __ Bind(&fall_through); 1316 __ Bind(&fall_through);
1355 return false;
1356 } 1317 }
1357 1318
1358 1319
1359 bool Intrinsifier::Math_sin(Assembler* assembler) { 1320 void Intrinsifier::Math_sin(Assembler* assembler) {
1360 return false;
1361 } 1321 }
1362 1322
1363 1323
1364 bool Intrinsifier::Math_cos(Assembler* assembler) { 1324 void Intrinsifier::Math_cos(Assembler* assembler) {
1365 return false;
1366 } 1325 }
1367 1326
1368 1327
1369 // var state = ((_A * (_state[kSTATE_LO])) + _state[kSTATE_HI]) & _MASK_64; 1328 // var state = ((_A * (_state[kSTATE_LO])) + _state[kSTATE_HI]) & _MASK_64;
1370 // _state[kSTATE_LO] = state & _MASK_32; 1329 // _state[kSTATE_LO] = state & _MASK_32;
1371 // _state[kSTATE_HI] = state >> 32; 1330 // _state[kSTATE_HI] = state >> 32;
1372 bool Intrinsifier::Random_nextState(Assembler* assembler) { 1331 void Intrinsifier::Random_nextState(Assembler* assembler) {
1373 const Library& math_lib = Library::Handle(Library::MathLibrary()); 1332 const Library& math_lib = Library::Handle(Library::MathLibrary());
1374 ASSERT(!math_lib.IsNull()); 1333 ASSERT(!math_lib.IsNull());
1375 const Class& random_class = Class::Handle( 1334 const Class& random_class = Class::Handle(
1376 math_lib.LookupClassAllowPrivate(Symbols::_Random(), NULL)); 1335 math_lib.LookupClassAllowPrivate(Symbols::_Random(), NULL));
1377 ASSERT(!random_class.IsNull()); 1336 ASSERT(!random_class.IsNull());
1378 const Field& state_field = Field::ZoneHandle( 1337 const Field& state_field = Field::ZoneHandle(
1379 random_class.LookupInstanceField(Symbols::_state())); 1338 random_class.LookupInstanceField(Symbols::_state()));
1380 ASSERT(!state_field.IsNull()); 1339 ASSERT(!state_field.IsNull());
1381 const Field& random_A_field = Field::ZoneHandle( 1340 const Field& random_A_field = Field::ZoneHandle(
1382 random_class.LookupStaticField(Symbols::_A())); 1341 random_class.LookupStaticField(Symbols::_A()));
(...skipping 18 matching lines...) Expand all
1401 1360
1402 __ LoadImmediate(R0, a_int32_value); 1361 __ LoadImmediate(R0, a_int32_value);
1403 __ LoadFromOffset(kWord, R2, R1, disp_0 - kHeapObjectTag); 1362 __ LoadFromOffset(kWord, R2, R1, disp_0 - kHeapObjectTag);
1404 __ LoadFromOffset(kWord, R3, R1, disp_1 - kHeapObjectTag); 1363 __ LoadFromOffset(kWord, R3, R1, disp_1 - kHeapObjectTag);
1405 __ mov(R6, ShifterOperand(0)); // Zero extend unsigned _state[kSTATE_HI]. 1364 __ mov(R6, ShifterOperand(0)); // Zero extend unsigned _state[kSTATE_HI].
1406 // Unsigned 32-bit multiply and 64-bit accumulate into R6:R3. 1365 // Unsigned 32-bit multiply and 64-bit accumulate into R6:R3.
1407 __ umlal(R3, R6, R0, R2); // R6:R3 <- R6:R3 + R0 * R2. 1366 __ umlal(R3, R6, R0, R2); // R6:R3 <- R6:R3 + R0 * R2.
1408 __ StoreToOffset(kWord, R3, R1, disp_0 - kHeapObjectTag); 1367 __ StoreToOffset(kWord, R3, R1, disp_0 - kHeapObjectTag);
1409 __ StoreToOffset(kWord, R6, R1, disp_1 - kHeapObjectTag); 1368 __ StoreToOffset(kWord, R6, R1, disp_1 - kHeapObjectTag);
1410 __ Ret(); 1369 __ Ret();
1411 return true;
1412 } 1370 }
1413 1371
1414 1372
1415 bool Intrinsifier::Object_equal(Assembler* assembler) { 1373 void Intrinsifier::Object_equal(Assembler* assembler) {
1416 __ ldr(R0, Address(SP, 0 * kWordSize)); 1374 __ ldr(R0, Address(SP, 0 * kWordSize));
1417 __ ldr(R1, Address(SP, 1 * kWordSize)); 1375 __ ldr(R1, Address(SP, 1 * kWordSize));
1418 __ cmp(R0, ShifterOperand(R1)); 1376 __ cmp(R0, ShifterOperand(R1));
1419 __ LoadObject(R0, Bool::False(), NE); 1377 __ LoadObject(R0, Bool::False(), NE);
1420 __ LoadObject(R0, Bool::True(), EQ); 1378 __ LoadObject(R0, Bool::True(), EQ);
1421 __ Ret(); 1379 __ Ret();
1422 return true;
1423 } 1380 }
1424 1381
1425 1382
1426 bool Intrinsifier::String_getHashCode(Assembler* assembler) { 1383 void Intrinsifier::String_getHashCode(Assembler* assembler) {
1427 __ ldr(R0, Address(SP, 0 * kWordSize)); 1384 __ ldr(R0, Address(SP, 0 * kWordSize));
1428 __ ldr(R0, FieldAddress(R0, String::hash_offset())); 1385 __ ldr(R0, FieldAddress(R0, String::hash_offset()));
1429 __ cmp(R0, ShifterOperand(0)); 1386 __ cmp(R0, ShifterOperand(0));
1430 __ bx(LR, NE); // Hash not yet computed. 1387 __ bx(LR, NE); // Hash not yet computed.
1431 return false;
1432 } 1388 }
1433 1389
1434 1390
1435 bool Intrinsifier::String_getLength(Assembler* assembler) { 1391 void Intrinsifier::String_getLength(Assembler* assembler) {
1436 __ ldr(R0, Address(SP, 0 * kWordSize)); 1392 __ ldr(R0, Address(SP, 0 * kWordSize));
1437 __ ldr(R0, FieldAddress(R0, String::length_offset())); 1393 __ ldr(R0, FieldAddress(R0, String::length_offset()));
1438 __ Ret(); 1394 __ Ret();
1439 return true;
1440 } 1395 }
1441 1396
1442 1397
1443 bool Intrinsifier::String_codeUnitAt(Assembler* assembler) { 1398 void Intrinsifier::String_codeUnitAt(Assembler* assembler) {
1444 Label fall_through, try_two_byte_string; 1399 Label fall_through, try_two_byte_string;
1445 1400
1446 __ ldr(R1, Address(SP, 0 * kWordSize)); // Index. 1401 __ ldr(R1, Address(SP, 0 * kWordSize)); // Index.
1447 __ ldr(R0, Address(SP, 1 * kWordSize)); // String. 1402 __ ldr(R0, Address(SP, 1 * kWordSize)); // String.
1448 __ tst(R1, ShifterOperand(kSmiTagMask)); 1403 __ tst(R1, ShifterOperand(kSmiTagMask));
1449 __ b(&fall_through, NE); // Index is not a Smi. 1404 __ b(&fall_through, NE); // Index is not a Smi.
1450 // Range check. 1405 // Range check.
1451 __ ldr(R2, FieldAddress(R0, String::length_offset())); 1406 __ ldr(R2, FieldAddress(R0, String::length_offset()));
1452 __ cmp(R1, ShifterOperand(R2)); 1407 __ cmp(R1, ShifterOperand(R2));
1453 __ b(&fall_through, CS); // Runtime throws exception. 1408 __ b(&fall_through, CS); // Runtime throws exception.
1454 __ CompareClassId(R0, kOneByteStringCid, R3); 1409 __ CompareClassId(R0, kOneByteStringCid, R3);
1455 __ b(&try_two_byte_string, NE); 1410 __ b(&try_two_byte_string, NE);
1456 __ SmiUntag(R1); 1411 __ SmiUntag(R1);
1457 __ AddImmediate(R0, OneByteString::data_offset() - kHeapObjectTag); 1412 __ AddImmediate(R0, OneByteString::data_offset() - kHeapObjectTag);
1458 __ ldrb(R0, Address(R0, R1)); 1413 __ ldrb(R0, Address(R0, R1));
1459 __ SmiTag(R0); 1414 __ SmiTag(R0);
1460 __ Ret(); 1415 __ Ret();
1461 1416
1462 __ Bind(&try_two_byte_string); 1417 __ Bind(&try_two_byte_string);
1463 __ CompareClassId(R0, kTwoByteStringCid, R3); 1418 __ CompareClassId(R0, kTwoByteStringCid, R3);
1464 __ b(&fall_through, NE); 1419 __ b(&fall_through, NE);
1465 ASSERT(kSmiTagShift == 1); 1420 ASSERT(kSmiTagShift == 1);
1466 __ AddImmediate(R0, OneByteString::data_offset() - kHeapObjectTag); 1421 __ AddImmediate(R0, OneByteString::data_offset() - kHeapObjectTag);
1467 __ ldrh(R0, Address(R0, R1)); 1422 __ ldrh(R0, Address(R0, R1));
1468 __ SmiTag(R0); 1423 __ SmiTag(R0);
1469 __ Ret(); 1424 __ Ret();
1470 1425
1471 __ Bind(&fall_through); 1426 __ Bind(&fall_through);
1472 return false;
1473 } 1427 }
1474 1428
1475 1429
1476 bool Intrinsifier::String_getIsEmpty(Assembler* assembler) { 1430 void Intrinsifier::String_getIsEmpty(Assembler* assembler) {
1477 __ ldr(R0, Address(SP, 0 * kWordSize)); 1431 __ ldr(R0, Address(SP, 0 * kWordSize));
1478 __ ldr(R0, FieldAddress(R0, String::length_offset())); 1432 __ ldr(R0, FieldAddress(R0, String::length_offset()));
1479 __ cmp(R0, ShifterOperand(Smi::RawValue(0))); 1433 __ cmp(R0, ShifterOperand(Smi::RawValue(0)));
1480 __ LoadObject(R0, Bool::True(), EQ); 1434 __ LoadObject(R0, Bool::True(), EQ);
1481 __ LoadObject(R0, Bool::False(), NE); 1435 __ LoadObject(R0, Bool::False(), NE);
1482 __ Ret(); 1436 __ Ret();
1483 return false;
1484 } 1437 }
1485 1438
1486 1439
1487 bool Intrinsifier::OneByteString_getHashCode(Assembler* assembler) { 1440 void Intrinsifier::OneByteString_getHashCode(Assembler* assembler) {
1488 __ ldr(R1, Address(SP, 0 * kWordSize)); 1441 __ ldr(R1, Address(SP, 0 * kWordSize));
1489 __ ldr(R0, FieldAddress(R1, String::hash_offset())); 1442 __ ldr(R0, FieldAddress(R1, String::hash_offset()));
1490 __ cmp(R0, ShifterOperand(0)); 1443 __ cmp(R0, ShifterOperand(0));
1491 __ bx(LR, NE); // Return if already computed. 1444 __ bx(LR, NE); // Return if already computed.
1492 1445
1493 __ ldr(R2, FieldAddress(R1, String::length_offset())); 1446 __ ldr(R2, FieldAddress(R1, String::length_offset()));
1494 1447
1495 Label done; 1448 Label done;
1496 // If the string is empty, set the hash to 1, and return. 1449 // If the string is empty, set the hash to 1, and return.
1497 __ cmp(R2, ShifterOperand(Smi::RawValue(0))); 1450 __ cmp(R2, ShifterOperand(Smi::RawValue(0)));
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
1533 // hash_ = hash_ & ((static_cast<intptr_t>(1) << bits) - 1); 1486 // hash_ = hash_ & ((static_cast<intptr_t>(1) << bits) - 1);
1534 __ LoadImmediate(R2, (static_cast<intptr_t>(1) << String::kHashBits) - 1); 1487 __ LoadImmediate(R2, (static_cast<intptr_t>(1) << String::kHashBits) - 1);
1535 __ and_(R0, R0, ShifterOperand(R2)); 1488 __ and_(R0, R0, ShifterOperand(R2));
1536 __ cmp(R0, ShifterOperand(0)); 1489 __ cmp(R0, ShifterOperand(0));
1537 // return hash_ == 0 ? 1 : hash_; 1490 // return hash_ == 0 ? 1 : hash_;
1538 __ Bind(&done); 1491 __ Bind(&done);
1539 __ mov(R0, ShifterOperand(1), EQ); 1492 __ mov(R0, ShifterOperand(1), EQ);
1540 __ SmiTag(R0); 1493 __ SmiTag(R0);
1541 __ str(R0, FieldAddress(R1, String::hash_offset())); 1494 __ str(R0, FieldAddress(R1, String::hash_offset()));
1542 __ Ret(); 1495 __ Ret();
1543 return true;
1544 } 1496 }
1545 1497
1546 1498
1547 // Allocates one-byte string of length 'end - start'. The content is not 1499 // Allocates one-byte string of length 'end - start'. The content is not
1548 // initialized. 1500 // initialized.
1549 // 'length-reg' (R2) contains tagged length. 1501 // 'length-reg' (R2) contains tagged length.
1550 // Returns new string as tagged pointer in R0. 1502 // Returns new string as tagged pointer in R0.
1551 static void TryAllocateOnebyteString(Assembler* assembler, 1503 static void TryAllocateOnebyteString(Assembler* assembler,
1552 Label* ok, 1504 Label* ok,
1553 Label* failure) { 1505 Label* failure) {
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after
1616 1568
1617 __ Bind(&fail); 1569 __ Bind(&fail);
1618 __ b(failure); 1570 __ b(failure);
1619 } 1571 }
1620 1572
1621 1573
1622 // Arg0: Onebyte String 1574 // Arg0: Onebyte String
1623 // Arg1: Start index as Smi. 1575 // Arg1: Start index as Smi.
1624 // Arg2: End index as Smi. 1576 // Arg2: End index as Smi.
1625 // The indexes must be valid. 1577 // The indexes must be valid.
1626 bool Intrinsifier::OneByteString_substringUnchecked(Assembler* assembler) { 1578 void Intrinsifier::OneByteString_substringUnchecked(Assembler* assembler) {
1627 const intptr_t kStringOffset = 2 * kWordSize; 1579 const intptr_t kStringOffset = 2 * kWordSize;
1628 const intptr_t kStartIndexOffset = 1 * kWordSize; 1580 const intptr_t kStartIndexOffset = 1 * kWordSize;
1629 const intptr_t kEndIndexOffset = 0 * kWordSize; 1581 const intptr_t kEndIndexOffset = 0 * kWordSize;
1630 Label fall_through, ok; 1582 Label fall_through, ok;
1631 1583
1632 __ ldr(R2, Address(SP, kEndIndexOffset)); 1584 __ ldr(R2, Address(SP, kEndIndexOffset));
1633 __ ldr(TMP, Address(SP, kStartIndexOffset)); 1585 __ ldr(TMP, Address(SP, kStartIndexOffset));
1634 __ sub(R2, R2, ShifterOperand(TMP)); 1586 __ sub(R2, R2, ShifterOperand(TMP));
1635 TryAllocateOnebyteString(assembler, &ok, &fall_through); 1587 TryAllocateOnebyteString(assembler, &ok, &fall_through);
1636 __ Bind(&ok); 1588 __ Bind(&ok);
(...skipping 28 matching lines...) Expand all
1665 __ AddImmediate(R6, 1); 1617 __ AddImmediate(R6, 1);
1666 __ sub(R2, R2, ShifterOperand(1)); 1618 __ sub(R2, R2, ShifterOperand(1));
1667 __ cmp(R2, ShifterOperand(0)); 1619 __ cmp(R2, ShifterOperand(0));
1668 __ strb(R1, FieldAddress(R7, OneByteString::data_offset())); 1620 __ strb(R1, FieldAddress(R7, OneByteString::data_offset()));
1669 __ AddImmediate(R7, 1); 1621 __ AddImmediate(R7, 1);
1670 __ b(&loop, GT); 1622 __ b(&loop, GT);
1671 1623
1672 __ Bind(&done); 1624 __ Bind(&done);
1673 __ Ret(); 1625 __ Ret();
1674 __ Bind(&fall_through); 1626 __ Bind(&fall_through);
1675 return false;
1676 } 1627 }
1677 1628
1678 1629
1679 bool Intrinsifier::OneByteString_setAt(Assembler* assembler) { 1630 void Intrinsifier::OneByteString_setAt(Assembler* assembler) {
1680 __ ldr(R2, Address(SP, 0 * kWordSize)); // Value. 1631 __ ldr(R2, Address(SP, 0 * kWordSize)); // Value.
1681 __ ldr(R1, Address(SP, 1 * kWordSize)); // Index. 1632 __ ldr(R1, Address(SP, 1 * kWordSize)); // Index.
1682 __ ldr(R0, Address(SP, 2 * kWordSize)); // OneByteString. 1633 __ ldr(R0, Address(SP, 2 * kWordSize)); // OneByteString.
1683 __ SmiUntag(R1); 1634 __ SmiUntag(R1);
1684 __ SmiUntag(R2); 1635 __ SmiUntag(R2);
1685 __ AddImmediate(R3, R0, OneByteString::data_offset() - kHeapObjectTag); 1636 __ AddImmediate(R3, R0, OneByteString::data_offset() - kHeapObjectTag);
1686 __ strb(R2, Address(R3, R1)); 1637 __ strb(R2, Address(R3, R1));
1687 __ Ret(); 1638 __ Ret();
1688 return true;
1689 } 1639 }
1690 1640
1691 1641
1692 bool Intrinsifier::OneByteString_allocate(Assembler* assembler) { 1642 void Intrinsifier::OneByteString_allocate(Assembler* assembler) {
1693 __ ldr(R2, Address(SP, 0 * kWordSize)); // Length. 1643 __ ldr(R2, Address(SP, 0 * kWordSize)); // Length.
1694 Label fall_through, ok; 1644 Label fall_through, ok;
1695 TryAllocateOnebyteString(assembler, &ok, &fall_through); 1645 TryAllocateOnebyteString(assembler, &ok, &fall_through);
1696 1646
1697 __ Bind(&ok); 1647 __ Bind(&ok);
1698 __ Ret(); 1648 __ Ret();
1699 1649
1700 __ Bind(&fall_through); 1650 __ Bind(&fall_through);
1701 return false;
1702 } 1651 }
1703 1652
1704 } // namespace dart 1653 } // namespace dart
1705 1654
1706 #endif // defined TARGET_ARCH_ARM 1655 #endif // defined TARGET_ARCH_ARM
OLDNEW
« no previous file with comments | « runtime/vm/intrinsifier.cc ('k') | runtime/vm/intrinsifier_ia32.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698