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

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

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

Powered by Google App Engine
This is Rietveld 408576698