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

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
« no previous file with comments | « runtime/vm/flow_graph_compiler_arm.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
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 __ bx(LR, CC);
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 __ bx(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 __ bx(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 __ bx(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 __ bx(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 __ bx(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 __ bx(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 __ bx(LR, EQ); // left is 0? Return 0.
681 __ cmp(left, ShifterOperand(right));
682 __ mov(R0, ShifterOperand(0), EQ);
683 __ bx(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 __ bx(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
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 // Check to see if we have integer division
715 if (!CPUFeatures::integer_division_supported())
716 return false;
717
718 Label fall_through, subtract;
719 TestBothArgumentsSmis(assembler, &fall_through);
720 // R1: Tagged left (dividend).
721 // R0: Tagged right (divisor).
722 // Check if modulo by zero -> exception thrown in main function.
723 __ cmp(R0, ShifterOperand(0));
724 __ b(&fall_through, EQ);
725 EmitRemainderOperation(assembler);
726 // Untagged right in R0. Untagged remainder result in R1.
727
728 __ cmp(R1, ShifterOperand(0));
729 __ mov(R0, ShifterOperand(R1, LSL, 1), GE); // Tag and move result to R0.
730 __ bx(LR, GE);
731
732 // Result is negative, adjust it.
733 __ cmp(R0, ShifterOperand(0));
734 __ sub(R0, R1, ShifterOperand(R0), LT);
735 __ add(R0, R1, ShifterOperand(R0), GE);
736 __ SmiTag(R0);
737 __ Ret();
738
739 __ Bind(&fall_through);
130 return false; 740 return false;
131 } 741 }
132 742
133 743
134 bool Intrinsifier::Integer_remainder(Assembler* assembler) { 744 bool Intrinsifier::Integer_remainder(Assembler* assembler) {
745 // Check to see if we have integer division
746 if (!CPUFeatures::integer_division_supported())
747 return false;
748
749 Label fall_through;
750 TestBothArgumentsSmis(assembler, &fall_through);
751 // R1: Tagged left (dividend).
752 // R0: Tagged right (divisor).
753 // Check if modulo by zero -> exception thrown in main function.
754 __ cmp(R0, ShifterOperand(0));
755 __ b(&fall_through, EQ);
756 EmitRemainderOperation(assembler);
757 // Untagged remainder result in R1.
758 __ mov(R0, ShifterOperand(R1, LSL, 1)); // Tag result and return.
759 __ Ret();
760
761 __ Bind(&fall_through);
135 return false; 762 return false;
136 } 763 }
137 764
138 765
139 bool Intrinsifier::Integer_truncDivide(Assembler* assembler) { 766 bool Intrinsifier::Integer_truncDivide(Assembler* assembler) {
767 // Check to see if we have integer division
768 if (!CPUFeatures::integer_division_supported())
769 return false;
770
771 Label fall_through;
772
773 TestBothArgumentsSmis(assembler, &fall_through);
774 __ cmp(R0, ShifterOperand(0));
775 __ b(&fall_through, EQ); // If b is 0, fall through.
776
777 __ SmiUntag(R0);
778 __ SmiUntag(R1);
779 __ sdiv(R0, R1, R0);
780 // Check the corner case of dividing the 'MIN_SMI' with -1, in which case we
781 // cannot tag the result.
782 __ CompareImmediate(R0, 0x40000000);
783 __ SmiTag(R0, NE); // Not equal. Okay to tag and return.
784 __ bx(LR, NE); // Return.
785 __ Bind(&fall_through);
140 return false; 786 return false;
141 } 787 }
142 788
143 789
144 bool Intrinsifier::Integer_negate(Assembler* assembler) { 790 bool Intrinsifier::Integer_negate(Assembler* assembler) {
791 __ ldr(R0, Address(SP, + 0 * kWordSize)); // Grab first argument.
792 __ tst(R0, ShifterOperand(kSmiTagMask)); // Test for Smi.
793 __ rsb(R0, R0, ShifterOperand(0), EQ); // R0 is a Smi. R0 <- 0 - R0.
794 __ bx(LR, EQ); // Return.
795 // R0 is not a Smi. Fall through.
145 return false; 796 return false;
146 } 797 }
147 798
148 799
149 bool Intrinsifier::Integer_bitAndFromInteger(Assembler* assembler) { 800 bool Intrinsifier::Integer_bitAndFromInteger(Assembler* assembler) {
801 Label fall_through;
802
803 TestBothArgumentsSmis(assembler, &fall_through); // checks two smis
804 __ and_(R0, R0, ShifterOperand(R1));
805
806 __ Ret();
807 __ Bind(&fall_through);
150 return false; 808 return false;
151 } 809 }
152 810
153 811
154 bool Intrinsifier::Integer_bitAnd(Assembler* assembler) { 812 bool Intrinsifier::Integer_bitAnd(Assembler* assembler) {
155 return false; 813 return Integer_bitAndFromInteger(assembler);
156 } 814 }
157 815
158 816
159 bool Intrinsifier::Integer_bitOrFromInteger(Assembler* assembler) { 817 bool Intrinsifier::Integer_bitOrFromInteger(Assembler* assembler) {
818 Label fall_through;
819
820 TestBothArgumentsSmis(assembler, &fall_through); // checks two smis
821 __ orr(R0, R0, ShifterOperand(R1));
822
823 __ Ret();
824 __ Bind(&fall_through);
160 return false; 825 return false;
161 } 826 }
162 827
163 828
164 bool Intrinsifier::Integer_bitOr(Assembler* assembler) { 829 bool Intrinsifier::Integer_bitOr(Assembler* assembler) {
165 return false; 830 return Integer_bitOrFromInteger(assembler);
166 } 831 }
167 832
168 833
169 bool Intrinsifier::Integer_bitXorFromInteger(Assembler* assembler) { 834 bool Intrinsifier::Integer_bitXorFromInteger(Assembler* assembler) {
835 Label fall_through;
836 __ Untested("Intrinsifier::Integer_bitXorFromInteger");
837
838 TestBothArgumentsSmis(assembler, &fall_through); // checks two smis
839 __ eor(R0, R0, ShifterOperand(R1));
840
841 __ Ret();
842 __ Bind(&fall_through);
170 return false; 843 return false;
171 } 844 }
172 845
173 846
174 bool Intrinsifier::Integer_bitXor(Assembler* assembler) { 847 bool Intrinsifier::Integer_bitXor(Assembler* assembler) {
175 return false; 848 return Integer_bitXorFromInteger(assembler);
176 } 849 }
177 850
178 851
179 bool Intrinsifier::Integer_shl(Assembler* assembler) { 852 bool Intrinsifier::Integer_shl(Assembler* assembler) {
853 ASSERT(kSmiTagShift == 1);
854 ASSERT(kSmiTag == 0);
855 Label fall_through;
856
857 TestBothArgumentsSmis(assembler, &fall_through);
858 __ CompareImmediate(R0, Smi::RawValue(Smi::kBits));
859 __ b(&fall_through, HI);
860
861 __ SmiUntag(R0);
862
863 // Check for overflow by shifting left and shifting back arithmetically.
864 // If the result is different from the original, there was overflow.
865 __ mov(IP, ShifterOperand(R1, LSL, R0));
866 __ cmp(R1, ShifterOperand(IP, ASR, R0));
867
868 // No overflow, result in R0.
869 __ mov(R0, ShifterOperand(R1, LSL, R0), EQ);
870 __ bx(LR, EQ);
871
872 // Arguments are Smi but the shift produced an overflow to Mint.
873 __ CompareImmediate(R6, 0);
874 __ b(&fall_through, LT);
875 __ SmiUntag(R6);
876
877 // Pull off high bits that will be shifted off of R6 by making a mask
878 // ((1 << R0) - 1), shifting it to the left, masking R6, then shifting back.
879 // high bits = (((1 << R0) - 1) << (32 - R0)) & R6) >> (32 - R0)
880 // lo bits = R6 << R0
881 __ LoadImmediate(R7, 1);
882 __ mov(R7, ShifterOperand(R7, LSL, R0)); // R7 <- 1 << R0
883 __ sub(R7, R7, ShifterOperand(1)); // R7 <- R7 - 1
884 __ rsb(R8, R0, ShifterOperand(32)); // R8 <- 32 - R0
885 __ mov(R7, ShifterOperand(R7, LSL, R8)); // R7 <- R7 << R8
886 __ and_(R7, R6, ShifterOperand(R7)); // R7 <- R7 & R6
887 __ mov(R7, ShifterOperand(R7, LSR, R8)); // R7 <- R7 >> R8
888 // Now R7 has the bits that fall off of R6 on a left shift.
889 __ mov(R1, ShifterOperand(R6, LSL, R0)); // R1 gets the low bits.
890
891 const Class& mint_class = Class::Handle(
892 Isolate::Current()->object_store()->mint_class());
893 __ TryAllocate(mint_class, &fall_through, R0);
894
895
896 __ str(R1, FieldAddress(R0, Mint::value_offset()));
897 __ str(R7, FieldAddress(R0, Mint::value_offset() + kWordSize));
898 __ Ret();
899 __ Bind(&fall_through);
900 return false;
901 }
902
903
904 static void Get64SmiOrMint(Assembler* assembler,
905 Register res_hi,
906 Register res_lo,
907 Register reg,
908 Label* not_smi_or_mint) {
909 Label not_smi, done;
910 __ tst(reg, ShifterOperand(kSmiTagMask));
911 __ b(&not_smi, NE);
912 __ SmiUntag(reg);
913
914 // Sign extend to 64 bit
915 __ mov(res_lo, ShifterOperand(reg));
916 __ mov(res_hi, ShifterOperand(res_lo, ASR, 31));
917 __ b(&done);
918
919 __ Bind(&not_smi);
920 __ CompareClassId(reg, kMintCid, res_lo);
921 __ b(not_smi_or_mint, NE);
922
923 // Mint.
924 __ ldr(res_lo, FieldAddress(reg, Mint::value_offset()));
925 __ ldr(res_hi, FieldAddress(reg, Mint::value_offset() + kWordSize));
926 __ Bind(&done);
927 return;
928 }
929
930
931 static bool CompareIntegers(Assembler* assembler, Condition true_condition) {
932 Label try_mint_smi, is_true, is_false, drop_two_fall_through, fall_through;
933 TestBothArgumentsSmis(assembler, &try_mint_smi);
934 // R0 contains the right argument. R1 contains left argument
935
936 __ cmp(R1, ShifterOperand(R0));
937 __ b(&is_true, true_condition);
938 __ Bind(&is_false);
939 __ LoadObject(R0, Bool::False());
940 __ Ret();
941 __ Bind(&is_true);
942 __ LoadObject(R0, Bool::True());
943 __ Ret();
944
945 // 64-bit comparison
946 Condition hi_true_cond, hi_false_cond, lo_false_cond;
947 switch (true_condition) {
948 case LT:
949 case LE:
950 hi_true_cond = LT;
951 hi_false_cond = GT;
952 lo_false_cond = (true_condition == LT) ? CS : HI;
953 break;
954 case GT:
955 case GE:
956 hi_true_cond = GT;
957 hi_false_cond = LT;
958 lo_false_cond = (true_condition == GT) ? LS : CC;
959 break;
960 default:
961 UNREACHABLE();
962 hi_true_cond = hi_false_cond = lo_false_cond = VS;
963 }
964
965 __ Bind(&try_mint_smi);
966 // Get left as 64 bit integer.
967 Get64SmiOrMint(assembler, R3, R2, R1, &fall_through);
968 // Get right as 64 bit integer.
969 Get64SmiOrMint(assembler, R7, R6, R0, &fall_through);
970 // R3: left high.
971 // R2: left low.
972 // R7: right high.
973 // R6: right low.
974
975 __ cmp(R3, ShifterOperand(R7)); // Compare left hi, right high.
976 __ b(&is_false, hi_false_cond);
977 __ b(&is_true, hi_true_cond);
978 __ cmp(R2, ShifterOperand(R6)); // Compare left lo, right lo.
979 __ b(&is_false, lo_false_cond);
980 // Else is true.
981 __ b(&is_true);
982
983 __ Bind(&fall_through);
180 return false; 984 return false;
181 } 985 }
182 986
183 987
184 bool Intrinsifier::Integer_greaterThanFromInt(Assembler* assembler) { 988 bool Intrinsifier::Integer_greaterThanFromInt(Assembler* assembler) {
185 return false; 989 return CompareIntegers(assembler, LT);
186 } 990 }
187 991
188 992
189 bool Intrinsifier::Integer_lessThan(Assembler* assembler) { 993 bool Intrinsifier::Integer_lessThan(Assembler* assembler) {
190 return false; 994 return Integer_greaterThanFromInt(assembler);
191 } 995 }
192 996
193 997
194 bool Intrinsifier::Integer_greaterThan(Assembler* assembler) { 998 bool Intrinsifier::Integer_greaterThan(Assembler* assembler) {
195 return false; 999 return CompareIntegers(assembler, GT);
196 } 1000 }
197 1001
198 1002
199 bool Intrinsifier::Integer_lessEqualThan(Assembler* assembler) { 1003 bool Intrinsifier::Integer_lessEqualThan(Assembler* assembler) {
200 return false; 1004 return CompareIntegers(assembler, LE);
201 } 1005 }
202 1006
203 1007
204 bool Intrinsifier::Integer_greaterEqualThan(Assembler* assembler) { 1008 bool Intrinsifier::Integer_greaterEqualThan(Assembler* assembler) {
205 return false; 1009 return CompareIntegers(assembler, GE);
206 } 1010 }
207 1011
208 1012
1013 // This is called for Smi, Mint and Bigint receivers. The right argument
1014 // can be Smi, Mint, Bigint or double.
209 bool Intrinsifier::Integer_equalToInteger(Assembler* assembler) { 1015 bool Intrinsifier::Integer_equalToInteger(Assembler* assembler) {
1016 Label fall_through, true_label, check_for_mint;
1017 // For integer receiver '===' check first.
1018 __ ldr(R0, Address(SP, 0 * kWordSize));
1019 __ ldr(R1, Address(SP, 1 * kWordSize));
1020 __ cmp(R0, ShifterOperand(R1));
1021 __ b(&true_label, EQ);
1022
1023 __ orr(R2, R0, ShifterOperand(R1));
1024 __ tst(R2, ShifterOperand(kSmiTagMask));
1025 __ b(&check_for_mint, NE); // If R0 or R1 is not a smi do Mint checks.
1026
1027 // Both arguments are smi, '===' is good enough.
1028 __ LoadObject(R0, Bool::False());
1029 __ Ret();
1030 __ Bind(&true_label);
1031 __ LoadObject(R0, Bool::True());
1032 __ Ret();
1033
1034 // At least one of the arguments was not Smi.
1035 Label receiver_not_smi;
1036 __ Bind(&check_for_mint);
1037
1038 __ tst(R1, ShifterOperand(kSmiTagMask)); // Check receiver.
1039 __ b(&receiver_not_smi, NE);
1040
1041 // Left (receiver) is Smi, return false if right is not Double.
1042 // Note that an instance of Mint or Bigint never contains a value that can be
1043 // represented by Smi.
1044
1045 __ CompareClassId(R0, kDoubleCid, R2);
1046 __ b(&fall_through, EQ);
1047 __ LoadObject(R0, Bool::False()); // Smi == Mint -> false.
1048 __ Ret();
1049
1050 __ Bind(&receiver_not_smi);
1051 // R1:: receiver.
1052
1053 __ CompareClassId(R1, kMintCid, R2);
1054 __ b(&fall_through, NE);
1055 // Receiver is Mint, return false if right is Smi.
1056 __ tst(R0, ShifterOperand(kSmiTagMask));
1057 __ b(&fall_through, NE);
1058 __ LoadObject(R0, Bool::False());
1059 __ Ret();
1060 // TODO(srdjan): Implement Mint == Mint comparison.
1061
1062 __ Bind(&fall_through);
210 return false; 1063 return false;
211 } 1064 }
212 1065
213 1066
214 bool Intrinsifier::Integer_equal(Assembler* assembler) { 1067 bool Intrinsifier::Integer_equal(Assembler* assembler) {
215 return false; 1068 return Integer_equalToInteger(assembler);
216 } 1069 }
217 1070
218 1071
219 bool Intrinsifier::Integer_sar(Assembler* assembler) { 1072 bool Intrinsifier::Integer_sar(Assembler* assembler) {
1073 Label fall_through;
1074
1075 TestBothArgumentsSmis(assembler, &fall_through);
1076 // Shift amount in R0. Value to shift in R1.
1077
1078 // Fall through if shift amount is negative.
1079 __ SmiUntag(R0);
1080 __ CompareImmediate(R0, 0);
1081 __ b(&fall_through, LT);
1082
1083 // If shift amount is bigger than 31, set to 31.
1084 __ CompareImmediate(R0, 0x1F);
1085 __ LoadImmediate(R0, 0x1F, GT);
1086 __ SmiUntag(R1);
1087 __ mov(R0, ShifterOperand(R1, ASR, R0));
1088 __ SmiTag(R0);
1089 __ Ret();
1090 __ Bind(&fall_through);
220 return false; 1091 return false;
221 } 1092 }
222 1093
223 1094
224 bool Intrinsifier::Smi_bitNegate(Assembler* assembler) { 1095 bool Intrinsifier::Smi_bitNegate(Assembler* assembler) {
1096 __ ldr(R0, Address(SP, 0 * kWordSize));
1097 __ mvn(R0, ShifterOperand(R0));
1098 __ bic(R0, R0, ShifterOperand(kSmiTagMask)); // Remove inverted smi-tag.
1099 __ Ret();
1100 return false;
1101 }
1102
1103
1104 // Check if the last argument is a double, jump to label 'is_smi' if smi
1105 // (easy to convert to double), otherwise jump to label 'not_double_smi',
1106 // Returns the last argument in R0.
1107 static void TestLastArgumentIsDouble(Assembler* assembler,
1108 Label* is_smi,
1109 Label* not_double_smi) {
1110 __ ldr(R0, Address(SP, 0 * kWordSize));
1111 __ tst(R0, ShifterOperand(kSmiTagMask));
1112 __ b(is_smi, EQ);
1113 __ CompareClassId(R0, kDoubleCid, R1);
1114 __ b(not_double_smi, NE);
1115 // Fall through with Double in R0.
1116 }
1117
1118
1119 // Both arguments on stack, arg0 (left) is a double, arg1 (right) is of unknown
1120 // type. Return true or false object in the register R0. Any NaN argument
1121 // returns false. Any non-double arg1 causes control flow to fall through to the
1122 // slow case (compiled method body).
1123 static bool CompareDoubles(Assembler* assembler, Condition true_condition) {
1124 Label fall_through, is_smi, double_op;
1125
1126 TestLastArgumentIsDouble(assembler, &is_smi, &fall_through);
1127 // Both arguments are double, right operand is in R0.
1128
1129 __ AddImmediate(R0, Double::value_offset() - kHeapObjectTag);
1130 __ vldrd(D1, Address(R0));
1131 __ Bind(&double_op);
1132 __ ldr(R0, Address(SP, 1 * kWordSize)); // Left argument.
1133 __ AddImmediate(R0, Double::value_offset() - kHeapObjectTag);
1134 __ vldrd(D0, Address(R0));
1135
1136 __ vcmpd(D0, D1);
1137 __ vmstat();
1138 __ LoadObject(R0, Bool::False());
1139 // Return false if D0 or D1 was NaN before checking true condition.
1140 __ bx(LR, VS);
1141 __ LoadObject(R0, Bool::True(), true_condition);
1142 __ Ret();
1143
1144 __ Bind(&is_smi); // Convert R0 to a double.
1145 __ SmiUntag(R0);
1146 __ vmovsr(S0, R0);
1147 __ vcvtdi(D1, S0);
1148 __ b(&double_op); // Then do the comparison.
1149 __ Bind(&fall_through);
225 return false; 1150 return false;
226 } 1151 }
227 1152
228 1153
229 bool Intrinsifier::Double_greaterThan(Assembler* assembler) { 1154 bool Intrinsifier::Double_greaterThan(Assembler* assembler) {
230 return false; 1155 return CompareDoubles(assembler, HI);
231 } 1156 }
232 1157
233 1158
234 bool Intrinsifier::Double_greaterEqualThan(Assembler* assembler) { 1159 bool Intrinsifier::Double_greaterEqualThan(Assembler* assembler) {
235 return false; 1160 return CompareDoubles(assembler, CS);
236 } 1161 }
237 1162
238 1163
239 bool Intrinsifier::Double_lessThan(Assembler* assembler) { 1164 bool Intrinsifier::Double_lessThan(Assembler* assembler) {
240 return false; 1165 return CompareDoubles(assembler, CC);
241 } 1166 }
242 1167
243 1168
244 bool Intrinsifier::Double_equal(Assembler* assembler) { 1169 bool Intrinsifier::Double_equal(Assembler* assembler) {
245 return false; 1170 return CompareDoubles(assembler, EQ);
246 } 1171 }
247 1172
248 1173
249 bool Intrinsifier::Double_lessEqualThan(Assembler* assembler) { 1174 bool Intrinsifier::Double_lessEqualThan(Assembler* assembler) {
1175 return CompareDoubles(assembler, LS);
1176 }
1177
1178
1179 // Expects left argument to be double (receiver). Right argument is unknown.
1180 // Both arguments are on stack.
1181 static bool DoubleArithmeticOperations(Assembler* assembler, Token::Kind kind) {
1182 Label fall_through;
1183
1184 TestLastArgumentIsDouble(assembler, &fall_through, &fall_through);
1185 // Both arguments are double, right operand is in R0.
1186 // Can't use FieldAddress here. R0 is heap-object-tagged, so the offset will
1187 // not be 4-byte aligned.
1188 __ AddImmediate(R0, Double::value_offset() - kHeapObjectTag);
1189 __ vldrd(D1, Address(R0));
1190 __ ldr(R0, Address(SP, 1 * kWordSize)); // Left argument.
1191 __ AddImmediate(R0, Double::value_offset() - kHeapObjectTag);
1192 __ vldrd(D0, Address(R0));
1193 switch (kind) {
1194 case Token::kADD: __ vaddd(D0, D0, D1); break;
1195 case Token::kSUB: __ vsubd(D0, D0, D1); break;
1196 case Token::kMUL: __ vmuld(D0, D0, D1); break;
1197 case Token::kDIV: __ vdivd(D0, D0, D1); break;
1198 default: UNREACHABLE();
1199 }
1200 const Class& double_class = Class::Handle(
1201 Isolate::Current()->object_store()->double_class());
1202 __ TryAllocate(double_class, &fall_through, R0); // Result register.
1203 __ AddImmediate(R1, R0, Double::value_offset() - kHeapObjectTag);
1204 __ vstrd(D0, Address(R1));
1205 __ Ret();
1206 __ Bind(&fall_through);
250 return false; 1207 return false;
251 } 1208 }
252 1209
253 1210
254 bool Intrinsifier::Double_add(Assembler* assembler) { 1211 bool Intrinsifier::Double_add(Assembler* assembler) {
255 return false; 1212 return DoubleArithmeticOperations(assembler, Token::kADD);
256 } 1213 }
257 1214
258 1215
259 bool Intrinsifier::Double_mul(Assembler* assembler) { 1216 bool Intrinsifier::Double_mul(Assembler* assembler) {
260 return false; 1217 return DoubleArithmeticOperations(assembler, Token::kMUL);
261 } 1218 }
262 1219
263 1220
264 bool Intrinsifier::Double_sub(Assembler* assembler) { 1221 bool Intrinsifier::Double_sub(Assembler* assembler) {
265 return false; 1222 return DoubleArithmeticOperations(assembler, Token::kSUB);
266 } 1223 }
267 1224
268 1225
269 bool Intrinsifier::Double_div(Assembler* assembler) { 1226 bool Intrinsifier::Double_div(Assembler* assembler) {
270 return false; 1227 return DoubleArithmeticOperations(assembler, Token::kDIV);
271 } 1228 }
272 1229
273 1230
1231 // Left is double right is integer (Bigint, Mint or Smi)
274 bool Intrinsifier::Double_mulFromInteger(Assembler* assembler) { 1232 bool Intrinsifier::Double_mulFromInteger(Assembler* assembler) {
1233 Label fall_through;
1234 __ Untested("Intrinsifier::Double_mulFromInteger");
1235 // Only Smi-s allowed.
1236 __ ldr(R0, Address(SP, 0 * kWordSize));
1237 __ tst(R0, ShifterOperand(kSmiTagMask));
1238 __ b(&fall_through, NE);
1239 // Is Smi.
1240 __ SmiUntag(R0);
1241 __ vmovsr(S0, R0);
1242 __ vcvtdi(D1, S0);
1243 __ ldr(R0, Address(SP, 1 * kWordSize));
1244 __ AddImmediate(R0, Double::value_offset() - kHeapObjectTag);
1245 __ vldrd(D0, Address(R0));
1246 __ vmuld(D0, D0, D1);
1247 const Class& double_class = Class::Handle(
1248 Isolate::Current()->object_store()->double_class());
1249 __ TryAllocate(double_class, &fall_through, R0); // Result register.
1250 __ AddImmediate(R1, R0, Double::value_offset() - kHeapObjectTag);
1251 __ vstrd(D0, Address(R1));
1252 __ Ret();
1253 __ Bind(&fall_through);
275 return false; 1254 return false;
276 } 1255 }
277 1256
278 1257
279 bool Intrinsifier::Double_fromInteger(Assembler* assembler) { 1258 bool Intrinsifier::Double_fromInteger(Assembler* assembler) {
1259 Label fall_through;
1260
1261 __ ldr(R0, Address(SP, 0 * kWordSize));
1262 __ tst(R0, ShifterOperand(kSmiTagMask));
1263 __ b(&fall_through, NE);
1264 // Is Smi.
1265 __ SmiUntag(R0);
1266 __ vmovsr(S0, R0);
1267 __ vcvtdi(D0, S0);
1268 const Class& double_class = Class::Handle(
1269 Isolate::Current()->object_store()->double_class());
1270 __ TryAllocate(double_class, &fall_through, R0); // Result register.
1271 __ AddImmediate(R1, R0, Double::value_offset() - kHeapObjectTag);
1272 __ vstrd(D0, Address(R1));
1273 __ Ret();
1274 __ Bind(&fall_through);
280 return false; 1275 return false;
281 } 1276 }
282 1277
283 1278
284 bool Intrinsifier::Double_getIsNaN(Assembler* assembler) { 1279 bool Intrinsifier::Double_getIsNaN(Assembler* assembler) {
285 return false; 1280 Label is_true;
1281 __ Untested("Intrinsifier::Double_getIsNaN");
1282 __ ldr(R0, Address(SP, 0 * kWordSize));
1283 __ AddImmediate(R0, Double::value_offset() - kHeapObjectTag);
1284 __ vldrd(D0, Address(R0));
1285 __ vcmpd(D0, D0);
1286 __ vmstat();
1287 __ LoadObject(R0, Bool::False(), VS);
1288 __ LoadObject(R0, Bool::True(), VC);
1289 __ Ret();
1290 return true;
286 } 1291 }
287 1292
288 1293
289 bool Intrinsifier::Double_getIsNegative(Assembler* assembler) { 1294 bool Intrinsifier::Double_getIsNegative(Assembler* assembler) {
290 return false; 1295 Label is_false, is_true, is_zero;
1296 __ Untested("Intrinsifier::Double_getIsNegative");
1297 __ ldr(R0, Address(SP, 0 * kWordSize));
1298 __ AddImmediate(R0, Double::value_offset() - kHeapObjectTag);
1299 __ vldrd(D0, Address(R0));
1300 __ LoadDImmediate(D1, 0.0, R1);
1301 __ vcmpd(D0, D1);
1302 __ vmstat();
1303 __ b(&is_false, VS); // NaN -> false.
1304 __ b(&is_zero, EQ); // Check for negative zero.
1305 __ b(&is_false, CS); // >= 0 -> false.
1306
1307 __ Bind(&is_true);
1308 __ LoadObject(R0, Bool::True());
1309 __ Ret();
1310
1311 __ Bind(&is_false);
1312 __ LoadObject(R0, Bool::False());
1313 __ Ret();
1314
1315 __ Bind(&is_zero);
1316 // Check for negative zero by looking at the sign bit.
1317 __ vmovrrd(R0, R1, D0); // R1:R0 <- D0, so sign bit is in bit 31 of R1.
1318 __ mov(R1, ShifterOperand(R1, LSR, 31));
1319 __ tst(R1, ShifterOperand(1));
1320 __ b(&is_true, NE); // Sign bit set.
1321 __ b(&is_false);
1322 return true;
291 } 1323 }
292 1324
293 1325
294 bool Intrinsifier::Double_toInt(Assembler* assembler) { 1326 bool Intrinsifier::Double_toInt(Assembler* assembler) {
1327 __ ldr(R0, Address(SP, 0 * kWordSize));
1328 __ AddImmediate(R0, Double::value_offset() - kHeapObjectTag);
1329 __ vldrd(D0, Address(R0));
1330 __ vcvtid(S0, D0);
1331 __ vmovrs(R0, S0);
1332 // Overflow is signaled with minint.
1333 Label fall_through;
1334 // Check for overflow and that it fits into Smi.
1335 __ CompareImmediate(R0, 0xC0000000);
1336 __ b(&fall_through, MI);
1337 __ SmiTag(R0);
1338 __ Ret();
1339 __ Bind(&fall_through);
295 return false; 1340 return false;
296 } 1341 }
297 1342
298 1343
299 bool Intrinsifier::Math_sqrt(Assembler* assembler) { 1344 bool Intrinsifier::Math_sqrt(Assembler* assembler) {
300 return false; 1345 Label fall_through, is_smi, double_op;
301 } 1346 __ Untested("Intrinsifier::Math_sqrt");
302 1347 TestLastArgumentIsDouble(assembler, &is_smi, &fall_through);
1348 // Argument is double and is in R0.
1349 __ AddImmediate(R0, Double::value_offset() - kHeapObjectTag);
1350 __ vldrd(D1, Address(R0));
1351 __ Bind(&double_op);
1352 __ vsqrtd(D0, D1);
1353 const Class& double_class = Class::Handle(
1354 Isolate::Current()->object_store()->double_class());
1355 __ TryAllocate(double_class, &fall_through, R0); // Result register.
1356 __ AddImmediate(R1, R0, Double::value_offset() - kHeapObjectTag);
1357 __ vstrd(D0, Address(R1));
1358 __ Ret();
1359 __ Bind(&is_smi);
1360 __ SmiUntag(R0);
1361 __ vmovsr(S0, R0);
1362 __ vcvtdi(D1, S0);
1363 __ b(&double_op);
1364 __ Bind(&fall_through);
1365 return false;
1366 }
1367
303 1368
304 bool Intrinsifier::Math_sin(Assembler* assembler) { 1369 bool Intrinsifier::Math_sin(Assembler* assembler) {
305 return false; 1370 return false;
306 } 1371 }
307 1372
308 1373
309 bool Intrinsifier::Math_cos(Assembler* assembler) { 1374 bool Intrinsifier::Math_cos(Assembler* assembler) {
310 return false; 1375 return false;
311 } 1376 }
312 1377
313 1378
1379 // var state = ((_A * (_state[kSTATE_LO])) + _state[kSTATE_HI]) & _MASK_64;
1380 // _state[kSTATE_LO] = state & _MASK_32;
1381 // _state[kSTATE_HI] = state >> 32;
314 bool Intrinsifier::Random_nextState(Assembler* assembler) { 1382 bool Intrinsifier::Random_nextState(Assembler* assembler) {
315 return false; 1383 const Library& math_lib = Library::Handle(Library::MathLibrary());
1384 ASSERT(!math_lib.IsNull());
1385 const Class& random_class =
1386 Class::Handle(math_lib.LookupClassAllowPrivate(Symbols::_Random()));
1387 ASSERT(!random_class.IsNull());
1388 const Field& state_field = Field::ZoneHandle(
1389 random_class.LookupInstanceField(Symbols::_state()));
1390 ASSERT(!state_field.IsNull());
1391 const Field& random_A_field = Field::ZoneHandle(
1392 random_class.LookupStaticField(Symbols::_A()));
1393 ASSERT(!random_A_field.IsNull());
1394 ASSERT(random_A_field.is_const());
1395 const Instance& a_value = Instance::Handle(random_A_field.value());
1396 const int64_t a_int_value = Integer::Cast(a_value).AsInt64Value();
1397 // 'a_int_value' is a mask.
1398 ASSERT(Utils::IsUint(32, a_int_value));
1399 int32_t a_int32_value = static_cast<int32_t>(a_int_value);
1400
1401 __ Untested("Random_nextState");
1402
1403 __ ldr(R0, Address(SP, 0 * kWordSize)); // Receiver.
1404 __ ldr(R1, FieldAddress(R0, state_field.Offset())); // Field '_state'.
1405 // Addresses of _state[0] and _state[1].
1406
1407 const int64_t disp_0 =
1408 FlowGraphCompiler::DataOffsetFor(kTypedDataUint32ArrayCid);
1409
1410 const int64_t disp_1 =
1411 FlowGraphCompiler::ElementSizeFor(kTypedDataUint32ArrayCid) +
1412 FlowGraphCompiler::DataOffsetFor(kTypedDataUint32ArrayCid);
1413
1414 __ LoadImmediate(R0, a_int32_value);
1415 __ LoadFromOffset(kLoadWord, R2, R1, disp_0 - 1);
1416 __ LoadFromOffset(kLoadWord, R3, R1, disp_1 - 1);
1417 __ mov(R6, ShifterOperand(R3, ASR, 31)); // Sign extend into R6.
1418 // 64-bit multiply and accumulate into R6:R3.
1419 __ smlal(R3, R6, R0, R2); // R6:R3 <- R6:R3 + R0 * R2.
1420 __ StoreToOffset(kStoreWord, R3, R1, disp_0 - 1);
1421 __ StoreToOffset(kStoreWord, R6, R1, disp_1 - 1);
1422 __ Ret();
1423 return true;
316 } 1424 }
317 1425
318 1426
319 bool Intrinsifier::Object_equal(Assembler* assembler) { 1427 bool Intrinsifier::Object_equal(Assembler* assembler) {
320 return false; 1428 __ ldr(R0, Address(SP, 0 * kWordSize));
1429 __ ldr(R1, Address(SP, 1 * kWordSize));
1430 __ cmp(R0, ShifterOperand(R1));
1431 __ LoadObject(R0, Bool::False(), NE);
1432 __ LoadObject(R0, Bool::True(), EQ);
1433 __ Ret();
1434 return true;
321 } 1435 }
322 1436
323 1437
324 bool Intrinsifier::String_getHashCode(Assembler* assembler) { 1438 bool Intrinsifier::String_getHashCode(Assembler* assembler) {
1439 __ Untested("Intrinsifier::String_getHashCode");
1440 __ ldr(R0, Address(SP, 0 * kWordSize));
1441 __ ldr(R0, FieldAddress(R0, String::hash_offset()));
1442 __ cmp(R0, ShifterOperand(0));
1443 __ bx(LR, NE); // Hash not yet computed.
325 return false; 1444 return false;
326 } 1445 }
327 1446
328 1447
329 bool Intrinsifier::String_getLength(Assembler* assembler) { 1448 bool Intrinsifier::String_getLength(Assembler* assembler) {
330 return false; 1449 __ ldr(R0, Address(SP, 0 * kWordSize));
331 } 1450 __ ldr(R0, FieldAddress(R0, String::length_offset()));
332 1451 __ Ret();
333 1452 return true;
1453 }
1454
1455
1456 // TODO(srdjan): Implement for two and four byte strings as well.
334 bool Intrinsifier::String_codeUnitAt(Assembler* assembler) { 1457 bool Intrinsifier::String_codeUnitAt(Assembler* assembler) {
1458 Label fall_through;
1459
1460 __ ldr(R1, Address(SP, 0 * kWordSize)); // Index.
1461 __ ldr(R0, Address(SP, 1 * kWordSize)); // String.
1462 __ tst(R1, ShifterOperand(kSmiTagMask));
1463 __ b(&fall_through, NE); // Index is not a Smi.
1464 // Range check.
1465 __ ldr(R2, FieldAddress(R0, String::length_offset()));
1466 __ cmp(R1, ShifterOperand(R2));
1467 __ b(&fall_through, CS); // Runtime throws exception.
1468 __ CompareClassId(R0, kOneByteStringCid, R3);
1469 __ b(&fall_through, NE);
1470 __ SmiUntag(R1);
1471 __ AddImmediate(R0, OneByteString::data_offset() - kHeapObjectTag);
1472 __ ldrb(R0, Address(R0, R1));
1473 __ SmiTag(R0);
1474 __ Ret();
1475 __ Bind(&fall_through);
335 return false; 1476 return false;
336 } 1477 }
337 1478
338 1479
339 bool Intrinsifier::String_getIsEmpty(Assembler* assembler) { 1480 bool Intrinsifier::String_getIsEmpty(Assembler* assembler) {
340 return false; 1481 __ ldr(R0, Address(SP, 0 * kWordSize));
1482 __ ldr(R0, FieldAddress(R0, String::length_offset()));
1483 __ cmp(R0, ShifterOperand(Smi::RawValue(0)));
1484 __ LoadObject(R0, Bool::True(), EQ);
1485 __ LoadObject(R0, Bool::False(), NE);
1486 __ Ret();
1487 return true;
341 } 1488 }
342 1489
343 1490
344 bool Intrinsifier::OneByteString_getHashCode(Assembler* assembler) { 1491 bool Intrinsifier::OneByteString_getHashCode(Assembler* assembler) {
345 return false; 1492 __ ldr(R1, Address(SP, 0 * kWordSize));
346 } 1493 __ ldr(R0, FieldAddress(R1, String::hash_offset()));
347 1494 __ cmp(R0, ShifterOperand(0));
348 1495 __ bx(LR, NE); // Return if already computed.
1496
1497 __ ldr(R2, FieldAddress(R1, String::length_offset()));
1498
1499 Label done;
1500 // If the string is empty, set the hash to 1, and return.
1501 __ cmp(R2, ShifterOperand(Smi::RawValue(0)));
1502 __ b(&done, EQ);
1503
1504 __ SmiUntag(R2);
1505 __ mov(R3, ShifterOperand(0));
1506 __ AddImmediate(R6, R1, OneByteString::data_offset() - kHeapObjectTag);
1507 // R1: Instance of OneByteString.
1508 // R2: String length, untagged integer.
1509 // R3: Loop counter, untagged integer.
1510 // R6: String data.
1511 // R0: Hash code, untagged integer.
1512
1513 Label loop;
1514 // Add to hash code: (hash_ is uint32)
1515 // hash_ += ch;
1516 // hash_ += hash_ << 10;
1517 // hash_ ^= hash_ >> 6;
1518 // Get one characters (ch).
1519 __ Bind(&loop);
1520 __ ldrb(R7, Address(R6, 0));
1521 // R7: ch.
1522 __ add(R3, R3, ShifterOperand(1));
1523 __ add(R6, R6, ShifterOperand(1));
1524 __ add(R0, R0, ShifterOperand(R7));
1525 __ add(R0, R0, ShifterOperand(R0, LSL, 10));
1526 __ eor(R0, R0, ShifterOperand(R0, LSR, 6));
1527 __ cmp(R3, ShifterOperand(R2));
1528 __ b(&loop, NE);
1529
1530 // Finalize.
1531 // hash_ += hash_ << 3;
1532 // hash_ ^= hash_ >> 11;
1533 // hash_ += hash_ << 15;
1534 __ add(R0, R0, ShifterOperand(R0, LSL, 3));
1535 __ eor(R0, R0, ShifterOperand(R0, LSR, 11));
1536 __ add(R0, R0, ShifterOperand(R0, LSL, 15));
1537 // hash_ = hash_ & ((static_cast<intptr_t>(1) << bits) - 1);
1538 __ LoadImmediate(R2, (static_cast<intptr_t>(1) << String::kHashBits) - 1);
1539 __ and_(R0, R0, ShifterOperand(R2));
1540 __ cmp(R0, ShifterOperand(0));
1541 // return hash_ == 0 ? 1 : hash_;
1542 __ Bind(&done);
1543 __ mov(R0, ShifterOperand(1), EQ);
1544 __ SmiTag(R0);
1545 __ str(R0, FieldAddress(R1, String::hash_offset()));
1546 __ Ret();
1547 return false;
1548 }
1549
1550
1551 // Allocates one-byte string of length 'end - start'. The content is not
1552 // initialized.
1553 // 'length-reg' (R2) contains tagged length.
1554 // Returns new string as tagged pointer in R0.
1555 static void TryAllocateOnebyteString(Assembler* assembler,
1556 Label* ok,
1557 Label* failure) {
1558 const Register length_reg = R2;
1559 Label fail;
1560
1561 __ mov(R6, ShifterOperand(length_reg)); // Save the length register.
1562 __ SmiUntag(length_reg);
1563 const intptr_t fixed_size = sizeof(RawString) + kObjectAlignment - 1;
1564 __ AddImmediate(length_reg, fixed_size);
1565 __ bic(length_reg, length_reg, ShifterOperand(kObjectAlignment - 1));
1566
1567 Isolate* isolate = Isolate::Current();
1568 Heap* heap = isolate->heap();
1569
1570 __ LoadImmediate(R3, heap->TopAddress());
1571 __ ldr(R0, Address(R3, 0));
1572
1573 // length_reg: allocation size.
1574 __ adds(R1, R0, ShifterOperand(length_reg));
1575 __ b(&fail, VS); // Fail on overflow.
1576
1577 // Check if the allocation fits into the remaining space.
1578 // R0: potential new object start.
1579 // R1: potential next object start.
1580 // R2: allocation size.
1581 // R3: heap->Top->Address().
1582 __ LoadImmediate(R7, heap->EndAddress());
1583 __ ldr(R7, Address(R7, 0));
1584 __ cmp(R1, ShifterOperand(R7));
1585 __ b(&fail, CS);
1586
1587 // Successfully allocated the object(s), now update top to point to
1588 // next object start and initialize the object.
1589 __ str(R1, Address(R3, 0));
1590 __ AddImmediate(R0, kHeapObjectTag);
1591
1592 // Initialize the tags.
1593 // R0: new object start as a tagged pointer.
1594 // R1: new object end address.
1595 // R2: allocation size.
1596 {
1597 const intptr_t shift = RawObject::kSizeTagBit - kObjectAlignmentLog2;
1598 const Class& cls =
1599 Class::Handle(isolate->object_store()->one_byte_string_class());
1600
1601 __ CompareImmediate(R2, RawObject::SizeTag::kMaxSizeTag);
1602 __ mov(R2, ShifterOperand(R2, LSL, shift), LS);
1603 __ mov(R2, ShifterOperand(0), HI);
1604
1605 // Get the class index and insert it into the tags.
1606 // R2: size and bit tags.
1607 __ LoadImmediate(TMP, RawObject::ClassIdTag::encode(cls.id()));
1608 __ orr(R2, R2, ShifterOperand(TMP));
1609 __ str(R2, FieldAddress(R0, String::tags_offset())); // Store tags.
1610 }
1611
1612 // Set the length field using the saved length (R6).
1613 __ StoreIntoObjectNoBarrier(R0,
1614 FieldAddress(R0, String::length_offset()),
1615 R6);
1616 // Clear hash.
1617 __ LoadImmediate(TMP, 0);
1618 __ str(TMP, FieldAddress(R0, String::hash_offset()));
1619 __ b(ok);
1620
1621 __ Bind(&fail);
1622 __ b(failure);
1623 }
1624
1625
1626 // Arg0: Onebyte String
1627 // Arg1: Start index as Smi.
1628 // Arg2: End index as Smi.
1629 // The indexes must be valid.
349 bool Intrinsifier::OneByteString_substringUnchecked(Assembler* assembler) { 1630 bool Intrinsifier::OneByteString_substringUnchecked(Assembler* assembler) {
1631 const intptr_t kStringOffset = 2 * kWordSize;
1632 const intptr_t kStartIndexOffset = 1 * kWordSize;
1633 const intptr_t kEndIndexOffset = 0 * kWordSize;
1634 Label fall_through, ok;
1635
1636 __ ldr(R2, Address(SP, kEndIndexOffset));
1637 __ ldr(TMP, Address(SP, kStartIndexOffset));
1638 __ sub(R2, R2, ShifterOperand(TMP));
1639 TryAllocateOnebyteString(assembler, &ok, &fall_through);
1640 __ Bind(&ok);
1641 // R0: new string as tagged pointer.
1642 // Copy string.
1643 __ ldr(R3, Address(SP, kStringOffset));
1644 __ ldr(R1, Address(SP, kStartIndexOffset));
1645 __ SmiUntag(R1);
1646 __ add(R3, R3, ShifterOperand(R1));
1647 // Calculate start address and untag (- 1).
1648 __ AddImmediate(R3, OneByteString::data_offset() - 1);
1649
1650 // R3: Start address to copy from (untagged).
1651 // R1: Untagged start index.
1652 __ ldr(R2, Address(SP, kEndIndexOffset));
1653 __ SmiUntag(R2);
1654 __ sub(R2, R2, ShifterOperand(R1));
1655
1656 // R3: Start address to copy from (untagged).
1657 // R2: Untagged number of bytes to copy.
1658 // R0: Tagged result string.
1659 // R6: Pointer into R3.
1660 // R7: Pointer into R0.
1661 // R1: Scratch register.
1662 Label loop, done;
1663 __ cmp(R2, ShifterOperand(0));
1664 __ b(&done, LE);
1665 __ mov(R6, ShifterOperand(R3));
1666 __ mov(R7, ShifterOperand(R0));
1667 __ Bind(&loop);
1668 __ ldrb(R1, Address(R6, 0));
1669 __ AddImmediate(R6, 1);
1670 __ sub(R2, R2, ShifterOperand(1));
1671 __ cmp(R2, ShifterOperand(0));
1672 __ strb(R1, FieldAddress(R7, OneByteString::data_offset()));
1673 __ AddImmediate(R7, 1);
1674 __ b(&loop, GT);
1675
1676 __ Bind(&done);
1677 __ Ret();
1678 __ Bind(&fall_through);
350 return false; 1679 return false;
351 } 1680 }
352 1681
353 1682
354 bool Intrinsifier::OneByteString_setAt(Assembler* assembler) { 1683 bool Intrinsifier::OneByteString_setAt(Assembler* assembler) {
355 return false; 1684 __ ldr(R2, Address(SP, 0 * kWordSize)); // Value.
1685 __ ldr(R1, Address(SP, 1 * kWordSize)); // Index.
1686 __ ldr(R0, Address(SP, 2 * kWordSize)); // OneByteString.
1687 __ SmiUntag(R1);
1688 __ SmiUntag(R2);
1689 __ AddImmediate(R3, R0, OneByteString::data_offset() - kHeapObjectTag);
1690 __ strb(R2, Address(R3, R1));
1691 __ Ret();
1692 return true;
356 } 1693 }
357 1694
358 1695
359 bool Intrinsifier::OneByteString_allocate(Assembler* assembler) { 1696 bool Intrinsifier::OneByteString_allocate(Assembler* assembler) {
360 return false; 1697 __ ldr(R2, Address(SP, 0 * kWordSize)); // Length.
361 } 1698 Label fall_through, ok;
362 1699 TryAllocateOnebyteString(assembler, &ok, &fall_through);
1700
1701 __ Bind(&ok);
1702 __ Ret();
1703
1704 __ Bind(&fall_through);
1705 return false;
1706 }
1707
363 } // namespace dart 1708 } // namespace dart
364 1709
365 #endif // defined TARGET_ARCH_ARM 1710 #endif // defined TARGET_ARCH_ARM
OLDNEW
« no previous file with comments | « runtime/vm/flow_graph_compiler_arm.cc ('k') | runtime/vm/intrinsifier_ia32.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698