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

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

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

Powered by Google App Engine
This is Rietveld 408576698