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

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

Issue 15822008: Implements intrinsics for ARM. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 7 years, 6 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
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
10 #include "vm/assembler.h"
11 #include "vm/flow_graph_compiler.h"
9 #include "vm/object.h" 12 #include "vm/object.h"
13 #include "vm/object_store.h"
14 #include "vm/symbols.h"
10 15
11 namespace dart { 16 namespace dart {
12 17
18 DECLARE_FLAG(bool, enable_type_checks);
19
20
21 #define __ assembler->
22
13 bool Intrinsifier::ObjectArray_Allocate(Assembler* assembler) { 23 bool Intrinsifier::ObjectArray_Allocate(Assembler* assembler) {
24 const intptr_t kTypeArgumentsOffset = 1 * kWordSize;
25 const intptr_t kArrayLengthOffset = 0 * kWordSize;
26 Label fall_through;
27
28 // Compute the size to be allocated, it is based on the array length
29 // and is computed as:
30 // RoundedAllocationSize((array_length * kwordSize) + sizeof(RawArray)).
31 __ ldr(R3, Address(SP, kArrayLengthOffset)); // Array length.
32
33 // Check that length is a positive Smi.
34 __ tst(R3, ShifterOperand(kSmiTagMask));
35 __ b(&fall_through, NE);
36 __ cmp(R3, ShifterOperand(0));
37 __ b(&fall_through, LT);
38
39 // Check for maximum allowed length.
40 const intptr_t max_len =
41 reinterpret_cast<int32_t>(Smi::New(Array::kMaxElements));
42 __ CompareImmediate(R3, max_len);
43 __ b(&fall_through, GT);
44
45 const intptr_t fixed_size = sizeof(RawArray) + kObjectAlignment - 1;
46 __ LoadImmediate(R2, fixed_size);
47 __ add(R2, R2, ShifterOperand(R3, LSL, 1)); // R3 is a Smi.
48 ASSERT(kSmiTagShift == 1);
49 __ bic(R2, R2, ShifterOperand(kObjectAlignment - 1));
50
51 // R2: Allocation size.
52
53 Isolate* isolate = Isolate::Current();
54 Heap* heap = isolate->heap();
55
56 __ LoadImmediate(R6, heap->TopAddress());
57 __ ldr(R0, Address(R6, 0)); // Potential new object start.
58 __ adds(R1, R0, ShifterOperand(R2)); // Potential next object start.
59 __ b(&fall_through, VS);
60
61 // Check if the allocation fits into the remaining space.
62 // R0: potential new object start.
63 // R1: potential next object start.
64 // R2: allocation size.
65 __ LoadImmediate(R3, heap->EndAddress());
66 __ ldr(R3, Address(R3, 0));
67 __ cmp(R1, ShifterOperand(R3));
68 __ b(&fall_through, CS);
69
70 // Successfully allocated the object(s), now update top to point to
71 // next object start and initialize the object.
72 __ str(R1, Address(R6, 0));
73 __ add(R0, R0, ShifterOperand(kHeapObjectTag));
74
75 // Initialize the tags.
76 // R0: new object start as a tagged pointer.
77 // R1: new object end address.
78 // R2: allocation size.
79 {
80 const intptr_t shift = RawObject::kSizeTagBit - kObjectAlignmentLog2;
81 const Class& cls = Class::Handle(isolate->object_store()->array_class());
82
83 __ CompareImmediate(R2, RawObject::SizeTag::kMaxSizeTag);
84 __ mov(R2, ShifterOperand(R2, LSL, shift), LS);
85 __ mov(R2, ShifterOperand(0), HI);
86
87 // Get the class index and insert it into the tags.
88 // R2: size and bit tags.
89 __ LoadImmediate(TMP, RawObject::ClassIdTag::encode(cls.id()));
90 __ orr(R2, R2, ShifterOperand(TMP));
91 __ str(R2, FieldAddress(R0, Array::tags_offset())); // Store tags.
92 }
93
94 // R0: new object start as a tagged pointer.
95 // R1: new object end address.
96 // Store the type argument field.
97 __ ldr(R2, Address(SP, kTypeArgumentsOffset)); // Type argument.
98 __ StoreIntoObjectNoBarrier(R0,
99 FieldAddress(R0, Array::type_arguments_offset()),
100 R2);
101
102 // Set the length field.
103 __ ldr(R2, Address(SP, kArrayLengthOffset)); // Array Length.
104 __ StoreIntoObjectNoBarrier(R0,
105 FieldAddress(R0, Array::length_offset()),
106 R2);
107
108 // Initialize all array elements to raw_null.
109 // R0: new object start as a tagged pointer.
110 // R1: new object end address.
111 // R2: iterator which initially points to the start of the variable
112 // data area to be initialized.
113 // R3: null
114 __ LoadImmediate(R3, reinterpret_cast<intptr_t>(Object::null()));
115 __ AddImmediate(R2, R0, sizeof(RawArray) - kHeapObjectTag);
116
117 Label init_loop;
118 __ Bind(&init_loop);
119 __ cmp(R2, ShifterOperand(R1));
120 __ str(R3, Address(R2, 0), CC);
121 __ AddImmediate(R2, kWordSize, CC);
122 __ b(&init_loop, CC);
123
124 __ Ret(); // Returns the newly allocated object in R0.
125 __ Bind(&fall_through);
14 return false; 126 return false;
15 } 127 }
16 128
17 129
18 bool Intrinsifier::Array_getLength(Assembler* assembler) { 130 bool Intrinsifier::Array_getLength(Assembler* assembler) {
19 return false; 131 __ ldr(R0, Address(SP, 0 * kWordSize));
132 __ ldr(R0, FieldAddress(R0, Array::length_offset()));
133 __ Ret();
134 return true;
20 } 135 }
21 136
22 137
23 bool Intrinsifier::ImmutableArray_getLength(Assembler* assembler) { 138 bool Intrinsifier::ImmutableArray_getLength(Assembler* assembler) {
24 return false; 139 return Array_getLength(assembler);
25 } 140 }
26 141
27 142
28 bool Intrinsifier::Array_getIndexed(Assembler* assembler) { 143 bool Intrinsifier::Array_getIndexed(Assembler* assembler) {
144 Label fall_through;
145
146 __ ldr(R0, Address(SP, + 0 * kWordSize)); // Index
147 __ ldr(R1, Address(SP, + 1 * kWordSize)); // Array
148
149 __ tst(R0, ShifterOperand(kSmiTagMask));
150 __ b(&fall_through, NE); // Index is not an smi, fall through
151
152 // range check
153 __ ldr(R6, FieldAddress(R1, Array::length_offset()));
154 __ cmp(R0, ShifterOperand(R6));
155
156 ASSERT(kSmiTagShift == 1);
157 // array element at R1 + R0*2 + Array::data_offset - 1
158 __ add(R6, R1, ShifterOperand(R0, LSL, 1), CC);
159 __ ldr(R0, FieldAddress(R6, Array::data_offset()), CC);
160 __ mov(PC, ShifterOperand(LR), CC);
regis 2013/05/28 22:01:44 The use of mov to pc to return is deprecated. You
zra 2013/05/28 22:49:31 Done.
161 __ Bind(&fall_through);
29 return false; 162 return false;
30 } 163 }
31 164
32 165
33 bool Intrinsifier::ImmutableArray_getIndexed(Assembler* assembler) { 166 bool Intrinsifier::ImmutableArray_getIndexed(Assembler* assembler) {
34 return false; 167 return Array_getIndexed(assembler);
35 } 168 }
36 169
37 170
171 static intptr_t ComputeObjectArrayTypeArgumentsOffset() {
172 const Library& core_lib = Library::Handle(Library::CoreLibrary());
173 const Class& cls =
174 Class::Handle(core_lib.LookupClassAllowPrivate(Symbols::ObjectArray()));
175 ASSERT(!cls.IsNull());
176 ASSERT(cls.HasTypeArguments());
177 ASSERT(cls.NumTypeArguments() == 1);
178 const intptr_t field_offset = cls.type_arguments_field_offset();
179 ASSERT(field_offset != Class::kNoTypeArguments);
180 return field_offset;
181 }
182
183
184 // Intrinsify only for Smi value and index. Non-smi values need a store buffer
185 // update. Array length is always a Smi.
38 bool Intrinsifier::Array_setIndexed(Assembler* assembler) { 186 bool Intrinsifier::Array_setIndexed(Assembler* assembler) {
39 return false; 187 Label fall_through;
40 } 188
41 189 if (FLAG_enable_type_checks) {
42 190 const intptr_t type_args_field_offset =
191 ComputeObjectArrayTypeArgumentsOffset();
192 // Inline simple tests (Smi, null), fallthrough if not positive.
193 const int32_t raw_null = reinterpret_cast<intptr_t>(Object::null());
194 Label checked_ok;
195 __ ldr(R2, Address(SP, 0 * kWordSize)); // Value.
196
197 // Null value is valid for any type.
198 __ CompareImmediate(R2, raw_null);
199 __ b(&checked_ok, EQ);
200
201 __ ldr(R1, Address(SP, 2 * kWordSize)); // Array.
202 __ ldr(R1, FieldAddress(R1, type_args_field_offset));
203
204 // R1: Type arguments of array.
205 __ CompareImmediate(R1, raw_null);
206 __ b(&checked_ok, EQ);
207
208 // Check if it's dynamic.
209 // For now handle only TypeArguments and bail out if InstantiatedTypeArgs.
210 __ CompareClassId(R1, kTypeArgumentsCid, R0);
211 __ b(&fall_through, NE);
212 // Get type at index 0.
213 __ ldr(R0, FieldAddress(R1, TypeArguments::type_at_offset(0)));
214 __ CompareObject(R0, Type::ZoneHandle(Type::DynamicType()));
215 __ b(&checked_ok, EQ);
216
217 // Check for int and num.
218 __ tst(R2, ShifterOperand(kSmiTagMask)); // Value is Smi?
219 __ b(&fall_through, NE); // Non-smi value.
220 __ CompareObject(R0, Type::ZoneHandle(Type::IntType()));
221 __ b(&checked_ok, EQ);
222 __ CompareObject(R0, Type::ZoneHandle(Type::Number()));
223 __ b(&fall_through, NE);
224 __ Bind(&checked_ok);
225 }
226 __ ldr(R1, Address(SP, 1 * kWordSize)); // Index.
227 __ tst(R1, ShifterOperand(kSmiTagMask));
228 // Index not Smi.
229 __ b(&fall_through, NE);
230 __ ldr(R0, Address(SP, 2 * kWordSize)); // Array.
231
232 // Range check.
233 __ ldr(R3, FieldAddress(R0, Array::length_offset())); // Array length.
234 __ cmp(R1, ShifterOperand(R3));
235 // Runtime throws exception.
236 __ b(&fall_through, CS);
237
238 // Note that R1 is Smi, i.e, times 2.
239 ASSERT(kSmiTagShift == 1);
240 // Destroy R2 as we will not continue in the function.
241 __ ldr(R2, Address(SP, 0 * kWordSize)); // Value.
242 __ add(R1, R0, ShifterOperand(R1, LSL, 1)); // R1 is Smi.
243 __ StoreIntoObject(R0,
244 FieldAddress(R1, Array::data_offset()),
245 R2);
246 // Caller is responsible of preserving the value if necessary.
247 __ Ret();
248 __ Bind(&fall_through);
249 return false;
250 }
251
252
253 // Allocate a GrowableObjectArray using the backing array specified.
254 // On stack: type argument (+1), data (+0).
43 bool Intrinsifier::GrowableArray_Allocate(Assembler* assembler) { 255 bool Intrinsifier::GrowableArray_Allocate(Assembler* assembler) {
256 // The newly allocated object is returned in R0.
257 const intptr_t kTypeArgumentsOffset = 1 * kWordSize;
258 const intptr_t kArrayOffset = 0 * kWordSize;
259 Label fall_through;
260
261 // Compute the size to be allocated, it is based on the array length
262 // and is computed as:
263 // RoundedAllocationSize(sizeof(RawGrowableObjectArray)) +
264 intptr_t fixed_size = GrowableObjectArray::InstanceSize();
265
266 Isolate* isolate = Isolate::Current();
267 Heap* heap = isolate->heap();
268
269 __ LoadImmediate(R2, heap->TopAddress());
270 __ ldr(R0, Address(R2, 0));
271 __ AddImmediate(R1, R0, fixed_size);
272
273 // Check if the allocation fits into the remaining space.
274 // R0: potential new backing array object start.
275 // R1: potential next object start.
276 __ LoadImmediate(R3, heap->EndAddress());
277 __ ldr(R3, Address(R3, 0));
278 __ cmp(R1, ShifterOperand(R3));
279 __ b(&fall_through, CS);
280
281 // Successfully allocated the object(s), now update top to point to
282 // next object start and initialize the object.
283 __ str(R1, Address(R2, 0));
284 __ AddImmediate(R0, kHeapObjectTag);
285
286 // Initialize the tags.
287 // R0: new growable array object start as a tagged pointer.
288 const Class& cls = Class::Handle(
289 isolate->object_store()->growable_object_array_class());
290 uword tags = 0;
291 tags = RawObject::SizeTag::update(fixed_size, tags);
292 tags = RawObject::ClassIdTag::update(cls.id(), tags);
293 __ LoadImmediate(R1, tags);
294 __ str(R1, FieldAddress(R0, GrowableObjectArray::tags_offset()));
295
296 // Store backing array object in growable array object.
297 __ ldr(R1, Address(SP, kArrayOffset)); // Data argument.
298 // R0 is new, no barrier needed.
299 __ StoreIntoObjectNoBarrier(
300 R0,
301 FieldAddress(R0, GrowableObjectArray::data_offset()),
302 R1);
303
304 // R0: new growable array object start as a tagged pointer.
305 // Store the type argument field in the growable array object.
306 __ ldr(R1, Address(SP, kTypeArgumentsOffset)); // Type argument.
307 __ StoreIntoObjectNoBarrier(
308 R0,
309 FieldAddress(R0, GrowableObjectArray::type_arguments_offset()),
310 R1);
311
312 // Set the length field in the growable array object to 0.
313 __ LoadImmediate(R1, 0);
314 __ str(R1, FieldAddress(R0, GrowableObjectArray::length_offset()));
315 __ Ret(); // Returns the newly allocated object in R0.
316
317 __ Bind(&fall_through);
44 return false; 318 return false;
45 } 319 }
46 320
47 321
48 bool Intrinsifier::GrowableArray_getLength(Assembler* assembler) { 322 bool Intrinsifier::GrowableArray_getLength(Assembler* assembler) {
49 return false; 323 __ ldr(R0, Address(SP, 0 * kWordSize));
324 __ ldr(R0, FieldAddress(R0, GrowableObjectArray::length_offset()));
325 __ Ret();
326 return true;
50 } 327 }
51 328
52 329
53 bool Intrinsifier::GrowableArray_getCapacity(Assembler* assembler) { 330 bool Intrinsifier::GrowableArray_getCapacity(Assembler* assembler) {
54 return false; 331 __ ldr(R0, Address(SP, 0 * kWordSize));
332 __ ldr(R0, FieldAddress(R0, GrowableObjectArray::data_offset()));
333 __ ldr(R0, FieldAddress(R0, Array::length_offset()));
334 __ Ret();
335 return true;
55 } 336 }
56 337
57 338
58 bool Intrinsifier::GrowableArray_getIndexed(Assembler* assembler) { 339 bool Intrinsifier::GrowableArray_getIndexed(Assembler* assembler) {
59 return false; 340 Label fall_through;
60 } 341
61 342 __ ldr(R0, Address(SP, + 0 * kWordSize)); // Index
62 343 __ ldr(R1, Address(SP, + 1 * kWordSize)); // Array
344
345 __ tst(R0, ShifterOperand(kSmiTagMask));
346 __ b(&fall_through, NE); // Index is not an smi, fall through
347
348 // range check
349 __ ldr(R6, FieldAddress(R1, GrowableObjectArray::length_offset()));
350 __ cmp(R0, ShifterOperand(R6));
351
352 ASSERT(kSmiTagShift == 1);
353 // array element at R6 + R0 * 2 + Array::data_offset - 1
354 __ ldr(R6, FieldAddress(R1, GrowableObjectArray::data_offset()), CC); // data
355 __ add(R6, R6, ShifterOperand(R0, LSL, 1), CC);
356 __ ldr(R0, FieldAddress(R6, Array::data_offset()), CC);
357 __ mov(PC, ShifterOperand(LR), CC);
358 __ Bind(&fall_through);
359 return false;
360 }
361
362
363 // Set value into growable object array at specified index.
364 // On stack: growable array (+2), index (+1), value (+0).
63 bool Intrinsifier::GrowableArray_setIndexed(Assembler* assembler) { 365 bool Intrinsifier::GrowableArray_setIndexed(Assembler* assembler) {
64 return false; 366 if (FLAG_enable_type_checks) {
65 } 367 return false;
66 368 }
67 369 Label fall_through;
370 __ ldr(R1, Address(SP, 1 * kWordSize)); // Index.
371 __ ldr(R0, Address(SP, 2 * kWordSize)); // GrowableArray.
372 __ tst(R1, ShifterOperand(kSmiTagMask));
373 __ b(&fall_through, NE); // Non-smi index.
374 // Range check using _length field.
375 __ ldr(R2, FieldAddress(R0, GrowableObjectArray::length_offset()));
376 __ cmp(R1, ShifterOperand(R2));
377 // Runtime throws exception.
378 __ b(&fall_through, CS);
379 __ ldr(R0, FieldAddress(R0, GrowableObjectArray::data_offset())); // data.
380 __ ldr(R2, Address(SP, 0 * kWordSize)); // Value.
381 // Note that R1 is Smi, i.e, times 2.
382 ASSERT(kSmiTagShift == 1);
383 __ add(R1, R0, ShifterOperand(R1, LSL, 1));
384 __ StoreIntoObject(R0,
385 FieldAddress(R1, Array::data_offset()),
386 R2);
387 __ Ret();
388 __ Bind(&fall_through);
389 return false;
390 }
391
392
393 // Set length of growable object array. The length cannot
394 // be greater than the length of the data container.
395 // On stack: growable array (+1), length (+0).
68 bool Intrinsifier::GrowableArray_setLength(Assembler* assembler) { 396 bool Intrinsifier::GrowableArray_setLength(Assembler* assembler) {
69 return false; 397 __ ldr(R0, Address(SP, 1 * kWordSize)); // Growable array.
70 } 398 __ ldr(R1, Address(SP, 0 * kWordSize)); // Length value.
71 399 __ tst(R1, ShifterOperand(kSmiTagMask)); // Check for Smi.
72 400 __ str(R1, FieldAddress(R0, GrowableObjectArray::length_offset()), EQ);
401 __ mov(PC, ShifterOperand(LR), EQ);
402 // Fall through on non-Smi.
403 return false;
404 }
405
406
407 // Set data of growable object array.
408 // On stack: growable array (+1), data (+0).
73 bool Intrinsifier::GrowableArray_setData(Assembler* assembler) { 409 bool Intrinsifier::GrowableArray_setData(Assembler* assembler) {
74 return false; 410 if (FLAG_enable_type_checks) {
75 } 411 return false;
76 412 }
77 413 Label fall_through;
414 __ ldr(R1, Address(SP, 0 * kWordSize)); // Data.
415 // Check that data is an ObjectArray.
416 __ tst(R1, ShifterOperand(kSmiTagMask));
417 __ b(&fall_through, EQ); // Data is Smi.
418 __ CompareClassId(R1, kArrayCid, R0);
419 __ b(&fall_through, NE);
420 __ ldr(R0, Address(SP, 1 * kWordSize)); // Growable array.
421 __ StoreIntoObject(R0,
422 FieldAddress(R0, GrowableObjectArray::data_offset()),
423 R1);
424 __ Ret();
425 __ Bind(&fall_through);
426 return false;
427 }
428
429
430 // Add an element to growable array if it doesn't need to grow, otherwise
431 // call into regular code.
432 // On stack: growable array (+1), value (+0).
78 bool Intrinsifier::GrowableArray_add(Assembler* assembler) { 433 bool Intrinsifier::GrowableArray_add(Assembler* assembler) {
79 return false; 434 // In checked mode we need to type-check the incoming argument.
80 } 435 if (FLAG_enable_type_checks) return false;
81 436 Label fall_through;
82 437 // R0: Array.
438 __ ldr(R0, Address(SP, 1 * kWordSize));
439 // R1: length.
440 __ ldr(R1, FieldAddress(R0, GrowableObjectArray::length_offset()));
441 // R2: data.
442 __ ldr(R2, FieldAddress(R0, GrowableObjectArray::data_offset()));
443 // R3: capacity.
444 __ ldr(R3, FieldAddress(R2, Array::length_offset()));
445 // Compare length with capacity.
446 __ cmp(R1, ShifterOperand(R3));
447 __ b(&fall_through, EQ); // Must grow data.
448 const int32_t value_one = reinterpret_cast<int32_t>(Smi::New(1));
449 // len = len + 1;
450 __ add(R3, R1, ShifterOperand(value_one));
451 __ str(R3, FieldAddress(R0, GrowableObjectArray::length_offset()));
452 __ ldr(R0, Address(SP, 0 * kWordSize)); // Value.
453 ASSERT(kSmiTagShift == 1);
454 __ add(R1, R2, ShifterOperand(R1, LSL, 1));
455 __ StoreIntoObject(R2,
456 FieldAddress(R1, Array::data_offset()),
457 R0);
458 const int32_t raw_null = reinterpret_cast<int32_t>(Object::null());
459 __ LoadImmediate(R0, raw_null);
460 __ Ret();
461 __ Bind(&fall_through);
462 return false;
463 }
464
465
466 #define TYPED_ARRAY_ALLOCATION(type_name, cid, max_len, scale_shift) \
467 Label fall_through; \
468 const intptr_t kArrayLengthStackOffset = 0 * kWordSize; \
469 __ ldr(R2, Address(SP, kArrayLengthStackOffset)); /* Array length. */ \
470 /* Check that length is a positive Smi. */ \
471 /* R2: requested array length argument. */ \
472 __ tst(R2, ShifterOperand(kSmiTagMask)); \
473 __ b(&fall_through, NE); \
474 __ CompareImmediate(R2, 0); \
475 __ b(&fall_through, LT); \
476 __ SmiUntag(R2); \
477 /* Check for maximum allowed length. */ \
478 /* R2: untagged array length. */ \
479 __ CompareImmediate(R2, max_len); \
480 __ b(&fall_through, GT); \
481 __ mov(R2, ShifterOperand(R2, LSL, scale_shift)); \
482 const intptr_t fixed_size = sizeof(Raw##type_name) + kObjectAlignment - 1; \
483 __ AddImmediate(R2, fixed_size); \
484 __ bic(R2, R2, ShifterOperand(kObjectAlignment - 1)); \
485 Heap* heap = Isolate::Current()->heap(); \
486 \
487 __ LoadImmediate(R0, heap->TopAddress()); \
488 __ ldr(R0, Address(R0, 0)); \
489 \
490 /* R2: allocation size. */ \
491 __ add(R1, R0, ShifterOperand(R2)); \
492 __ b(&fall_through, VS); \
493 \
494 /* Check if the allocation fits into the remaining space. */ \
495 /* R0: potential new object start. */ \
496 /* R1: potential next object start. */ \
497 /* R2: allocation size. */ \
498 __ LoadImmediate(R3, heap->EndAddress()); \
499 __ ldr(R3, Address(R3, 0)); \
500 __ cmp(R1, ShifterOperand(R3)); \
501 __ b(&fall_through, CS); \
502 \
503 /* Successfully allocated the object(s), now update top to point to */ \
504 /* next object start and initialize the object. */ \
505 __ LoadImmediate(R3, heap->TopAddress()); \
506 __ str(R1, Address(R3, 0)); \
507 __ AddImmediate(R0, kHeapObjectTag); \
508 \
509 /* Initialize the tags. */ \
510 /* R0: new object start as a tagged pointer. */ \
511 /* R1: new object end address. */ \
512 /* R2: allocation size. */ \
513 { \
514 __ CompareImmediate(R2, RawObject::SizeTag::kMaxSizeTag); \
515 __ mov(R2, ShifterOperand(R2, LSL, \
516 RawObject::kSizeTagBit - kObjectAlignmentLog2), LS); \
517 __ mov(R2, ShifterOperand(0), HI); \
518 \
519 /* Get the class index and insert it into the tags. */ \
520 __ LoadImmediate(TMP, RawObject::ClassIdTag::encode(cid)); \
521 __ orr(R2, R2, ShifterOperand(TMP)); \
522 __ str(R2, FieldAddress(R0, type_name::tags_offset())); /* Tags. */ \
523 } \
524 /* Set the length field. */ \
525 /* R0: new object start as a tagged pointer. */ \
526 /* R1: new object end address. */ \
527 __ ldr(R2, Address(SP, kArrayLengthStackOffset)); /* Array length. */ \
528 __ StoreIntoObjectNoBarrier(R0, \
529 FieldAddress(R0, type_name::length_offset()), \
530 R2); \
531 /* Initialize all array elements to 0. */ \
532 /* R0: new object start as a tagged pointer. */ \
533 /* R1: new object end address. */ \
534 /* R2: iterator which initially points to the start of the variable */ \
535 /* R3: scratch register. */ \
536 /* data area to be initialized. */ \
537 __ LoadImmediate(R3, 0); \
538 __ AddImmediate(R2, R0, sizeof(Raw##type_name) - 1); \
539 Label init_loop; \
540 __ Bind(&init_loop); \
541 __ cmp(R2, ShifterOperand(R1)); \
542 __ str(R3, Address(R2, 0), CC); \
543 __ add(R2, R2, ShifterOperand(kWordSize), CC); \
544 __ b(&init_loop, CC); \
545 \
546 __ Ret(); \
547 __ Bind(&fall_through); \
548
549
550 // Gets the length of a TypedData.
83 bool Intrinsifier::TypedData_getLength(Assembler* assembler) { 551 bool Intrinsifier::TypedData_getLength(Assembler* assembler) {
84 return false; 552 __ ldr(R0, Address(SP, 0 * kWordSize));
85 } 553 __ ldr(R0, FieldAddress(R0, TypedData::length_offset()));
554 __ Ret();
555 return true;
556 }
557
558
559 static int GetScaleFactor(intptr_t size) {
560 switch (size) {
561 case 1: return 0;
562 case 2: return 1;
563 case 4: return 2;
564 case 8: return 3;
565 case 16: return 4;
566 }
567 UNREACHABLE();
568 return -1;
569 };
86 570
87 571
88 #define TYPED_DATA_ALLOCATOR(clazz) \ 572 #define TYPED_DATA_ALLOCATOR(clazz) \
89 bool Intrinsifier::TypedData_##clazz##_new(Assembler* assembler) { \ 573 bool Intrinsifier::TypedData_##clazz##_new(Assembler* assembler) { \
574 intptr_t size = TypedData::ElementSizeInBytes(kTypedData##clazz##Cid); \
575 intptr_t max_len = TypedData::MaxElements(kTypedData##clazz##Cid); \
576 int shift = GetScaleFactor(size); \
577 TYPED_ARRAY_ALLOCATION(TypedData, kTypedData##clazz##Cid, max_len, shift); \
90 return false; \ 578 return false; \
91 } \ 579 } \
92 bool Intrinsifier::TypedData_##clazz##_factory(Assembler* assembler) { \ 580 bool Intrinsifier::TypedData_##clazz##_factory(Assembler* assembler) { \
581 intptr_t size = TypedData::ElementSizeInBytes(kTypedData##clazz##Cid); \
582 intptr_t max_len = TypedData::MaxElements(kTypedData##clazz##Cid); \
583 int shift = GetScaleFactor(size); \
584 TYPED_ARRAY_ALLOCATION(TypedData, kTypedData##clazz##Cid, max_len, shift); \
93 return false; \ 585 return false; \
94 } 586 }
95 CLASS_LIST_TYPED_DATA(TYPED_DATA_ALLOCATOR) 587 CLASS_LIST_TYPED_DATA(TYPED_DATA_ALLOCATOR)
96 #undef TYPED_DATA_ALLOCATOR 588 #undef TYPED_DATA_ALLOCATOR
97 589
98 590
591 // Loads args from stack into R0 and R1
592 // Tests if they are smis, jumps to label not_smi if not.
593 static void TestBothArgumentsSmis(Assembler* assembler, Label* not_smi) {
594 __ ldr(R0, Address(SP, + 0 * kWordSize));
595 __ ldr(R1, Address(SP, + 1 * kWordSize));
596 __ orr(TMP, R0, ShifterOperand(R1));
597 __ tst(TMP, ShifterOperand(kSmiTagMask));
598 __ b(not_smi, NE);
599 return;
600 }
601
602
99 bool Intrinsifier::Integer_addFromInteger(Assembler* assembler) { 603 bool Intrinsifier::Integer_addFromInteger(Assembler* assembler) {
604 Label fall_through;
605 TestBothArgumentsSmis(assembler, &fall_through); // Checks two smis.
606 __ adds(R0, R0, ShifterOperand(R1)); // Adds.
607 __ mov(PC, ShifterOperand(LR), VC); // Return if no overflow.
608 // Otherwise fall through.
609 __ Bind(&fall_through);
100 return false; 610 return false;
101 } 611 }
102 612
103 613
104 bool Intrinsifier::Integer_add(Assembler* assembler) { 614 bool Intrinsifier::Integer_add(Assembler* assembler) {
105 return false; 615 return Integer_addFromInteger(assembler);
106 } 616 }
107 617
108 618
109 bool Intrinsifier::Integer_subFromInteger(Assembler* assembler) { 619 bool Intrinsifier::Integer_subFromInteger(Assembler* assembler) {
620 Label fall_through;
621 TestBothArgumentsSmis(assembler, &fall_through);
622 __ subs(R0, R0, ShifterOperand(R1)); // Subtract.
623 __ mov(PC, ShifterOperand(LR), VC); // Return if no overflow.
624 // Otherwise fall through.
625 __ Bind(&fall_through);
110 return false; 626 return false;
111 } 627 }
112 628
113 629
114 bool Intrinsifier::Integer_sub(Assembler* assembler) { 630 bool Intrinsifier::Integer_sub(Assembler* assembler) {
631 Label fall_through;
632 TestBothArgumentsSmis(assembler, &fall_through);
633 __ subs(R0, R1, ShifterOperand(R0)); // Subtract.
634 __ mov(PC, ShifterOperand(LR), VC); // Return if no overflow.
635 // Otherwise fall through.
636 __ Bind(&fall_through);
115 return false; 637 return false;
116 } 638 }
117 639
118 640
119 bool Intrinsifier::Integer_mulFromInteger(Assembler* assembler) { 641 bool Intrinsifier::Integer_mulFromInteger(Assembler* assembler) {
642 Label fall_through;
643
644 TestBothArgumentsSmis(assembler, &fall_through); // checks two smis
645 __ SmiUntag(R0); // untags R6. only want result shifted by one
646
647 __ smull(R0, IP, R0, R1); // IP:R0 <- R0 * R1.
648 __ cmp(IP, ShifterOperand(R0, ASR, 31));
649 __ mov(PC, ShifterOperand(LR), EQ);
650 __ Bind(&fall_through); // Fall through on overflow.
120 return false; 651 return false;
121 } 652 }
122 653
123 654
124 bool Intrinsifier::Integer_mul(Assembler* assembler) { 655 bool Intrinsifier::Integer_mul(Assembler* assembler) {
125 return false; 656 return Integer_mulFromInteger(assembler);
126 } 657 }
127 658
128 659
660 // Optimizations:
661 // - result is 0 if:
662 // - left is 0
663 // - left equals right
664 // - result is left if
665 // - left > 0 && left < right
666 // R1: Tagged left (dividend).
667 // R0: Tagged right (divisor).
668 // Returns with result in R0, OR:
669 // R1: Untagged result (remainder).
670 static void EmitRemainderOperation(Assembler* assembler) {
671 Label modulo;
672 const Register left = R1;
673 const Register right = R0;
674 const Register result = R1;
675 ASSERT(left == result);
676
677 // Check for quick zero results.
678 __ cmp(left, ShifterOperand(0));
679 __ mov(R0, ShifterOperand(0), EQ);
680 __ mov(PC, ShifterOperand(LR), EQ); // left is 0? Return 0.
681 __ cmp(left, ShifterOperand(right));
682 __ mov(R0, ShifterOperand(0), EQ);
683 __ mov(PC, ShifterOperand(LR), EQ); // left == right? Return 0.
684
685 // Check if result should be left.
686 __ cmp(left, ShifterOperand(0));
687 __ b(&modulo, LT);
688 // left is positive.
689 __ cmp(left, ShifterOperand(right));
690 // left is less than right, result is left.
691 __ mov(R0, ShifterOperand(left), LT);
692 __ mov(PC, ShifterOperand(LR), LT);
693
694 __ Bind(&modulo);
695 // result <- left - right * (left / right)
696 __ SmiUntag(left);
697 __ SmiUntag(right);
698 __ sdiv(TMP, left, right); // TMP <- left / right
regis 2013/05/28 22:01:44 Shouldn't you verify in the caller that integer di
zra 2013/05/28 22:49:31 Yes. Done.
699 __ mls(result, right, TMP, left); // result <- left - right * TMP
700 return;
701 }
702
703
704 // Implementation:
705 // res = left % right;
706 // if (res < 0) {
707 // if (right < 0) {
708 // res = res - right;
709 // } else {
710 // res = res + right;
711 // }
712 // }
129 bool Intrinsifier::Integer_modulo(Assembler* assembler) { 713 bool Intrinsifier::Integer_modulo(Assembler* assembler) {
714 Label fall_through, subtract;
715 TestBothArgumentsSmis(assembler, &fall_through);
716 // R1: Tagged left (dividend).
717 // R0: Tagged right (divisor).
718 // Check if modulo by zero -> exception thrown in main function.
719 __ cmp(R0, ShifterOperand(0));
720 __ b(&fall_through, EQ);
721 EmitRemainderOperation(assembler);
722 // Untagged right in R0. Untagged remainder result in R1.
723
724 __ cmp(R1, ShifterOperand(0));
725 __ mov(R0, ShifterOperand(R1, LSL, 1), GE); // Tag and move result to R0.
726 __ mov(PC, ShifterOperand(LR), GE);
727
728 // Result is negative, adjust it.
729 __ cmp(R0, ShifterOperand(0));
730 __ sub(R0, R1, ShifterOperand(R0), LT);
731 __ add(R0, R1, ShifterOperand(R0), GE);
732 __ SmiTag(R0);
733 __ Ret();
734
735 __ Bind(&fall_through);
130 return false; 736 return false;
131 } 737 }
132 738
133 739
134 bool Intrinsifier::Integer_remainder(Assembler* assembler) { 740 bool Intrinsifier::Integer_remainder(Assembler* assembler) {
741 Label fall_through;
742 TestBothArgumentsSmis(assembler, &fall_through);
743 // R1: Tagged left (dividend).
744 // R0: Tagged right (divisor).
745 // Check if modulo by zero -> exception thrown in main function.
746 __ cmp(R0, ShifterOperand(0));
747 __ b(&fall_through, EQ);
748 EmitRemainderOperation(assembler);
749 // Untagged remainder result in R1.
750 __ mov(R0, ShifterOperand(R1, LSL, 1)); // Tag result and return.
751 __ Ret();
752
753 __ Bind(&fall_through);
135 return false; 754 return false;
136 } 755 }
137 756
138 757
139 bool Intrinsifier::Integer_truncDivide(Assembler* assembler) { 758 bool Intrinsifier::Integer_truncDivide(Assembler* assembler) {
759 // Check to see if we have integer division
760 if (!CPUFeatures::integer_division_supported())
761 return false;
762
763 Label fall_through;
764
765 TestBothArgumentsSmis(assembler, &fall_through);
766 __ cmp(R0, ShifterOperand(0));
767 __ b(&fall_through, EQ); // If b is 0, fall through.
768
769 __ SmiUntag(R0);
770 __ SmiUntag(R1);
771 __ sdiv(R0, R1, R0);
772 // Check the corner case of dividing the 'MIN_SMI' with -1, in which case we
773 // cannot tag the result.
774 __ CompareImmediate(R0, 0x40000000);
775 __ SmiTag(R0, NE); // Not equal. Okay to tag and return.
776 __ mov(PC, ShifterOperand(LR), NE); // Return.
777 __ Bind(&fall_through);
140 return false; 778 return false;
141 } 779 }
142 780
143 781
144 bool Intrinsifier::Integer_negate(Assembler* assembler) { 782 bool Intrinsifier::Integer_negate(Assembler* assembler) {
783 __ ldr(R0, Address(SP, + 0 * kWordSize)); // Grab first argument.
784 __ tst(R0, ShifterOperand(kSmiTagMask)); // Test for Smi.
785 __ rsb(R0, R0, ShifterOperand(0), EQ); // R0 is a Smi. R0 <- 0 - R0.
786 __ mov(PC, ShifterOperand(LR), EQ); // Return.
787 // R0 is not a Smi. Fall through.
145 return false; 788 return false;
146 } 789 }
147 790
148 791
149 bool Intrinsifier::Integer_bitAndFromInteger(Assembler* assembler) { 792 bool Intrinsifier::Integer_bitAndFromInteger(Assembler* assembler) {
793 Label fall_through;
794
795 TestBothArgumentsSmis(assembler, &fall_through); // checks two smis
796 __ and_(R0, R0, ShifterOperand(R1));
797
798 __ Ret();
799 __ Bind(&fall_through);
150 return false; 800 return false;
151 } 801 }
152 802
153 803
154 bool Intrinsifier::Integer_bitAnd(Assembler* assembler) { 804 bool Intrinsifier::Integer_bitAnd(Assembler* assembler) {
155 return false; 805 return Integer_bitAndFromInteger(assembler);
156 } 806 }
157 807
158 808
159 bool Intrinsifier::Integer_bitOrFromInteger(Assembler* assembler) { 809 bool Intrinsifier::Integer_bitOrFromInteger(Assembler* assembler) {
810 Label fall_through;
811
812 TestBothArgumentsSmis(assembler, &fall_through); // checks two smis
813 __ orr(R0, R0, ShifterOperand(R1));
814
815 __ Ret();
816 __ Bind(&fall_through);
160 return false; 817 return false;
161 } 818 }
162 819
163 820
164 bool Intrinsifier::Integer_bitOr(Assembler* assembler) { 821 bool Intrinsifier::Integer_bitOr(Assembler* assembler) {
165 return false; 822 return Integer_bitOrFromInteger(assembler);
166 } 823 }
167 824
168 825
169 bool Intrinsifier::Integer_bitXorFromInteger(Assembler* assembler) { 826 bool Intrinsifier::Integer_bitXorFromInteger(Assembler* assembler) {
827 Label fall_through;
828 __ Untested("Intrinsifier::Integer_bitXorFromInteger");
829
830 TestBothArgumentsSmis(assembler, &fall_through); // checks two smis
831 __ eor(R0, R0, ShifterOperand(R1));
832
833 __ Ret();
834 __ Bind(&fall_through);
170 return false; 835 return false;
171 } 836 }
172 837
173 838
174 bool Intrinsifier::Integer_bitXor(Assembler* assembler) { 839 bool Intrinsifier::Integer_bitXor(Assembler* assembler) {
175 return false; 840 return Integer_bitXorFromInteger(assembler);
176 } 841 }
177 842
178 843
179 bool Intrinsifier::Integer_shl(Assembler* assembler) { 844 bool Intrinsifier::Integer_shl(Assembler* assembler) {
845 ASSERT(kSmiTagShift == 1);
846 ASSERT(kSmiTag == 0);
847 Label fall_through;
848
849 TestBothArgumentsSmis(assembler, &fall_through);
850 __ CompareImmediate(R0, Smi::RawValue(Smi::kBits));
851 __ b(&fall_through, HI);
852
853 __ SmiUntag(R0);
854
855 // Check for overflow by shifting left and shifting back arithmetically.
856 // If the result is different from the original, there was overflow.
857 __ mov(R6, ShifterOperand(R1));
858 __ mov(R1, ShifterOperand(R1, LSL, R0));
859 __ mov(R1, ShifterOperand(R1, ASR, R0));
860 __ cmp(R1, ShifterOperand(R6));
regis 2013/05/28 22:01:44 You can make this sequence shorter as I did in my
zra 2013/05/28 22:49:31 Done.
861
862 // No overflow, result in R0.
863 __ mov(R0, ShifterOperand(R1, LSL, R0), EQ);
864 __ mov(PC, ShifterOperand(LR), EQ);
865
866 // Arguments are Smi but the shift produced an overflow to Mint.
867 __ CompareImmediate(R6, 0);
868 __ b(&fall_through, LT);
869 __ SmiUntag(R6);
870
871 // Pull off high bits that will be shifted off of R6 by making a mask
872 // ((1 << R0) - 1), shifting it to the left, masking R6, then shifting back.
873 // high bits = (((1 << R0) - 1) << (32 - R0)) & R6) >> (32 - R0)
874 // lo bits = R6 << R0
875 __ LoadImmediate(R7, 1);
876 __ mov(R7, ShifterOperand(R7, LSL, R0)); // R7 <- 1 << R0
877 __ sub(R7, R7, ShifterOperand(1)); // R7 <- R7 - 1
878 __ rsb(R8, R0, ShifterOperand(32)); // R8 <- 32 - R0
879 __ mov(R7, ShifterOperand(R7, LSL, R8)); // R7 <- R7 << R8
880 __ and_(R7, R6, ShifterOperand(R7)); // R7 <- R7 & R6
881 __ mov(R7, ShifterOperand(R7, LSR, R8)); // R7 <- R7 >> R8
882 // Now R7 has the bits that fall off of R6 on a left shift.
883 __ mov(R1, ShifterOperand(R6, LSL, R0)); // R1 gets the low bits.
884
885 const Class& mint_class = Class::Handle(
886 Isolate::Current()->object_store()->mint_class());
887 __ TryAllocate(mint_class, &fall_through, R0);
888
889
890 __ str(R1, FieldAddress(R0, Mint::value_offset()));
891 __ str(R7, FieldAddress(R0, Mint::value_offset() + kWordSize));
892 __ Ret();
893 __ Bind(&fall_through);
894 return false;
895 }
896
897
898 static void Get64SmiOrMint(Assembler* assembler,
899 Register res_hi,
900 Register res_lo,
901 Register reg,
902 Label* not_smi_or_mint) {
903 Label not_smi, done;
904 __ tst(reg, ShifterOperand(kSmiTagMask));
905 __ b(&not_smi, NE);
906 __ SmiUntag(reg);
907
908 // Sign extend to 64 bit
909 __ mov(res_lo, ShifterOperand(reg));
910 __ mov(res_hi, ShifterOperand(res_lo, ASR, 31));
911 __ b(&done);
912
913 __ Bind(&not_smi);
914 __ CompareClassId(reg, kMintCid, res_lo);
915 __ b(not_smi_or_mint, NE);
916
917 // Mint.
918 __ ldr(res_lo, FieldAddress(reg, Mint::value_offset()));
919 __ ldr(res_hi, FieldAddress(reg, Mint::value_offset() + kWordSize));
920 __ Bind(&done);
921 return;
922 }
923
924
925 static bool CompareIntegers(Assembler* assembler, Condition true_condition) {
926 Label try_mint_smi, is_true, is_false, drop_two_fall_through, fall_through;
927 TestBothArgumentsSmis(assembler, &try_mint_smi);
928 // R0 contains the right argument. R1 contains left argument
929
930 __ cmp(R1, ShifterOperand(R0));
931 __ b(&is_true, true_condition);
932 __ Bind(&is_false);
933 __ LoadObject(R0, Bool::False());
934 __ Ret();
935 __ Bind(&is_true);
936 __ LoadObject(R0, Bool::True());
937 __ Ret();
938
939 // 64-bit comparison
940 Condition hi_true_cond, hi_false_cond, lo_false_cond;
941 switch (true_condition) {
942 case LT:
943 case LE:
944 hi_true_cond = LT;
945 hi_false_cond = GT;
946 lo_false_cond = (true_condition == LT) ? CS : HI;
947 break;
948 case GT:
949 case GE:
950 hi_true_cond = GT;
951 hi_false_cond = LT;
952 lo_false_cond = (true_condition == GT) ? LS : CC;
953 break;
954 default:
955 UNREACHABLE();
956 hi_true_cond = hi_false_cond = lo_false_cond = VS;
957 }
958
959 __ Bind(&try_mint_smi);
960 // Get left as 64 bit integer.
961 Get64SmiOrMint(assembler, R3, R2, R1, &fall_through);
962 // Get right as 64 bit integer.
963 Get64SmiOrMint(assembler, R7, R6, R0, &fall_through);
964 // R3: left high.
965 // R2: left low.
966 // R7: right high.
967 // R6: right low.
968
969 __ cmp(R3, ShifterOperand(R7)); // Compare left hi, right high.
970 __ b(&is_false, hi_false_cond);
971 __ b(&is_true, hi_true_cond);
972 __ cmp(R2, ShifterOperand(R6)); // Compare left lo, right lo.
973 __ b(&is_false, lo_false_cond);
974 // Else is true.
975 __ b(&is_true);
976
977 __ Bind(&fall_through);
180 return false; 978 return false;
181 } 979 }
182 980
183 981
184 bool Intrinsifier::Integer_greaterThanFromInt(Assembler* assembler) { 982 bool Intrinsifier::Integer_greaterThanFromInt(Assembler* assembler) {
185 return false; 983 return CompareIntegers(assembler, LT);
186 } 984 }
187 985
188 986
189 bool Intrinsifier::Integer_lessThan(Assembler* assembler) { 987 bool Intrinsifier::Integer_lessThan(Assembler* assembler) {
190 return false; 988 return Integer_greaterThanFromInt(assembler);
191 } 989 }
192 990
193 991
194 bool Intrinsifier::Integer_greaterThan(Assembler* assembler) { 992 bool Intrinsifier::Integer_greaterThan(Assembler* assembler) {
195 return false; 993 return CompareIntegers(assembler, GT);
196 } 994 }
197 995
198 996
199 bool Intrinsifier::Integer_lessEqualThan(Assembler* assembler) { 997 bool Intrinsifier::Integer_lessEqualThan(Assembler* assembler) {
200 return false; 998 return CompareIntegers(assembler, LE);
201 } 999 }
202 1000
203 1001
204 bool Intrinsifier::Integer_greaterEqualThan(Assembler* assembler) { 1002 bool Intrinsifier::Integer_greaterEqualThan(Assembler* assembler) {
205 return false; 1003 return CompareIntegers(assembler, GE);
206 } 1004 }
207 1005
208 1006
1007 // This is called for Smi, Mint and Bigint receivers. The right argument
1008 // can be Smi, Mint, Bigint or double.
209 bool Intrinsifier::Integer_equalToInteger(Assembler* assembler) { 1009 bool Intrinsifier::Integer_equalToInteger(Assembler* assembler) {
1010 Label fall_through, true_label, check_for_mint;
1011 // For integer receiver '===' check first.
1012 __ ldr(R0, Address(SP, 0 * kWordSize));
1013 __ ldr(R1, Address(SP, 1 * kWordSize));
1014 __ cmp(R0, ShifterOperand(R1));
1015 __ b(&true_label, EQ);
1016
1017 __ orr(R2, R0, ShifterOperand(R1));
1018 __ tst(R2, ShifterOperand(kSmiTagMask));
1019 __ b(&check_for_mint, NE); // If R0 or R1 is not a smi do Mint checks.
1020
1021 // Both arguments are smi, '===' is good enough.
1022 __ LoadObject(R0, Bool::False());
1023 __ Ret();
1024 __ Bind(&true_label);
1025 __ LoadObject(R0, Bool::True());
1026 __ Ret();
1027
1028 // At least one of the arguments was not Smi.
1029 Label receiver_not_smi;
1030 __ Bind(&check_for_mint);
1031
1032 __ tst(R1, ShifterOperand(kSmiTagMask)); // Check receiver.
1033 __ b(&receiver_not_smi, NE);
1034
1035 // Left (receiver) is Smi, return false if right is not Double.
1036 // Note that an instance of Mint or Bigint never contains a value that can be
1037 // represented by Smi.
1038
1039 __ CompareClassId(R0, kDoubleCid, R2);
1040 __ b(&fall_through, EQ);
1041 __ LoadObject(R0, Bool::False()); // Smi == Mint -> false.
1042 __ Ret();
1043
1044 __ Bind(&receiver_not_smi);
1045 // R1:: receiver.
1046
1047 __ CompareClassId(R1, kMintCid, R2);
1048 __ b(&fall_through, NE);
1049 // Receiver is Mint, return false if right is Smi.
1050 __ tst(R0, ShifterOperand(kSmiTagMask));
1051 __ b(&fall_through, NE);
1052 __ LoadObject(R0, Bool::False());
1053 __ Ret();
1054 // TODO(srdjan): Implement Mint == Mint comparison.
1055
1056 __ Bind(&fall_through);
210 return false; 1057 return false;
211 } 1058 }
212 1059
213 1060
214 bool Intrinsifier::Integer_equal(Assembler* assembler) { 1061 bool Intrinsifier::Integer_equal(Assembler* assembler) {
215 return false; 1062 return Integer_equalToInteger(assembler);
216 } 1063 }
217 1064
218 1065
219 bool Intrinsifier::Integer_sar(Assembler* assembler) { 1066 bool Intrinsifier::Integer_sar(Assembler* assembler) {
1067 Label fall_through;
1068
1069 TestBothArgumentsSmis(assembler, &fall_through);
1070 // Shift amount in R0. Value to shift in R1.
1071
1072 // Fall through if shift amount is negative.
1073 __ SmiUntag(R0);
1074 __ CompareImmediate(R0, 0);
1075 __ b(&fall_through, LT);
1076
1077 // If shift amount is bigger than 31, set to 31.
1078 __ CompareImmediate(R0, 0x1F);
1079 __ LoadImmediate(R0, 0x1F, GT);
1080 __ SmiUntag(R1);
1081 __ mov(R0, ShifterOperand(R1, ASR, R0));
1082 __ SmiTag(R0);
1083 __ Ret();
1084 __ Bind(&fall_through);
220 return false; 1085 return false;
221 } 1086 }
222 1087
223 1088
224 bool Intrinsifier::Smi_bitNegate(Assembler* assembler) { 1089 bool Intrinsifier::Smi_bitNegate(Assembler* assembler) {
1090 __ ldr(R0, Address(SP, 0 * kWordSize));
1091 __ mvn(R0, ShifterOperand(R0));
1092 __ bic(R0, R0, ShifterOperand(kSmiTagMask)); // Remove inverted smi-tag.
1093 __ Ret();
1094 return false;
1095 }
1096
1097
1098 // Check if the last argument is a double, jump to label 'is_smi' if smi
1099 // (easy to convert to double), otherwise jump to label 'not_double_smi',
1100 // Returns the last argument in R0.
1101 static void TestLastArgumentIsDouble(Assembler* assembler,
1102 Label* is_smi,
1103 Label* not_double_smi) {
1104 __ ldr(R0, Address(SP, 0 * kWordSize));
1105 __ tst(R0, ShifterOperand(kSmiTagMask));
1106 __ b(is_smi, EQ);
1107 __ CompareClassId(R0, kDoubleCid, R1);
1108 __ b(not_double_smi, NE);
1109 // Fall through with Double in R0.
1110 }
1111
1112
1113 // Both arguments on stack, arg0 (left) is a double, arg1 (right) is of unknown
1114 // type. Return true or false object in the register R0. Any NaN argument
1115 // returns false. Any non-double arg1 causes control flow to fall through to the
1116 // slow case (compiled method body).
1117 static bool CompareDoubles(Assembler* assembler, Condition true_condition) {
1118 Label fall_through, is_smi, double_op;
1119
1120 TestLastArgumentIsDouble(assembler, &is_smi, &fall_through);
1121 // Both arguments are double, right operand is in R0.
1122
1123 __ AddImmediate(R0, Double::value_offset() - kHeapObjectTag);
1124 __ vldrd(D1, Address(R0));
1125 __ Bind(&double_op);
1126 __ ldr(R0, Address(SP, 1 * kWordSize)); // Left argument.
1127 __ AddImmediate(R0, Double::value_offset() - kHeapObjectTag);
1128 __ vldrd(D0, Address(R0));
1129
1130 __ vcmpd(D0, D1);
1131 __ vmstat();
1132 __ LoadObject(R0, Bool::False());
1133 // Return false if D0 or D1 was NaN before checking true condition.
1134 __ mov(PC, ShifterOperand(LR), VS);
1135 __ LoadObject(R0, Bool::True(), true_condition);
1136 __ Ret();
1137
1138 __ Bind(&is_smi); // Convert R0 to a double.
1139 __ SmiUntag(R0);
1140 __ vmovsr(S0, R0);
1141 __ vcvtdi(D1, S0);
1142 __ b(&double_op); // Then do the comparison.
1143 __ Bind(&fall_through);
225 return false; 1144 return false;
226 } 1145 }
227 1146
228 1147
229 bool Intrinsifier::Double_greaterThan(Assembler* assembler) { 1148 bool Intrinsifier::Double_greaterThan(Assembler* assembler) {
230 return false; 1149 return CompareDoubles(assembler, HI);
231 } 1150 }
232 1151
233 1152
234 bool Intrinsifier::Double_greaterEqualThan(Assembler* assembler) { 1153 bool Intrinsifier::Double_greaterEqualThan(Assembler* assembler) {
235 return false; 1154 return CompareDoubles(assembler, CS);
236 } 1155 }
237 1156
238 1157
239 bool Intrinsifier::Double_lessThan(Assembler* assembler) { 1158 bool Intrinsifier::Double_lessThan(Assembler* assembler) {
240 return false; 1159 return CompareDoubles(assembler, CC);
241 } 1160 }
242 1161
243 1162
244 bool Intrinsifier::Double_equal(Assembler* assembler) { 1163 bool Intrinsifier::Double_equal(Assembler* assembler) {
245 return false; 1164 return CompareDoubles(assembler, EQ);
246 } 1165 }
247 1166
248 1167
249 bool Intrinsifier::Double_lessEqualThan(Assembler* assembler) { 1168 bool Intrinsifier::Double_lessEqualThan(Assembler* assembler) {
1169 return CompareDoubles(assembler, LS);
1170 }
1171
1172
1173 // Expects left argument to be double (receiver). Right argument is unknown.
1174 // Both arguments are on stack.
1175 static bool DoubleArithmeticOperations(Assembler* assembler, Token::Kind kind) {
1176 Label fall_through;
1177
1178 TestLastArgumentIsDouble(assembler, &fall_through, &fall_through);
1179 // Both arguments are double, right operand is in R0.
1180 // Can't use FieldAddress here. R0 is heap-object-tagged, so the offset will
1181 // not be 4-byte aligned.
1182 __ AddImmediate(R0, Double::value_offset() - kHeapObjectTag);
1183 __ vldrd(D1, Address(R0));
1184 __ ldr(R0, Address(SP, 1 * kWordSize)); // Left argument.
1185 __ AddImmediate(R0, Double::value_offset() - kHeapObjectTag);
1186 __ vldrd(D0, Address(R0));
1187 switch (kind) {
1188 case Token::kADD: __ vaddd(D0, D0, D1); break;
1189 case Token::kSUB: __ vsubd(D0, D0, D1); break;
1190 case Token::kMUL: __ vmuld(D0, D0, D1); break;
1191 case Token::kDIV: __ vdivd(D0, D0, D1); break;
1192 default: UNREACHABLE();
1193 }
1194 const Class& double_class = Class::Handle(
1195 Isolate::Current()->object_store()->double_class());
1196 __ TryAllocate(double_class, &fall_through, R0); // Result register.
1197 __ AddImmediate(R1, R0, Double::value_offset() - kHeapObjectTag);
1198 __ vstrd(D0, Address(R1));
1199 __ Ret();
1200 __ Bind(&fall_through);
250 return false; 1201 return false;
251 } 1202 }
252 1203
253 1204
254 bool Intrinsifier::Double_add(Assembler* assembler) { 1205 bool Intrinsifier::Double_add(Assembler* assembler) {
255 return false; 1206 return DoubleArithmeticOperations(assembler, Token::kADD);
256 } 1207 }
257 1208
258 1209
259 bool Intrinsifier::Double_mul(Assembler* assembler) { 1210 bool Intrinsifier::Double_mul(Assembler* assembler) {
260 return false; 1211 return DoubleArithmeticOperations(assembler, Token::kMUL);
261 } 1212 }
262 1213
263 1214
264 bool Intrinsifier::Double_sub(Assembler* assembler) { 1215 bool Intrinsifier::Double_sub(Assembler* assembler) {
265 return false; 1216 return DoubleArithmeticOperations(assembler, Token::kSUB);
266 } 1217 }
267 1218
268 1219
269 bool Intrinsifier::Double_div(Assembler* assembler) { 1220 bool Intrinsifier::Double_div(Assembler* assembler) {
270 return false; 1221 return DoubleArithmeticOperations(assembler, Token::kDIV);
271 } 1222 }
272 1223
273 1224
1225 // Left is double right is integer (Bigint, Mint or Smi)
274 bool Intrinsifier::Double_mulFromInteger(Assembler* assembler) { 1226 bool Intrinsifier::Double_mulFromInteger(Assembler* assembler) {
1227 Label fall_through;
1228 __ Untested("Intrinsifier::Double_mulFromInteger");
1229 // Only Smi-s allowed.
1230 __ ldr(R0, Address(SP, 0 * kWordSize));
1231 __ tst(R0, ShifterOperand(kSmiTagMask));
1232 __ b(&fall_through, NE);
1233 // Is Smi.
1234 __ SmiUntag(R0);
1235 __ vmovsr(S0, R0);
1236 __ vcvtdi(D1, S0);
1237 __ ldr(R0, Address(SP, 1 * kWordSize));
1238 __ AddImmediate(R0, Double::value_offset() - kHeapObjectTag);
1239 __ vldrd(D0, Address(R0));
1240 __ vmuld(D0, D0, D1);
1241 const Class& double_class = Class::Handle(
1242 Isolate::Current()->object_store()->double_class());
1243 __ TryAllocate(double_class, &fall_through, R0); // Result register.
1244 __ AddImmediate(R1, R0, Double::value_offset() - kHeapObjectTag);
1245 __ vstrd(D0, Address(R1));
1246 __ Ret();
1247 __ Bind(&fall_through);
275 return false; 1248 return false;
276 } 1249 }
277 1250
278 1251
279 bool Intrinsifier::Double_fromInteger(Assembler* assembler) { 1252 bool Intrinsifier::Double_fromInteger(Assembler* assembler) {
1253 Label fall_through;
1254
1255 __ ldr(R0, Address(SP, 0 * kWordSize));
1256 __ tst(R0, ShifterOperand(kSmiTagMask));
1257 __ b(&fall_through, NE);
1258 // Is Smi.
1259 __ SmiUntag(R0);
1260 __ vmovsr(S0, R0);
1261 __ vcvtdi(D0, S0);
1262 const Class& double_class = Class::Handle(
1263 Isolate::Current()->object_store()->double_class());
1264 __ TryAllocate(double_class, &fall_through, R0); // Result register.
1265 __ AddImmediate(R1, R0, Double::value_offset() - kHeapObjectTag);
1266 __ vstrd(D0, Address(R1));
1267 __ Ret();
1268 __ Bind(&fall_through);
280 return false; 1269 return false;
281 } 1270 }
282 1271
283 1272
284 bool Intrinsifier::Double_getIsNaN(Assembler* assembler) { 1273 bool Intrinsifier::Double_getIsNaN(Assembler* assembler) {
285 return false; 1274 Label is_true;
1275 __ Untested("Intrinsifier::Double_getIsNaN");
1276 __ ldr(R0, Address(SP, 0 * kWordSize));
1277 __ AddImmediate(R0, Double::value_offset() - kHeapObjectTag);
1278 __ vldrd(D0, Address(R0));
1279 __ vcmpd(D0, D0);
1280 __ vmstat();
1281 __ LoadObject(R0, Bool::False(), VS);
1282 __ LoadObject(R0, Bool::True(), VC);
1283 __ Ret();
1284 return true;
286 } 1285 }
287 1286
288 1287
289 bool Intrinsifier::Double_getIsNegative(Assembler* assembler) { 1288 bool Intrinsifier::Double_getIsNegative(Assembler* assembler) {
290 return false; 1289 Label is_false, is_true, is_zero;
1290 __ Untested("Intrinsifier::Double_getIsNegative");
1291 __ ldr(R0, Address(SP, 0 * kWordSize));
1292 __ AddImmediate(R0, Double::value_offset() - kHeapObjectTag);
1293 __ vldrd(D0, Address(R0));
1294 __ LoadDImmediate(D1, 0.0, R1);
1295 __ vcmpd(D0, D1);
1296 __ vmstat();
1297 __ b(&is_false, VS); // NaN -> false.
1298 __ b(&is_zero, EQ); // Check for negative zero.
1299 __ b(&is_false, CS); // >= 0 -> false.
1300
1301 __ Bind(&is_true);
1302 __ LoadObject(R0, Bool::True());
1303 __ Ret();
1304
1305 __ Bind(&is_false);
1306 __ LoadObject(R0, Bool::False());
1307 __ Ret();
1308
1309 __ Bind(&is_zero);
1310 // Check for negative zero by looking at the sign bit.
1311 __ vmovrrd(R0, R1, D0); // R1:R0 <- D0, so sign bit is in bit 31 of R1.
1312 __ mov(R1, ShifterOperand(R1, LSR, 31));
1313 __ tst(R1, ShifterOperand(1));
1314 __ b(&is_true, NE); // Sign bit set.
1315 __ b(&is_false);
1316 return true;
291 } 1317 }
292 1318
293 1319
294 bool Intrinsifier::Double_toInt(Assembler* assembler) { 1320 bool Intrinsifier::Double_toInt(Assembler* assembler) {
1321 __ ldr(R0, Address(SP, 0 * kWordSize));
1322 __ AddImmediate(R0, Double::value_offset() - kHeapObjectTag);
1323 __ vldrd(D0, Address(R0));
1324 __ vcvtid(S0, D0);
1325 __ vmovrs(R0, S0);
1326 // Overflow is signaled with minint.
1327 Label fall_through;
1328 // Check for overflow and that it fits into Smi.
1329 __ CompareImmediate(R0, 0xC0000000);
1330 __ b(&fall_through, MI);
1331 __ SmiTag(R0);
1332 __ Ret();
1333 __ Bind(&fall_through);
295 return false; 1334 return false;
296 } 1335 }
297 1336
298 1337
299 bool Intrinsifier::Math_sqrt(Assembler* assembler) { 1338 bool Intrinsifier::Math_sqrt(Assembler* assembler) {
300 return false; 1339 Label fall_through, is_smi, double_op;
301 } 1340 __ Untested("Intrinsifier::Math_sqrt");
302 1341 TestLastArgumentIsDouble(assembler, &is_smi, &fall_through);
1342 // Argument is double and is in R0.
1343 __ AddImmediate(R0, Double::value_offset() - kHeapObjectTag);
1344 __ vldrd(D1, Address(R0));
1345 __ Bind(&double_op);
1346 __ vsqrtd(D0, D1);
1347 const Class& double_class = Class::Handle(
1348 Isolate::Current()->object_store()->double_class());
1349 __ TryAllocate(double_class, &fall_through, R0); // Result register.
1350 __ AddImmediate(R1, R0, Double::value_offset() - kHeapObjectTag);
1351 __ vstrd(D0, Address(R1));
1352 __ Ret();
1353 __ Bind(&is_smi);
1354 __ SmiUntag(R0);
1355 __ vmovsr(S0, R0);
1356 __ vcvtdi(D1, S0);
1357 __ b(&double_op);
1358 __ Bind(&fall_through);
1359 return false;
1360 }
1361
303 1362
304 bool Intrinsifier::Math_sin(Assembler* assembler) { 1363 bool Intrinsifier::Math_sin(Assembler* assembler) {
305 return false; 1364 return false;
306 } 1365 }
307 1366
308 1367
309 bool Intrinsifier::Math_cos(Assembler* assembler) { 1368 bool Intrinsifier::Math_cos(Assembler* assembler) {
310 return false; 1369 return false;
311 } 1370 }
312 1371
313 1372
1373 // var state = ((_A * (_state[kSTATE_LO])) + _state[kSTATE_HI]) & _MASK_64;
1374 // _state[kSTATE_LO] = state & _MASK_32;
1375 // _state[kSTATE_HI] = state >> 32;
314 bool Intrinsifier::Random_nextState(Assembler* assembler) { 1376 bool Intrinsifier::Random_nextState(Assembler* assembler) {
315 return false; 1377 const Library& math_lib = Library::Handle(Library::MathLibrary());
1378 ASSERT(!math_lib.IsNull());
1379 const Class& random_class =
1380 Class::Handle(math_lib.LookupClassAllowPrivate(Symbols::_Random()));
1381 ASSERT(!random_class.IsNull());
1382 const Field& state_field = Field::ZoneHandle(
1383 random_class.LookupInstanceField(Symbols::_state()));
1384 ASSERT(!state_field.IsNull());
1385 const Field& random_A_field = Field::ZoneHandle(
1386 random_class.LookupStaticField(Symbols::_A()));
1387 ASSERT(!random_A_field.IsNull());
1388 ASSERT(random_A_field.is_const());
1389 const Instance& a_value = Instance::Handle(random_A_field.value());
1390 const int64_t a_int_value = Integer::Cast(a_value).AsInt64Value();
1391 // 'a_int_value' is a mask.
1392 ASSERT(Utils::IsUint(32, a_int_value));
1393 int32_t a_int32_value = static_cast<int32_t>(a_int_value);
1394
1395 __ Untested("Random_nextState");
1396
1397 __ ldr(R0, Address(SP, 0 * kWordSize)); // Receiver.
1398 __ ldr(R1, FieldAddress(R0, state_field.Offset())); // Field '_state'.
1399 // Addresses of _state[0] and _state[1].
1400 Address addr_0 = FlowGraphCompiler::ElementAddressForIntIndex(
1401 kTypedDataUint32ArrayCid,
1402 FlowGraphCompiler::ElementSizeFor(kTypedDataUint32ArrayCid),
1403 R1,
1404 0);
1405 Address addr_1 = FlowGraphCompiler::ElementAddressForIntIndex(
1406 kTypedDataUint32ArrayCid,
1407 FlowGraphCompiler::ElementSizeFor(kTypedDataUint32ArrayCid),
1408 R1,
1409 1);
1410 __ LoadImmediate(R0, a_int32_value);
1411 __ ldr(R2, addr_0);
1412 __ ldr(R3, addr_1);
1413 __ mov(R6, ShifterOperand(R3, ASR, 31)); // Sign extend into R6.
1414 // 64-bit multiply and accumulate into R6:R3.
1415 __ smlal(R3, R6, R0, R2); // R6:R3 <- R6:R3 + R0 * R2.
1416 __ str(R3, addr_0);
1417 __ str(R6, addr_1);
1418 __ Ret();
1419 return true;
316 } 1420 }
317 1421
318 1422
319 bool Intrinsifier::Object_equal(Assembler* assembler) { 1423 bool Intrinsifier::Object_equal(Assembler* assembler) {
320 return false; 1424 __ ldr(R0, Address(SP, 0 * kWordSize));
1425 __ ldr(R1, Address(SP, 1 * kWordSize));
1426 __ cmp(R0, ShifterOperand(R1));
1427 __ LoadObject(R0, Bool::False(), NE);
1428 __ LoadObject(R0, Bool::True(), EQ);
1429 __ Ret();
1430 return true;
321 } 1431 }
322 1432
323 1433
324 bool Intrinsifier::String_getHashCode(Assembler* assembler) { 1434 bool Intrinsifier::String_getHashCode(Assembler* assembler) {
1435 __ Untested("Intrinsifier::String_getHashCode");
1436 __ ldr(R0, Address(SP, 0 * kWordSize));
1437 __ ldr(R0, FieldAddress(R0, String::hash_offset()));
1438 __ cmp(R0, ShifterOperand(0));
1439 __ mov(PC, ShifterOperand(LR), NE); // Hash not yet computed.
325 return false; 1440 return false;
326 } 1441 }
327 1442
328 1443
329 bool Intrinsifier::String_getLength(Assembler* assembler) { 1444 bool Intrinsifier::String_getLength(Assembler* assembler) {
330 return false; 1445 __ ldr(R0, Address(SP, 0 * kWordSize));
331 } 1446 __ ldr(R0, FieldAddress(R0, String::length_offset()));
332 1447 __ Ret();
333 1448 return true;
1449 }
1450
1451
1452 // TODO(srdjan): Implement for two and four byte strings as well.
334 bool Intrinsifier::String_codeUnitAt(Assembler* assembler) { 1453 bool Intrinsifier::String_codeUnitAt(Assembler* assembler) {
1454 Label fall_through;
1455
1456 __ ldr(R1, Address(SP, 0 * kWordSize)); // Index.
1457 __ ldr(R0, Address(SP, 1 * kWordSize)); // String.
1458 __ tst(R1, ShifterOperand(kSmiTagMask));
1459 __ b(&fall_through, NE); // Index is not a Smi.
1460 // Range check.
1461 __ ldr(R2, FieldAddress(R0, String::length_offset()));
1462 __ cmp(R1, ShifterOperand(R2));
1463 __ b(&fall_through, CS); // Runtime throws exception.
1464 __ CompareClassId(R0, kOneByteStringCid, R3);
1465 __ b(&fall_through, NE);
1466 __ SmiUntag(R1);
1467 __ AddImmediate(R0, OneByteString::data_offset() - kHeapObjectTag);
1468 __ ldrb(R0, Address(R0, R1));
1469 __ SmiTag(R0);
1470 __ Ret();
1471 __ Bind(&fall_through);
335 return false; 1472 return false;
336 } 1473 }
337 1474
338 1475
339 bool Intrinsifier::String_getIsEmpty(Assembler* assembler) { 1476 bool Intrinsifier::String_getIsEmpty(Assembler* assembler) {
340 return false; 1477 __ ldr(R0, Address(SP, 0 * kWordSize));
1478 __ ldr(R0, FieldAddress(R0, String::length_offset()));
1479 __ cmp(R0, ShifterOperand(Smi::RawValue(0)));
1480 __ LoadObject(R0, Bool::True(), EQ);
1481 __ LoadObject(R0, Bool::False(), NE);
1482 __ Ret();
1483 return true;
341 } 1484 }
342 1485
343 1486
344 bool Intrinsifier::OneByteString_getHashCode(Assembler* assembler) { 1487 bool Intrinsifier::OneByteString_getHashCode(Assembler* assembler) {
345 return false; 1488 __ ldr(R1, Address(SP, 0 * kWordSize));
346 } 1489 __ ldr(R0, FieldAddress(R1, String::hash_offset()));
347 1490 __ cmp(R0, ShifterOperand(0));
348 1491 __ mov(PC, ShifterOperand(LR), NE); // Return if already computed.
1492
1493 __ ldr(R2, FieldAddress(R1, String::length_offset()));
1494
1495 Label done;
1496 // If the string is empty, set the hash to 1, and return.
1497 __ cmp(R2, ShifterOperand(Smi::RawValue(0)));
1498 __ b(&done, EQ);
1499
1500 __ SmiUntag(R2);
1501 __ mov(R3, ShifterOperand(0));
1502 __ AddImmediate(R6, R1, OneByteString::data_offset() - kHeapObjectTag);
1503 // R1: Instance of OneByteString.
1504 // R2: String length, untagged integer.
1505 // R3: Loop counter, untagged integer.
1506 // R6: String data.
1507 // R0: Hash code, untagged integer.
1508
1509 Label loop;
1510 // Add to hash code: (hash_ is uint32)
1511 // hash_ += ch;
1512 // hash_ += hash_ << 10;
1513 // hash_ ^= hash_ >> 6;
1514 // Get one characters (ch).
1515 __ Bind(&loop);
1516 __ ldrb(R7, Address(R6, 0));
1517 // R7: ch.
1518 __ add(R3, R3, ShifterOperand(1));
1519 __ add(R6, R6, ShifterOperand(1));
1520 __ add(R0, R0, ShifterOperand(R7));
1521 __ add(R0, R0, ShifterOperand(R0, LSL, 10));
1522 __ eor(R0, R0, ShifterOperand(R0, LSR, 6));
1523 __ cmp(R3, ShifterOperand(R2));
1524 __ b(&loop, NE);
1525
1526 // Finalize.
1527 // hash_ += hash_ << 3;
1528 // hash_ ^= hash_ >> 11;
1529 // hash_ += hash_ << 15;
1530 __ add(R0, R0, ShifterOperand(R0, LSL, 3));
1531 __ eor(R0, R0, ShifterOperand(R0, LSR, 11));
1532 __ add(R0, R0, ShifterOperand(R0, LSL, 15));
1533 // hash_ = hash_ & ((static_cast<intptr_t>(1) << bits) - 1);
1534 __ LoadImmediate(R2, (static_cast<intptr_t>(1) << String::kHashBits) - 1);
1535 __ and_(R0, R0, ShifterOperand(R2));
1536 __ cmp(R0, ShifterOperand(0));
1537 // return hash_ == 0 ? 1 : hash_;
1538 __ Bind(&done);
1539 __ mov(R0, ShifterOperand(1), EQ);
1540 __ SmiTag(R0);
1541 __ str(R0, FieldAddress(R1, String::hash_offset()));
1542 __ Ret();
1543 return false;
1544 }
1545
1546
1547 // Allocates one-byte string of length 'end - start'. The content is not
1548 // initialized.
1549 // 'length-reg' (R2) contains tagged length.
1550 // Returns new string as tagged pointer in R0.
1551 static void TryAllocateOnebyteString(Assembler* assembler,
1552 Label* ok,
1553 Label* failure) {
1554 const Register length_reg = R2;
1555 Label fail;
1556
1557 __ mov(R6, ShifterOperand(length_reg)); // Save the length register.
1558 __ SmiUntag(length_reg);
1559 const intptr_t fixed_size = sizeof(RawString) + kObjectAlignment - 1;
1560 __ AddImmediate(length_reg, fixed_size);
1561 __ bic(length_reg, length_reg, ShifterOperand(kObjectAlignment - 1));
1562
1563 Isolate* isolate = Isolate::Current();
1564 Heap* heap = isolate->heap();
1565
1566 __ LoadImmediate(R3, heap->TopAddress());
1567 __ ldr(R0, Address(R3, 0));
1568
1569 // length_reg: allocation size.
1570 __ adds(R1, R0, ShifterOperand(length_reg));
1571 __ b(&fail, VS); // Fail on overflow.
1572
1573 // Check if the allocation fits into the remaining space.
1574 // R0: potential new object start.
1575 // R1: potential next object start.
1576 // R2: allocation size.
1577 // R3: heap->Top->Address().
1578 __ LoadImmediate(R7, heap->EndAddress());
1579 __ ldr(R7, Address(R7, 0));
1580 __ cmp(R1, ShifterOperand(R7));
1581 __ b(&fail, CS);
1582
1583 // Successfully allocated the object(s), now update top to point to
1584 // next object start and initialize the object.
1585 __ str(R1, Address(R3, 0));
1586 __ AddImmediate(R0, kHeapObjectTag);
1587
1588 // Initialize the tags.
1589 // R0: new object start as a tagged pointer.
1590 // R1: new object end address.
1591 // R2: allocation size.
1592 {
1593 const intptr_t shift = RawObject::kSizeTagBit - kObjectAlignmentLog2;
1594 const Class& cls =
1595 Class::Handle(isolate->object_store()->one_byte_string_class());
1596
1597 __ CompareImmediate(R2, RawObject::SizeTag::kMaxSizeTag);
1598 __ mov(R2, ShifterOperand(R2, LSL, shift), LS);
1599 __ mov(R2, ShifterOperand(0), HI);
1600
1601 // Get the class index and insert it into the tags.
1602 // R2: size and bit tags.
1603 __ LoadImmediate(TMP, RawObject::ClassIdTag::encode(cls.id()));
1604 __ orr(R2, R2, ShifterOperand(TMP));
1605 __ str(R2, FieldAddress(R0, String::tags_offset())); // Store tags.
1606 }
1607
1608 // Set the length field using the saved length (R6).
1609 __ StoreIntoObjectNoBarrier(R0,
1610 FieldAddress(R0, String::length_offset()),
1611 R6);
1612 // Clear hash.
1613 __ LoadImmediate(TMP, 0);
1614 __ str(TMP, FieldAddress(R0, String::hash_offset()));
1615 __ b(ok);
1616
1617 __ Bind(&fail);
1618 __ b(failure);
1619 }
1620
1621
1622 // Arg0: Onebyte String
1623 // Arg1: Start index as Smi.
1624 // Arg2: End index as Smi.
1625 // The indexes must be valid.
349 bool Intrinsifier::OneByteString_substringUnchecked(Assembler* assembler) { 1626 bool Intrinsifier::OneByteString_substringUnchecked(Assembler* assembler) {
1627 const intptr_t kStringOffset = 2 * kWordSize;
1628 const intptr_t kStartIndexOffset = 1 * kWordSize;
1629 const intptr_t kEndIndexOffset = 0 * kWordSize;
1630 Label fall_through, ok;
1631
1632 __ ldr(R2, Address(SP, kEndIndexOffset));
1633 __ ldr(TMP, Address(SP, kStartIndexOffset));
1634 __ sub(R2, R2, ShifterOperand(TMP));
1635 TryAllocateOnebyteString(assembler, &ok, &fall_through);
1636 __ Bind(&ok);
1637 // R0: new string as tagged pointer.
1638 // Copy string.
1639 __ ldr(R3, Address(SP, kStringOffset));
1640 __ ldr(R1, Address(SP, kStartIndexOffset));
1641 __ SmiUntag(R1);
1642 __ add(R3, R3, ShifterOperand(R1));
1643 // Calculate start address and untag (- 1).
1644 __ AddImmediate(R3, OneByteString::data_offset() - 1);
1645
1646 // R3: Start address to copy from (untagged).
1647 // R1: Untagged start index.
1648 __ ldr(R2, Address(SP, kEndIndexOffset));
1649 __ SmiUntag(R2);
1650 __ sub(R2, R2, ShifterOperand(R1));
1651
1652 // R3: Start address to copy from (untagged).
1653 // R2: Untagged number of bytes to copy.
1654 // R0: Tagged result string.
1655 // R6: Pointer into R3.
1656 // R7: Pointer into R0.
1657 // R1: Scratch register.
1658 Label loop, done;
1659 __ cmp(R2, ShifterOperand(0));
1660 __ b(&done, LE);
1661 __ mov(R6, ShifterOperand(R3));
1662 __ mov(R7, ShifterOperand(R0));
1663 __ Bind(&loop);
1664 __ ldrb(R1, Address(R6, 0));
1665 __ AddImmediate(R6, 1);
1666 __ sub(R2, R2, ShifterOperand(1));
1667 __ cmp(R2, ShifterOperand(0));
1668 __ strb(R1, FieldAddress(R7, OneByteString::data_offset()));
1669 __ AddImmediate(R7, 1);
1670 __ b(&loop, GT);
1671
1672 __ Bind(&done);
1673 __ Ret();
1674 __ Bind(&fall_through);
350 return false; 1675 return false;
351 } 1676 }
352 1677
353 1678
354 bool Intrinsifier::OneByteString_setAt(Assembler* assembler) { 1679 bool Intrinsifier::OneByteString_setAt(Assembler* assembler) {
355 return false; 1680 __ ldr(R2, Address(SP, 0 * kWordSize)); // Value.
1681 __ ldr(R1, Address(SP, 1 * kWordSize)); // Index.
1682 __ ldr(R0, Address(SP, 2 * kWordSize)); // OneByteString.
1683 __ SmiUntag(R1);
1684 __ SmiUntag(R2);
1685 __ AddImmediate(R3, R0, OneByteString::data_offset() - kHeapObjectTag);
1686 __ strb(R2, Address(R3, R1));
1687 __ Ret();
1688 return true;
356 } 1689 }
357 1690
358 1691
359 bool Intrinsifier::OneByteString_allocate(Assembler* assembler) { 1692 bool Intrinsifier::OneByteString_allocate(Assembler* assembler) {
360 return false; 1693 __ ldr(R2, Address(SP, 0 * kWordSize)); // Length.
361 } 1694 Label fall_through, ok;
362 1695 TryAllocateOnebyteString(assembler, &ok, &fall_through);
1696
1697 __ Bind(&ok);
1698 __ Ret();
1699
1700 __ Bind(&fall_through);
1701 return false;
1702 }
1703
363 } // namespace dart 1704 } // namespace dart
364 1705
365 #endif // defined TARGET_ARCH_ARM 1706 #endif // defined TARGET_ARCH_ARM
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698