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

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

Issue 22866025: Always generate full unoptimized code for intrinsified methods. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 7 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « runtime/vm/intrinsifier_ia32.cc ('k') | runtime/vm/intrinsifier_x64.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 9
10 #include "vm/assembler.h" 10 #include "vm/assembler.h"
11 #include "vm/flow_graph_compiler.h" 11 #include "vm/flow_graph_compiler.h"
12 #include "vm/object.h" 12 #include "vm/object.h"
13 #include "vm/object_store.h" 13 #include "vm/object_store.h"
14 #include "vm/symbols.h" 14 #include "vm/symbols.h"
15 15
16 namespace dart { 16 namespace dart {
17 17
18 DECLARE_FLAG(bool, enable_type_checks); 18 DECLARE_FLAG(bool, enable_type_checks);
19 19
20 20
21 #define __ assembler-> 21 #define __ assembler->
22 22
23 bool Intrinsifier::ObjectArray_Allocate(Assembler* assembler) { 23 void Intrinsifier::ObjectArray_Allocate(Assembler* assembler) {
24 const intptr_t kTypeArgumentsOffset = 1 * kWordSize; 24 const intptr_t kTypeArgumentsOffset = 1 * kWordSize;
25 const intptr_t kArrayLengthOffset = 0 * kWordSize; 25 const intptr_t kArrayLengthOffset = 0 * kWordSize;
26 Label fall_through; 26 Label fall_through;
27 27
28 // Compute the size to be allocated, it is based on the array length 28 // Compute the size to be allocated, it is based on the array length
29 // and is computed as: 29 // and is computed as:
30 // RoundedAllocationSize((array_length * kwordSize) + sizeof(RawArray)). 30 // RoundedAllocationSize((array_length * kwordSize) + sizeof(RawArray)).
31 __ lw(T3, Address(SP, kArrayLengthOffset)); // Array length. 31 __ lw(T3, Address(SP, kArrayLengthOffset)); // Array length.
32 32
33 // Check that length is a positive Smi. 33 // Check that length is a positive Smi.
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after
123 __ Bind(&init_loop); 123 __ Bind(&init_loop);
124 __ BranchUnsignedGreaterEqual(T2, T1, &done); 124 __ BranchUnsignedGreaterEqual(T2, T1, &done);
125 __ sw(T7, Address(T2, 0)); 125 __ sw(T7, Address(T2, 0));
126 __ b(&init_loop); 126 __ b(&init_loop);
127 __ delay_slot()->addiu(T2, T2, Immediate(kWordSize)); 127 __ delay_slot()->addiu(T2, T2, Immediate(kWordSize));
128 __ Bind(&done); 128 __ Bind(&done);
129 129
130 __ Ret(); // Returns the newly allocated object in V0. 130 __ Ret(); // Returns the newly allocated object in V0.
131 __ delay_slot()->mov(V0, T0); 131 __ delay_slot()->mov(V0, T0);
132 __ Bind(&fall_through); 132 __ Bind(&fall_through);
133 return false;
134 } 133 }
135 134
136 135
137 bool Intrinsifier::Array_getLength(Assembler* assembler) { 136 void Intrinsifier::Array_getLength(Assembler* assembler) {
138 __ lw(V0, Address(SP, 0 * kWordSize)); 137 __ lw(V0, Address(SP, 0 * kWordSize));
139 __ Ret(); 138 __ Ret();
140 __ delay_slot()->lw(V0, FieldAddress(V0, Array::length_offset())); 139 __ delay_slot()->lw(V0, FieldAddress(V0, Array::length_offset()));
141 return true;
142 } 140 }
143 141
144 142
145 bool Intrinsifier::ImmutableArray_getLength(Assembler* assembler) { 143 void Intrinsifier::ImmutableArray_getLength(Assembler* assembler) {
146 return Array_getLength(assembler); 144 return Array_getLength(assembler);
147 } 145 }
148 146
149 147
150 bool Intrinsifier::Array_getIndexed(Assembler* assembler) { 148 void Intrinsifier::Array_getIndexed(Assembler* assembler) {
151 Label fall_through; 149 Label fall_through;
152 150
153 __ lw(T0, Address(SP, + 0 * kWordSize)); // Index 151 __ lw(T0, Address(SP, + 0 * kWordSize)); // Index
154 152
155 __ andi(CMPRES, T0, Immediate(kSmiTagMask)); 153 __ andi(CMPRES, T0, Immediate(kSmiTagMask));
156 __ bne(CMPRES, ZR, &fall_through); // Index is not an smi, fall through 154 __ bne(CMPRES, ZR, &fall_through); // Index is not an smi, fall through
157 __ delay_slot()->lw(T1, Address(SP, + 1 * kWordSize)); // Array 155 __ delay_slot()->lw(T1, Address(SP, + 1 * kWordSize)); // Array
158 156
159 // range check 157 // range check
160 __ lw(T2, FieldAddress(T1, Array::length_offset())); 158 __ lw(T2, FieldAddress(T1, Array::length_offset()));
161 __ BranchUnsignedGreaterEqual(T0, T2, &fall_through); 159 __ BranchUnsignedGreaterEqual(T0, T2, &fall_through);
162 160
163 ASSERT(kSmiTagShift == 1); 161 ASSERT(kSmiTagShift == 1);
164 // array element at T1 + T0*2 + Array::data_offset - 1 162 // array element at T1 + T0*2 + Array::data_offset - 1
165 __ sll(T2, T0, 1); 163 __ sll(T2, T0, 1);
166 __ addu(T2, T1, T2); 164 __ addu(T2, T1, T2);
167 __ Ret(); 165 __ Ret();
168 __ delay_slot()->lw(V0, FieldAddress(T2, Array::data_offset())); 166 __ delay_slot()->lw(V0, FieldAddress(T2, Array::data_offset()));
169 __ Bind(&fall_through); 167 __ Bind(&fall_through);
170 return false;
171 } 168 }
172 169
173 170
174 bool Intrinsifier::ImmutableArray_getIndexed(Assembler* assembler) { 171 void Intrinsifier::ImmutableArray_getIndexed(Assembler* assembler) {
175 return Array_getIndexed(assembler); 172 return Array_getIndexed(assembler);
176 } 173 }
177 174
178 175
179 static intptr_t ComputeObjectArrayTypeArgumentsOffset() { 176 static intptr_t ComputeObjectArrayTypeArgumentsOffset() {
180 const Library& core_lib = Library::Handle(Library::CoreLibrary()); 177 const Library& core_lib = Library::Handle(Library::CoreLibrary());
181 const Class& cls = Class::Handle( 178 const Class& cls = Class::Handle(
182 core_lib.LookupClassAllowPrivate(Symbols::ObjectArray(), NULL)); 179 core_lib.LookupClassAllowPrivate(Symbols::ObjectArray(), NULL));
183 ASSERT(!cls.IsNull()); 180 ASSERT(!cls.IsNull());
184 ASSERT(cls.HasTypeArguments()); 181 ASSERT(cls.HasTypeArguments());
185 ASSERT(cls.NumTypeArguments() == 1); 182 ASSERT(cls.NumTypeArguments() == 1);
186 const intptr_t field_offset = cls.type_arguments_field_offset(); 183 const intptr_t field_offset = cls.type_arguments_field_offset();
187 ASSERT(field_offset != Class::kNoTypeArguments); 184 ASSERT(field_offset != Class::kNoTypeArguments);
188 return field_offset; 185 return field_offset;
189 } 186 }
190 187
191 188
192 // Intrinsify only for Smi value and index. Non-smi values need a store buffer 189 // Intrinsify only for Smi value and index. Non-smi values need a store buffer
193 // update. Array length is always a Smi. 190 // update. Array length is always a Smi.
194 bool Intrinsifier::Array_setIndexed(Assembler* assembler) { 191 void Intrinsifier::Array_setIndexed(Assembler* assembler) {
195 Label fall_through; 192 Label fall_through;
196 193
197 if (FLAG_enable_type_checks) { 194 if (FLAG_enable_type_checks) {
198 const intptr_t type_args_field_offset = 195 const intptr_t type_args_field_offset =
199 ComputeObjectArrayTypeArgumentsOffset(); 196 ComputeObjectArrayTypeArgumentsOffset();
200 // Inline simple tests (Smi, null), fallthrough if not positive. 197 // Inline simple tests (Smi, null), fallthrough if not positive.
201 Label checked_ok; 198 Label checked_ok;
202 __ lw(T2, Address(SP, 0 * kWordSize)); // Value. 199 __ lw(T2, Address(SP, 0 * kWordSize)); // Value.
203 200
204 // Null value is valid for any type. 201 // Null value is valid for any type.
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
243 ASSERT(kSmiTagShift == 1); 240 ASSERT(kSmiTagShift == 1);
244 __ lw(T2, Address(SP, 0 * kWordSize)); // Value. 241 __ lw(T2, Address(SP, 0 * kWordSize)); // Value.
245 __ sll(T1, T1, 1); // T1 is Smi. 242 __ sll(T1, T1, 1); // T1 is Smi.
246 __ addu(T1, T0, T1); 243 __ addu(T1, T0, T1);
247 __ StoreIntoObject(T0, 244 __ StoreIntoObject(T0,
248 FieldAddress(T1, Array::data_offset()), 245 FieldAddress(T1, Array::data_offset()),
249 T2); 246 T2);
250 // Caller is responsible for preserving the value if necessary. 247 // Caller is responsible for preserving the value if necessary.
251 __ Ret(); 248 __ Ret();
252 __ Bind(&fall_through); 249 __ Bind(&fall_through);
253 return false;
254 } 250 }
255 251
256 252
257 // Allocate a GrowableObjectArray using the backing array specified. 253 // Allocate a GrowableObjectArray using the backing array specified.
258 // On stack: type argument (+1), data (+0). 254 // On stack: type argument (+1), data (+0).
259 bool Intrinsifier::GrowableArray_Allocate(Assembler* assembler) { 255 void Intrinsifier::GrowableArray_Allocate(Assembler* assembler) {
260 // The newly allocated object is returned in V0. 256 // The newly allocated object is returned in V0.
261 const intptr_t kTypeArgumentsOffset = 1 * kWordSize; 257 const intptr_t kTypeArgumentsOffset = 1 * kWordSize;
262 const intptr_t kArrayOffset = 0 * kWordSize; 258 const intptr_t kArrayOffset = 0 * kWordSize;
263 Label fall_through; 259 Label fall_through;
264 260
265 // Compute the size to be allocated, it is based on the array length 261 // Compute the size to be allocated, it is based on the array length
266 // and is computed as: 262 // and is computed as:
267 // RoundedAllocationSize(sizeof(RawGrowableObjectArray)) + 263 // RoundedAllocationSize(sizeof(RawGrowableObjectArray)) +
268 intptr_t fixed_size = GrowableObjectArray::InstanceSize(); 264 intptr_t fixed_size = GrowableObjectArray::InstanceSize();
269 265
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
311 V0, 307 V0,
312 FieldAddress(V0, GrowableObjectArray::type_arguments_offset()), 308 FieldAddress(V0, GrowableObjectArray::type_arguments_offset()),
313 T1); 309 T1);
314 310
315 // Set the length field in the growable array object to 0. 311 // Set the length field in the growable array object to 0.
316 __ Ret(); // Returns the newly allocated object in V0. 312 __ Ret(); // Returns the newly allocated object in V0.
317 __ delay_slot()->sw(ZR, 313 __ delay_slot()->sw(ZR,
318 FieldAddress(V0, GrowableObjectArray::length_offset())); 314 FieldAddress(V0, GrowableObjectArray::length_offset()));
319 315
320 __ Bind(&fall_through); 316 __ Bind(&fall_through);
321 return false;
322 } 317 }
323 318
324 319
325 bool Intrinsifier::GrowableArray_getLength(Assembler* assembler) { 320 void Intrinsifier::GrowableArray_getLength(Assembler* assembler) {
326 __ lw(V0, Address(SP, 0 * kWordSize)); 321 __ lw(V0, Address(SP, 0 * kWordSize));
327 __ Ret(); 322 __ Ret();
328 __ delay_slot()->lw(V0, 323 __ delay_slot()->lw(V0,
329 FieldAddress(V0, GrowableObjectArray::length_offset())); 324 FieldAddress(V0, GrowableObjectArray::length_offset()));
330 return true;
331 } 325 }
332 326
333 327
334 bool Intrinsifier::GrowableArray_getCapacity(Assembler* assembler) { 328 void Intrinsifier::GrowableArray_getCapacity(Assembler* assembler) {
335 __ lw(V0, Address(SP, 0 * kWordSize)); 329 __ lw(V0, Address(SP, 0 * kWordSize));
336 __ lw(V0, FieldAddress(V0, GrowableObjectArray::data_offset())); 330 __ lw(V0, FieldAddress(V0, GrowableObjectArray::data_offset()));
337 __ Ret(); 331 __ Ret();
338 __ delay_slot()->lw(V0, FieldAddress(V0, Array::length_offset())); 332 __ delay_slot()->lw(V0, FieldAddress(V0, Array::length_offset()));
339 return true;
340 } 333 }
341 334
342 335
343 bool Intrinsifier::GrowableArray_getIndexed(Assembler* assembler) { 336 void Intrinsifier::GrowableArray_getIndexed(Assembler* assembler) {
344 Label fall_through; 337 Label fall_through;
345 338
346 __ lw(T0, Address(SP, 0 * kWordSize)); // Index 339 __ lw(T0, Address(SP, 0 * kWordSize)); // Index
347 340
348 __ andi(CMPRES, T0, Immediate(kSmiTagMask)); 341 __ andi(CMPRES, T0, Immediate(kSmiTagMask));
349 __ bne(CMPRES, ZR, &fall_through); // Index is not an smi, fall through 342 __ bne(CMPRES, ZR, &fall_through); // Index is not an smi, fall through
350 __ delay_slot()->lw(T1, Address(SP, 1 * kWordSize)); // Array 343 __ delay_slot()->lw(T1, Address(SP, 1 * kWordSize)); // Array
351 344
352 // range check 345 // range check
353 __ lw(T2, FieldAddress(T1, GrowableObjectArray::length_offset())); 346 __ lw(T2, FieldAddress(T1, GrowableObjectArray::length_offset()));
354 __ BranchUnsignedGreaterEqual(T0, T2, &fall_through); 347 __ BranchUnsignedGreaterEqual(T0, T2, &fall_through);
355 348
356 __ lw(T2, FieldAddress(T1, GrowableObjectArray::data_offset())); // data 349 __ lw(T2, FieldAddress(T1, GrowableObjectArray::data_offset())); // data
357 350
358 ASSERT(kSmiTagShift == 1); 351 ASSERT(kSmiTagShift == 1);
359 // array element at T2 + T0 * 2 + Array::data_offset - 1 352 // array element at T2 + T0 * 2 + Array::data_offset - 1
360 __ sll(T3, T0, 1); 353 __ sll(T3, T0, 1);
361 __ addu(T2, T2, T3); 354 __ addu(T2, T2, T3);
362 __ Ret(); 355 __ Ret();
363 __ delay_slot()->lw(V0, FieldAddress(T2, Array::data_offset())); 356 __ delay_slot()->lw(V0, FieldAddress(T2, Array::data_offset()));
364 __ Bind(&fall_through); 357 __ Bind(&fall_through);
365 return false;
366 } 358 }
367 359
368 360
369 // Set value into growable object array at specified index. 361 // Set value into growable object array at specified index.
370 // On stack: growable array (+2), index (+1), value (+0). 362 // On stack: growable array (+2), index (+1), value (+0).
371 bool Intrinsifier::GrowableArray_setIndexed(Assembler* assembler) { 363 void Intrinsifier::GrowableArray_setIndexed(Assembler* assembler) {
372 if (FLAG_enable_type_checks) { 364 if (FLAG_enable_type_checks) {
373 return false; 365 return;
374 } 366 }
375 Label fall_through; 367 Label fall_through;
376 __ lw(T1, Address(SP, 1 * kWordSize)); // Index. 368 __ lw(T1, Address(SP, 1 * kWordSize)); // Index.
377 __ andi(CMPRES, T1, Immediate(kSmiTagMask)); 369 __ andi(CMPRES, T1, Immediate(kSmiTagMask));
378 __ bne(CMPRES, ZR, &fall_through); // Non-smi index. 370 __ bne(CMPRES, ZR, &fall_through); // Non-smi index.
379 __ delay_slot()->lw(T0, Address(SP, 2 * kWordSize)); // GrowableArray. 371 __ delay_slot()->lw(T0, Address(SP, 2 * kWordSize)); // GrowableArray.
380 // Range check using _length field. 372 // Range check using _length field.
381 __ lw(T2, FieldAddress(T0, GrowableObjectArray::length_offset())); 373 __ lw(T2, FieldAddress(T0, GrowableObjectArray::length_offset()));
382 // Runtime throws exception. 374 // Runtime throws exception.
383 __ BranchUnsignedGreaterEqual(T1, T2, &fall_through); 375 __ BranchUnsignedGreaterEqual(T1, T2, &fall_through);
384 __ lw(T0, FieldAddress(T0, GrowableObjectArray::data_offset())); // data. 376 __ lw(T0, FieldAddress(T0, GrowableObjectArray::data_offset())); // data.
385 __ lw(T2, Address(SP, 0 * kWordSize)); // Value. 377 __ lw(T2, Address(SP, 0 * kWordSize)); // Value.
386 // Note that T1 is Smi, i.e, times 2. 378 // Note that T1 is Smi, i.e, times 2.
387 ASSERT(kSmiTagShift == 1); 379 ASSERT(kSmiTagShift == 1);
388 __ sll(T1, T1, 1); 380 __ sll(T1, T1, 1);
389 __ addu(T1, T0, T1); 381 __ addu(T1, T0, T1);
390 __ StoreIntoObject(T0, 382 __ StoreIntoObject(T0,
391 FieldAddress(T1, Array::data_offset()), 383 FieldAddress(T1, Array::data_offset()),
392 T2); 384 T2);
393 __ Ret(); 385 __ Ret();
394 __ Bind(&fall_through); 386 __ Bind(&fall_through);
395 return false;
396 } 387 }
397 388
398 389
399 // Set length of growable object array. The length cannot 390 // Set length of growable object array. The length cannot
400 // be greater than the length of the data container. 391 // be greater than the length of the data container.
401 // On stack: growable array (+1), length (+0). 392 // On stack: growable array (+1), length (+0).
402 bool Intrinsifier::GrowableArray_setLength(Assembler* assembler) { 393 void Intrinsifier::GrowableArray_setLength(Assembler* assembler) {
403 Label fall_through; 394 Label fall_through;
404 __ lw(T1, Address(SP, 0 * kWordSize)); // Length value. 395 __ lw(T1, Address(SP, 0 * kWordSize)); // Length value.
405 __ andi(CMPRES, T1, Immediate(kSmiTagMask)); 396 __ andi(CMPRES, T1, Immediate(kSmiTagMask));
406 __ bne(CMPRES, ZR, &fall_through); // Non-smi length. 397 __ bne(CMPRES, ZR, &fall_through); // Non-smi length.
407 __ delay_slot()->lw(T0, Address(SP, 1 * kWordSize)); // Growable array. 398 __ delay_slot()->lw(T0, Address(SP, 1 * kWordSize)); // Growable array.
408 __ Ret(); 399 __ Ret();
409 __ delay_slot()->sw(T1, 400 __ delay_slot()->sw(T1,
410 FieldAddress(T0, GrowableObjectArray::length_offset())); 401 FieldAddress(T0, GrowableObjectArray::length_offset()));
411 __ Bind(&fall_through); 402 __ Bind(&fall_through);
412 return false;
413 } 403 }
414 404
415 405
416 // Set data of growable object array. 406 // Set data of growable object array.
417 // On stack: growable array (+1), data (+0). 407 // On stack: growable array (+1), data (+0).
418 bool Intrinsifier::GrowableArray_setData(Assembler* assembler) { 408 void Intrinsifier::GrowableArray_setData(Assembler* assembler) {
419 if (FLAG_enable_type_checks) { 409 if (FLAG_enable_type_checks) {
420 return false; 410 return;
421 } 411 }
422 Label fall_through; 412 Label fall_through;
423 __ lw(T1, Address(SP, 0 * kWordSize)); // Data. 413 __ lw(T1, Address(SP, 0 * kWordSize)); // Data.
424 // Check that data is an ObjectArray. 414 // Check that data is an ObjectArray.
425 __ andi(CMPRES, T1, Immediate(kSmiTagMask)); 415 __ andi(CMPRES, T1, Immediate(kSmiTagMask));
426 __ beq(CMPRES, ZR, &fall_through); // Data is Smi. 416 __ beq(CMPRES, ZR, &fall_through); // Data is Smi.
427 __ LoadClassId(CMPRES1, T1); 417 __ LoadClassId(CMPRES1, T1);
428 __ BranchNotEqual(CMPRES1, kArrayCid, &fall_through); 418 __ BranchNotEqual(CMPRES1, kArrayCid, &fall_through);
429 __ lw(T0, Address(SP, 1 * kWordSize)); // Growable array. 419 __ lw(T0, Address(SP, 1 * kWordSize)); // Growable array.
430 __ StoreIntoObject(T0, 420 __ StoreIntoObject(T0,
431 FieldAddress(T0, GrowableObjectArray::data_offset()), 421 FieldAddress(T0, GrowableObjectArray::data_offset()),
432 T1); 422 T1);
433 __ Ret(); 423 __ Ret();
434 __ Bind(&fall_through); 424 __ Bind(&fall_through);
435 return false;
436 } 425 }
437 426
438 427
439 // Add an element to growable array if it doesn't need to grow, otherwise 428 // Add an element to growable array if it doesn't need to grow, otherwise
440 // call into regular code. 429 // call into regular code.
441 // On stack: growable array (+1), value (+0). 430 // On stack: growable array (+1), value (+0).
442 bool Intrinsifier::GrowableArray_add(Assembler* assembler) { 431 void Intrinsifier::GrowableArray_add(Assembler* assembler) {
443 // In checked mode we need to type-check the incoming argument. 432 // In checked mode we need to type-check the incoming argument.
444 if (FLAG_enable_type_checks) return false; 433 if (FLAG_enable_type_checks) return;
445 Label fall_through; 434 Label fall_through;
446 __ lw(T0, Address(SP, 1 * kWordSize)); // Array. 435 __ lw(T0, Address(SP, 1 * kWordSize)); // Array.
447 __ lw(T1, FieldAddress(T0, GrowableObjectArray::length_offset())); 436 __ lw(T1, FieldAddress(T0, GrowableObjectArray::length_offset()));
448 // T1: length. 437 // T1: length.
449 __ lw(T2, FieldAddress(T0, GrowableObjectArray::data_offset())); 438 __ lw(T2, FieldAddress(T0, GrowableObjectArray::data_offset()));
450 // T2: data. 439 // T2: data.
451 __ lw(T3, FieldAddress(T2, Array::length_offset())); 440 __ lw(T3, FieldAddress(T2, Array::length_offset()));
452 // Compare length with capacity. 441 // Compare length with capacity.
453 // T3: capacity. 442 // T3: capacity.
454 __ beq(T1, T3, &fall_through); // Must grow data. 443 __ beq(T1, T3, &fall_through); // Must grow data.
455 const int32_t value_one = reinterpret_cast<int32_t>(Smi::New(1)); 444 const int32_t value_one = reinterpret_cast<int32_t>(Smi::New(1));
456 // len = len + 1; 445 // len = len + 1;
457 __ addiu(T3, T1, Immediate(value_one)); 446 __ addiu(T3, T1, Immediate(value_one));
458 __ sw(T3, FieldAddress(T0, GrowableObjectArray::length_offset())); 447 __ sw(T3, FieldAddress(T0, GrowableObjectArray::length_offset()));
459 __ lw(T0, Address(SP, 0 * kWordSize)); // Value. 448 __ lw(T0, Address(SP, 0 * kWordSize)); // Value.
460 ASSERT(kSmiTagShift == 1); 449 ASSERT(kSmiTagShift == 1);
461 __ sll(T1, T1, 1); 450 __ sll(T1, T1, 1);
462 __ addu(T1, T2, T1); 451 __ addu(T1, T2, T1);
463 __ StoreIntoObject(T2, 452 __ StoreIntoObject(T2,
464 FieldAddress(T1, Array::data_offset()), 453 FieldAddress(T1, Array::data_offset()),
465 T0); 454 T0);
466 __ LoadImmediate(T7, reinterpret_cast<int32_t>(Object::null())); 455 __ LoadImmediate(T7, reinterpret_cast<int32_t>(Object::null()));
467 __ Ret(); 456 __ Ret();
468 __ delay_slot()->mov(V0, T7); 457 __ delay_slot()->mov(V0, T7);
469 __ Bind(&fall_through); 458 __ Bind(&fall_through);
470 return false;
471 } 459 }
472 460
473 461
474 #define TYPED_ARRAY_ALLOCATION(type_name, cid, max_len, scale_shift) \ 462 #define TYPED_ARRAY_ALLOCATION(type_name, cid, max_len, scale_shift) \
475 Label fall_through; \ 463 Label fall_through; \
476 const intptr_t kArrayLengthStackOffset = 0 * kWordSize; \ 464 const intptr_t kArrayLengthStackOffset = 0 * kWordSize; \
477 __ lw(T2, Address(SP, kArrayLengthStackOffset)); /* Array length. */ \ 465 __ lw(T2, Address(SP, kArrayLengthStackOffset)); /* Array length. */ \
478 /* Check that length is a positive Smi. */ \ 466 /* Check that length is a positive Smi. */ \
479 /* T2: requested array length argument. */ \ 467 /* T2: requested array length argument. */ \
480 __ andi(CMPRES, T2, Immediate(kSmiTagMask)); \ 468 __ andi(CMPRES, T2, Immediate(kSmiTagMask)); \
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after
552 __ sw(ZR, Address(T2, 0)); \ 540 __ sw(ZR, Address(T2, 0)); \
553 __ b(&init_loop); \ 541 __ b(&init_loop); \
554 __ delay_slot()->addiu(T2, T2, Immediate(kWordSize)); \ 542 __ delay_slot()->addiu(T2, T2, Immediate(kWordSize)); \
555 __ Bind(&done); \ 543 __ Bind(&done); \
556 \ 544 \
557 __ Ret(); \ 545 __ Ret(); \
558 __ Bind(&fall_through); \ 546 __ Bind(&fall_through); \
559 547
560 548
561 // Gets the length of a TypedData. 549 // Gets the length of a TypedData.
562 bool Intrinsifier::TypedData_getLength(Assembler* assembler) { 550 void Intrinsifier::TypedData_getLength(Assembler* assembler) {
563 __ lw(T0, Address(SP, 0 * kWordSize)); 551 __ lw(T0, Address(SP, 0 * kWordSize));
564 __ Ret(); 552 __ Ret();
565 __ delay_slot()->lw(V0, FieldAddress(T0, TypedData::length_offset())); 553 __ delay_slot()->lw(V0, FieldAddress(T0, TypedData::length_offset()));
566 return true;
567 } 554 }
568 555
569 556
570 static int GetScaleFactor(intptr_t size) { 557 static int GetScaleFactor(intptr_t size) {
571 switch (size) { 558 switch (size) {
572 case 1: return 0; 559 case 1: return 0;
573 case 2: return 1; 560 case 2: return 1;
574 case 4: return 2; 561 case 4: return 2;
575 case 8: return 3; 562 case 8: return 3;
576 case 16: return 4; 563 case 16: return 4;
577 } 564 }
578 UNREACHABLE(); 565 UNREACHABLE();
579 return -1; 566 return -1;
580 }; 567 };
581 568
582 569
583 #define TYPED_DATA_ALLOCATOR(clazz) \ 570 #define TYPED_DATA_ALLOCATOR(clazz) \
584 bool Intrinsifier::TypedData_##clazz##_new(Assembler* assembler) { \ 571 void Intrinsifier::TypedData_##clazz##_new(Assembler* assembler) { \
585 intptr_t size = TypedData::ElementSizeInBytes(kTypedData##clazz##Cid); \ 572 intptr_t size = TypedData::ElementSizeInBytes(kTypedData##clazz##Cid); \
586 intptr_t max_len = TypedData::MaxElements(kTypedData##clazz##Cid); \ 573 intptr_t max_len = TypedData::MaxElements(kTypedData##clazz##Cid); \
587 int shift = GetScaleFactor(size); \ 574 int shift = GetScaleFactor(size); \
588 TYPED_ARRAY_ALLOCATION(TypedData, kTypedData##clazz##Cid, max_len, shift); \ 575 TYPED_ARRAY_ALLOCATION(TypedData, kTypedData##clazz##Cid, max_len, shift); \
589 return false; \
590 } \ 576 } \
591 bool Intrinsifier::TypedData_##clazz##_factory(Assembler* assembler) { \ 577 void Intrinsifier::TypedData_##clazz##_factory(Assembler* assembler) { \
592 intptr_t size = TypedData::ElementSizeInBytes(kTypedData##clazz##Cid); \ 578 intptr_t size = TypedData::ElementSizeInBytes(kTypedData##clazz##Cid); \
593 intptr_t max_len = TypedData::MaxElements(kTypedData##clazz##Cid); \ 579 intptr_t max_len = TypedData::MaxElements(kTypedData##clazz##Cid); \
594 int shift = GetScaleFactor(size); \ 580 int shift = GetScaleFactor(size); \
595 TYPED_ARRAY_ALLOCATION(TypedData, kTypedData##clazz##Cid, max_len, shift); \ 581 TYPED_ARRAY_ALLOCATION(TypedData, kTypedData##clazz##Cid, max_len, shift); \
596 return false; \
597 } 582 }
598 CLASS_LIST_TYPED_DATA(TYPED_DATA_ALLOCATOR) 583 CLASS_LIST_TYPED_DATA(TYPED_DATA_ALLOCATOR)
599 #undef TYPED_DATA_ALLOCATOR 584 #undef TYPED_DATA_ALLOCATOR
600 585
601 586
602 // Loads args from stack into T0 and T1 587 // Loads args from stack into T0 and T1
603 // Tests if they are smis, jumps to label not_smi if not. 588 // Tests if they are smis, jumps to label not_smi if not.
604 static void TestBothArgumentsSmis(Assembler* assembler, Label* not_smi) { 589 static void TestBothArgumentsSmis(Assembler* assembler, Label* not_smi) {
605 __ lw(T0, Address(SP, 0 * kWordSize)); 590 __ lw(T0, Address(SP, 0 * kWordSize));
606 __ lw(T1, Address(SP, 1 * kWordSize)); 591 __ lw(T1, Address(SP, 1 * kWordSize));
607 __ or_(CMPRES, T0, T1); 592 __ or_(CMPRES, T0, T1);
608 __ andi(CMPRES, CMPRES, Immediate(kSmiTagMask)); 593 __ andi(CMPRES, CMPRES, Immediate(kSmiTagMask));
609 __ bne(CMPRES, ZR, not_smi); 594 __ bne(CMPRES, ZR, not_smi);
610 return; 595 return;
611 } 596 }
612 597
613 598
614 bool Intrinsifier::Integer_addFromInteger(Assembler* assembler) { 599 void Intrinsifier::Integer_addFromInteger(Assembler* assembler) {
615 Label fall_through; 600 Label fall_through;
616 601
617 TestBothArgumentsSmis(assembler, &fall_through); // Checks two Smis. 602 TestBothArgumentsSmis(assembler, &fall_through); // Checks two Smis.
618 __ AdduDetectOverflow(V0, T0, T1, CMPRES); // Add. 603 __ AdduDetectOverflow(V0, T0, T1, CMPRES); // Add.
619 __ bltz(CMPRES, &fall_through); // Fall through on overflow. 604 __ bltz(CMPRES, &fall_through); // Fall through on overflow.
620 __ Ret(); // Nothing in branch delay slot. 605 __ Ret(); // Nothing in branch delay slot.
621 __ Bind(&fall_through); 606 __ Bind(&fall_through);
622 return false;
623 } 607 }
624 608
625 609
626 bool Intrinsifier::Integer_add(Assembler* assembler) { 610 void Intrinsifier::Integer_add(Assembler* assembler) {
627 return Integer_addFromInteger(assembler); 611 return Integer_addFromInteger(assembler);
628 } 612 }
629 613
630 614
631 bool Intrinsifier::Integer_subFromInteger(Assembler* assembler) { 615 void Intrinsifier::Integer_subFromInteger(Assembler* assembler) {
632 Label fall_through; 616 Label fall_through;
633 617
634 TestBothArgumentsSmis(assembler, &fall_through); 618 TestBothArgumentsSmis(assembler, &fall_through);
635 __ SubuDetectOverflow(V0, T0, T1, CMPRES); // Subtract. 619 __ SubuDetectOverflow(V0, T0, T1, CMPRES); // Subtract.
636 __ bltz(CMPRES, &fall_through); // Fall through on overflow. 620 __ bltz(CMPRES, &fall_through); // Fall through on overflow.
637 __ Ret(); 621 __ Ret();
638 __ Bind(&fall_through); 622 __ Bind(&fall_through);
639 return false;
640 } 623 }
641 624
642 625
643 bool Intrinsifier::Integer_sub(Assembler* assembler) { 626 void Intrinsifier::Integer_sub(Assembler* assembler) {
644 Label fall_through; 627 Label fall_through;
645 628
646 TestBothArgumentsSmis(assembler, &fall_through); 629 TestBothArgumentsSmis(assembler, &fall_through);
647 __ SubuDetectOverflow(V0, T1, T0, CMPRES); // Subtract. 630 __ SubuDetectOverflow(V0, T1, T0, CMPRES); // Subtract.
648 __ bltz(CMPRES, &fall_through); // Fall through on overflow. 631 __ bltz(CMPRES, &fall_through); // Fall through on overflow.
649 __ Ret(); // Nothing in branch delay slot. 632 __ Ret(); // Nothing in branch delay slot.
650 __ Bind(&fall_through); 633 __ Bind(&fall_through);
651 return false;
652 } 634 }
653 635
654 636
655 bool Intrinsifier::Integer_mulFromInteger(Assembler* assembler) { 637 void Intrinsifier::Integer_mulFromInteger(Assembler* assembler) {
656 Label fall_through; 638 Label fall_through;
657 639
658 TestBothArgumentsSmis(assembler, &fall_through); // checks two smis 640 TestBothArgumentsSmis(assembler, &fall_through); // checks two smis
659 __ SmiUntag(T0); // untags T0. only want result shifted by one 641 __ SmiUntag(T0); // untags T0. only want result shifted by one
660 642
661 __ mult(T0, T1); // HI:LO <- T0 * T1. 643 __ mult(T0, T1); // HI:LO <- T0 * T1.
662 __ mflo(V0); // V0 <- LO. 644 __ mflo(V0); // V0 <- LO.
663 __ mfhi(T2); // T2 <- HI. 645 __ mfhi(T2); // T2 <- HI.
664 __ sra(T3, V0, 31); // T3 <- V0 >> 31. 646 __ sra(T3, V0, 31); // T3 <- V0 >> 31.
665 __ bne(T2, T3, &fall_through); // Fall through on overflow. 647 __ bne(T2, T3, &fall_through); // Fall through on overflow.
666 __ Ret(); 648 __ Ret();
667 __ Bind(&fall_through); 649 __ Bind(&fall_through);
668 return false;
669 } 650 }
670 651
671 652
672 bool Intrinsifier::Integer_mul(Assembler* assembler) { 653 void Intrinsifier::Integer_mul(Assembler* assembler) {
673 return Integer_mulFromInteger(assembler); 654 return Integer_mulFromInteger(assembler);
674 } 655 }
675 656
676 657
677 // Optimizations: 658 // Optimizations:
678 // - result is 0 if: 659 // - result is 0 if:
679 // - left is 0 660 // - left is 0
680 // - left equals right 661 // - left equals right
681 // - result is left if 662 // - result is left if
682 // - left > 0 && left < right 663 // - left > 0 && left < right
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
714 695
715 // Implementation: 696 // Implementation:
716 // res = left % right; 697 // res = left % right;
717 // if (res < 0) { 698 // if (res < 0) {
718 // if (right < 0) { 699 // if (right < 0) {
719 // res = res - right; 700 // res = res - right;
720 // } else { 701 // } else {
721 // res = res + right; 702 // res = res + right;
722 // } 703 // }
723 // } 704 // }
724 bool Intrinsifier::Integer_moduloFromInteger(Assembler* assembler) { 705 void Intrinsifier::Integer_moduloFromInteger(Assembler* assembler) {
725 Label fall_through, subtract; 706 Label fall_through, subtract;
726 // Test arguments for smi. 707 // Test arguments for smi.
727 __ lw(T1, Address(SP, 0 * kWordSize)); 708 __ lw(T1, Address(SP, 0 * kWordSize));
728 __ lw(T0, Address(SP, 1 * kWordSize)); 709 __ lw(T0, Address(SP, 1 * kWordSize));
729 __ or_(CMPRES, T0, T1); 710 __ or_(CMPRES, T0, T1);
730 __ andi(CMPRES, CMPRES, Immediate(kSmiTagMask)); 711 __ andi(CMPRES, CMPRES, Immediate(kSmiTagMask));
731 __ bne(CMPRES, ZR, &fall_through); 712 __ bne(CMPRES, ZR, &fall_through);
732 // T1: Tagged left (dividend). 713 // T1: Tagged left (dividend).
733 // T0: Tagged right (divisor). 714 // T0: Tagged right (divisor).
734 // Check if modulo by zero -> exception thrown in main function. 715 // Check if modulo by zero -> exception thrown in main function.
(...skipping 11 matching lines...) Expand all
746 __ Bind(&subtract); 727 __ Bind(&subtract);
747 __ subu(V0, V0, T0); 728 __ subu(V0, V0, T0);
748 __ Ret(); 729 __ Ret();
749 __ delay_slot()->SmiTag(V0); 730 __ delay_slot()->SmiTag(V0);
750 731
751 __ Bind(&done); 732 __ Bind(&done);
752 __ Ret(); 733 __ Ret();
753 __ delay_slot()->SmiTag(V0); 734 __ delay_slot()->SmiTag(V0);
754 735
755 __ Bind(&fall_through); 736 __ Bind(&fall_through);
756 return false;
757 } 737 }
758 738
759 739
760 bool Intrinsifier::Integer_remainder(Assembler* assembler) { 740 void Intrinsifier::Integer_remainder(Assembler* assembler) {
761 Label fall_through; 741 Label fall_through;
762 742
763 TestBothArgumentsSmis(assembler, &fall_through); 743 TestBothArgumentsSmis(assembler, &fall_through);
764 // T1: Tagged left (dividend). 744 // T1: Tagged left (dividend).
765 // T0: Tagged right (divisor). 745 // T0: Tagged right (divisor).
766 // Check if modulo by zero -> exception thrown in main function. 746 // Check if modulo by zero -> exception thrown in main function.
767 __ beq(T0, ZR, &fall_through); 747 __ beq(T0, ZR, &fall_through);
768 EmitRemainderOperation(assembler); 748 EmitRemainderOperation(assembler);
769 // Untagged right in T0. Untagged remainder result in V0. 749 // Untagged right in T0. Untagged remainder result in V0.
770 750
771 __ Ret(); 751 __ Ret();
772 __ delay_slot()->SmiTag(V0); 752 __ delay_slot()->SmiTag(V0);
773 753
774 __ Bind(&fall_through); 754 __ Bind(&fall_through);
775 return false;
776 } 755 }
777 756
778 757
779 bool Intrinsifier::Integer_truncDivide(Assembler* assembler) { 758 void Intrinsifier::Integer_truncDivide(Assembler* assembler) {
780 Label fall_through; 759 Label fall_through;
781 760
782 TestBothArgumentsSmis(assembler, &fall_through); 761 TestBothArgumentsSmis(assembler, &fall_through);
783 __ beq(T0, ZR, &fall_through); // If b is 0, fall through. 762 __ beq(T0, ZR, &fall_through); // If b is 0, fall through.
784 763
785 __ SmiUntag(T0); 764 __ SmiUntag(T0);
786 __ SmiUntag(T1); 765 __ SmiUntag(T1);
787 __ div(T1, T0); // LO <- T1 / T0 766 __ div(T1, T0); // LO <- T1 / T0
788 __ mflo(V0); // V0 <- LO 767 __ mflo(V0); // V0 <- LO
789 // Check the corner case of dividing the 'MIN_SMI' with -1, in which case we 768 // Check the corner case of dividing the 'MIN_SMI' with -1, in which case we
790 // cannot tag the result. 769 // cannot tag the result.
791 __ BranchEqual(V0, 0x40000000, &fall_through); 770 __ BranchEqual(V0, 0x40000000, &fall_through);
792 __ Ret(); 771 __ Ret();
793 __ delay_slot()->SmiTag(V0); 772 __ delay_slot()->SmiTag(V0);
794 __ Bind(&fall_through); 773 __ Bind(&fall_through);
795 return false;
796 } 774 }
797 775
798 776
799 bool Intrinsifier::Integer_negate(Assembler* assembler) { 777 void Intrinsifier::Integer_negate(Assembler* assembler) {
800 Label fall_through; 778 Label fall_through;
801 779
802 __ lw(T0, Address(SP, + 0 * kWordSize)); // Grabs first argument. 780 __ lw(T0, Address(SP, + 0 * kWordSize)); // Grabs first argument.
803 __ andi(CMPRES, T0, Immediate(kSmiTagMask)); // Test for Smi. 781 __ andi(CMPRES, T0, Immediate(kSmiTagMask)); // Test for Smi.
804 __ bne(CMPRES, ZR, &fall_through); // Fall through if not a Smi. 782 __ bne(CMPRES, ZR, &fall_through); // Fall through if not a Smi.
805 __ SubuDetectOverflow(V0, ZR, T0, CMPRES); 783 __ SubuDetectOverflow(V0, ZR, T0, CMPRES);
806 __ bltz(CMPRES, &fall_through); // There was overflow. 784 __ bltz(CMPRES, &fall_through); // There was overflow.
807 __ Ret(); 785 __ Ret();
808 __ Bind(&fall_through); 786 __ Bind(&fall_through);
809 return false;
810 } 787 }
811 788
812 789
813 bool Intrinsifier::Integer_bitAndFromInteger(Assembler* assembler) { 790 void Intrinsifier::Integer_bitAndFromInteger(Assembler* assembler) {
814 Label fall_through; 791 Label fall_through;
815 792
816 TestBothArgumentsSmis(assembler, &fall_through); // Checks two smis. 793 TestBothArgumentsSmis(assembler, &fall_through); // Checks two smis.
817 __ Ret(); 794 __ Ret();
818 __ delay_slot()->and_(V0, T0, T1); 795 __ delay_slot()->and_(V0, T0, T1);
819 __ Bind(&fall_through); 796 __ Bind(&fall_through);
820 return false;
821 } 797 }
822 798
823 799
824 bool Intrinsifier::Integer_bitAnd(Assembler* assembler) { 800 void Intrinsifier::Integer_bitAnd(Assembler* assembler) {
825 return Integer_bitAndFromInteger(assembler); 801 return Integer_bitAndFromInteger(assembler);
826 } 802 }
827 803
828 804
829 bool Intrinsifier::Integer_bitOrFromInteger(Assembler* assembler) { 805 void Intrinsifier::Integer_bitOrFromInteger(Assembler* assembler) {
830 Label fall_through; 806 Label fall_through;
831 807
832 TestBothArgumentsSmis(assembler, &fall_through); // Checks two smis. 808 TestBothArgumentsSmis(assembler, &fall_through); // Checks two smis.
833 __ Ret(); 809 __ Ret();
834 __ delay_slot()->or_(V0, T0, T1); 810 __ delay_slot()->or_(V0, T0, T1);
835 __ Bind(&fall_through); 811 __ Bind(&fall_through);
836 return false;
837 } 812 }
838 813
839 814
840 bool Intrinsifier::Integer_bitOr(Assembler* assembler) { 815 void Intrinsifier::Integer_bitOr(Assembler* assembler) {
841 return Integer_bitOrFromInteger(assembler); 816 return Integer_bitOrFromInteger(assembler);
842 } 817 }
843 818
844 819
845 bool Intrinsifier::Integer_bitXorFromInteger(Assembler* assembler) { 820 void Intrinsifier::Integer_bitXorFromInteger(Assembler* assembler) {
846 Label fall_through; 821 Label fall_through;
847 822
848 TestBothArgumentsSmis(assembler, &fall_through); // Checks two smis. 823 TestBothArgumentsSmis(assembler, &fall_through); // Checks two smis.
849 __ Ret(); 824 __ Ret();
850 __ delay_slot()->xor_(V0, T0, T1); 825 __ delay_slot()->xor_(V0, T0, T1);
851 __ Bind(&fall_through); 826 __ Bind(&fall_through);
852 return false;
853 } 827 }
854 828
855 829
856 bool Intrinsifier::Integer_bitXor(Assembler* assembler) { 830 void Intrinsifier::Integer_bitXor(Assembler* assembler) {
857 return Integer_bitXorFromInteger(assembler); 831 return Integer_bitXorFromInteger(assembler);
858 } 832 }
859 833
860 834
861 bool Intrinsifier::Integer_shl(Assembler* assembler) { 835 void Intrinsifier::Integer_shl(Assembler* assembler) {
862 ASSERT(kSmiTagShift == 1); 836 ASSERT(kSmiTagShift == 1);
863 ASSERT(kSmiTag == 0); 837 ASSERT(kSmiTag == 0);
864 Label fall_through, overflow; 838 Label fall_through, overflow;
865 839
866 TestBothArgumentsSmis(assembler, &fall_through); 840 TestBothArgumentsSmis(assembler, &fall_through);
867 __ BranchUnsignedGreater(T0, Smi::RawValue(Smi::kBits), &fall_through); 841 __ BranchUnsignedGreater(T0, Smi::RawValue(Smi::kBits), &fall_through);
868 __ SmiUntag(T0); 842 __ SmiUntag(T0);
869 843
870 // Check for overflow by shifting left and shifting back arithmetically. 844 // Check for overflow by shifting left and shifting back arithmetically.
871 // If the result is different from the original, there was overflow. 845 // If the result is different from the original, there was overflow.
(...skipping 26 matching lines...) Expand all
898 __ sllv(T0, T1, T0); // T0 gets low bits. 872 __ sllv(T0, T1, T0); // T0 gets low bits.
899 873
900 const Class& mint_class = Class::Handle( 874 const Class& mint_class = Class::Handle(
901 Isolate::Current()->object_store()->mint_class()); 875 Isolate::Current()->object_store()->mint_class());
902 __ TryAllocate(mint_class, &fall_through, V0); 876 __ TryAllocate(mint_class, &fall_through, V0);
903 877
904 __ sw(T0, FieldAddress(V0, Mint::value_offset())); 878 __ sw(T0, FieldAddress(V0, Mint::value_offset()));
905 __ Ret(); 879 __ Ret();
906 __ delay_slot()->sw(T3, FieldAddress(V0, Mint::value_offset() + kWordSize)); 880 __ delay_slot()->sw(T3, FieldAddress(V0, Mint::value_offset() + kWordSize));
907 __ Bind(&fall_through); 881 __ Bind(&fall_through);
908 return false;
909 } 882 }
910 883
911 884
912 static void Get64SmiOrMint(Assembler* assembler, 885 static void Get64SmiOrMint(Assembler* assembler,
913 Register res_hi, 886 Register res_hi,
914 Register res_lo, 887 Register res_lo,
915 Register reg, 888 Register reg,
916 Label* not_smi_or_mint) { 889 Label* not_smi_or_mint) {
917 Label not_smi, done; 890 Label not_smi, done;
918 __ andi(CMPRES, reg, Immediate(kSmiTagMask)); 891 __ andi(CMPRES, reg, Immediate(kSmiTagMask));
(...skipping 10 matching lines...) Expand all
929 __ BranchNotEqual(CMPRES1, kMintCid, not_smi_or_mint); 902 __ BranchNotEqual(CMPRES1, kMintCid, not_smi_or_mint);
930 903
931 // Mint. 904 // Mint.
932 __ lw(res_lo, FieldAddress(reg, Mint::value_offset())); 905 __ lw(res_lo, FieldAddress(reg, Mint::value_offset()));
933 __ lw(res_hi, FieldAddress(reg, Mint::value_offset() + kWordSize)); 906 __ lw(res_hi, FieldAddress(reg, Mint::value_offset() + kWordSize));
934 __ Bind(&done); 907 __ Bind(&done);
935 return; 908 return;
936 } 909 }
937 910
938 911
939 static bool CompareIntegers(Assembler* assembler, Condition true_condition) { 912 static void CompareIntegers(Assembler* assembler, Condition true_condition) {
940 Label try_mint_smi, is_true, is_false, drop_two_fall_through, fall_through; 913 Label try_mint_smi, is_true, is_false, drop_two_fall_through, fall_through;
941 TestBothArgumentsSmis(assembler, &try_mint_smi); 914 TestBothArgumentsSmis(assembler, &try_mint_smi);
942 // T0 contains the right argument. T1 contains left argument 915 // T0 contains the right argument. T1 contains left argument
943 916
944 switch (true_condition) { 917 switch (true_condition) {
945 case LT: __ BranchSignedLess(T1, T0, &is_true); break; 918 case LT: __ BranchSignedLess(T1, T0, &is_true); break;
946 case LE: __ BranchSignedLessEqual(T1, T0, &is_true); break; 919 case LE: __ BranchSignedLessEqual(T1, T0, &is_true); break;
947 case GT: __ BranchSignedGreater(T1, T0, &is_true); break; 920 case GT: __ BranchSignedGreater(T1, T0, &is_true); break;
948 case GE: __ BranchSignedGreaterEqual(T1, T0, &is_true); break; 921 case GE: __ BranchSignedGreaterEqual(T1, T0, &is_true); break;
949 default: 922 default:
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
998 break; 971 break;
999 } 972 }
1000 default: 973 default:
1001 UNREACHABLE(); 974 UNREACHABLE();
1002 break; 975 break;
1003 } 976 }
1004 // Else is true. 977 // Else is true.
1005 __ b(&is_true); 978 __ b(&is_true);
1006 979
1007 __ Bind(&fall_through); 980 __ Bind(&fall_through);
1008 return false;
1009 } 981 }
1010 982
1011 983
1012 bool Intrinsifier::Integer_greaterThanFromInt(Assembler* assembler) { 984 void Intrinsifier::Integer_greaterThanFromInt(Assembler* assembler) {
1013 return CompareIntegers(assembler, LT); 985 return CompareIntegers(assembler, LT);
1014 } 986 }
1015 987
1016 988
1017 bool Intrinsifier::Integer_lessThan(Assembler* assembler) { 989 void Intrinsifier::Integer_lessThan(Assembler* assembler) {
1018 return Integer_greaterThanFromInt(assembler); 990 return Integer_greaterThanFromInt(assembler);
1019 } 991 }
1020 992
1021 993
1022 bool Intrinsifier::Integer_greaterThan(Assembler* assembler) { 994 void Intrinsifier::Integer_greaterThan(Assembler* assembler) {
1023 return CompareIntegers(assembler, GT); 995 return CompareIntegers(assembler, GT);
1024 } 996 }
1025 997
1026 998
1027 bool Intrinsifier::Integer_lessEqualThan(Assembler* assembler) { 999 void Intrinsifier::Integer_lessEqualThan(Assembler* assembler) {
1028 return CompareIntegers(assembler, LE); 1000 return CompareIntegers(assembler, LE);
1029 } 1001 }
1030 1002
1031 1003
1032 bool Intrinsifier::Integer_greaterEqualThan(Assembler* assembler) { 1004 void Intrinsifier::Integer_greaterEqualThan(Assembler* assembler) {
1033 return CompareIntegers(assembler, GE); 1005 return CompareIntegers(assembler, GE);
1034 } 1006 }
1035 1007
1036 1008
1037 // This is called for Smi, Mint and Bigint receivers. The right argument 1009 // This is called for Smi, Mint and Bigint receivers. The right argument
1038 // can be Smi, Mint, Bigint or double. 1010 // can be Smi, Mint, Bigint or double.
1039 bool Intrinsifier::Integer_equalToInteger(Assembler* assembler) { 1011 void Intrinsifier::Integer_equalToInteger(Assembler* assembler) {
1040 Label fall_through, true_label, check_for_mint; 1012 Label fall_through, true_label, check_for_mint;
1041 // For integer receiver '===' check first. 1013 // For integer receiver '===' check first.
1042 __ lw(T0, Address(SP, 0 * kWordSize)); 1014 __ lw(T0, Address(SP, 0 * kWordSize));
1043 __ lw(T1, Address(SP, 1 * kWordSize)); 1015 __ lw(T1, Address(SP, 1 * kWordSize));
1044 __ beq(T0, T1, &true_label); 1016 __ beq(T0, T1, &true_label);
1045 1017
1046 __ or_(T2, T0, T1); 1018 __ or_(T2, T0, T1);
1047 __ andi(CMPRES, T2, Immediate(kSmiTagMask)); 1019 __ andi(CMPRES, T2, Immediate(kSmiTagMask));
1048 // If T0 or T1 is not a smi do Mint checks. 1020 // If T0 or T1 is not a smi do Mint checks.
1049 __ bne(CMPRES, ZR, &check_for_mint); 1021 __ bne(CMPRES, ZR, &check_for_mint);
(...skipping 27 matching lines...) Expand all
1077 __ LoadClassId(CMPRES1, T1); 1049 __ LoadClassId(CMPRES1, T1);
1078 __ BranchNotEqual(CMPRES1, kMintCid, &fall_through); 1050 __ BranchNotEqual(CMPRES1, kMintCid, &fall_through);
1079 // Receiver is Mint, return false if right is Smi. 1051 // Receiver is Mint, return false if right is Smi.
1080 __ andi(CMPRES, T0, Immediate(kSmiTagMask)); 1052 __ andi(CMPRES, T0, Immediate(kSmiTagMask));
1081 __ bne(CMPRES, ZR, &fall_through); 1053 __ bne(CMPRES, ZR, &fall_through);
1082 __ LoadObject(V0, Bool::False()); 1054 __ LoadObject(V0, Bool::False());
1083 __ Ret(); 1055 __ Ret();
1084 // TODO(srdjan): Implement Mint == Mint comparison. 1056 // TODO(srdjan): Implement Mint == Mint comparison.
1085 1057
1086 __ Bind(&fall_through); 1058 __ Bind(&fall_through);
1087 return false;
1088 } 1059 }
1089 1060
1090 1061
1091 bool Intrinsifier::Integer_equal(Assembler* assembler) { 1062 void Intrinsifier::Integer_equal(Assembler* assembler) {
1092 return Integer_equalToInteger(assembler); 1063 return Integer_equalToInteger(assembler);
1093 } 1064 }
1094 1065
1095 1066
1096 bool Intrinsifier::Integer_sar(Assembler* assembler) { 1067 void Intrinsifier::Integer_sar(Assembler* assembler) {
1097 Label fall_through; 1068 Label fall_through;
1098 1069
1099 TestBothArgumentsSmis(assembler, &fall_through); 1070 TestBothArgumentsSmis(assembler, &fall_through);
1100 // Shift amount in T0. Value to shift in T1. 1071 // Shift amount in T0. Value to shift in T1.
1101 1072
1102 __ SmiUntag(T0); 1073 __ SmiUntag(T0);
1103 __ bltz(T0, &fall_through); 1074 __ bltz(T0, &fall_through);
1104 1075
1105 __ LoadImmediate(T2, 0x1F); 1076 __ LoadImmediate(T2, 0x1F);
1106 __ slt(CMPRES, T2, T0); // CMPRES <- 0x1F < T0 ? 1 : 0 1077 __ slt(CMPRES, T2, T0); // CMPRES <- 0x1F < T0 ? 1 : 0
1107 __ movn(T0, T2, CMPRES); // T0 <- 0x1F < T0 ? 0x1F : T0 1078 __ movn(T0, T2, CMPRES); // T0 <- 0x1F < T0 ? 0x1F : T0
1108 1079
1109 __ SmiUntag(T1); 1080 __ SmiUntag(T1);
1110 __ srav(V0, T1, T0); 1081 __ srav(V0, T1, T0);
1111 __ Ret(); 1082 __ Ret();
1112 __ delay_slot()->SmiTag(V0); 1083 __ delay_slot()->SmiTag(V0);
1113 __ Bind(&fall_through); 1084 __ Bind(&fall_through);
1114 return false;
1115 } 1085 }
1116 1086
1117 1087
1118 bool Intrinsifier::Smi_bitNegate(Assembler* assembler) { 1088 void Intrinsifier::Smi_bitNegate(Assembler* assembler) {
1119 __ lw(T0, Address(SP, 0 * kWordSize)); 1089 __ lw(T0, Address(SP, 0 * kWordSize));
1120 __ nor(V0, T0, ZR); 1090 __ nor(V0, T0, ZR);
1121 __ Ret(); 1091 __ Ret();
1122 __ delay_slot()->addiu(V0, V0, Immediate(-1)); // Remove inverted smi-tag. 1092 __ delay_slot()->addiu(V0, V0, Immediate(-1)); // Remove inverted smi-tag.
1123 return false;
1124 } 1093 }
1125 1094
1126 1095
1127 // Check if the last argument is a double, jump to label 'is_smi' if smi 1096 // Check if the last argument is a double, jump to label 'is_smi' if smi
1128 // (easy to convert to double), otherwise jump to label 'not_double_smi', 1097 // (easy to convert to double), otherwise jump to label 'not_double_smi',
1129 // Returns the last argument in T0. 1098 // Returns the last argument in T0.
1130 static void TestLastArgumentIsDouble(Assembler* assembler, 1099 static void TestLastArgumentIsDouble(Assembler* assembler,
1131 Label* is_smi, 1100 Label* is_smi,
1132 Label* not_double_smi) { 1101 Label* not_double_smi) {
1133 __ lw(T0, Address(SP, 0 * kWordSize)); 1102 __ lw(T0, Address(SP, 0 * kWordSize));
1134 __ andi(CMPRES, T0, Immediate(kSmiTagMask)); 1103 __ andi(CMPRES, T0, Immediate(kSmiTagMask));
1135 __ beq(CMPRES, ZR, is_smi); 1104 __ beq(CMPRES, ZR, is_smi);
1136 __ LoadClassId(CMPRES1, T0); 1105 __ LoadClassId(CMPRES1, T0);
1137 __ BranchNotEqual(CMPRES1, kDoubleCid, not_double_smi); 1106 __ BranchNotEqual(CMPRES1, kDoubleCid, not_double_smi);
1138 // Fall through with Double in T0. 1107 // Fall through with Double in T0.
1139 } 1108 }
1140 1109
1141 1110
1142 // Both arguments on stack, arg0 (left) is a double, arg1 (right) is of unknown 1111 // Both arguments on stack, arg0 (left) is a double, arg1 (right) is of unknown
1143 // type. Return true or false object in the register V0. Any NaN argument 1112 // type. Return true or false object in the register V0. Any NaN argument
1144 // returns false. Any non-double arg1 causes control flow to fall through to the 1113 // returns false. Any non-double arg1 causes control flow to fall through to the
1145 // slow case (compiled method body). 1114 // slow case (compiled method body).
1146 static bool CompareDoubles(Assembler* assembler, Condition true_condition) { 1115 static void CompareDoubles(Assembler* assembler, Condition true_condition) {
1147 Label is_smi, double_op, no_NaN, fall_through; 1116 Label is_smi, double_op, no_NaN, fall_through;
1148 __ Comment("CompareDoubles Intrinsic"); 1117 __ Comment("CompareDoubles Intrinsic");
1149 1118
1150 TestLastArgumentIsDouble(assembler, &is_smi, &fall_through); 1119 TestLastArgumentIsDouble(assembler, &is_smi, &fall_through);
1151 // Both arguments are double, right operand is in T0. 1120 // Both arguments are double, right operand is in T0.
1152 __ LoadDFromOffset(D1, T0, Double::value_offset() - kHeapObjectTag); 1121 __ LoadDFromOffset(D1, T0, Double::value_offset() - kHeapObjectTag);
1153 __ Bind(&double_op); 1122 __ Bind(&double_op);
1154 __ lw(T0, Address(SP, 1 * kWordSize)); // Left argument. 1123 __ lw(T0, Address(SP, 1 * kWordSize)); // Left argument.
1155 __ LoadDFromOffset(D0, T0, Double::value_offset() - kHeapObjectTag); 1124 __ LoadDFromOffset(D0, T0, Double::value_offset() - kHeapObjectTag);
1156 // Now, left is in D0, right is in D1. 1125 // Now, left is in D0, right is in D1.
(...skipping 26 matching lines...) Expand all
1183 __ Ret(); 1152 __ Ret();
1184 1153
1185 1154
1186 __ Bind(&is_smi); 1155 __ Bind(&is_smi);
1187 __ SmiUntag(T0); 1156 __ SmiUntag(T0);
1188 __ mtc1(T0, STMP1); 1157 __ mtc1(T0, STMP1);
1189 __ cvtdw(D1, STMP1); 1158 __ cvtdw(D1, STMP1);
1190 __ b(&double_op); 1159 __ b(&double_op);
1191 1160
1192 __ Bind(&fall_through); 1161 __ Bind(&fall_through);
1193 return false;
1194 } 1162 }
1195 1163
1196 1164
1197 bool Intrinsifier::Double_greaterThan(Assembler* assembler) { 1165 void Intrinsifier::Double_greaterThan(Assembler* assembler) {
1198 return CompareDoubles(assembler, GT); 1166 return CompareDoubles(assembler, GT);
1199 } 1167 }
1200 1168
1201 1169
1202 bool Intrinsifier::Double_greaterEqualThan(Assembler* assembler) { 1170 void Intrinsifier::Double_greaterEqualThan(Assembler* assembler) {
1203 return CompareDoubles(assembler, GE); 1171 return CompareDoubles(assembler, GE);
1204 } 1172 }
1205 1173
1206 1174
1207 bool Intrinsifier::Double_lessThan(Assembler* assembler) { 1175 void Intrinsifier::Double_lessThan(Assembler* assembler) {
1208 return CompareDoubles(assembler, LT); 1176 return CompareDoubles(assembler, LT);
1209 } 1177 }
1210 1178
1211 1179
1212 bool Intrinsifier::Double_equal(Assembler* assembler) { 1180 void Intrinsifier::Double_equal(Assembler* assembler) {
1213 return CompareDoubles(assembler, EQ); 1181 return CompareDoubles(assembler, EQ);
1214 } 1182 }
1215 1183
1216 1184
1217 bool Intrinsifier::Double_lessEqualThan(Assembler* assembler) { 1185 void Intrinsifier::Double_lessEqualThan(Assembler* assembler) {
1218 return CompareDoubles(assembler, LE); 1186 return CompareDoubles(assembler, LE);
1219 } 1187 }
1220 1188
1221 1189
1222 // Expects left argument to be double (receiver). Right argument is unknown. 1190 // Expects left argument to be double (receiver). Right argument is unknown.
1223 // Both arguments are on stack. 1191 // Both arguments are on stack.
1224 static bool DoubleArithmeticOperations(Assembler* assembler, Token::Kind kind) { 1192 static void DoubleArithmeticOperations(Assembler* assembler, Token::Kind kind) {
1225 Label fall_through; 1193 Label fall_through;
1226 1194
1227 TestLastArgumentIsDouble(assembler, &fall_through, &fall_through); 1195 TestLastArgumentIsDouble(assembler, &fall_through, &fall_through);
1228 // Both arguments are double, right operand is in T0. 1196 // Both arguments are double, right operand is in T0.
1229 __ lwc1(F2, FieldAddress(T0, Double::value_offset())); 1197 __ lwc1(F2, FieldAddress(T0, Double::value_offset()));
1230 __ lwc1(F3, FieldAddress(T0, Double::value_offset() + kWordSize)); 1198 __ lwc1(F3, FieldAddress(T0, Double::value_offset() + kWordSize));
1231 __ lw(T0, Address(SP, 1 * kWordSize)); // Left argument. 1199 __ lw(T0, Address(SP, 1 * kWordSize)); // Left argument.
1232 __ lwc1(F0, FieldAddress(T0, Double::value_offset())); 1200 __ lwc1(F0, FieldAddress(T0, Double::value_offset()));
1233 __ lwc1(F1, FieldAddress(T0, Double::value_offset() + kWordSize)); 1201 __ lwc1(F1, FieldAddress(T0, Double::value_offset() + kWordSize));
1234 switch (kind) { 1202 switch (kind) {
1235 case Token::kADD: __ addd(D0, D0, D1); break; 1203 case Token::kADD: __ addd(D0, D0, D1); break;
1236 case Token::kSUB: __ subd(D0, D0, D1); break; 1204 case Token::kSUB: __ subd(D0, D0, D1); break;
1237 case Token::kMUL: __ muld(D0, D0, D1); break; 1205 case Token::kMUL: __ muld(D0, D0, D1); break;
1238 case Token::kDIV: __ divd(D0, D0, D1); break; 1206 case Token::kDIV: __ divd(D0, D0, D1); break;
1239 default: UNREACHABLE(); 1207 default: UNREACHABLE();
1240 } 1208 }
1241 const Class& double_class = Class::Handle( 1209 const Class& double_class = Class::Handle(
1242 Isolate::Current()->object_store()->double_class()); 1210 Isolate::Current()->object_store()->double_class());
1243 __ TryAllocate(double_class, &fall_through, V0); // Result register. 1211 __ TryAllocate(double_class, &fall_through, V0); // Result register.
1244 __ swc1(F0, FieldAddress(V0, Double::value_offset())); 1212 __ swc1(F0, FieldAddress(V0, Double::value_offset()));
1245 __ Ret(); 1213 __ Ret();
1246 __ delay_slot()->swc1(F1, 1214 __ delay_slot()->swc1(F1,
1247 FieldAddress(V0, Double::value_offset() + kWordSize)); 1215 FieldAddress(V0, Double::value_offset() + kWordSize));
1248 __ Bind(&fall_through); 1216 __ Bind(&fall_through);
1249 return false;
1250 } 1217 }
1251 1218
1252 1219
1253 bool Intrinsifier::Double_add(Assembler* assembler) { 1220 void Intrinsifier::Double_add(Assembler* assembler) {
1254 return DoubleArithmeticOperations(assembler, Token::kADD); 1221 return DoubleArithmeticOperations(assembler, Token::kADD);
1255 } 1222 }
1256 1223
1257 1224
1258 bool Intrinsifier::Double_mul(Assembler* assembler) { 1225 void Intrinsifier::Double_mul(Assembler* assembler) {
1259 return DoubleArithmeticOperations(assembler, Token::kMUL); 1226 return DoubleArithmeticOperations(assembler, Token::kMUL);
1260 } 1227 }
1261 1228
1262 1229
1263 bool Intrinsifier::Double_sub(Assembler* assembler) { 1230 void Intrinsifier::Double_sub(Assembler* assembler) {
1264 return DoubleArithmeticOperations(assembler, Token::kSUB); 1231 return DoubleArithmeticOperations(assembler, Token::kSUB);
1265 } 1232 }
1266 1233
1267 1234
1268 bool Intrinsifier::Double_div(Assembler* assembler) { 1235 void Intrinsifier::Double_div(Assembler* assembler) {
1269 return DoubleArithmeticOperations(assembler, Token::kDIV); 1236 return DoubleArithmeticOperations(assembler, Token::kDIV);
1270 } 1237 }
1271 1238
1272 1239
1273 // Left is double right is integer (Bigint, Mint or Smi) 1240 // Left is double right is integer (Bigint, Mint or Smi)
1274 bool Intrinsifier::Double_mulFromInteger(Assembler* assembler) { 1241 void Intrinsifier::Double_mulFromInteger(Assembler* assembler) {
1275 Label fall_through; 1242 Label fall_through;
1276 // Only Smi-s allowed. 1243 // Only Smi-s allowed.
1277 __ lw(T0, Address(SP, 0 * kWordSize)); 1244 __ lw(T0, Address(SP, 0 * kWordSize));
1278 __ andi(CMPRES, T0, Immediate(kSmiTagMask)); 1245 __ andi(CMPRES, T0, Immediate(kSmiTagMask));
1279 __ bne(CMPRES, ZR, &fall_through); 1246 __ bne(CMPRES, ZR, &fall_through);
1280 1247
1281 // Is Smi. 1248 // Is Smi.
1282 __ SmiUntag(T0); 1249 __ SmiUntag(T0);
1283 __ mtc1(T0, F4); 1250 __ mtc1(T0, F4);
1284 __ cvtdw(D1, F4); 1251 __ cvtdw(D1, F4);
1285 1252
1286 __ lw(T0, Address(SP, 1 * kWordSize)); 1253 __ lw(T0, Address(SP, 1 * kWordSize));
1287 __ lwc1(F0, FieldAddress(T0, Double::value_offset())); 1254 __ lwc1(F0, FieldAddress(T0, Double::value_offset()));
1288 __ lwc1(F1, FieldAddress(T0, Double::value_offset() + kWordSize)); 1255 __ lwc1(F1, FieldAddress(T0, Double::value_offset() + kWordSize));
1289 __ muld(D0, D0, D1); 1256 __ muld(D0, D0, D1);
1290 const Class& double_class = Class::Handle( 1257 const Class& double_class = Class::Handle(
1291 Isolate::Current()->object_store()->double_class()); 1258 Isolate::Current()->object_store()->double_class());
1292 __ TryAllocate(double_class, &fall_through, V0); // Result register. 1259 __ TryAllocate(double_class, &fall_through, V0); // Result register.
1293 __ swc1(F0, FieldAddress(V0, Double::value_offset())); 1260 __ swc1(F0, FieldAddress(V0, Double::value_offset()));
1294 __ Ret(); 1261 __ Ret();
1295 __ delay_slot()->swc1(F1, 1262 __ delay_slot()->swc1(F1,
1296 FieldAddress(V0, Double::value_offset() + kWordSize)); 1263 FieldAddress(V0, Double::value_offset() + kWordSize));
1297 __ Bind(&fall_through); 1264 __ Bind(&fall_through);
1298 return false;
1299 } 1265 }
1300 1266
1301 1267
1302 bool Intrinsifier::Double_fromInteger(Assembler* assembler) { 1268 void Intrinsifier::Double_fromInteger(Assembler* assembler) {
1303 Label fall_through; 1269 Label fall_through;
1304 1270
1305 __ lw(T0, Address(SP, 0 * kWordSize)); 1271 __ lw(T0, Address(SP, 0 * kWordSize));
1306 __ andi(CMPRES, T0, Immediate(kSmiTagMask)); 1272 __ andi(CMPRES, T0, Immediate(kSmiTagMask));
1307 __ bne(T0, ZR, &fall_through); 1273 __ bne(T0, ZR, &fall_through);
1308 1274
1309 // Is Smi. 1275 // Is Smi.
1310 __ SmiUntag(T0); 1276 __ SmiUntag(T0);
1311 __ mtc1(T0, F4); 1277 __ mtc1(T0, F4);
1312 __ cvtdw(D0, F4); 1278 __ cvtdw(D0, F4);
1313 const Class& double_class = Class::Handle( 1279 const Class& double_class = Class::Handle(
1314 Isolate::Current()->object_store()->double_class()); 1280 Isolate::Current()->object_store()->double_class());
1315 __ TryAllocate(double_class, &fall_through, V0); // Result register. 1281 __ TryAllocate(double_class, &fall_through, V0); // Result register.
1316 __ swc1(F0, FieldAddress(V0, Double::value_offset())); 1282 __ swc1(F0, FieldAddress(V0, Double::value_offset()));
1317 __ Ret(); 1283 __ Ret();
1318 __ delay_slot()->swc1(F1, 1284 __ delay_slot()->swc1(F1,
1319 FieldAddress(V0, Double::value_offset() + kWordSize)); 1285 FieldAddress(V0, Double::value_offset() + kWordSize));
1320 __ Bind(&fall_through); 1286 __ Bind(&fall_through);
1321 return false;
1322 } 1287 }
1323 1288
1324 1289
1325 bool Intrinsifier::Double_getIsNaN(Assembler* assembler) { 1290 void Intrinsifier::Double_getIsNaN(Assembler* assembler) {
1326 Label is_true; 1291 Label is_true;
1327 1292
1328 __ lw(T0, Address(SP, 0 * kWordSize)); 1293 __ lw(T0, Address(SP, 0 * kWordSize));
1329 __ lwc1(F0, FieldAddress(T0, Double::value_offset())); 1294 __ lwc1(F0, FieldAddress(T0, Double::value_offset()));
1330 __ lwc1(F1, FieldAddress(T0, Double::value_offset() + kWordSize)); 1295 __ lwc1(F1, FieldAddress(T0, Double::value_offset() + kWordSize));
1331 __ cund(D0, D0); // Check for NaN. 1296 __ cund(D0, D0); // Check for NaN.
1332 __ bc1t(&is_true); 1297 __ bc1t(&is_true);
1333 __ LoadObject(V0, Bool::False()); // Return false if either is NaN. 1298 __ LoadObject(V0, Bool::False()); // Return false if either is NaN.
1334 __ Ret(); 1299 __ Ret();
1335 __ Bind(&is_true); 1300 __ Bind(&is_true);
1336 __ LoadObject(V0, Bool::True()); 1301 __ LoadObject(V0, Bool::True());
1337 __ Ret(); 1302 __ Ret();
1338 return true;
1339 } 1303 }
1340 1304
1341 1305
1342 bool Intrinsifier::Double_getIsNegative(Assembler* assembler) { 1306 void Intrinsifier::Double_getIsNegative(Assembler* assembler) {
1343 Label is_false, is_true, is_zero; 1307 Label is_false, is_true, is_zero;
1344 __ lw(T0, Address(SP, 0 * kWordSize)); 1308 __ lw(T0, Address(SP, 0 * kWordSize));
1345 __ LoadDFromOffset(D0, T0, Double::value_offset() - kHeapObjectTag); 1309 __ LoadDFromOffset(D0, T0, Double::value_offset() - kHeapObjectTag);
1346 1310
1347 __ cund(D0, D0); 1311 __ cund(D0, D0);
1348 __ bc1t(&is_false); // NaN -> false. 1312 __ bc1t(&is_false); // NaN -> false.
1349 1313
1350 __ LoadImmediate(D1, 0.0); 1314 __ LoadImmediate(D1, 0.0);
1351 __ ceqd(D0, D1); 1315 __ ceqd(D0, D1);
1352 __ bc1t(&is_zero); // Check for negative zero. 1316 __ bc1t(&is_zero); // Check for negative zero.
1353 1317
1354 __ coled(D1, D0); 1318 __ coled(D1, D0);
1355 __ bc1t(&is_false); // >= 0 -> false. 1319 __ bc1t(&is_false); // >= 0 -> false.
1356 1320
1357 __ Bind(&is_true); 1321 __ Bind(&is_true);
1358 __ LoadObject(V0, Bool::True()); 1322 __ LoadObject(V0, Bool::True());
1359 __ Ret(); 1323 __ Ret();
1360 1324
1361 __ Bind(&is_false); 1325 __ Bind(&is_false);
1362 __ LoadObject(V0, Bool::False()); 1326 __ LoadObject(V0, Bool::False());
1363 __ Ret(); 1327 __ Ret();
1364 1328
1365 __ Bind(&is_zero); 1329 __ Bind(&is_zero);
1366 // Check for negative zero by looking at the sign bit. 1330 // Check for negative zero by looking at the sign bit.
1367 __ mfc1(T0, F1); // Moves bits 32...63 of D0 to T0. 1331 __ mfc1(T0, F1); // Moves bits 32...63 of D0 to T0.
1368 __ srl(T0, T0, 31); // Get the sign bit down to bit 0 of T0. 1332 __ srl(T0, T0, 31); // Get the sign bit down to bit 0 of T0.
1369 __ andi(CMPRES, T0, Immediate(1)); // Check if the bit is set. 1333 __ andi(CMPRES, T0, Immediate(1)); // Check if the bit is set.
1370 __ bne(T0, ZR, &is_true); // Sign bit set. True. 1334 __ bne(T0, ZR, &is_true); // Sign bit set. True.
1371 __ b(&is_false); 1335 __ b(&is_false);
1372 return true;
1373 } 1336 }
1374 1337
1375 1338
1376 bool Intrinsifier::Double_toInt(Assembler* assembler) { 1339 void Intrinsifier::Double_toInt(Assembler* assembler) {
1377 __ lw(T0, Address(SP, 0 * kWordSize)); 1340 __ lw(T0, Address(SP, 0 * kWordSize));
1378 __ LoadDFromOffset(D0, T0, Double::value_offset() - kHeapObjectTag); 1341 __ LoadDFromOffset(D0, T0, Double::value_offset() - kHeapObjectTag);
1379 1342
1380 __ cvtwd(F2, D0); 1343 __ cvtwd(F2, D0);
1381 __ mfc1(V0, F2); 1344 __ mfc1(V0, F2);
1382 1345
1383 // Overflow is signaled with minint. 1346 // Overflow is signaled with minint.
1384 Label fall_through; 1347 Label fall_through;
1385 // Check for overflow and that it fits into Smi. 1348 // Check for overflow and that it fits into Smi.
1386 __ LoadImmediate(TMP, 0xC0000000); 1349 __ LoadImmediate(TMP, 0xC0000000);
1387 __ subu(CMPRES, V0, TMP); 1350 __ subu(CMPRES, V0, TMP);
1388 __ bltz(CMPRES, &fall_through); 1351 __ bltz(CMPRES, &fall_through);
1389 __ Ret(); 1352 __ Ret();
1390 __ delay_slot()->SmiTag(V0); 1353 __ delay_slot()->SmiTag(V0);
1391 __ Bind(&fall_through); 1354 __ Bind(&fall_through);
1392 return false;
1393 } 1355 }
1394 1356
1395 1357
1396 bool Intrinsifier::Math_sqrt(Assembler* assembler) { 1358 void Intrinsifier::Math_sqrt(Assembler* assembler) {
1397 Label fall_through, is_smi, double_op; 1359 Label fall_through, is_smi, double_op;
1398 TestLastArgumentIsDouble(assembler, &is_smi, &fall_through); 1360 TestLastArgumentIsDouble(assembler, &is_smi, &fall_through);
1399 // Argument is double and is in T0. 1361 // Argument is double and is in T0.
1400 __ LoadDFromOffset(D1, T0, Double::value_offset() - kHeapObjectTag); 1362 __ LoadDFromOffset(D1, T0, Double::value_offset() - kHeapObjectTag);
1401 __ Bind(&double_op); 1363 __ Bind(&double_op);
1402 __ sqrtd(D0, D1); 1364 __ sqrtd(D0, D1);
1403 const Class& double_class = Class::Handle( 1365 const Class& double_class = Class::Handle(
1404 Isolate::Current()->object_store()->double_class()); 1366 Isolate::Current()->object_store()->double_class());
1405 __ TryAllocate(double_class, &fall_through, V0); // Result register. 1367 __ TryAllocate(double_class, &fall_through, V0); // Result register.
1406 __ swc1(F0, FieldAddress(V0, Double::value_offset())); 1368 __ swc1(F0, FieldAddress(V0, Double::value_offset()));
1407 __ Ret(); 1369 __ Ret();
1408 __ delay_slot()->swc1(F1, 1370 __ delay_slot()->swc1(F1,
1409 FieldAddress(V0, Double::value_offset() + kWordSize)); 1371 FieldAddress(V0, Double::value_offset() + kWordSize));
1410 1372
1411 __ Bind(&is_smi); 1373 __ Bind(&is_smi);
1412 __ SmiUntag(T0); 1374 __ SmiUntag(T0);
1413 __ mtc1(T0, F2); 1375 __ mtc1(T0, F2);
1414 __ b(&double_op); 1376 __ b(&double_op);
1415 __ delay_slot()->cvtdw(D1, F2); 1377 __ delay_slot()->cvtdw(D1, F2);
1416 __ Bind(&fall_through); 1378 __ Bind(&fall_through);
1417 return false;
1418 } 1379 }
1419 1380
1420 1381
1421 bool Intrinsifier::Math_sin(Assembler* assembler) { 1382 void Intrinsifier::Math_sin(Assembler* assembler) {
1422 return false;
1423 } 1383 }
1424 1384
1425 1385
1426 bool Intrinsifier::Math_cos(Assembler* assembler) { 1386 void Intrinsifier::Math_cos(Assembler* assembler) {
1427 return false;
1428 } 1387 }
1429 1388
1430 1389
1431 // var state = ((_A * (_state[kSTATE_LO])) + _state[kSTATE_HI]) & _MASK_64; 1390 // var state = ((_A * (_state[kSTATE_LO])) + _state[kSTATE_HI]) & _MASK_64;
1432 // _state[kSTATE_LO] = state & _MASK_32; 1391 // _state[kSTATE_LO] = state & _MASK_32;
1433 // _state[kSTATE_HI] = state >> 32; 1392 // _state[kSTATE_HI] = state >> 32;
1434 bool Intrinsifier::Random_nextState(Assembler* assembler) { 1393 void Intrinsifier::Random_nextState(Assembler* assembler) {
1435 const Library& math_lib = Library::Handle(Library::MathLibrary()); 1394 const Library& math_lib = Library::Handle(Library::MathLibrary());
1436 ASSERT(!math_lib.IsNull()); 1395 ASSERT(!math_lib.IsNull());
1437 const Class& random_class = Class::Handle( 1396 const Class& random_class = Class::Handle(
1438 math_lib.LookupClassAllowPrivate(Symbols::_Random(), NULL)); 1397 math_lib.LookupClassAllowPrivate(Symbols::_Random(), NULL));
1439 ASSERT(!random_class.IsNull()); 1398 ASSERT(!random_class.IsNull());
1440 const Field& state_field = Field::ZoneHandle( 1399 const Field& state_field = Field::ZoneHandle(
1441 random_class.LookupInstanceField(Symbols::_state())); 1400 random_class.LookupInstanceField(Symbols::_state()));
1442 ASSERT(!state_field.IsNull()); 1401 ASSERT(!state_field.IsNull());
1443 const Field& random_A_field = Field::ZoneHandle( 1402 const Field& random_A_field = Field::ZoneHandle(
1444 random_class.LookupStaticField(Symbols::_A())); 1403 random_class.LookupStaticField(Symbols::_A()));
(...skipping 21 matching lines...) Expand all
1466 __ lw(T3, addr_1); 1425 __ lw(T3, addr_1);
1467 __ mtlo(T3); 1426 __ mtlo(T3);
1468 __ mthi(ZR); // HI:LO <- ZR:T3 Zero extend T3 into HI. 1427 __ mthi(ZR); // HI:LO <- ZR:T3 Zero extend T3 into HI.
1469 // 64-bit multiply and accumulate into T6:T3. 1428 // 64-bit multiply and accumulate into T6:T3.
1470 __ maddu(T0, T2); // HI:LO <- HI:LO + T0 * T2. 1429 __ maddu(T0, T2); // HI:LO <- HI:LO + T0 * T2.
1471 __ mflo(T3); 1430 __ mflo(T3);
1472 __ mfhi(T6); 1431 __ mfhi(T6);
1473 __ sw(T3, addr_0); 1432 __ sw(T3, addr_0);
1474 __ sw(T6, addr_1); 1433 __ sw(T6, addr_1);
1475 __ Ret(); 1434 __ Ret();
1476 return true;
1477 } 1435 }
1478 1436
1479 1437
1480 bool Intrinsifier::Object_equal(Assembler* assembler) { 1438 void Intrinsifier::Object_equal(Assembler* assembler) {
1481 Label is_true; 1439 Label is_true;
1482 1440
1483 __ lw(T0, Address(SP, 0 * kWordSize)); 1441 __ lw(T0, Address(SP, 0 * kWordSize));
1484 __ lw(T1, Address(SP, 1 * kWordSize)); 1442 __ lw(T1, Address(SP, 1 * kWordSize));
1485 __ beq(T0, T1, &is_true); 1443 __ beq(T0, T1, &is_true);
1486 __ LoadObject(V0, Bool::False()); 1444 __ LoadObject(V0, Bool::False());
1487 __ Ret(); 1445 __ Ret();
1488 __ Bind(&is_true); 1446 __ Bind(&is_true);
1489 __ LoadObject(V0, Bool::True()); 1447 __ LoadObject(V0, Bool::True());
1490 __ Ret(); 1448 __ Ret();
1491 return true;
1492 } 1449 }
1493 1450
1494 1451
1495 bool Intrinsifier::String_getHashCode(Assembler* assembler) { 1452 void Intrinsifier::String_getHashCode(Assembler* assembler) {
1496 Label fall_through; 1453 Label fall_through;
1497 __ lw(T0, Address(SP, 0 * kWordSize)); 1454 __ lw(T0, Address(SP, 0 * kWordSize));
1498 __ lw(V0, FieldAddress(T0, String::hash_offset())); 1455 __ lw(V0, FieldAddress(T0, String::hash_offset()));
1499 __ beq(V0, ZR, &fall_through); 1456 __ beq(V0, ZR, &fall_through);
1500 __ Ret(); 1457 __ Ret();
1501 __ Bind(&fall_through); // Hash not yet computed. 1458 __ Bind(&fall_through); // Hash not yet computed.
1502 return false;
1503 } 1459 }
1504 1460
1505 1461
1506 bool Intrinsifier::String_getLength(Assembler* assembler) { 1462 void Intrinsifier::String_getLength(Assembler* assembler) {
1507 __ lw(T0, Address(SP, 0 * kWordSize)); 1463 __ lw(T0, Address(SP, 0 * kWordSize));
1508 __ Ret(); 1464 __ Ret();
1509 __ delay_slot()->lw(V0, FieldAddress(T0, String::length_offset())); 1465 __ delay_slot()->lw(V0, FieldAddress(T0, String::length_offset()));
1510 return true;
1511 } 1466 }
1512 1467
1513 1468
1514 bool Intrinsifier::String_codeUnitAt(Assembler* assembler) { 1469 void Intrinsifier::String_codeUnitAt(Assembler* assembler) {
1515 Label fall_through, try_two_byte_string; 1470 Label fall_through, try_two_byte_string;
1516 1471
1517 __ lw(T1, Address(SP, 0 * kWordSize)); // Index. 1472 __ lw(T1, Address(SP, 0 * kWordSize)); // Index.
1518 __ lw(T0, Address(SP, 1 * kWordSize)); // String. 1473 __ lw(T0, Address(SP, 1 * kWordSize)); // String.
1519 1474
1520 // Checks. 1475 // Checks.
1521 __ andi(CMPRES, T1, Immediate(kSmiTagMask)); 1476 __ andi(CMPRES, T1, Immediate(kSmiTagMask));
1522 __ bne(T1, ZR, &fall_through); // Index is not a Smi. 1477 __ bne(T1, ZR, &fall_through); // Index is not a Smi.
1523 __ lw(T2, FieldAddress(T0, String::length_offset())); // Range check. 1478 __ lw(T2, FieldAddress(T0, String::length_offset())); // Range check.
1524 // Runtime throws exception. 1479 // Runtime throws exception.
(...skipping 10 matching lines...) Expand all
1535 1490
1536 __ Bind(&try_two_byte_string); 1491 __ Bind(&try_two_byte_string);
1537 __ BranchNotEqual(CMPRES1, kTwoByteStringCid, &fall_through); 1492 __ BranchNotEqual(CMPRES1, kTwoByteStringCid, &fall_through);
1538 ASSERT(kSmiTagShift == 1); 1493 ASSERT(kSmiTagShift == 1);
1539 __ addu(T2, T0, T1); 1494 __ addu(T2, T0, T1);
1540 __ lhu(V0, FieldAddress(T2, OneByteString::data_offset())); 1495 __ lhu(V0, FieldAddress(T2, OneByteString::data_offset()));
1541 __ Ret(); 1496 __ Ret();
1542 __ delay_slot()->SmiTag(V0); 1497 __ delay_slot()->SmiTag(V0);
1543 1498
1544 __ Bind(&fall_through); 1499 __ Bind(&fall_through);
1545 return false;
1546 } 1500 }
1547 1501
1548 1502
1549 bool Intrinsifier::String_getIsEmpty(Assembler* assembler) { 1503 void Intrinsifier::String_getIsEmpty(Assembler* assembler) {
1550 Label is_true; 1504 Label is_true;
1551 1505
1552 __ lw(T0, Address(SP, 0 * kWordSize)); 1506 __ lw(T0, Address(SP, 0 * kWordSize));
1553 __ lw(T0, FieldAddress(T0, String::length_offset())); 1507 __ lw(T0, FieldAddress(T0, String::length_offset()));
1554 1508
1555 __ beq(T0, ZR, &is_true); 1509 __ beq(T0, ZR, &is_true);
1556 __ LoadObject(V0, Bool::False()); 1510 __ LoadObject(V0, Bool::False());
1557 __ Ret(); 1511 __ Ret();
1558 __ Bind(&is_true); 1512 __ Bind(&is_true);
1559 __ LoadObject(V0, Bool::True()); 1513 __ LoadObject(V0, Bool::True());
1560 __ Ret(); 1514 __ Ret();
1561 return false;
1562 } 1515 }
1563 1516
1564 1517
1565 bool Intrinsifier::OneByteString_getHashCode(Assembler* assembler) { 1518 void Intrinsifier::OneByteString_getHashCode(Assembler* assembler) {
1566 Label no_hash; 1519 Label no_hash;
1567 1520
1568 __ lw(T1, Address(SP, 0 * kWordSize)); 1521 __ lw(T1, Address(SP, 0 * kWordSize));
1569 __ lw(V0, FieldAddress(T1, String::hash_offset())); 1522 __ lw(V0, FieldAddress(T1, String::hash_offset()));
1570 __ beq(V0, ZR, &no_hash); 1523 __ beq(V0, ZR, &no_hash);
1571 __ Ret(); // Return if already computed. 1524 __ Ret(); // Return if already computed.
1572 __ Bind(&no_hash); 1525 __ Bind(&no_hash);
1573 1526
1574 __ lw(T2, FieldAddress(T1, String::length_offset())); 1527 __ lw(T2, FieldAddress(T1, String::length_offset()));
1575 1528
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
1618 __ LoadImmediate(T6, (static_cast<intptr_t>(1) << String::kHashBits) - 1); 1571 __ LoadImmediate(T6, (static_cast<intptr_t>(1) << String::kHashBits) - 1);
1619 __ and_(V0, V0, T6); 1572 __ and_(V0, V0, T6);
1620 __ Bind(&done); 1573 __ Bind(&done);
1621 1574
1622 __ LoadImmediate(T2, 1); 1575 __ LoadImmediate(T2, 1);
1623 __ movz(V0, T2, V0); // If V0 is 0, set to 1. 1576 __ movz(V0, T2, V0); // If V0 is 0, set to 1.
1624 __ SmiTag(V0); 1577 __ SmiTag(V0);
1625 1578
1626 __ Ret(); 1579 __ Ret();
1627 __ delay_slot()->sw(V0, FieldAddress(T1, String::hash_offset())); 1580 __ delay_slot()->sw(V0, FieldAddress(T1, String::hash_offset()));
1628 return true;
1629 } 1581 }
1630 1582
1631 1583
1632 // Allocates one-byte string of length 'end - start'. The content is not 1584 // Allocates one-byte string of length 'end - start'. The content is not
1633 // initialized. 1585 // initialized.
1634 // 'length-reg' (T2) contains tagged length. 1586 // 'length-reg' (T2) contains tagged length.
1635 // Returns new string as tagged pointer in V0. 1587 // Returns new string as tagged pointer in V0.
1636 static void TryAllocateOnebyteString(Assembler* assembler, 1588 static void TryAllocateOnebyteString(Assembler* assembler,
1637 Label* ok, 1589 Label* ok,
1638 Label* failure) { 1590 Label* failure) {
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after
1700 // Clear hash. 1652 // Clear hash.
1701 __ b(ok); 1653 __ b(ok);
1702 __ delay_slot()->sw(ZR, FieldAddress(V0, String::hash_offset())); 1654 __ delay_slot()->sw(ZR, FieldAddress(V0, String::hash_offset()));
1703 } 1655 }
1704 1656
1705 1657
1706 // Arg0: Onebyte String 1658 // Arg0: Onebyte String
1707 // Arg1: Start index as Smi. 1659 // Arg1: Start index as Smi.
1708 // Arg2: End index as Smi. 1660 // Arg2: End index as Smi.
1709 // The indexes must be valid. 1661 // The indexes must be valid.
1710 bool Intrinsifier::OneByteString_substringUnchecked(Assembler* assembler) { 1662 void Intrinsifier::OneByteString_substringUnchecked(Assembler* assembler) {
1711 const intptr_t kStringOffset = 2 * kWordSize; 1663 const intptr_t kStringOffset = 2 * kWordSize;
1712 const intptr_t kStartIndexOffset = 1 * kWordSize; 1664 const intptr_t kStartIndexOffset = 1 * kWordSize;
1713 const intptr_t kEndIndexOffset = 0 * kWordSize; 1665 const intptr_t kEndIndexOffset = 0 * kWordSize;
1714 Label fall_through, ok; 1666 Label fall_through, ok;
1715 1667
1716 __ lw(T2, Address(SP, kEndIndexOffset)); 1668 __ lw(T2, Address(SP, kEndIndexOffset));
1717 __ lw(TMP, Address(SP, kStartIndexOffset)); 1669 __ lw(TMP, Address(SP, kStartIndexOffset));
1718 __ subu(T2, T2, TMP); 1670 __ subu(T2, T2, TMP);
1719 TryAllocateOnebyteString(assembler, &ok, &fall_through); 1671 TryAllocateOnebyteString(assembler, &ok, &fall_through);
1720 __ Bind(&ok); 1672 __ Bind(&ok);
(...skipping 26 matching lines...) Expand all
1747 __ lbu(T1, Address(T6, 0)); 1699 __ lbu(T1, Address(T6, 0));
1748 __ AddImmediate(T6, 1); 1700 __ AddImmediate(T6, 1);
1749 __ addiu(T2, T2, Immediate(-1)); 1701 __ addiu(T2, T2, Immediate(-1));
1750 __ sb(T1, FieldAddress(T7, OneByteString::data_offset())); 1702 __ sb(T1, FieldAddress(T7, OneByteString::data_offset()));
1751 __ bgtz(T2, &loop); 1703 __ bgtz(T2, &loop);
1752 __ delay_slot()->addiu(T7, T7, Immediate(1)); 1704 __ delay_slot()->addiu(T7, T7, Immediate(1));
1753 1705
1754 __ Bind(&done); 1706 __ Bind(&done);
1755 __ Ret(); 1707 __ Ret();
1756 __ Bind(&fall_through); 1708 __ Bind(&fall_through);
1757 return false;
1758 } 1709 }
1759 1710
1760 1711
1761 bool Intrinsifier::OneByteString_setAt(Assembler* assembler) { 1712 void Intrinsifier::OneByteString_setAt(Assembler* assembler) {
1762 __ lw(T2, Address(SP, 0 * kWordSize)); // Value. 1713 __ lw(T2, Address(SP, 0 * kWordSize)); // Value.
1763 __ lw(T1, Address(SP, 1 * kWordSize)); // Index. 1714 __ lw(T1, Address(SP, 1 * kWordSize)); // Index.
1764 __ lw(T0, Address(SP, 2 * kWordSize)); // OneByteString. 1715 __ lw(T0, Address(SP, 2 * kWordSize)); // OneByteString.
1765 __ SmiUntag(T1); 1716 __ SmiUntag(T1);
1766 __ SmiUntag(T2); 1717 __ SmiUntag(T2);
1767 __ addu(T3, T0, T1); 1718 __ addu(T3, T0, T1);
1768 __ Ret(); 1719 __ Ret();
1769 __ delay_slot()->sb(T2, FieldAddress(T3, OneByteString::data_offset())); 1720 __ delay_slot()->sb(T2, FieldAddress(T3, OneByteString::data_offset()));
1770 return true;
1771 } 1721 }
1772 1722
1773 1723
1774 bool Intrinsifier::OneByteString_allocate(Assembler* assembler) { 1724 void Intrinsifier::OneByteString_allocate(Assembler* assembler) {
1775 Label fall_through, ok; 1725 Label fall_through, ok;
1776 1726
1777 __ lw(T2, Address(SP, 0 * kWordSize)); // Length. 1727 __ lw(T2, Address(SP, 0 * kWordSize)); // Length.
1778 TryAllocateOnebyteString(assembler, &ok, &fall_through); 1728 TryAllocateOnebyteString(assembler, &ok, &fall_through);
1779 1729
1780 __ Bind(&ok); 1730 __ Bind(&ok);
1781 __ Ret(); 1731 __ Ret();
1782 1732
1783 __ Bind(&fall_through); 1733 __ Bind(&fall_through);
1784 return false;
1785 } 1734 }
1786 1735
1787 } // namespace dart 1736 } // namespace dart
1788 1737
1789 #endif // defined TARGET_ARCH_MIPS 1738 #endif // defined TARGET_ARCH_MIPS
OLDNEW
« no previous file with comments | « runtime/vm/intrinsifier_ia32.cc ('k') | runtime/vm/intrinsifier_x64.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698