OLD | NEW |
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_X64. | 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_X64. |
6 #if defined(TARGET_ARCH_X64) | 6 #if defined(TARGET_ARCH_X64) |
7 | 7 |
8 #include "vm/intrinsifier.h" | 8 #include "vm/intrinsifier.h" |
9 | 9 |
10 #include "vm/assembler.h" | 10 #include "vm/assembler.h" |
(...skipping 10 matching lines...) Expand all Loading... |
21 // When entering intrinsics code: | 21 // When entering intrinsics code: |
22 // R10: Arguments descriptor | 22 // R10: Arguments descriptor |
23 // TOS: Return address | 23 // TOS: Return address |
24 // The R10 registers can be destroyed only if there is no slow-path, i.e. | 24 // The R10 registers can be destroyed only if there is no slow-path, i.e. |
25 // if the intrinsified method always executes a return. | 25 // if the intrinsified method always executes a return. |
26 // The RBP register should not be modified, because it is used by the profiler. | 26 // The RBP register should not be modified, because it is used by the profiler. |
27 // The PP and THR registers (see constants_x64.h) must be preserved. | 27 // The PP and THR registers (see constants_x64.h) must be preserved. |
28 | 28 |
29 #define __ assembler-> | 29 #define __ assembler-> |
30 | 30 |
31 | |
32 intptr_t Intrinsifier::ParameterSlotFromSp() { | 31 intptr_t Intrinsifier::ParameterSlotFromSp() { |
33 return 0; | 32 return 0; |
34 } | 33 } |
35 | 34 |
36 | |
37 static bool IsABIPreservedRegister(Register reg) { | 35 static bool IsABIPreservedRegister(Register reg) { |
38 return ((1 << reg) & CallingConventions::kCalleeSaveCpuRegisters) != 0; | 36 return ((1 << reg) & CallingConventions::kCalleeSaveCpuRegisters) != 0; |
39 } | 37 } |
40 | 38 |
41 | |
42 void Intrinsifier::IntrinsicCallPrologue(Assembler* assembler) { | 39 void Intrinsifier::IntrinsicCallPrologue(Assembler* assembler) { |
43 ASSERT(IsABIPreservedRegister(CODE_REG)); | 40 ASSERT(IsABIPreservedRegister(CODE_REG)); |
44 ASSERT(!IsABIPreservedRegister(ARGS_DESC_REG)); | 41 ASSERT(!IsABIPreservedRegister(ARGS_DESC_REG)); |
45 ASSERT(IsABIPreservedRegister(CALLEE_SAVED_TEMP)); | 42 ASSERT(IsABIPreservedRegister(CALLEE_SAVED_TEMP)); |
46 ASSERT(CALLEE_SAVED_TEMP != CODE_REG); | 43 ASSERT(CALLEE_SAVED_TEMP != CODE_REG); |
47 ASSERT(CALLEE_SAVED_TEMP != ARGS_DESC_REG); | 44 ASSERT(CALLEE_SAVED_TEMP != ARGS_DESC_REG); |
48 | 45 |
49 assembler->Comment("IntrinsicCallPrologue"); | 46 assembler->Comment("IntrinsicCallPrologue"); |
50 assembler->movq(CALLEE_SAVED_TEMP, ARGS_DESC_REG); | 47 assembler->movq(CALLEE_SAVED_TEMP, ARGS_DESC_REG); |
51 } | 48 } |
52 | 49 |
53 | |
54 void Intrinsifier::IntrinsicCallEpilogue(Assembler* assembler) { | 50 void Intrinsifier::IntrinsicCallEpilogue(Assembler* assembler) { |
55 assembler->Comment("IntrinsicCallEpilogue"); | 51 assembler->Comment("IntrinsicCallEpilogue"); |
56 assembler->movq(ARGS_DESC_REG, CALLEE_SAVED_TEMP); | 52 assembler->movq(ARGS_DESC_REG, CALLEE_SAVED_TEMP); |
57 } | 53 } |
58 | 54 |
59 | |
60 void Intrinsifier::ObjectArraySetIndexed(Assembler* assembler) { | 55 void Intrinsifier::ObjectArraySetIndexed(Assembler* assembler) { |
61 if (Isolate::Current()->type_checks()) { | 56 if (Isolate::Current()->type_checks()) { |
62 return; | 57 return; |
63 } | 58 } |
64 | 59 |
65 Label fall_through; | 60 Label fall_through; |
66 __ movq(RDX, Address(RSP, +1 * kWordSize)); // Value. | 61 __ movq(RDX, Address(RSP, +1 * kWordSize)); // Value. |
67 __ movq(RCX, Address(RSP, +2 * kWordSize)); // Index. | 62 __ movq(RCX, Address(RSP, +2 * kWordSize)); // Index. |
68 __ movq(RAX, Address(RSP, +3 * kWordSize)); // Array. | 63 __ movq(RAX, Address(RSP, +3 * kWordSize)); // Array. |
69 __ testq(RCX, Immediate(kSmiTagMask)); | 64 __ testq(RCX, Immediate(kSmiTagMask)); |
70 __ j(NOT_ZERO, &fall_through); | 65 __ j(NOT_ZERO, &fall_through); |
71 // Range check. | 66 // Range check. |
72 __ cmpq(RCX, FieldAddress(RAX, Array::length_offset())); | 67 __ cmpq(RCX, FieldAddress(RAX, Array::length_offset())); |
73 // Runtime throws exception. | 68 // Runtime throws exception. |
74 __ j(ABOVE_EQUAL, &fall_through); | 69 __ j(ABOVE_EQUAL, &fall_through); |
75 // Note that RBX is Smi, i.e, times 2. | 70 // Note that RBX is Smi, i.e, times 2. |
76 ASSERT(kSmiTagShift == 1); | 71 ASSERT(kSmiTagShift == 1); |
77 // Destroy RCX (ic data) as we will not continue in the function. | 72 // Destroy RCX (ic data) as we will not continue in the function. |
78 __ StoreIntoObject(RAX, FieldAddress(RAX, RCX, TIMES_4, Array::data_offset()), | 73 __ StoreIntoObject(RAX, FieldAddress(RAX, RCX, TIMES_4, Array::data_offset()), |
79 RDX); | 74 RDX); |
80 // Caller is responsible of preserving the value if necessary. | 75 // Caller is responsible of preserving the value if necessary. |
81 __ ret(); | 76 __ ret(); |
82 __ Bind(&fall_through); | 77 __ Bind(&fall_through); |
83 } | 78 } |
84 | 79 |
85 | |
86 // Allocate a GrowableObjectArray using the backing array specified. | 80 // Allocate a GrowableObjectArray using the backing array specified. |
87 // On stack: type argument (+2), data (+1), return-address (+0). | 81 // On stack: type argument (+2), data (+1), return-address (+0). |
88 void Intrinsifier::GrowableArray_Allocate(Assembler* assembler) { | 82 void Intrinsifier::GrowableArray_Allocate(Assembler* assembler) { |
89 // This snippet of inlined code uses the following registers: | 83 // This snippet of inlined code uses the following registers: |
90 // RAX, RCX, R13 | 84 // RAX, RCX, R13 |
91 // and the newly allocated object is returned in RAX. | 85 // and the newly allocated object is returned in RAX. |
92 const intptr_t kTypeArgumentsOffset = 2 * kWordSize; | 86 const intptr_t kTypeArgumentsOffset = 2 * kWordSize; |
93 const intptr_t kArrayOffset = 1 * kWordSize; | 87 const intptr_t kArrayOffset = 1 * kWordSize; |
94 Label fall_through; | 88 Label fall_through; |
95 | 89 |
(...skipping 15 matching lines...) Expand all Loading... |
111 RAX, FieldAddress(RAX, GrowableObjectArray::type_arguments_offset()), | 105 RAX, FieldAddress(RAX, GrowableObjectArray::type_arguments_offset()), |
112 RCX); | 106 RCX); |
113 | 107 |
114 // Set the length field in the growable array object to 0. | 108 // Set the length field in the growable array object to 0. |
115 __ ZeroInitSmiField(FieldAddress(RAX, GrowableObjectArray::length_offset())); | 109 __ ZeroInitSmiField(FieldAddress(RAX, GrowableObjectArray::length_offset())); |
116 __ ret(); // returns the newly allocated object in RAX. | 110 __ ret(); // returns the newly allocated object in RAX. |
117 | 111 |
118 __ Bind(&fall_through); | 112 __ Bind(&fall_through); |
119 } | 113 } |
120 | 114 |
121 | |
122 // Add an element to growable array if it doesn't need to grow, otherwise | 115 // Add an element to growable array if it doesn't need to grow, otherwise |
123 // call into regular code. | 116 // call into regular code. |
124 // On stack: growable array (+2), value (+1), return-address (+0). | 117 // On stack: growable array (+2), value (+1), return-address (+0). |
125 void Intrinsifier::GrowableArray_add(Assembler* assembler) { | 118 void Intrinsifier::GrowableArray_add(Assembler* assembler) { |
126 // In checked mode we need to check the incoming argument. | 119 // In checked mode we need to check the incoming argument. |
127 if (Isolate::Current()->type_checks()) return; | 120 if (Isolate::Current()->type_checks()) return; |
128 Label fall_through; | 121 Label fall_through; |
129 __ movq(RAX, Address(RSP, +2 * kWordSize)); // Array. | 122 __ movq(RAX, Address(RSP, +2 * kWordSize)); // Array. |
130 __ movq(RCX, FieldAddress(RAX, GrowableObjectArray::length_offset())); | 123 __ movq(RCX, FieldAddress(RAX, GrowableObjectArray::length_offset())); |
131 // RCX: length. | 124 // RCX: length. |
132 __ movq(RDX, FieldAddress(RAX, GrowableObjectArray::data_offset())); | 125 __ movq(RDX, FieldAddress(RAX, GrowableObjectArray::data_offset())); |
133 // RDX: data. | 126 // RDX: data. |
134 // Compare length with capacity. | 127 // Compare length with capacity. |
135 __ cmpq(RCX, FieldAddress(RDX, Array::length_offset())); | 128 __ cmpq(RCX, FieldAddress(RDX, Array::length_offset())); |
136 __ j(EQUAL, &fall_through); // Must grow data. | 129 __ j(EQUAL, &fall_through); // Must grow data. |
137 // len = len + 1; | 130 // len = len + 1; |
138 __ IncrementSmiField(FieldAddress(RAX, GrowableObjectArray::length_offset()), | 131 __ IncrementSmiField(FieldAddress(RAX, GrowableObjectArray::length_offset()), |
139 1); | 132 1); |
140 __ movq(RAX, Address(RSP, +1 * kWordSize)); // Value | 133 __ movq(RAX, Address(RSP, +1 * kWordSize)); // Value |
141 ASSERT(kSmiTagShift == 1); | 134 ASSERT(kSmiTagShift == 1); |
142 __ StoreIntoObject(RDX, FieldAddress(RDX, RCX, TIMES_4, Array::data_offset()), | 135 __ StoreIntoObject(RDX, FieldAddress(RDX, RCX, TIMES_4, Array::data_offset()), |
143 RAX); | 136 RAX); |
144 __ LoadObject(RAX, Object::null_object()); | 137 __ LoadObject(RAX, Object::null_object()); |
145 __ ret(); | 138 __ ret(); |
146 __ Bind(&fall_through); | 139 __ Bind(&fall_through); |
147 } | 140 } |
148 | 141 |
149 | |
150 #define TYPED_ARRAY_ALLOCATION(type_name, cid, max_len, scale_factor) \ | 142 #define TYPED_ARRAY_ALLOCATION(type_name, cid, max_len, scale_factor) \ |
151 Label fall_through; \ | 143 Label fall_through; \ |
152 const intptr_t kArrayLengthStackOffset = 1 * kWordSize; \ | 144 const intptr_t kArrayLengthStackOffset = 1 * kWordSize; \ |
153 NOT_IN_PRODUCT(__ MaybeTraceAllocation(cid, &fall_through, false)); \ | 145 NOT_IN_PRODUCT(__ MaybeTraceAllocation(cid, &fall_through, false)); \ |
154 __ movq(RDI, Address(RSP, kArrayLengthStackOffset)); /* Array length. */ \ | 146 __ movq(RDI, Address(RSP, kArrayLengthStackOffset)); /* Array length. */ \ |
155 /* Check that length is a positive Smi. */ \ | 147 /* Check that length is a positive Smi. */ \ |
156 /* RDI: requested array length argument. */ \ | 148 /* RDI: requested array length argument. */ \ |
157 __ testq(RDI, Immediate(kSmiTagMask)); \ | 149 __ testq(RDI, Immediate(kSmiTagMask)); \ |
158 __ j(NOT_ZERO, &fall_through); \ | 150 __ j(NOT_ZERO, &fall_through); \ |
159 __ cmpq(RDI, Immediate(0)); \ | 151 __ cmpq(RDI, Immediate(0)); \ |
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
235 __ cmpq(RDI, RCX); \ | 227 __ cmpq(RDI, RCX); \ |
236 __ j(ABOVE_EQUAL, &done, Assembler::kNearJump); \ | 228 __ j(ABOVE_EQUAL, &done, Assembler::kNearJump); \ |
237 __ movq(Address(RDI, 0), RBX); \ | 229 __ movq(Address(RDI, 0), RBX); \ |
238 __ addq(RDI, Immediate(kWordSize)); \ | 230 __ addq(RDI, Immediate(kWordSize)); \ |
239 __ jmp(&init_loop, Assembler::kNearJump); \ | 231 __ jmp(&init_loop, Assembler::kNearJump); \ |
240 __ Bind(&done); \ | 232 __ Bind(&done); \ |
241 \ | 233 \ |
242 __ ret(); \ | 234 __ ret(); \ |
243 __ Bind(&fall_through); | 235 __ Bind(&fall_through); |
244 | 236 |
245 | |
246 static ScaleFactor GetScaleFactor(intptr_t size) { | 237 static ScaleFactor GetScaleFactor(intptr_t size) { |
247 switch (size) { | 238 switch (size) { |
248 case 1: | 239 case 1: |
249 return TIMES_1; | 240 return TIMES_1; |
250 case 2: | 241 case 2: |
251 return TIMES_2; | 242 return TIMES_2; |
252 case 4: | 243 case 4: |
253 return TIMES_4; | 244 return TIMES_4; |
254 case 8: | 245 case 8: |
255 return TIMES_8; | 246 return TIMES_8; |
256 case 16: | 247 case 16: |
257 return TIMES_16; | 248 return TIMES_16; |
258 } | 249 } |
259 UNREACHABLE(); | 250 UNREACHABLE(); |
260 return static_cast<ScaleFactor>(0); | 251 return static_cast<ScaleFactor>(0); |
261 } | 252 } |
262 | 253 |
263 | |
264 #define TYPED_DATA_ALLOCATOR(clazz) \ | 254 #define TYPED_DATA_ALLOCATOR(clazz) \ |
265 void Intrinsifier::TypedData_##clazz##_factory(Assembler* assembler) { \ | 255 void Intrinsifier::TypedData_##clazz##_factory(Assembler* assembler) { \ |
266 intptr_t size = TypedData::ElementSizeInBytes(kTypedData##clazz##Cid); \ | 256 intptr_t size = TypedData::ElementSizeInBytes(kTypedData##clazz##Cid); \ |
267 intptr_t max_len = TypedData::MaxElements(kTypedData##clazz##Cid); \ | 257 intptr_t max_len = TypedData::MaxElements(kTypedData##clazz##Cid); \ |
268 ScaleFactor scale = GetScaleFactor(size); \ | 258 ScaleFactor scale = GetScaleFactor(size); \ |
269 TYPED_ARRAY_ALLOCATION(TypedData, kTypedData##clazz##Cid, max_len, scale); \ | 259 TYPED_ARRAY_ALLOCATION(TypedData, kTypedData##clazz##Cid, max_len, scale); \ |
270 } | 260 } |
271 CLASS_LIST_TYPED_DATA(TYPED_DATA_ALLOCATOR) | 261 CLASS_LIST_TYPED_DATA(TYPED_DATA_ALLOCATOR) |
272 #undef TYPED_DATA_ALLOCATOR | 262 #undef TYPED_DATA_ALLOCATOR |
273 | 263 |
274 | |
275 // Tests if two top most arguments are smis, jumps to label not_smi if not. | 264 // Tests if two top most arguments are smis, jumps to label not_smi if not. |
276 // Topmost argument is in RAX. | 265 // Topmost argument is in RAX. |
277 static void TestBothArgumentsSmis(Assembler* assembler, Label* not_smi) { | 266 static void TestBothArgumentsSmis(Assembler* assembler, Label* not_smi) { |
278 __ movq(RAX, Address(RSP, +1 * kWordSize)); | 267 __ movq(RAX, Address(RSP, +1 * kWordSize)); |
279 __ movq(RCX, Address(RSP, +2 * kWordSize)); | 268 __ movq(RCX, Address(RSP, +2 * kWordSize)); |
280 __ orq(RCX, RAX); | 269 __ orq(RCX, RAX); |
281 __ testq(RCX, Immediate(kSmiTagMask)); | 270 __ testq(RCX, Immediate(kSmiTagMask)); |
282 __ j(NOT_ZERO, not_smi); | 271 __ j(NOT_ZERO, not_smi); |
283 } | 272 } |
284 | 273 |
285 | |
286 void Intrinsifier::Integer_addFromInteger(Assembler* assembler) { | 274 void Intrinsifier::Integer_addFromInteger(Assembler* assembler) { |
287 Label fall_through; | 275 Label fall_through; |
288 TestBothArgumentsSmis(assembler, &fall_through); | 276 TestBothArgumentsSmis(assembler, &fall_through); |
289 // RAX contains right argument. | 277 // RAX contains right argument. |
290 __ addq(RAX, Address(RSP, +2 * kWordSize)); | 278 __ addq(RAX, Address(RSP, +2 * kWordSize)); |
291 __ j(OVERFLOW, &fall_through, Assembler::kNearJump); | 279 __ j(OVERFLOW, &fall_through, Assembler::kNearJump); |
292 // Result is in RAX. | 280 // Result is in RAX. |
293 __ ret(); | 281 __ ret(); |
294 __ Bind(&fall_through); | 282 __ Bind(&fall_through); |
295 } | 283 } |
296 | 284 |
297 | |
298 void Intrinsifier::Integer_add(Assembler* assembler) { | 285 void Intrinsifier::Integer_add(Assembler* assembler) { |
299 Integer_addFromInteger(assembler); | 286 Integer_addFromInteger(assembler); |
300 } | 287 } |
301 | 288 |
302 | |
303 void Intrinsifier::Integer_subFromInteger(Assembler* assembler) { | 289 void Intrinsifier::Integer_subFromInteger(Assembler* assembler) { |
304 Label fall_through; | 290 Label fall_through; |
305 TestBothArgumentsSmis(assembler, &fall_through); | 291 TestBothArgumentsSmis(assembler, &fall_through); |
306 // RAX contains right argument, which is the actual minuend of subtraction. | 292 // RAX contains right argument, which is the actual minuend of subtraction. |
307 __ subq(RAX, Address(RSP, +2 * kWordSize)); | 293 __ subq(RAX, Address(RSP, +2 * kWordSize)); |
308 __ j(OVERFLOW, &fall_through, Assembler::kNearJump); | 294 __ j(OVERFLOW, &fall_through, Assembler::kNearJump); |
309 // Result is in RAX. | 295 // Result is in RAX. |
310 __ ret(); | 296 __ ret(); |
311 __ Bind(&fall_through); | 297 __ Bind(&fall_through); |
312 } | 298 } |
313 | 299 |
314 | |
315 void Intrinsifier::Integer_sub(Assembler* assembler) { | 300 void Intrinsifier::Integer_sub(Assembler* assembler) { |
316 Label fall_through; | 301 Label fall_through; |
317 TestBothArgumentsSmis(assembler, &fall_through); | 302 TestBothArgumentsSmis(assembler, &fall_through); |
318 // RAX contains right argument, which is the actual subtrahend of subtraction. | 303 // RAX contains right argument, which is the actual subtrahend of subtraction. |
319 __ movq(RCX, RAX); | 304 __ movq(RCX, RAX); |
320 __ movq(RAX, Address(RSP, +2 * kWordSize)); | 305 __ movq(RAX, Address(RSP, +2 * kWordSize)); |
321 __ subq(RAX, RCX); | 306 __ subq(RAX, RCX); |
322 __ j(OVERFLOW, &fall_through, Assembler::kNearJump); | 307 __ j(OVERFLOW, &fall_through, Assembler::kNearJump); |
323 // Result is in RAX. | 308 // Result is in RAX. |
324 __ ret(); | 309 __ ret(); |
325 __ Bind(&fall_through); | 310 __ Bind(&fall_through); |
326 } | 311 } |
327 | 312 |
328 | |
329 void Intrinsifier::Integer_mulFromInteger(Assembler* assembler) { | 313 void Intrinsifier::Integer_mulFromInteger(Assembler* assembler) { |
330 Label fall_through; | 314 Label fall_through; |
331 TestBothArgumentsSmis(assembler, &fall_through); | 315 TestBothArgumentsSmis(assembler, &fall_through); |
332 // RAX is the right argument. | 316 // RAX is the right argument. |
333 ASSERT(kSmiTag == 0); // Adjust code below if not the case. | 317 ASSERT(kSmiTag == 0); // Adjust code below if not the case. |
334 __ SmiUntag(RAX); | 318 __ SmiUntag(RAX); |
335 __ imulq(RAX, Address(RSP, +2 * kWordSize)); | 319 __ imulq(RAX, Address(RSP, +2 * kWordSize)); |
336 __ j(OVERFLOW, &fall_through, Assembler::kNearJump); | 320 __ j(OVERFLOW, &fall_through, Assembler::kNearJump); |
337 // Result is in RAX. | 321 // Result is in RAX. |
338 __ ret(); | 322 __ ret(); |
339 __ Bind(&fall_through); | 323 __ Bind(&fall_through); |
340 } | 324 } |
341 | 325 |
342 | |
343 void Intrinsifier::Integer_mul(Assembler* assembler) { | 326 void Intrinsifier::Integer_mul(Assembler* assembler) { |
344 Integer_mulFromInteger(assembler); | 327 Integer_mulFromInteger(assembler); |
345 } | 328 } |
346 | 329 |
347 | |
348 // Optimizations: | 330 // Optimizations: |
349 // - result is 0 if: | 331 // - result is 0 if: |
350 // - left is 0 | 332 // - left is 0 |
351 // - left equals right | 333 // - left equals right |
352 // - result is left if | 334 // - result is left if |
353 // - left > 0 && left < right | 335 // - left > 0 && left < right |
354 // RAX: Tagged left (dividend). | 336 // RAX: Tagged left (dividend). |
355 // RCX: Tagged right (divisor). | 337 // RCX: Tagged right (divisor). |
356 // Returns: | 338 // Returns: |
357 // RAX: Untagged fallthrough result (remainder to be adjusted), or | 339 // RAX: Untagged fallthrough result (remainder to be adjusted), or |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
401 // Divide using 64bit idiv. | 383 // Divide using 64bit idiv. |
402 __ Bind(¬_32bit); | 384 __ Bind(¬_32bit); |
403 __ SmiUntag(RAX); | 385 __ SmiUntag(RAX); |
404 __ SmiUntag(RCX); | 386 __ SmiUntag(RCX); |
405 __ cqo(); | 387 __ cqo(); |
406 __ idivq(RCX); | 388 __ idivq(RCX); |
407 __ movq(RAX, RDX); | 389 __ movq(RAX, RDX); |
408 __ Bind(&done); | 390 __ Bind(&done); |
409 } | 391 } |
410 | 392 |
411 | |
412 // Implementation: | 393 // Implementation: |
413 // res = left % right; | 394 // res = left % right; |
414 // if (res < 0) { | 395 // if (res < 0) { |
415 // if (right < 0) { | 396 // if (right < 0) { |
416 // res = res - right; | 397 // res = res - right; |
417 // } else { | 398 // } else { |
418 // res = res + right; | 399 // res = res + right; |
419 // } | 400 // } |
420 // } | 401 // } |
421 void Intrinsifier::Integer_moduloFromInteger(Assembler* assembler) { | 402 void Intrinsifier::Integer_moduloFromInteger(Assembler* assembler) { |
(...skipping 22 matching lines...) Expand all Loading... |
444 __ ret(); | 425 __ ret(); |
445 | 426 |
446 __ Bind(&subtract); | 427 __ Bind(&subtract); |
447 __ subq(RAX, RCX); | 428 __ subq(RAX, RCX); |
448 __ SmiTag(RAX); | 429 __ SmiTag(RAX); |
449 __ ret(); | 430 __ ret(); |
450 | 431 |
451 __ Bind(&fall_through); | 432 __ Bind(&fall_through); |
452 } | 433 } |
453 | 434 |
454 | |
455 void Intrinsifier::Integer_truncDivide(Assembler* assembler) { | 435 void Intrinsifier::Integer_truncDivide(Assembler* assembler) { |
456 Label fall_through, not_32bit; | 436 Label fall_through, not_32bit; |
457 TestBothArgumentsSmis(assembler, &fall_through); | 437 TestBothArgumentsSmis(assembler, &fall_through); |
458 // RAX: right argument (divisor) | 438 // RAX: right argument (divisor) |
459 __ cmpq(RAX, Immediate(0)); | 439 __ cmpq(RAX, Immediate(0)); |
460 __ j(EQUAL, &fall_through, Assembler::kNearJump); | 440 __ j(EQUAL, &fall_through, Assembler::kNearJump); |
461 __ movq(RCX, RAX); | 441 __ movq(RCX, RAX); |
462 __ movq(RAX, Address(RSP, +2 * kWordSize)); // Left argument (dividend). | 442 __ movq(RAX, Address(RSP, +2 * kWordSize)); // Left argument (dividend). |
463 | 443 |
464 // Check if both operands fit into 32bits as idiv with 64bit operands | 444 // Check if both operands fit into 32bits as idiv with 64bit operands |
(...skipping 26 matching lines...) Expand all Loading... |
491 __ popq(RDX); | 471 __ popq(RDX); |
492 // Check the corner case of dividing the 'MIN_SMI' with -1, in which case we | 472 // Check the corner case of dividing the 'MIN_SMI' with -1, in which case we |
493 // cannot tag the result. | 473 // cannot tag the result. |
494 __ cmpq(RAX, Immediate(0x4000000000000000)); | 474 __ cmpq(RAX, Immediate(0x4000000000000000)); |
495 __ j(EQUAL, &fall_through); | 475 __ j(EQUAL, &fall_through); |
496 __ SmiTag(RAX); | 476 __ SmiTag(RAX); |
497 __ ret(); | 477 __ ret(); |
498 __ Bind(&fall_through); | 478 __ Bind(&fall_through); |
499 } | 479 } |
500 | 480 |
501 | |
502 void Intrinsifier::Integer_negate(Assembler* assembler) { | 481 void Intrinsifier::Integer_negate(Assembler* assembler) { |
503 Label fall_through; | 482 Label fall_through; |
504 __ movq(RAX, Address(RSP, +1 * kWordSize)); | 483 __ movq(RAX, Address(RSP, +1 * kWordSize)); |
505 __ testq(RAX, Immediate(kSmiTagMask)); | 484 __ testq(RAX, Immediate(kSmiTagMask)); |
506 __ j(NOT_ZERO, &fall_through, Assembler::kNearJump); // Non-smi value. | 485 __ j(NOT_ZERO, &fall_through, Assembler::kNearJump); // Non-smi value. |
507 __ negq(RAX); | 486 __ negq(RAX); |
508 __ j(OVERFLOW, &fall_through, Assembler::kNearJump); | 487 __ j(OVERFLOW, &fall_through, Assembler::kNearJump); |
509 // Result is in RAX. | 488 // Result is in RAX. |
510 __ ret(); | 489 __ ret(); |
511 __ Bind(&fall_through); | 490 __ Bind(&fall_through); |
512 } | 491 } |
513 | 492 |
514 | |
515 void Intrinsifier::Integer_bitAndFromInteger(Assembler* assembler) { | 493 void Intrinsifier::Integer_bitAndFromInteger(Assembler* assembler) { |
516 Label fall_through; | 494 Label fall_through; |
517 TestBothArgumentsSmis(assembler, &fall_through); | 495 TestBothArgumentsSmis(assembler, &fall_through); |
518 // RAX is the right argument. | 496 // RAX is the right argument. |
519 __ andq(RAX, Address(RSP, +2 * kWordSize)); | 497 __ andq(RAX, Address(RSP, +2 * kWordSize)); |
520 // Result is in RAX. | 498 // Result is in RAX. |
521 __ ret(); | 499 __ ret(); |
522 __ Bind(&fall_through); | 500 __ Bind(&fall_through); |
523 } | 501 } |
524 | 502 |
525 | |
526 void Intrinsifier::Integer_bitAnd(Assembler* assembler) { | 503 void Intrinsifier::Integer_bitAnd(Assembler* assembler) { |
527 Integer_bitAndFromInteger(assembler); | 504 Integer_bitAndFromInteger(assembler); |
528 } | 505 } |
529 | 506 |
530 | |
531 void Intrinsifier::Integer_bitOrFromInteger(Assembler* assembler) { | 507 void Intrinsifier::Integer_bitOrFromInteger(Assembler* assembler) { |
532 Label fall_through; | 508 Label fall_through; |
533 TestBothArgumentsSmis(assembler, &fall_through); | 509 TestBothArgumentsSmis(assembler, &fall_through); |
534 // RAX is the right argument. | 510 // RAX is the right argument. |
535 __ orq(RAX, Address(RSP, +2 * kWordSize)); | 511 __ orq(RAX, Address(RSP, +2 * kWordSize)); |
536 // Result is in RAX. | 512 // Result is in RAX. |
537 __ ret(); | 513 __ ret(); |
538 __ Bind(&fall_through); | 514 __ Bind(&fall_through); |
539 } | 515 } |
540 | 516 |
541 | |
542 void Intrinsifier::Integer_bitOr(Assembler* assembler) { | 517 void Intrinsifier::Integer_bitOr(Assembler* assembler) { |
543 Integer_bitOrFromInteger(assembler); | 518 Integer_bitOrFromInteger(assembler); |
544 } | 519 } |
545 | 520 |
546 | |
547 void Intrinsifier::Integer_bitXorFromInteger(Assembler* assembler) { | 521 void Intrinsifier::Integer_bitXorFromInteger(Assembler* assembler) { |
548 Label fall_through; | 522 Label fall_through; |
549 TestBothArgumentsSmis(assembler, &fall_through); | 523 TestBothArgumentsSmis(assembler, &fall_through); |
550 // RAX is the right argument. | 524 // RAX is the right argument. |
551 __ xorq(RAX, Address(RSP, +2 * kWordSize)); | 525 __ xorq(RAX, Address(RSP, +2 * kWordSize)); |
552 // Result is in RAX. | 526 // Result is in RAX. |
553 __ ret(); | 527 __ ret(); |
554 __ Bind(&fall_through); | 528 __ Bind(&fall_through); |
555 } | 529 } |
556 | 530 |
557 | |
558 void Intrinsifier::Integer_bitXor(Assembler* assembler) { | 531 void Intrinsifier::Integer_bitXor(Assembler* assembler) { |
559 Integer_bitXorFromInteger(assembler); | 532 Integer_bitXorFromInteger(assembler); |
560 } | 533 } |
561 | 534 |
562 | |
563 void Intrinsifier::Integer_shl(Assembler* assembler) { | 535 void Intrinsifier::Integer_shl(Assembler* assembler) { |
564 ASSERT(kSmiTagShift == 1); | 536 ASSERT(kSmiTagShift == 1); |
565 ASSERT(kSmiTag == 0); | 537 ASSERT(kSmiTag == 0); |
566 Label fall_through, overflow; | 538 Label fall_through, overflow; |
567 TestBothArgumentsSmis(assembler, &fall_through); | 539 TestBothArgumentsSmis(assembler, &fall_through); |
568 // Shift value is in RAX. Compare with tagged Smi. | 540 // Shift value is in RAX. Compare with tagged Smi. |
569 __ cmpq(RAX, Immediate(Smi::RawValue(Smi::kBits))); | 541 __ cmpq(RAX, Immediate(Smi::RawValue(Smi::kBits))); |
570 __ j(ABOVE_EQUAL, &fall_through, Assembler::kNearJump); | 542 __ j(ABOVE_EQUAL, &fall_through, Assembler::kNearJump); |
571 | 543 |
572 __ SmiUntag(RAX); | 544 __ SmiUntag(RAX); |
(...skipping 11 matching lines...) Expand all Loading... |
584 | 556 |
585 // RAX is a correctly tagged Smi. | 557 // RAX is a correctly tagged Smi. |
586 __ ret(); | 558 __ ret(); |
587 | 559 |
588 __ Bind(&overflow); | 560 __ Bind(&overflow); |
589 // Mint is rarely used on x64 (only for integers requiring 64 bit instead of | 561 // Mint is rarely used on x64 (only for integers requiring 64 bit instead of |
590 // 63 bits as represented by Smi). | 562 // 63 bits as represented by Smi). |
591 __ Bind(&fall_through); | 563 __ Bind(&fall_through); |
592 } | 564 } |
593 | 565 |
594 | |
595 static void CompareIntegers(Assembler* assembler, Condition true_condition) { | 566 static void CompareIntegers(Assembler* assembler, Condition true_condition) { |
596 Label fall_through, true_label; | 567 Label fall_through, true_label; |
597 TestBothArgumentsSmis(assembler, &fall_through); | 568 TestBothArgumentsSmis(assembler, &fall_through); |
598 // RAX contains the right argument. | 569 // RAX contains the right argument. |
599 __ cmpq(Address(RSP, +2 * kWordSize), RAX); | 570 __ cmpq(Address(RSP, +2 * kWordSize), RAX); |
600 __ j(true_condition, &true_label, Assembler::kNearJump); | 571 __ j(true_condition, &true_label, Assembler::kNearJump); |
601 __ LoadObject(RAX, Bool::False()); | 572 __ LoadObject(RAX, Bool::False()); |
602 __ ret(); | 573 __ ret(); |
603 __ Bind(&true_label); | 574 __ Bind(&true_label); |
604 __ LoadObject(RAX, Bool::True()); | 575 __ LoadObject(RAX, Bool::True()); |
605 __ ret(); | 576 __ ret(); |
606 __ Bind(&fall_through); | 577 __ Bind(&fall_through); |
607 } | 578 } |
608 | 579 |
609 | |
610 void Intrinsifier::Integer_lessThan(Assembler* assembler) { | 580 void Intrinsifier::Integer_lessThan(Assembler* assembler) { |
611 CompareIntegers(assembler, LESS); | 581 CompareIntegers(assembler, LESS); |
612 } | 582 } |
613 | 583 |
614 | |
615 void Intrinsifier::Integer_greaterThanFromInt(Assembler* assembler) { | 584 void Intrinsifier::Integer_greaterThanFromInt(Assembler* assembler) { |
616 CompareIntegers(assembler, LESS); | 585 CompareIntegers(assembler, LESS); |
617 } | 586 } |
618 | 587 |
619 | |
620 void Intrinsifier::Integer_greaterThan(Assembler* assembler) { | 588 void Intrinsifier::Integer_greaterThan(Assembler* assembler) { |
621 CompareIntegers(assembler, GREATER); | 589 CompareIntegers(assembler, GREATER); |
622 } | 590 } |
623 | 591 |
624 | |
625 void Intrinsifier::Integer_lessEqualThan(Assembler* assembler) { | 592 void Intrinsifier::Integer_lessEqualThan(Assembler* assembler) { |
626 CompareIntegers(assembler, LESS_EQUAL); | 593 CompareIntegers(assembler, LESS_EQUAL); |
627 } | 594 } |
628 | 595 |
629 | |
630 void Intrinsifier::Integer_greaterEqualThan(Assembler* assembler) { | 596 void Intrinsifier::Integer_greaterEqualThan(Assembler* assembler) { |
631 CompareIntegers(assembler, GREATER_EQUAL); | 597 CompareIntegers(assembler, GREATER_EQUAL); |
632 } | 598 } |
633 | 599 |
634 | |
635 // This is called for Smi, Mint and Bigint receivers. The right argument | 600 // This is called for Smi, Mint and Bigint receivers. The right argument |
636 // can be Smi, Mint, Bigint or double. | 601 // can be Smi, Mint, Bigint or double. |
637 void Intrinsifier::Integer_equalToInteger(Assembler* assembler) { | 602 void Intrinsifier::Integer_equalToInteger(Assembler* assembler) { |
638 Label fall_through, true_label, check_for_mint; | 603 Label fall_through, true_label, check_for_mint; |
639 const intptr_t kReceiverOffset = 2; | 604 const intptr_t kReceiverOffset = 2; |
640 const intptr_t kArgumentOffset = 1; | 605 const intptr_t kArgumentOffset = 1; |
641 | 606 |
642 // For integer receiver '===' check first. | 607 // For integer receiver '===' check first. |
643 __ movq(RAX, Address(RSP, +kArgumentOffset * kWordSize)); | 608 __ movq(RAX, Address(RSP, +kArgumentOffset * kWordSize)); |
644 __ movq(RCX, Address(RSP, +kReceiverOffset * kWordSize)); | 609 __ movq(RCX, Address(RSP, +kReceiverOffset * kWordSize)); |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
679 __ testq(RAX, Immediate(kSmiTagMask)); | 644 __ testq(RAX, Immediate(kSmiTagMask)); |
680 __ j(NOT_ZERO, &fall_through); | 645 __ j(NOT_ZERO, &fall_through); |
681 // Smi == Mint -> false. | 646 // Smi == Mint -> false. |
682 __ LoadObject(RAX, Bool::False()); | 647 __ LoadObject(RAX, Bool::False()); |
683 __ ret(); | 648 __ ret(); |
684 // TODO(srdjan): Implement Mint == Mint comparison. | 649 // TODO(srdjan): Implement Mint == Mint comparison. |
685 | 650 |
686 __ Bind(&fall_through); | 651 __ Bind(&fall_through); |
687 } | 652 } |
688 | 653 |
689 | |
690 void Intrinsifier::Integer_equal(Assembler* assembler) { | 654 void Intrinsifier::Integer_equal(Assembler* assembler) { |
691 Integer_equalToInteger(assembler); | 655 Integer_equalToInteger(assembler); |
692 } | 656 } |
693 | 657 |
694 | |
695 void Intrinsifier::Integer_sar(Assembler* assembler) { | 658 void Intrinsifier::Integer_sar(Assembler* assembler) { |
696 Label fall_through, shift_count_ok; | 659 Label fall_through, shift_count_ok; |
697 TestBothArgumentsSmis(assembler, &fall_through); | 660 TestBothArgumentsSmis(assembler, &fall_through); |
698 const Immediate& count_limit = Immediate(0x3F); | 661 const Immediate& count_limit = Immediate(0x3F); |
699 // Check that the count is not larger than what the hardware can handle. | 662 // Check that the count is not larger than what the hardware can handle. |
700 // For shifting right a Smi the result is the same for all numbers | 663 // For shifting right a Smi the result is the same for all numbers |
701 // >= count_limit. | 664 // >= count_limit. |
702 __ SmiUntag(RAX); | 665 __ SmiUntag(RAX); |
703 // Negative counts throw exception. | 666 // Negative counts throw exception. |
704 __ cmpq(RAX, Immediate(0)); | 667 __ cmpq(RAX, Immediate(0)); |
705 __ j(LESS, &fall_through, Assembler::kNearJump); | 668 __ j(LESS, &fall_through, Assembler::kNearJump); |
706 __ cmpq(RAX, count_limit); | 669 __ cmpq(RAX, count_limit); |
707 __ j(LESS_EQUAL, &shift_count_ok, Assembler::kNearJump); | 670 __ j(LESS_EQUAL, &shift_count_ok, Assembler::kNearJump); |
708 __ movq(RAX, count_limit); | 671 __ movq(RAX, count_limit); |
709 __ Bind(&shift_count_ok); | 672 __ Bind(&shift_count_ok); |
710 __ movq(RCX, RAX); // Shift amount must be in RCX. | 673 __ movq(RCX, RAX); // Shift amount must be in RCX. |
711 __ movq(RAX, Address(RSP, +2 * kWordSize)); // Value. | 674 __ movq(RAX, Address(RSP, +2 * kWordSize)); // Value. |
712 __ SmiUntag(RAX); // Value. | 675 __ SmiUntag(RAX); // Value. |
713 __ sarq(RAX, RCX); | 676 __ sarq(RAX, RCX); |
714 __ SmiTag(RAX); | 677 __ SmiTag(RAX); |
715 __ ret(); | 678 __ ret(); |
716 __ Bind(&fall_through); | 679 __ Bind(&fall_through); |
717 } | 680 } |
718 | 681 |
719 | |
720 // Argument is Smi (receiver). | 682 // Argument is Smi (receiver). |
721 void Intrinsifier::Smi_bitNegate(Assembler* assembler) { | 683 void Intrinsifier::Smi_bitNegate(Assembler* assembler) { |
722 __ movq(RAX, Address(RSP, +1 * kWordSize)); // Index. | 684 __ movq(RAX, Address(RSP, +1 * kWordSize)); // Index. |
723 __ notq(RAX); | 685 __ notq(RAX); |
724 __ andq(RAX, Immediate(~kSmiTagMask)); // Remove inverted smi-tag. | 686 __ andq(RAX, Immediate(~kSmiTagMask)); // Remove inverted smi-tag. |
725 __ ret(); | 687 __ ret(); |
726 } | 688 } |
727 | 689 |
728 | |
729 void Intrinsifier::Smi_bitLength(Assembler* assembler) { | 690 void Intrinsifier::Smi_bitLength(Assembler* assembler) { |
730 ASSERT(kSmiTagShift == 1); | 691 ASSERT(kSmiTagShift == 1); |
731 __ movq(RAX, Address(RSP, +1 * kWordSize)); // Index. | 692 __ movq(RAX, Address(RSP, +1 * kWordSize)); // Index. |
732 // XOR with sign bit to complement bits if value is negative. | 693 // XOR with sign bit to complement bits if value is negative. |
733 __ movq(RCX, RAX); | 694 __ movq(RCX, RAX); |
734 __ sarq(RCX, Immediate(63)); // All 0 or all 1. | 695 __ sarq(RCX, Immediate(63)); // All 0 or all 1. |
735 __ xorq(RAX, RCX); | 696 __ xorq(RAX, RCX); |
736 // BSR does not write the destination register if source is zero. Put a 1 in | 697 // BSR does not write the destination register if source is zero. Put a 1 in |
737 // the Smi tag bit to ensure BSR writes to destination register. | 698 // the Smi tag bit to ensure BSR writes to destination register. |
738 __ orq(RAX, Immediate(kSmiTagMask)); | 699 __ orq(RAX, Immediate(kSmiTagMask)); |
739 __ bsrq(RAX, RAX); | 700 __ bsrq(RAX, RAX); |
740 __ SmiTag(RAX); | 701 __ SmiTag(RAX); |
741 __ ret(); | 702 __ ret(); |
742 } | 703 } |
743 | 704 |
744 | |
745 void Intrinsifier::Smi_bitAndFromSmi(Assembler* assembler) { | 705 void Intrinsifier::Smi_bitAndFromSmi(Assembler* assembler) { |
746 Integer_bitAndFromInteger(assembler); | 706 Integer_bitAndFromInteger(assembler); |
747 } | 707 } |
748 | 708 |
749 | |
750 void Intrinsifier::Bigint_lsh(Assembler* assembler) { | 709 void Intrinsifier::Bigint_lsh(Assembler* assembler) { |
751 // static void _lsh(Uint32List x_digits, int x_used, int n, | 710 // static void _lsh(Uint32List x_digits, int x_used, int n, |
752 // Uint32List r_digits) | 711 // Uint32List r_digits) |
753 | 712 |
754 __ movq(RDI, Address(RSP, 4 * kWordSize)); // x_digits | 713 __ movq(RDI, Address(RSP, 4 * kWordSize)); // x_digits |
755 __ movq(R8, Address(RSP, 3 * kWordSize)); // x_used is Smi | 714 __ movq(R8, Address(RSP, 3 * kWordSize)); // x_used is Smi |
756 __ subq(R8, Immediate(2)); // x_used > 0, Smi. R8 = x_used - 1, round up. | 715 __ subq(R8, Immediate(2)); // x_used > 0, Smi. R8 = x_used - 1, round up. |
757 __ sarq(R8, Immediate(2)); // R8 + 1 = number of digit pairs to read. | 716 __ sarq(R8, Immediate(2)); // R8 + 1 = number of digit pairs to read. |
758 __ movq(RCX, Address(RSP, 2 * kWordSize)); // n is Smi | 717 __ movq(RCX, Address(RSP, 2 * kWordSize)); // n is Smi |
759 __ SmiUntag(RCX); | 718 __ SmiUntag(RCX); |
760 __ movq(RBX, Address(RSP, 1 * kWordSize)); // r_digits | 719 __ movq(RBX, Address(RSP, 1 * kWordSize)); // r_digits |
761 __ movq(RSI, RCX); | 720 __ movq(RSI, RCX); |
762 __ sarq(RSI, Immediate(6)); // RSI = n ~/ (2*_DIGIT_BITS). | 721 __ sarq(RSI, Immediate(6)); // RSI = n ~/ (2*_DIGIT_BITS). |
763 __ leaq(RBX, FieldAddress(RBX, RSI, TIMES_8, TypedData::data_offset())); | 722 __ leaq(RBX, FieldAddress(RBX, RSI, TIMES_8, TypedData::data_offset())); |
764 __ xorq(RAX, RAX); // RAX = 0. | 723 __ xorq(RAX, RAX); // RAX = 0. |
765 __ movq(RDX, FieldAddress(RDI, R8, TIMES_8, TypedData::data_offset())); | 724 __ movq(RDX, FieldAddress(RDI, R8, TIMES_8, TypedData::data_offset())); |
766 __ shldq(RAX, RDX, RCX); | 725 __ shldq(RAX, RDX, RCX); |
767 __ movq(Address(RBX, R8, TIMES_8, 2 * Bigint::kBytesPerDigit), RAX); | 726 __ movq(Address(RBX, R8, TIMES_8, 2 * Bigint::kBytesPerDigit), RAX); |
768 Label last; | 727 Label last; |
769 __ cmpq(R8, Immediate(0)); | 728 __ cmpq(R8, Immediate(0)); |
770 __ j(EQUAL, &last, Assembler::kNearJump); | 729 __ j(EQUAL, &last, Assembler::kNearJump); |
771 Label loop; | 730 Label loop; |
772 __ Bind(&loop); | 731 __ Bind(&loop); |
773 __ movq(RAX, RDX); | 732 __ movq(RAX, RDX); |
774 __ movq(RDX, FieldAddress(RDI, R8, TIMES_8, TypedData::data_offset() - | 733 __ movq(RDX, |
775 2 * Bigint::kBytesPerDigit)); | 734 FieldAddress(RDI, R8, TIMES_8, |
| 735 TypedData::data_offset() - 2 * Bigint::kBytesPerDigit)); |
776 __ shldq(RAX, RDX, RCX); | 736 __ shldq(RAX, RDX, RCX); |
777 __ movq(Address(RBX, R8, TIMES_8, 0), RAX); | 737 __ movq(Address(RBX, R8, TIMES_8, 0), RAX); |
778 __ decq(R8); | 738 __ decq(R8); |
779 __ j(NOT_ZERO, &loop, Assembler::kNearJump); | 739 __ j(NOT_ZERO, &loop, Assembler::kNearJump); |
780 __ Bind(&last); | 740 __ Bind(&last); |
781 __ shldq(RDX, R8, RCX); // R8 == 0. | 741 __ shldq(RDX, R8, RCX); // R8 == 0. |
782 __ movq(Address(RBX, 0), RDX); | 742 __ movq(Address(RBX, 0), RDX); |
783 // Returning Object::null() is not required, since this method is private. | 743 // Returning Object::null() is not required, since this method is private. |
784 __ ret(); | 744 __ ret(); |
785 } | 745 } |
786 | 746 |
787 | |
788 void Intrinsifier::Bigint_rsh(Assembler* assembler) { | 747 void Intrinsifier::Bigint_rsh(Assembler* assembler) { |
789 // static void _rsh(Uint32List x_digits, int x_used, int n, | 748 // static void _rsh(Uint32List x_digits, int x_used, int n, |
790 // Uint32List r_digits) | 749 // Uint32List r_digits) |
791 | 750 |
792 __ movq(RDI, Address(RSP, 4 * kWordSize)); // x_digits | 751 __ movq(RDI, Address(RSP, 4 * kWordSize)); // x_digits |
793 __ movq(RCX, Address(RSP, 2 * kWordSize)); // n is Smi | 752 __ movq(RCX, Address(RSP, 2 * kWordSize)); // n is Smi |
794 __ SmiUntag(RCX); | 753 __ SmiUntag(RCX); |
795 __ movq(RBX, Address(RSP, 1 * kWordSize)); // r_digits | 754 __ movq(RBX, Address(RSP, 1 * kWordSize)); // r_digits |
796 __ movq(RDX, RCX); | 755 __ movq(RDX, RCX); |
797 __ sarq(RDX, Immediate(6)); // RDX = n ~/ (2*_DIGIT_BITS). | 756 __ sarq(RDX, Immediate(6)); // RDX = n ~/ (2*_DIGIT_BITS). |
(...skipping 16 matching lines...) Expand all Loading... |
814 __ movq(Address(RBX, RSI, TIMES_8, 0), RAX); | 773 __ movq(Address(RBX, RSI, TIMES_8, 0), RAX); |
815 __ incq(RSI); | 774 __ incq(RSI); |
816 __ j(NOT_ZERO, &loop, Assembler::kNearJump); | 775 __ j(NOT_ZERO, &loop, Assembler::kNearJump); |
817 __ Bind(&last); | 776 __ Bind(&last); |
818 __ shrdq(RDX, RSI, RCX); // RSI == 0. | 777 __ shrdq(RDX, RSI, RCX); // RSI == 0. |
819 __ movq(Address(RBX, 0), RDX); | 778 __ movq(Address(RBX, 0), RDX); |
820 // Returning Object::null() is not required, since this method is private. | 779 // Returning Object::null() is not required, since this method is private. |
821 __ ret(); | 780 __ ret(); |
822 } | 781 } |
823 | 782 |
824 | |
825 void Intrinsifier::Bigint_absAdd(Assembler* assembler) { | 783 void Intrinsifier::Bigint_absAdd(Assembler* assembler) { |
826 // static void _absAdd(Uint32List digits, int used, | 784 // static void _absAdd(Uint32List digits, int used, |
827 // Uint32List a_digits, int a_used, | 785 // Uint32List a_digits, int a_used, |
828 // Uint32List r_digits) | 786 // Uint32List r_digits) |
829 | 787 |
830 __ movq(RDI, Address(RSP, 5 * kWordSize)); // digits | 788 __ movq(RDI, Address(RSP, 5 * kWordSize)); // digits |
831 __ movq(R8, Address(RSP, 4 * kWordSize)); // used is Smi | 789 __ movq(R8, Address(RSP, 4 * kWordSize)); // used is Smi |
832 __ addq(R8, Immediate(2)); // used > 0, Smi. R8 = used + 1, round up. | 790 __ addq(R8, Immediate(2)); // used > 0, Smi. R8 = used + 1, round up. |
833 __ sarq(R8, Immediate(2)); // R8 = number of digit pairs to process. | 791 __ sarq(R8, Immediate(2)); // R8 = number of digit pairs to process. |
834 __ movq(RSI, Address(RSP, 3 * kWordSize)); // a_digits | 792 __ movq(RSI, Address(RSP, 3 * kWordSize)); // a_digits |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
870 Label done; | 828 Label done; |
871 __ j(NOT_CARRY, &done); | 829 __ j(NOT_CARRY, &done); |
872 __ movq(FieldAddress(RBX, RDX, TIMES_8, TypedData::data_offset()), | 830 __ movq(FieldAddress(RBX, RDX, TIMES_8, TypedData::data_offset()), |
873 Immediate(1)); | 831 Immediate(1)); |
874 | 832 |
875 __ Bind(&done); | 833 __ Bind(&done); |
876 // Returning Object::null() is not required, since this method is private. | 834 // Returning Object::null() is not required, since this method is private. |
877 __ ret(); | 835 __ ret(); |
878 } | 836 } |
879 | 837 |
880 | |
881 void Intrinsifier::Bigint_absSub(Assembler* assembler) { | 838 void Intrinsifier::Bigint_absSub(Assembler* assembler) { |
882 // static void _absSub(Uint32List digits, int used, | 839 // static void _absSub(Uint32List digits, int used, |
883 // Uint32List a_digits, int a_used, | 840 // Uint32List a_digits, int a_used, |
884 // Uint32List r_digits) | 841 // Uint32List r_digits) |
885 | 842 |
886 __ movq(RDI, Address(RSP, 5 * kWordSize)); // digits | 843 __ movq(RDI, Address(RSP, 5 * kWordSize)); // digits |
887 __ movq(R8, Address(RSP, 4 * kWordSize)); // used is Smi | 844 __ movq(R8, Address(RSP, 4 * kWordSize)); // used is Smi |
888 __ addq(R8, Immediate(2)); // used > 0, Smi. R8 = used + 1, round up. | 845 __ addq(R8, Immediate(2)); // used > 0, Smi. R8 = used + 1, round up. |
889 __ sarq(R8, Immediate(2)); // R8 = number of digit pairs to process. | 846 __ sarq(R8, Immediate(2)); // R8 = number of digit pairs to process. |
890 __ movq(RSI, Address(RSP, 3 * kWordSize)); // a_digits | 847 __ movq(RSI, Address(RSP, 3 * kWordSize)); // a_digits |
(...skipping 29 matching lines...) Expand all Loading... |
920 __ movq(FieldAddress(RBX, RDX, TIMES_8, TypedData::data_offset()), RAX); | 877 __ movq(FieldAddress(RBX, RDX, TIMES_8, TypedData::data_offset()), RAX); |
921 __ incq(RDX); // Does not affect carry flag. | 878 __ incq(RDX); // Does not affect carry flag. |
922 __ decq(R8); // Does not affect carry flag. | 879 __ decq(R8); // Does not affect carry flag. |
923 __ j(NOT_ZERO, &carry_loop, Assembler::kNearJump); | 880 __ j(NOT_ZERO, &carry_loop, Assembler::kNearJump); |
924 | 881 |
925 __ Bind(&done); | 882 __ Bind(&done); |
926 // Returning Object::null() is not required, since this method is private. | 883 // Returning Object::null() is not required, since this method is private. |
927 __ ret(); | 884 __ ret(); |
928 } | 885 } |
929 | 886 |
930 | |
931 void Intrinsifier::Bigint_mulAdd(Assembler* assembler) { | 887 void Intrinsifier::Bigint_mulAdd(Assembler* assembler) { |
932 // Pseudo code: | 888 // Pseudo code: |
933 // static int _mulAdd(Uint32List x_digits, int xi, | 889 // static int _mulAdd(Uint32List x_digits, int xi, |
934 // Uint32List m_digits, int i, | 890 // Uint32List m_digits, int i, |
935 // Uint32List a_digits, int j, int n) { | 891 // Uint32List a_digits, int j, int n) { |
936 // uint64_t x = x_digits[xi >> 1 .. (xi >> 1) + 1]; // xi is Smi and even. | 892 // uint64_t x = x_digits[xi >> 1 .. (xi >> 1) + 1]; // xi is Smi and even. |
937 // if (x == 0 || n == 0) { | 893 // if (x == 0 || n == 0) { |
938 // return 2; | 894 // return 2; |
939 // } | 895 // } |
940 // uint64_t* mip = &m_digits[i >> 1]; // i is Smi and even. | 896 // uint64_t* mip = &m_digits[i >> 1]; // i is Smi and even. |
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1028 __ Bind(&propagate_carry_loop); | 984 __ Bind(&propagate_carry_loop); |
1029 __ addq(RSI, Immediate(2 * Bigint::kBytesPerDigit)); | 985 __ addq(RSI, Immediate(2 * Bigint::kBytesPerDigit)); |
1030 __ incq(Address(RSI, 0)); // c == 0 or 1 | 986 __ incq(Address(RSI, 0)); // c == 0 or 1 |
1031 __ j(CARRY, &propagate_carry_loop, Assembler::kNearJump); | 987 __ j(CARRY, &propagate_carry_loop, Assembler::kNearJump); |
1032 | 988 |
1033 __ Bind(&done); | 989 __ Bind(&done); |
1034 __ movq(RAX, Immediate(Smi::RawValue(2))); // Two digits processed. | 990 __ movq(RAX, Immediate(Smi::RawValue(2))); // Two digits processed. |
1035 __ ret(); | 991 __ ret(); |
1036 } | 992 } |
1037 | 993 |
1038 | |
1039 void Intrinsifier::Bigint_sqrAdd(Assembler* assembler) { | 994 void Intrinsifier::Bigint_sqrAdd(Assembler* assembler) { |
1040 // Pseudo code: | 995 // Pseudo code: |
1041 // static int _sqrAdd(Uint32List x_digits, int i, | 996 // static int _sqrAdd(Uint32List x_digits, int i, |
1042 // Uint32List a_digits, int used) { | 997 // Uint32List a_digits, int used) { |
1043 // uint64_t* xip = &x_digits[i >> 1]; // i is Smi and even. | 998 // uint64_t* xip = &x_digits[i >> 1]; // i is Smi and even. |
1044 // uint64_t x = *xip++; | 999 // uint64_t x = *xip++; |
1045 // if (x == 0) return 2; | 1000 // if (x == 0) return 2; |
1046 // uint64_t* ajp = &a_digits[i]; // j == 2*i, i is Smi. | 1001 // uint64_t* ajp = &a_digits[i]; // j == 2*i, i is Smi. |
1047 // uint64_t aj = *ajp; | 1002 // uint64_t aj = *ajp; |
1048 // uint128_t t = x*x + aj; | 1003 // uint128_t t = x*x + aj; |
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1148 // *ajp++ = low64(t) | 1103 // *ajp++ = low64(t) |
1149 // *ajp = high64(t) | 1104 // *ajp = high64(t) |
1150 __ movq(Address(RSI, 0), R12); | 1105 __ movq(Address(RSI, 0), R12); |
1151 __ movq(Address(RSI, 2 * Bigint::kBytesPerDigit), R13); | 1106 __ movq(Address(RSI, 2 * Bigint::kBytesPerDigit), R13); |
1152 | 1107 |
1153 __ Bind(&x_zero); | 1108 __ Bind(&x_zero); |
1154 __ movq(RAX, Immediate(Smi::RawValue(2))); // Two digits processed. | 1109 __ movq(RAX, Immediate(Smi::RawValue(2))); // Two digits processed. |
1155 __ ret(); | 1110 __ ret(); |
1156 } | 1111 } |
1157 | 1112 |
1158 | |
1159 void Intrinsifier::Bigint_estQuotientDigit(Assembler* assembler) { | 1113 void Intrinsifier::Bigint_estQuotientDigit(Assembler* assembler) { |
1160 // Pseudo code: | 1114 // Pseudo code: |
1161 // static int _estQuotientDigit(Uint32List args, Uint32List digits, int i) { | 1115 // static int _estQuotientDigit(Uint32List args, Uint32List digits, int i) { |
1162 // uint64_t yt = args[_YT_LO .. _YT]; // _YT_LO == 0, _YT == 1. | 1116 // uint64_t yt = args[_YT_LO .. _YT]; // _YT_LO == 0, _YT == 1. |
1163 // uint64_t* dp = &digits[(i >> 1) - 1]; // i is Smi. | 1117 // uint64_t* dp = &digits[(i >> 1) - 1]; // i is Smi. |
1164 // uint64_t dh = dp[0]; // dh == digits[(i >> 1) - 1 .. i >> 1]. | 1118 // uint64_t dh = dp[0]; // dh == digits[(i >> 1) - 1 .. i >> 1]. |
1165 // uint64_t qd; | 1119 // uint64_t qd; |
1166 // if (dh == yt) { | 1120 // if (dh == yt) { |
1167 // qd = (DIGIT_MASK << 32) | DIGIT_MASK; | 1121 // qd = (DIGIT_MASK << 32) | DIGIT_MASK; |
1168 // } else { | 1122 // } else { |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1205 __ Bind(&return_qd); | 1159 __ Bind(&return_qd); |
1206 // args[2..3] = qd | 1160 // args[2..3] = qd |
1207 __ movq( | 1161 __ movq( |
1208 FieldAddress(RDI, TypedData::data_offset() + 2 * Bigint::kBytesPerDigit), | 1162 FieldAddress(RDI, TypedData::data_offset() + 2 * Bigint::kBytesPerDigit), |
1209 RAX); | 1163 RAX); |
1210 | 1164 |
1211 __ movq(RAX, Immediate(Smi::RawValue(2))); // Two digits processed. | 1165 __ movq(RAX, Immediate(Smi::RawValue(2))); // Two digits processed. |
1212 __ ret(); | 1166 __ ret(); |
1213 } | 1167 } |
1214 | 1168 |
1215 | |
1216 void Intrinsifier::Montgomery_mulMod(Assembler* assembler) { | 1169 void Intrinsifier::Montgomery_mulMod(Assembler* assembler) { |
1217 // Pseudo code: | 1170 // Pseudo code: |
1218 // static int _mulMod(Uint32List args, Uint32List digits, int i) { | 1171 // static int _mulMod(Uint32List args, Uint32List digits, int i) { |
1219 // uint64_t rho = args[_RHO .. _RHO_HI]; // _RHO == 2, _RHO_HI == 3. | 1172 // uint64_t rho = args[_RHO .. _RHO_HI]; // _RHO == 2, _RHO_HI == 3. |
1220 // uint64_t d = digits[i >> 1 .. (i >> 1) + 1]; // i is Smi and even. | 1173 // uint64_t d = digits[i >> 1 .. (i >> 1) + 1]; // i is Smi and even. |
1221 // uint128_t t = rho*d; | 1174 // uint128_t t = rho*d; |
1222 // args[_MU .. _MU_HI] = t mod DIGIT_BASE^2; // _MU == 4, _MU_HI == 5. | 1175 // args[_MU .. _MU_HI] = t mod DIGIT_BASE^2; // _MU == 4, _MU_HI == 5. |
1223 // return 2; | 1176 // return 2; |
1224 // } | 1177 // } |
1225 | 1178 |
(...skipping 14 matching lines...) Expand all Loading... |
1240 | 1193 |
1241 // args[4 .. 5] = t mod DIGIT_BASE^2 = low64(t) | 1194 // args[4 .. 5] = t mod DIGIT_BASE^2 = low64(t) |
1242 __ movq( | 1195 __ movq( |
1243 FieldAddress(RDI, TypedData::data_offset() + 4 * Bigint::kBytesPerDigit), | 1196 FieldAddress(RDI, TypedData::data_offset() + 4 * Bigint::kBytesPerDigit), |
1244 RAX); | 1197 RAX); |
1245 | 1198 |
1246 __ movq(RAX, Immediate(Smi::RawValue(2))); // Two digits processed. | 1199 __ movq(RAX, Immediate(Smi::RawValue(2))); // Two digits processed. |
1247 __ ret(); | 1200 __ ret(); |
1248 } | 1201 } |
1249 | 1202 |
1250 | |
1251 // Check if the last argument is a double, jump to label 'is_smi' if smi | 1203 // Check if the last argument is a double, jump to label 'is_smi' if smi |
1252 // (easy to convert to double), otherwise jump to label 'not_double_smi', | 1204 // (easy to convert to double), otherwise jump to label 'not_double_smi', |
1253 // Returns the last argument in RAX. | 1205 // Returns the last argument in RAX. |
1254 static void TestLastArgumentIsDouble(Assembler* assembler, | 1206 static void TestLastArgumentIsDouble(Assembler* assembler, |
1255 Label* is_smi, | 1207 Label* is_smi, |
1256 Label* not_double_smi) { | 1208 Label* not_double_smi) { |
1257 __ movq(RAX, Address(RSP, +1 * kWordSize)); | 1209 __ movq(RAX, Address(RSP, +1 * kWordSize)); |
1258 __ testq(RAX, Immediate(kSmiTagMask)); | 1210 __ testq(RAX, Immediate(kSmiTagMask)); |
1259 __ j(ZERO, is_smi); // Jump if Smi. | 1211 __ j(ZERO, is_smi); // Jump if Smi. |
1260 __ CompareClassId(RAX, kDoubleCid); | 1212 __ CompareClassId(RAX, kDoubleCid); |
1261 __ j(NOT_EQUAL, not_double_smi); | 1213 __ j(NOT_EQUAL, not_double_smi); |
1262 // Fall through if double. | 1214 // Fall through if double. |
1263 } | 1215 } |
1264 | 1216 |
1265 | |
1266 // Both arguments on stack, left argument is a double, right argument is of | 1217 // Both arguments on stack, left argument is a double, right argument is of |
1267 // unknown type. Return true or false object in RAX. Any NaN argument | 1218 // unknown type. Return true or false object in RAX. Any NaN argument |
1268 // returns false. Any non-double argument causes control flow to fall through | 1219 // returns false. Any non-double argument causes control flow to fall through |
1269 // to the slow case (compiled method body). | 1220 // to the slow case (compiled method body). |
1270 static void CompareDoubles(Assembler* assembler, Condition true_condition) { | 1221 static void CompareDoubles(Assembler* assembler, Condition true_condition) { |
1271 Label fall_through, is_false, is_true, is_smi, double_op; | 1222 Label fall_through, is_false, is_true, is_smi, double_op; |
1272 TestLastArgumentIsDouble(assembler, &is_smi, &fall_through); | 1223 TestLastArgumentIsDouble(assembler, &is_smi, &fall_through); |
1273 // Both arguments are double, right operand is in RAX. | 1224 // Both arguments are double, right operand is in RAX. |
1274 __ movsd(XMM1, FieldAddress(RAX, Double::value_offset())); | 1225 __ movsd(XMM1, FieldAddress(RAX, Double::value_offset())); |
1275 __ Bind(&double_op); | 1226 __ Bind(&double_op); |
1276 __ movq(RAX, Address(RSP, +2 * kWordSize)); // Left argument. | 1227 __ movq(RAX, Address(RSP, +2 * kWordSize)); // Left argument. |
1277 __ movsd(XMM0, FieldAddress(RAX, Double::value_offset())); | 1228 __ movsd(XMM0, FieldAddress(RAX, Double::value_offset())); |
1278 __ comisd(XMM0, XMM1); | 1229 __ comisd(XMM0, XMM1); |
1279 __ j(PARITY_EVEN, &is_false, Assembler::kNearJump); // NaN -> false; | 1230 __ j(PARITY_EVEN, &is_false, Assembler::kNearJump); // NaN -> false; |
1280 __ j(true_condition, &is_true, Assembler::kNearJump); | 1231 __ j(true_condition, &is_true, Assembler::kNearJump); |
1281 // Fall through false. | 1232 // Fall through false. |
1282 __ Bind(&is_false); | 1233 __ Bind(&is_false); |
1283 __ LoadObject(RAX, Bool::False()); | 1234 __ LoadObject(RAX, Bool::False()); |
1284 __ ret(); | 1235 __ ret(); |
1285 __ Bind(&is_true); | 1236 __ Bind(&is_true); |
1286 __ LoadObject(RAX, Bool::True()); | 1237 __ LoadObject(RAX, Bool::True()); |
1287 __ ret(); | 1238 __ ret(); |
1288 __ Bind(&is_smi); | 1239 __ Bind(&is_smi); |
1289 __ SmiUntag(RAX); | 1240 __ SmiUntag(RAX); |
1290 __ cvtsi2sdq(XMM1, RAX); | 1241 __ cvtsi2sdq(XMM1, RAX); |
1291 __ jmp(&double_op); | 1242 __ jmp(&double_op); |
1292 __ Bind(&fall_through); | 1243 __ Bind(&fall_through); |
1293 } | 1244 } |
1294 | 1245 |
1295 | |
1296 void Intrinsifier::Double_greaterThan(Assembler* assembler) { | 1246 void Intrinsifier::Double_greaterThan(Assembler* assembler) { |
1297 CompareDoubles(assembler, ABOVE); | 1247 CompareDoubles(assembler, ABOVE); |
1298 } | 1248 } |
1299 | 1249 |
1300 | |
1301 void Intrinsifier::Double_greaterEqualThan(Assembler* assembler) { | 1250 void Intrinsifier::Double_greaterEqualThan(Assembler* assembler) { |
1302 CompareDoubles(assembler, ABOVE_EQUAL); | 1251 CompareDoubles(assembler, ABOVE_EQUAL); |
1303 } | 1252 } |
1304 | 1253 |
1305 | |
1306 void Intrinsifier::Double_lessThan(Assembler* assembler) { | 1254 void Intrinsifier::Double_lessThan(Assembler* assembler) { |
1307 CompareDoubles(assembler, BELOW); | 1255 CompareDoubles(assembler, BELOW); |
1308 } | 1256 } |
1309 | 1257 |
1310 | |
1311 void Intrinsifier::Double_equal(Assembler* assembler) { | 1258 void Intrinsifier::Double_equal(Assembler* assembler) { |
1312 CompareDoubles(assembler, EQUAL); | 1259 CompareDoubles(assembler, EQUAL); |
1313 } | 1260 } |
1314 | 1261 |
1315 | |
1316 void Intrinsifier::Double_lessEqualThan(Assembler* assembler) { | 1262 void Intrinsifier::Double_lessEqualThan(Assembler* assembler) { |
1317 CompareDoubles(assembler, BELOW_EQUAL); | 1263 CompareDoubles(assembler, BELOW_EQUAL); |
1318 } | 1264 } |
1319 | 1265 |
1320 | |
1321 // Expects left argument to be double (receiver). Right argument is unknown. | 1266 // Expects left argument to be double (receiver). Right argument is unknown. |
1322 // Both arguments are on stack. | 1267 // Both arguments are on stack. |
1323 static void DoubleArithmeticOperations(Assembler* assembler, Token::Kind kind) { | 1268 static void DoubleArithmeticOperations(Assembler* assembler, Token::Kind kind) { |
1324 Label fall_through, is_smi, double_op; | 1269 Label fall_through, is_smi, double_op; |
1325 TestLastArgumentIsDouble(assembler, &is_smi, &fall_through); | 1270 TestLastArgumentIsDouble(assembler, &is_smi, &fall_through); |
1326 // Both arguments are double, right operand is in RAX. | 1271 // Both arguments are double, right operand is in RAX. |
1327 __ movsd(XMM1, FieldAddress(RAX, Double::value_offset())); | 1272 __ movsd(XMM1, FieldAddress(RAX, Double::value_offset())); |
1328 __ Bind(&double_op); | 1273 __ Bind(&double_op); |
1329 __ movq(RAX, Address(RSP, +2 * kWordSize)); // Left argument. | 1274 __ movq(RAX, Address(RSP, +2 * kWordSize)); // Left argument. |
1330 __ movsd(XMM0, FieldAddress(RAX, Double::value_offset())); | 1275 __ movsd(XMM0, FieldAddress(RAX, Double::value_offset())); |
(...skipping 20 matching lines...) Expand all Loading... |
1351 R13); | 1296 R13); |
1352 __ movsd(FieldAddress(RAX, Double::value_offset()), XMM0); | 1297 __ movsd(FieldAddress(RAX, Double::value_offset()), XMM0); |
1353 __ ret(); | 1298 __ ret(); |
1354 __ Bind(&is_smi); | 1299 __ Bind(&is_smi); |
1355 __ SmiUntag(RAX); | 1300 __ SmiUntag(RAX); |
1356 __ cvtsi2sdq(XMM1, RAX); | 1301 __ cvtsi2sdq(XMM1, RAX); |
1357 __ jmp(&double_op); | 1302 __ jmp(&double_op); |
1358 __ Bind(&fall_through); | 1303 __ Bind(&fall_through); |
1359 } | 1304 } |
1360 | 1305 |
1361 | |
1362 void Intrinsifier::Double_add(Assembler* assembler) { | 1306 void Intrinsifier::Double_add(Assembler* assembler) { |
1363 DoubleArithmeticOperations(assembler, Token::kADD); | 1307 DoubleArithmeticOperations(assembler, Token::kADD); |
1364 } | 1308 } |
1365 | 1309 |
1366 | |
1367 void Intrinsifier::Double_mul(Assembler* assembler) { | 1310 void Intrinsifier::Double_mul(Assembler* assembler) { |
1368 DoubleArithmeticOperations(assembler, Token::kMUL); | 1311 DoubleArithmeticOperations(assembler, Token::kMUL); |
1369 } | 1312 } |
1370 | 1313 |
1371 | |
1372 void Intrinsifier::Double_sub(Assembler* assembler) { | 1314 void Intrinsifier::Double_sub(Assembler* assembler) { |
1373 DoubleArithmeticOperations(assembler, Token::kSUB); | 1315 DoubleArithmeticOperations(assembler, Token::kSUB); |
1374 } | 1316 } |
1375 | 1317 |
1376 | |
1377 void Intrinsifier::Double_div(Assembler* assembler) { | 1318 void Intrinsifier::Double_div(Assembler* assembler) { |
1378 DoubleArithmeticOperations(assembler, Token::kDIV); | 1319 DoubleArithmeticOperations(assembler, Token::kDIV); |
1379 } | 1320 } |
1380 | 1321 |
1381 | |
1382 void Intrinsifier::Double_mulFromInteger(Assembler* assembler) { | 1322 void Intrinsifier::Double_mulFromInteger(Assembler* assembler) { |
1383 Label fall_through; | 1323 Label fall_through; |
1384 // Only smis allowed. | 1324 // Only smis allowed. |
1385 __ movq(RAX, Address(RSP, +1 * kWordSize)); | 1325 __ movq(RAX, Address(RSP, +1 * kWordSize)); |
1386 __ testq(RAX, Immediate(kSmiTagMask)); | 1326 __ testq(RAX, Immediate(kSmiTagMask)); |
1387 __ j(NOT_ZERO, &fall_through); | 1327 __ j(NOT_ZERO, &fall_through); |
1388 // Is Smi. | 1328 // Is Smi. |
1389 __ SmiUntag(RAX); | 1329 __ SmiUntag(RAX); |
1390 __ cvtsi2sdq(XMM1, RAX); | 1330 __ cvtsi2sdq(XMM1, RAX); |
1391 __ movq(RAX, Address(RSP, +2 * kWordSize)); | 1331 __ movq(RAX, Address(RSP, +2 * kWordSize)); |
1392 __ movsd(XMM0, FieldAddress(RAX, Double::value_offset())); | 1332 __ movsd(XMM0, FieldAddress(RAX, Double::value_offset())); |
1393 __ mulsd(XMM0, XMM1); | 1333 __ mulsd(XMM0, XMM1); |
1394 const Class& double_class = | 1334 const Class& double_class = |
1395 Class::Handle(Isolate::Current()->object_store()->double_class()); | 1335 Class::Handle(Isolate::Current()->object_store()->double_class()); |
1396 __ TryAllocate(double_class, &fall_through, Assembler::kFarJump, | 1336 __ TryAllocate(double_class, &fall_through, Assembler::kFarJump, |
1397 RAX, // Result register. | 1337 RAX, // Result register. |
1398 R13); | 1338 R13); |
1399 __ movsd(FieldAddress(RAX, Double::value_offset()), XMM0); | 1339 __ movsd(FieldAddress(RAX, Double::value_offset()), XMM0); |
1400 __ ret(); | 1340 __ ret(); |
1401 __ Bind(&fall_through); | 1341 __ Bind(&fall_through); |
1402 } | 1342 } |
1403 | 1343 |
1404 | |
1405 // Left is double right is integer (Bigint, Mint or Smi) | 1344 // Left is double right is integer (Bigint, Mint or Smi) |
1406 void Intrinsifier::DoubleFromInteger(Assembler* assembler) { | 1345 void Intrinsifier::DoubleFromInteger(Assembler* assembler) { |
1407 Label fall_through; | 1346 Label fall_through; |
1408 __ movq(RAX, Address(RSP, +1 * kWordSize)); | 1347 __ movq(RAX, Address(RSP, +1 * kWordSize)); |
1409 __ testq(RAX, Immediate(kSmiTagMask)); | 1348 __ testq(RAX, Immediate(kSmiTagMask)); |
1410 __ j(NOT_ZERO, &fall_through); | 1349 __ j(NOT_ZERO, &fall_through); |
1411 // Is Smi. | 1350 // Is Smi. |
1412 __ SmiUntag(RAX); | 1351 __ SmiUntag(RAX); |
1413 __ cvtsi2sdq(XMM0, RAX); | 1352 __ cvtsi2sdq(XMM0, RAX); |
1414 const Class& double_class = | 1353 const Class& double_class = |
1415 Class::Handle(Isolate::Current()->object_store()->double_class()); | 1354 Class::Handle(Isolate::Current()->object_store()->double_class()); |
1416 __ TryAllocate(double_class, &fall_through, Assembler::kFarJump, | 1355 __ TryAllocate(double_class, &fall_through, Assembler::kFarJump, |
1417 RAX, // Result register. | 1356 RAX, // Result register. |
1418 R13); | 1357 R13); |
1419 __ movsd(FieldAddress(RAX, Double::value_offset()), XMM0); | 1358 __ movsd(FieldAddress(RAX, Double::value_offset()), XMM0); |
1420 __ ret(); | 1359 __ ret(); |
1421 __ Bind(&fall_through); | 1360 __ Bind(&fall_through); |
1422 } | 1361 } |
1423 | 1362 |
1424 | |
1425 void Intrinsifier::Double_getIsNaN(Assembler* assembler) { | 1363 void Intrinsifier::Double_getIsNaN(Assembler* assembler) { |
1426 Label is_true; | 1364 Label is_true; |
1427 __ movq(RAX, Address(RSP, +1 * kWordSize)); | 1365 __ movq(RAX, Address(RSP, +1 * kWordSize)); |
1428 __ movsd(XMM0, FieldAddress(RAX, Double::value_offset())); | 1366 __ movsd(XMM0, FieldAddress(RAX, Double::value_offset())); |
1429 __ comisd(XMM0, XMM0); | 1367 __ comisd(XMM0, XMM0); |
1430 __ j(PARITY_EVEN, &is_true, Assembler::kNearJump); // NaN -> true; | 1368 __ j(PARITY_EVEN, &is_true, Assembler::kNearJump); // NaN -> true; |
1431 __ LoadObject(RAX, Bool::False()); | 1369 __ LoadObject(RAX, Bool::False()); |
1432 __ ret(); | 1370 __ ret(); |
1433 __ Bind(&is_true); | 1371 __ Bind(&is_true); |
1434 __ LoadObject(RAX, Bool::True()); | 1372 __ LoadObject(RAX, Bool::True()); |
1435 __ ret(); | 1373 __ ret(); |
1436 } | 1374 } |
1437 | 1375 |
1438 | |
1439 void Intrinsifier::Double_getIsInfinite(Assembler* assembler) { | 1376 void Intrinsifier::Double_getIsInfinite(Assembler* assembler) { |
1440 Label is_inf, done; | 1377 Label is_inf, done; |
1441 __ movq(RAX, Address(RSP, +1 * kWordSize)); | 1378 __ movq(RAX, Address(RSP, +1 * kWordSize)); |
1442 __ movq(RAX, FieldAddress(RAX, Double::value_offset())); | 1379 __ movq(RAX, FieldAddress(RAX, Double::value_offset())); |
1443 // Mask off the sign. | 1380 // Mask off the sign. |
1444 __ AndImmediate(RAX, Immediate(0x7FFFFFFFFFFFFFFFLL)); | 1381 __ AndImmediate(RAX, Immediate(0x7FFFFFFFFFFFFFFFLL)); |
1445 // Compare with +infinity. | 1382 // Compare with +infinity. |
1446 __ CompareImmediate(RAX, Immediate(0x7FF0000000000000LL)); | 1383 __ CompareImmediate(RAX, Immediate(0x7FF0000000000000LL)); |
1447 __ j(EQUAL, &is_inf, Assembler::kNearJump); | 1384 __ j(EQUAL, &is_inf, Assembler::kNearJump); |
1448 __ LoadObject(RAX, Bool::False()); | 1385 __ LoadObject(RAX, Bool::False()); |
1449 __ jmp(&done); | 1386 __ jmp(&done); |
1450 | 1387 |
1451 __ Bind(&is_inf); | 1388 __ Bind(&is_inf); |
1452 __ LoadObject(RAX, Bool::True()); | 1389 __ LoadObject(RAX, Bool::True()); |
1453 | 1390 |
1454 __ Bind(&done); | 1391 __ Bind(&done); |
1455 __ ret(); | 1392 __ ret(); |
1456 } | 1393 } |
1457 | 1394 |
1458 | |
1459 void Intrinsifier::Double_getIsNegative(Assembler* assembler) { | 1395 void Intrinsifier::Double_getIsNegative(Assembler* assembler) { |
1460 Label is_false, is_true, is_zero; | 1396 Label is_false, is_true, is_zero; |
1461 __ movq(RAX, Address(RSP, +1 * kWordSize)); | 1397 __ movq(RAX, Address(RSP, +1 * kWordSize)); |
1462 __ movsd(XMM0, FieldAddress(RAX, Double::value_offset())); | 1398 __ movsd(XMM0, FieldAddress(RAX, Double::value_offset())); |
1463 __ xorpd(XMM1, XMM1); // 0.0 -> XMM1. | 1399 __ xorpd(XMM1, XMM1); // 0.0 -> XMM1. |
1464 __ comisd(XMM0, XMM1); | 1400 __ comisd(XMM0, XMM1); |
1465 __ j(PARITY_EVEN, &is_false, Assembler::kNearJump); // NaN -> false. | 1401 __ j(PARITY_EVEN, &is_false, Assembler::kNearJump); // NaN -> false. |
1466 __ j(EQUAL, &is_zero, Assembler::kNearJump); // Check for negative zero. | 1402 __ j(EQUAL, &is_zero, Assembler::kNearJump); // Check for negative zero. |
1467 __ j(ABOVE_EQUAL, &is_false, Assembler::kNearJump); // >= 0 -> false. | 1403 __ j(ABOVE_EQUAL, &is_false, Assembler::kNearJump); // >= 0 -> false. |
1468 __ Bind(&is_true); | 1404 __ Bind(&is_true); |
1469 __ LoadObject(RAX, Bool::True()); | 1405 __ LoadObject(RAX, Bool::True()); |
1470 __ ret(); | 1406 __ ret(); |
1471 __ Bind(&is_false); | 1407 __ Bind(&is_false); |
1472 __ LoadObject(RAX, Bool::False()); | 1408 __ LoadObject(RAX, Bool::False()); |
1473 __ ret(); | 1409 __ ret(); |
1474 __ Bind(&is_zero); | 1410 __ Bind(&is_zero); |
1475 // Check for negative zero (get the sign bit). | 1411 // Check for negative zero (get the sign bit). |
1476 __ movmskpd(RAX, XMM0); | 1412 __ movmskpd(RAX, XMM0); |
1477 __ testq(RAX, Immediate(1)); | 1413 __ testq(RAX, Immediate(1)); |
1478 __ j(NOT_ZERO, &is_true, Assembler::kNearJump); | 1414 __ j(NOT_ZERO, &is_true, Assembler::kNearJump); |
1479 __ jmp(&is_false, Assembler::kNearJump); | 1415 __ jmp(&is_false, Assembler::kNearJump); |
1480 } | 1416 } |
1481 | 1417 |
1482 | |
1483 void Intrinsifier::DoubleToInteger(Assembler* assembler) { | 1418 void Intrinsifier::DoubleToInteger(Assembler* assembler) { |
1484 __ movq(RAX, Address(RSP, +1 * kWordSize)); | 1419 __ movq(RAX, Address(RSP, +1 * kWordSize)); |
1485 __ movsd(XMM0, FieldAddress(RAX, Double::value_offset())); | 1420 __ movsd(XMM0, FieldAddress(RAX, Double::value_offset())); |
1486 __ cvttsd2siq(RAX, XMM0); | 1421 __ cvttsd2siq(RAX, XMM0); |
1487 // Overflow is signalled with minint. | 1422 // Overflow is signalled with minint. |
1488 Label fall_through; | 1423 Label fall_through; |
1489 // Check for overflow and that it fits into Smi. | 1424 // Check for overflow and that it fits into Smi. |
1490 __ movq(RCX, RAX); | 1425 __ movq(RCX, RAX); |
1491 __ shlq(RCX, Immediate(1)); | 1426 __ shlq(RCX, Immediate(1)); |
1492 __ j(OVERFLOW, &fall_through, Assembler::kNearJump); | 1427 __ j(OVERFLOW, &fall_through, Assembler::kNearJump); |
1493 __ SmiTag(RAX); | 1428 __ SmiTag(RAX); |
1494 __ ret(); | 1429 __ ret(); |
1495 __ Bind(&fall_through); | 1430 __ Bind(&fall_through); |
1496 } | 1431 } |
1497 | 1432 |
1498 | |
1499 void Intrinsifier::MathSqrt(Assembler* assembler) { | 1433 void Intrinsifier::MathSqrt(Assembler* assembler) { |
1500 Label fall_through, is_smi, double_op; | 1434 Label fall_through, is_smi, double_op; |
1501 TestLastArgumentIsDouble(assembler, &is_smi, &fall_through); | 1435 TestLastArgumentIsDouble(assembler, &is_smi, &fall_through); |
1502 // Argument is double and is in RAX. | 1436 // Argument is double and is in RAX. |
1503 __ movsd(XMM1, FieldAddress(RAX, Double::value_offset())); | 1437 __ movsd(XMM1, FieldAddress(RAX, Double::value_offset())); |
1504 __ Bind(&double_op); | 1438 __ Bind(&double_op); |
1505 __ sqrtsd(XMM0, XMM1); | 1439 __ sqrtsd(XMM0, XMM1); |
1506 const Class& double_class = | 1440 const Class& double_class = |
1507 Class::Handle(Isolate::Current()->object_store()->double_class()); | 1441 Class::Handle(Isolate::Current()->object_store()->double_class()); |
1508 __ TryAllocate(double_class, &fall_through, Assembler::kFarJump, | 1442 __ TryAllocate(double_class, &fall_through, Assembler::kFarJump, |
1509 RAX, // Result register. | 1443 RAX, // Result register. |
1510 R13); | 1444 R13); |
1511 __ movsd(FieldAddress(RAX, Double::value_offset()), XMM0); | 1445 __ movsd(FieldAddress(RAX, Double::value_offset()), XMM0); |
1512 __ ret(); | 1446 __ ret(); |
1513 __ Bind(&is_smi); | 1447 __ Bind(&is_smi); |
1514 __ SmiUntag(RAX); | 1448 __ SmiUntag(RAX); |
1515 __ cvtsi2sdq(XMM1, RAX); | 1449 __ cvtsi2sdq(XMM1, RAX); |
1516 __ jmp(&double_op); | 1450 __ jmp(&double_op); |
1517 __ Bind(&fall_through); | 1451 __ Bind(&fall_through); |
1518 } | 1452 } |
1519 | 1453 |
1520 | |
1521 // var state = ((_A * (_state[kSTATE_LO])) + _state[kSTATE_HI]) & _MASK_64; | 1454 // var state = ((_A * (_state[kSTATE_LO])) + _state[kSTATE_HI]) & _MASK_64; |
1522 // _state[kSTATE_LO] = state & _MASK_32; | 1455 // _state[kSTATE_LO] = state & _MASK_32; |
1523 // _state[kSTATE_HI] = state >> 32; | 1456 // _state[kSTATE_HI] = state >> 32; |
1524 void Intrinsifier::Random_nextState(Assembler* assembler) { | 1457 void Intrinsifier::Random_nextState(Assembler* assembler) { |
1525 const Library& math_lib = Library::Handle(Library::MathLibrary()); | 1458 const Library& math_lib = Library::Handle(Library::MathLibrary()); |
1526 ASSERT(!math_lib.IsNull()); | 1459 ASSERT(!math_lib.IsNull()); |
1527 const Class& random_class = | 1460 const Class& random_class = |
1528 Class::Handle(math_lib.LookupClassAllowPrivate(Symbols::_Random())); | 1461 Class::Handle(math_lib.LookupClassAllowPrivate(Symbols::_Random())); |
1529 ASSERT(!random_class.IsNull()); | 1462 ASSERT(!random_class.IsNull()); |
1530 const Field& state_field = Field::ZoneHandle( | 1463 const Field& state_field = Field::ZoneHandle( |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1570 __ movq(RAX, Address(RSP, +kArgumentOffset * kWordSize)); | 1503 __ movq(RAX, Address(RSP, +kArgumentOffset * kWordSize)); |
1571 __ cmpq(RAX, Address(RSP, +kReceiverOffset * kWordSize)); | 1504 __ cmpq(RAX, Address(RSP, +kReceiverOffset * kWordSize)); |
1572 __ j(EQUAL, &is_true, Assembler::kNearJump); | 1505 __ j(EQUAL, &is_true, Assembler::kNearJump); |
1573 __ LoadObject(RAX, Bool::False()); | 1506 __ LoadObject(RAX, Bool::False()); |
1574 __ ret(); | 1507 __ ret(); |
1575 __ Bind(&is_true); | 1508 __ Bind(&is_true); |
1576 __ LoadObject(RAX, Bool::True()); | 1509 __ LoadObject(RAX, Bool::True()); |
1577 __ ret(); | 1510 __ ret(); |
1578 } | 1511 } |
1579 | 1512 |
1580 | |
1581 static void RangeCheck(Assembler* assembler, | 1513 static void RangeCheck(Assembler* assembler, |
1582 Register reg, | 1514 Register reg, |
1583 intptr_t low, | 1515 intptr_t low, |
1584 intptr_t high, | 1516 intptr_t high, |
1585 Condition cc, | 1517 Condition cc, |
1586 Label* target) { | 1518 Label* target) { |
1587 __ subq(reg, Immediate(low)); | 1519 __ subq(reg, Immediate(low)); |
1588 __ cmpq(reg, Immediate(high - low)); | 1520 __ cmpq(reg, Immediate(high - low)); |
1589 __ j(cc, target); | 1521 __ j(cc, target); |
1590 } | 1522 } |
1591 | 1523 |
1592 | |
1593 const Condition kIfNotInRange = ABOVE; | 1524 const Condition kIfNotInRange = ABOVE; |
1594 const Condition kIfInRange = BELOW_EQUAL; | 1525 const Condition kIfInRange = BELOW_EQUAL; |
1595 | 1526 |
1596 | |
1597 static void JumpIfInteger(Assembler* assembler, Register cid, Label* target) { | 1527 static void JumpIfInteger(Assembler* assembler, Register cid, Label* target) { |
1598 RangeCheck(assembler, cid, kSmiCid, kBigintCid, kIfInRange, target); | 1528 RangeCheck(assembler, cid, kSmiCid, kBigintCid, kIfInRange, target); |
1599 } | 1529 } |
1600 | 1530 |
1601 | |
1602 static void JumpIfNotInteger(Assembler* assembler, | 1531 static void JumpIfNotInteger(Assembler* assembler, |
1603 Register cid, | 1532 Register cid, |
1604 Label* target) { | 1533 Label* target) { |
1605 RangeCheck(assembler, cid, kSmiCid, kBigintCid, kIfNotInRange, target); | 1534 RangeCheck(assembler, cid, kSmiCid, kBigintCid, kIfNotInRange, target); |
1606 } | 1535 } |
1607 | 1536 |
1608 | |
1609 static void JumpIfString(Assembler* assembler, Register cid, Label* target) { | 1537 static void JumpIfString(Assembler* assembler, Register cid, Label* target) { |
1610 RangeCheck(assembler, cid, kOneByteStringCid, kExternalTwoByteStringCid, | 1538 RangeCheck(assembler, cid, kOneByteStringCid, kExternalTwoByteStringCid, |
1611 kIfInRange, target); | 1539 kIfInRange, target); |
1612 } | 1540 } |
1613 | 1541 |
1614 | |
1615 static void JumpIfNotString(Assembler* assembler, Register cid, Label* target) { | 1542 static void JumpIfNotString(Assembler* assembler, Register cid, Label* target) { |
1616 RangeCheck(assembler, cid, kOneByteStringCid, kExternalTwoByteStringCid, | 1543 RangeCheck(assembler, cid, kOneByteStringCid, kExternalTwoByteStringCid, |
1617 kIfNotInRange, target); | 1544 kIfNotInRange, target); |
1618 } | 1545 } |
1619 | 1546 |
1620 | |
1621 // Return type quickly for simple types (not parameterized and not signature). | 1547 // Return type quickly for simple types (not parameterized and not signature). |
1622 void Intrinsifier::ObjectRuntimeType(Assembler* assembler) { | 1548 void Intrinsifier::ObjectRuntimeType(Assembler* assembler) { |
1623 Label fall_through, use_canonical_type, not_integer, not_double; | 1549 Label fall_through, use_canonical_type, not_integer, not_double; |
1624 __ movq(RAX, Address(RSP, +1 * kWordSize)); | 1550 __ movq(RAX, Address(RSP, +1 * kWordSize)); |
1625 __ LoadClassIdMayBeSmi(RCX, RAX); | 1551 __ LoadClassIdMayBeSmi(RCX, RAX); |
1626 | 1552 |
1627 // RCX: untagged cid of instance (RAX). | 1553 // RCX: untagged cid of instance (RAX). |
1628 __ cmpq(RCX, Immediate(kClosureCid)); | 1554 __ cmpq(RCX, Immediate(kClosureCid)); |
1629 __ j(EQUAL, &fall_through); // Instance is a closure. | 1555 __ j(EQUAL, &fall_through); // Instance is a closure. |
1630 | 1556 |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1668 __ cmpq(RCX, Immediate(0)); | 1594 __ cmpq(RCX, Immediate(0)); |
1669 __ j(NOT_EQUAL, &fall_through, Assembler::kNearJump); | 1595 __ j(NOT_EQUAL, &fall_through, Assembler::kNearJump); |
1670 __ movq(RAX, FieldAddress(RDI, Class::canonical_type_offset())); | 1596 __ movq(RAX, FieldAddress(RDI, Class::canonical_type_offset())); |
1671 __ CompareObject(RAX, Object::null_object()); | 1597 __ CompareObject(RAX, Object::null_object()); |
1672 __ j(EQUAL, &fall_through, Assembler::kNearJump); // Not yet set. | 1598 __ j(EQUAL, &fall_through, Assembler::kNearJump); // Not yet set. |
1673 __ ret(); | 1599 __ ret(); |
1674 | 1600 |
1675 __ Bind(&fall_through); | 1601 __ Bind(&fall_through); |
1676 } | 1602 } |
1677 | 1603 |
1678 | |
1679 void Intrinsifier::ObjectHaveSameRuntimeType(Assembler* assembler) { | 1604 void Intrinsifier::ObjectHaveSameRuntimeType(Assembler* assembler) { |
1680 Label fall_through, different_cids, equal, not_equal, not_integer; | 1605 Label fall_through, different_cids, equal, not_equal, not_integer; |
1681 | 1606 |
1682 __ movq(RAX, Address(RSP, +1 * kWordSize)); | 1607 __ movq(RAX, Address(RSP, +1 * kWordSize)); |
1683 __ LoadClassIdMayBeSmi(RCX, RAX); | 1608 __ LoadClassIdMayBeSmi(RCX, RAX); |
1684 | 1609 |
1685 // Check if left hand size is a closure. Closures are handled in the runtime. | 1610 // Check if left hand size is a closure. Closures are handled in the runtime. |
1686 __ cmpq(RCX, Immediate(kClosureCid)); | 1611 __ cmpq(RCX, Immediate(kClosureCid)); |
1687 __ j(EQUAL, &fall_through); | 1612 __ j(EQUAL, &fall_through); |
1688 | 1613 |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1732 // Strings only have the same runtime type as other strings. | 1657 // Strings only have the same runtime type as other strings. |
1733 // Fall-through to the not equal case. | 1658 // Fall-through to the not equal case. |
1734 | 1659 |
1735 __ Bind(¬_equal); | 1660 __ Bind(¬_equal); |
1736 __ LoadObject(RAX, Bool::False()); | 1661 __ LoadObject(RAX, Bool::False()); |
1737 __ ret(); | 1662 __ ret(); |
1738 | 1663 |
1739 __ Bind(&fall_through); | 1664 __ Bind(&fall_through); |
1740 } | 1665 } |
1741 | 1666 |
1742 | |
1743 void Intrinsifier::String_getHashCode(Assembler* assembler) { | 1667 void Intrinsifier::String_getHashCode(Assembler* assembler) { |
1744 Label fall_through; | 1668 Label fall_through; |
1745 __ movq(RAX, Address(RSP, +1 * kWordSize)); // String object. | 1669 __ movq(RAX, Address(RSP, +1 * kWordSize)); // String object. |
1746 __ movl(RAX, FieldAddress(RAX, String::hash_offset())); | 1670 __ movl(RAX, FieldAddress(RAX, String::hash_offset())); |
1747 ASSERT(kSmiTag == 0); | 1671 ASSERT(kSmiTag == 0); |
1748 ASSERT(kSmiTagShift == 1); | 1672 ASSERT(kSmiTagShift == 1); |
1749 __ addq(RAX, RAX); // Smi tag RAX, setting Z flag. | 1673 __ addq(RAX, RAX); // Smi tag RAX, setting Z flag. |
1750 __ j(ZERO, &fall_through, Assembler::kNearJump); | 1674 __ j(ZERO, &fall_through, Assembler::kNearJump); |
1751 __ ret(); | 1675 __ ret(); |
1752 __ Bind(&fall_through); | 1676 __ Bind(&fall_through); |
1753 // Hash not yet computed. | 1677 // Hash not yet computed. |
1754 } | 1678 } |
1755 | 1679 |
1756 | |
1757 void Intrinsifier::Object_getHash(Assembler* assembler) { | 1680 void Intrinsifier::Object_getHash(Assembler* assembler) { |
1758 __ movq(RAX, Address(RSP, +1 * kWordSize)); // Object. | 1681 __ movq(RAX, Address(RSP, +1 * kWordSize)); // Object. |
1759 __ movl(RAX, FieldAddress(RAX, String::hash_offset())); | 1682 __ movl(RAX, FieldAddress(RAX, String::hash_offset())); |
1760 __ SmiTag(RAX); | 1683 __ SmiTag(RAX); |
1761 __ ret(); | 1684 __ ret(); |
1762 } | 1685 } |
1763 | 1686 |
1764 | |
1765 void Intrinsifier::Object_setHash(Assembler* assembler) { | 1687 void Intrinsifier::Object_setHash(Assembler* assembler) { |
1766 __ movq(RAX, Address(RSP, +2 * kWordSize)); // Object. | 1688 __ movq(RAX, Address(RSP, +2 * kWordSize)); // Object. |
1767 __ movq(RDX, Address(RSP, +1 * kWordSize)); // Value. | 1689 __ movq(RDX, Address(RSP, +1 * kWordSize)); // Value. |
1768 __ SmiUntag(RDX); | 1690 __ SmiUntag(RDX); |
1769 __ movl(FieldAddress(RAX, String::hash_offset()), RDX); | 1691 __ movl(FieldAddress(RAX, String::hash_offset()), RDX); |
1770 __ ret(); | 1692 __ ret(); |
1771 } | 1693 } |
1772 | 1694 |
1773 | |
1774 void GenerateSubstringMatchesSpecialization(Assembler* assembler, | 1695 void GenerateSubstringMatchesSpecialization(Assembler* assembler, |
1775 intptr_t receiver_cid, | 1696 intptr_t receiver_cid, |
1776 intptr_t other_cid, | 1697 intptr_t other_cid, |
1777 Label* return_true, | 1698 Label* return_true, |
1778 Label* return_false) { | 1699 Label* return_false) { |
1779 __ movq(R8, FieldAddress(RAX, String::length_offset())); | 1700 __ movq(R8, FieldAddress(RAX, String::length_offset())); |
1780 __ movq(R9, FieldAddress(RCX, String::length_offset())); | 1701 __ movq(R9, FieldAddress(RCX, String::length_offset())); |
1781 | 1702 |
1782 // if (other.length == 0) return true; | 1703 // if (other.length == 0) return true; |
1783 __ testq(R9, R9); | 1704 __ testq(R9, R9); |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1826 __ j(NOT_EQUAL, return_false); | 1747 __ j(NOT_EQUAL, return_false); |
1827 | 1748 |
1828 // i++, while (i < len) | 1749 // i++, while (i < len) |
1829 __ addq(R11, Immediate(1)); | 1750 __ addq(R11, Immediate(1)); |
1830 __ cmpq(R11, R9); | 1751 __ cmpq(R11, R9); |
1831 __ j(LESS, &loop, Assembler::kNearJump); | 1752 __ j(LESS, &loop, Assembler::kNearJump); |
1832 | 1753 |
1833 __ jmp(return_true); | 1754 __ jmp(return_true); |
1834 } | 1755 } |
1835 | 1756 |
1836 | |
1837 // bool _substringMatches(int start, String other) | 1757 // bool _substringMatches(int start, String other) |
1838 // This intrinsic handles a OneByteString or TwoByteString receiver with a | 1758 // This intrinsic handles a OneByteString or TwoByteString receiver with a |
1839 // OneByteString other. | 1759 // OneByteString other. |
1840 void Intrinsifier::StringBaseSubstringMatches(Assembler* assembler) { | 1760 void Intrinsifier::StringBaseSubstringMatches(Assembler* assembler) { |
1841 Label fall_through, return_true, return_false, try_two_byte; | 1761 Label fall_through, return_true, return_false, try_two_byte; |
1842 __ movq(RAX, Address(RSP, +3 * kWordSize)); // receiver | 1762 __ movq(RAX, Address(RSP, +3 * kWordSize)); // receiver |
1843 __ movq(RBX, Address(RSP, +2 * kWordSize)); // start | 1763 __ movq(RBX, Address(RSP, +2 * kWordSize)); // start |
1844 __ movq(RCX, Address(RSP, +1 * kWordSize)); // other | 1764 __ movq(RCX, Address(RSP, +1 * kWordSize)); // other |
1845 | 1765 |
1846 __ testq(RBX, Immediate(kSmiTagMask)); | 1766 __ testq(RBX, Immediate(kSmiTagMask)); |
(...skipping 21 matching lines...) Expand all Loading... |
1868 __ LoadObject(RAX, Bool::True()); | 1788 __ LoadObject(RAX, Bool::True()); |
1869 __ ret(); | 1789 __ ret(); |
1870 | 1790 |
1871 __ Bind(&return_false); | 1791 __ Bind(&return_false); |
1872 __ LoadObject(RAX, Bool::False()); | 1792 __ LoadObject(RAX, Bool::False()); |
1873 __ ret(); | 1793 __ ret(); |
1874 | 1794 |
1875 __ Bind(&fall_through); | 1795 __ Bind(&fall_through); |
1876 } | 1796 } |
1877 | 1797 |
1878 | |
1879 void Intrinsifier::StringBaseCharAt(Assembler* assembler) { | 1798 void Intrinsifier::StringBaseCharAt(Assembler* assembler) { |
1880 Label fall_through, try_two_byte_string; | 1799 Label fall_through, try_two_byte_string; |
1881 __ movq(RCX, Address(RSP, +1 * kWordSize)); // Index. | 1800 __ movq(RCX, Address(RSP, +1 * kWordSize)); // Index. |
1882 __ movq(RAX, Address(RSP, +2 * kWordSize)); // String. | 1801 __ movq(RAX, Address(RSP, +2 * kWordSize)); // String. |
1883 __ testq(RCX, Immediate(kSmiTagMask)); | 1802 __ testq(RCX, Immediate(kSmiTagMask)); |
1884 __ j(NOT_ZERO, &fall_through); // Non-smi index. | 1803 __ j(NOT_ZERO, &fall_through); // Non-smi index. |
1885 // Range check. | 1804 // Range check. |
1886 __ cmpq(RCX, FieldAddress(RAX, String::length_offset())); | 1805 __ cmpq(RCX, FieldAddress(RAX, String::length_offset())); |
1887 // Runtime throws exception. | 1806 // Runtime throws exception. |
1888 __ j(ABOVE_EQUAL, &fall_through); | 1807 __ j(ABOVE_EQUAL, &fall_through); |
(...skipping 16 matching lines...) Expand all Loading... |
1905 __ cmpq(RCX, Immediate(Symbols::kNumberOfOneCharCodeSymbols)); | 1824 __ cmpq(RCX, Immediate(Symbols::kNumberOfOneCharCodeSymbols)); |
1906 __ j(GREATER_EQUAL, &fall_through); | 1825 __ j(GREATER_EQUAL, &fall_through); |
1907 __ movq(RAX, Address(THR, Thread::predefined_symbols_address_offset())); | 1826 __ movq(RAX, Address(THR, Thread::predefined_symbols_address_offset())); |
1908 __ movq(RAX, Address(RAX, RCX, TIMES_8, | 1827 __ movq(RAX, Address(RAX, RCX, TIMES_8, |
1909 Symbols::kNullCharCodeSymbolOffset * kWordSize)); | 1828 Symbols::kNullCharCodeSymbolOffset * kWordSize)); |
1910 __ ret(); | 1829 __ ret(); |
1911 | 1830 |
1912 __ Bind(&fall_through); | 1831 __ Bind(&fall_through); |
1913 } | 1832 } |
1914 | 1833 |
1915 | |
1916 void Intrinsifier::StringBaseIsEmpty(Assembler* assembler) { | 1834 void Intrinsifier::StringBaseIsEmpty(Assembler* assembler) { |
1917 Label is_true; | 1835 Label is_true; |
1918 // Get length. | 1836 // Get length. |
1919 __ movq(RAX, Address(RSP, +1 * kWordSize)); // String object. | 1837 __ movq(RAX, Address(RSP, +1 * kWordSize)); // String object. |
1920 __ movq(RAX, FieldAddress(RAX, String::length_offset())); | 1838 __ movq(RAX, FieldAddress(RAX, String::length_offset())); |
1921 __ cmpq(RAX, Immediate(Smi::RawValue(0))); | 1839 __ cmpq(RAX, Immediate(Smi::RawValue(0))); |
1922 __ j(EQUAL, &is_true, Assembler::kNearJump); | 1840 __ j(EQUAL, &is_true, Assembler::kNearJump); |
1923 __ LoadObject(RAX, Bool::False()); | 1841 __ LoadObject(RAX, Bool::False()); |
1924 __ ret(); | 1842 __ ret(); |
1925 __ Bind(&is_true); | 1843 __ Bind(&is_true); |
1926 __ LoadObject(RAX, Bool::True()); | 1844 __ LoadObject(RAX, Bool::True()); |
1927 __ ret(); | 1845 __ ret(); |
1928 } | 1846 } |
1929 | 1847 |
1930 | |
1931 void Intrinsifier::OneByteString_getHashCode(Assembler* assembler) { | 1848 void Intrinsifier::OneByteString_getHashCode(Assembler* assembler) { |
1932 Label compute_hash; | 1849 Label compute_hash; |
1933 __ movq(RBX, Address(RSP, +1 * kWordSize)); // OneByteString object. | 1850 __ movq(RBX, Address(RSP, +1 * kWordSize)); // OneByteString object. |
1934 __ movl(RAX, FieldAddress(RBX, String::hash_offset())); | 1851 __ movl(RAX, FieldAddress(RBX, String::hash_offset())); |
1935 __ cmpq(RAX, Immediate(0)); | 1852 __ cmpq(RAX, Immediate(0)); |
1936 __ j(EQUAL, &compute_hash, Assembler::kNearJump); | 1853 __ j(EQUAL, &compute_hash, Assembler::kNearJump); |
1937 __ SmiTag(RAX); | 1854 __ SmiTag(RAX); |
1938 __ ret(); | 1855 __ ret(); |
1939 | 1856 |
1940 __ Bind(&compute_hash); | 1857 __ Bind(&compute_hash); |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1990 // return hash_ == 0 ? 1 : hash_; | 1907 // return hash_ == 0 ? 1 : hash_; |
1991 __ cmpq(RAX, Immediate(0)); | 1908 __ cmpq(RAX, Immediate(0)); |
1992 __ j(NOT_EQUAL, &set_hash_code, Assembler::kNearJump); | 1909 __ j(NOT_EQUAL, &set_hash_code, Assembler::kNearJump); |
1993 __ incq(RAX); | 1910 __ incq(RAX); |
1994 __ Bind(&set_hash_code); | 1911 __ Bind(&set_hash_code); |
1995 __ movl(FieldAddress(RBX, String::hash_offset()), RAX); | 1912 __ movl(FieldAddress(RBX, String::hash_offset()), RAX); |
1996 __ SmiTag(RAX); | 1913 __ SmiTag(RAX); |
1997 __ ret(); | 1914 __ ret(); |
1998 } | 1915 } |
1999 | 1916 |
2000 | |
2001 // Allocates one-byte string of length 'end - start'. The content is not | 1917 // Allocates one-byte string of length 'end - start'. The content is not |
2002 // initialized. 'length-reg' contains tagged length. | 1918 // initialized. 'length-reg' contains tagged length. |
2003 // Returns new string as tagged pointer in RAX. | 1919 // Returns new string as tagged pointer in RAX. |
2004 static void TryAllocateOnebyteString(Assembler* assembler, | 1920 static void TryAllocateOnebyteString(Assembler* assembler, |
2005 Label* ok, | 1921 Label* ok, |
2006 Label* failure, | 1922 Label* failure, |
2007 Register length_reg) { | 1923 Register length_reg) { |
2008 NOT_IN_PRODUCT(__ MaybeTraceAllocation(kOneByteStringCid, failure, false)); | 1924 NOT_IN_PRODUCT(__ MaybeTraceAllocation(kOneByteStringCid, failure, false)); |
2009 if (length_reg != RDI) { | 1925 if (length_reg != RDI) { |
2010 __ movq(RDI, length_reg); | 1926 __ movq(RDI, length_reg); |
2011 } | 1927 } |
2012 Label pop_and_fail, not_zero_length; | 1928 Label pop_and_fail, not_zero_length; |
2013 __ pushq(RDI); // Preserve length. | 1929 __ pushq(RDI); // Preserve length. |
2014 __ sarq(RDI, Immediate(kSmiTagShift)); // Untag length. | 1930 __ sarq(RDI, Immediate(kSmiTagShift)); // Untag length. |
2015 // If the length is 0 then we have to make the allocated size a bit bigger, | 1931 // If the length is 0 then we have to make the allocated size a bit bigger, |
2016 // otherwise the string takes up less space than an ExternalOneByteString, | 1932 // otherwise the string takes up less space than an ExternalOneByteString, |
2017 // and cannot be externalized. TODO(erikcorry): We should probably just | 1933 // and cannot be externalized. TODO(erikcorry): We should probably just |
2018 // return a static zero length string here instead. | 1934 // return a static zero length string here instead. |
2019 __ j(NOT_ZERO, ¬_zero_length); | 1935 __ j(NOT_ZERO, ¬_zero_length); |
2020 __ addq(RDI, Immediate(1)); | 1936 __ addq(RDI, Immediate(1)); |
2021 __ Bind(¬_zero_length); | 1937 __ Bind(¬_zero_length); |
2022 const intptr_t fixed_size_plus_alignment_padding = | 1938 const intptr_t fixed_size_plus_alignment_padding = |
2023 sizeof(RawString) + kObjectAlignment - 1; | 1939 sizeof(RawString) + kObjectAlignment - 1; |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2072 __ popq(RDI); | 1988 __ popq(RDI); |
2073 __ StoreIntoObjectNoBarrier(RAX, FieldAddress(RAX, String::length_offset()), | 1989 __ StoreIntoObjectNoBarrier(RAX, FieldAddress(RAX, String::length_offset()), |
2074 RDI); | 1990 RDI); |
2075 __ jmp(ok, Assembler::kNearJump); | 1991 __ jmp(ok, Assembler::kNearJump); |
2076 | 1992 |
2077 __ Bind(&pop_and_fail); | 1993 __ Bind(&pop_and_fail); |
2078 __ popq(RDI); | 1994 __ popq(RDI); |
2079 __ jmp(failure); | 1995 __ jmp(failure); |
2080 } | 1996 } |
2081 | 1997 |
2082 | |
2083 // Arg0: OneByteString (receiver). | 1998 // Arg0: OneByteString (receiver). |
2084 // Arg1: Start index as Smi. | 1999 // Arg1: Start index as Smi. |
2085 // Arg2: End index as Smi. | 2000 // Arg2: End index as Smi. |
2086 // The indexes must be valid. | 2001 // The indexes must be valid. |
2087 void Intrinsifier::OneByteString_substringUnchecked(Assembler* assembler) { | 2002 void Intrinsifier::OneByteString_substringUnchecked(Assembler* assembler) { |
2088 const intptr_t kStringOffset = 3 * kWordSize; | 2003 const intptr_t kStringOffset = 3 * kWordSize; |
2089 const intptr_t kStartIndexOffset = 2 * kWordSize; | 2004 const intptr_t kStartIndexOffset = 2 * kWordSize; |
2090 const intptr_t kEndIndexOffset = 1 * kWordSize; | 2005 const intptr_t kEndIndexOffset = 1 * kWordSize; |
2091 Label fall_through, ok; | 2006 Label fall_through, ok; |
2092 __ movq(RSI, Address(RSP, +kStartIndexOffset)); | 2007 __ movq(RSI, Address(RSP, +kStartIndexOffset)); |
(...skipping 28 matching lines...) Expand all Loading... |
2121 __ movzxb(RBX, Address(RSI, RDX, TIMES_1, 0)); | 2036 __ movzxb(RBX, Address(RSI, RDX, TIMES_1, 0)); |
2122 __ movb(FieldAddress(RAX, RDX, TIMES_1, OneByteString::data_offset()), RBX); | 2037 __ movb(FieldAddress(RAX, RDX, TIMES_1, OneByteString::data_offset()), RBX); |
2123 __ incq(RDX); | 2038 __ incq(RDX); |
2124 __ Bind(&check); | 2039 __ Bind(&check); |
2125 __ cmpq(RDX, RCX); | 2040 __ cmpq(RDX, RCX); |
2126 __ j(LESS, &loop, Assembler::kNearJump); | 2041 __ j(LESS, &loop, Assembler::kNearJump); |
2127 __ ret(); | 2042 __ ret(); |
2128 __ Bind(&fall_through); | 2043 __ Bind(&fall_through); |
2129 } | 2044 } |
2130 | 2045 |
2131 | |
2132 void Intrinsifier::OneByteStringSetAt(Assembler* assembler) { | 2046 void Intrinsifier::OneByteStringSetAt(Assembler* assembler) { |
2133 __ movq(RCX, Address(RSP, +1 * kWordSize)); // Value. | 2047 __ movq(RCX, Address(RSP, +1 * kWordSize)); // Value. |
2134 __ movq(RBX, Address(RSP, +2 * kWordSize)); // Index. | 2048 __ movq(RBX, Address(RSP, +2 * kWordSize)); // Index. |
2135 __ movq(RAX, Address(RSP, +3 * kWordSize)); // OneByteString. | 2049 __ movq(RAX, Address(RSP, +3 * kWordSize)); // OneByteString. |
2136 __ SmiUntag(RBX); | 2050 __ SmiUntag(RBX); |
2137 __ SmiUntag(RCX); | 2051 __ SmiUntag(RCX); |
2138 __ movb(FieldAddress(RAX, RBX, TIMES_1, OneByteString::data_offset()), RCX); | 2052 __ movb(FieldAddress(RAX, RBX, TIMES_1, OneByteString::data_offset()), RCX); |
2139 __ ret(); | 2053 __ ret(); |
2140 } | 2054 } |
2141 | 2055 |
2142 | |
2143 void Intrinsifier::OneByteString_allocate(Assembler* assembler) { | 2056 void Intrinsifier::OneByteString_allocate(Assembler* assembler) { |
2144 __ movq(RDI, Address(RSP, +1 * kWordSize)); // Length.v= | 2057 __ movq(RDI, Address(RSP, +1 * kWordSize)); // Length.v= |
2145 Label fall_through, ok; | 2058 Label fall_through, ok; |
2146 TryAllocateOnebyteString(assembler, &ok, &fall_through, RDI); | 2059 TryAllocateOnebyteString(assembler, &ok, &fall_through, RDI); |
2147 // RDI: Start address to copy from (untagged). | 2060 // RDI: Start address to copy from (untagged). |
2148 | 2061 |
2149 __ Bind(&ok); | 2062 __ Bind(&ok); |
2150 __ ret(); | 2063 __ ret(); |
2151 | 2064 |
2152 __ Bind(&fall_through); | 2065 __ Bind(&fall_through); |
2153 } | 2066 } |
2154 | 2067 |
2155 | |
2156 // TODO(srdjan): Add combinations (one-byte/two-byte/external strings). | 2068 // TODO(srdjan): Add combinations (one-byte/two-byte/external strings). |
2157 static void StringEquality(Assembler* assembler, intptr_t string_cid) { | 2069 static void StringEquality(Assembler* assembler, intptr_t string_cid) { |
2158 Label fall_through, is_true, is_false, loop; | 2070 Label fall_through, is_true, is_false, loop; |
2159 __ movq(RAX, Address(RSP, +2 * kWordSize)); // This. | 2071 __ movq(RAX, Address(RSP, +2 * kWordSize)); // This. |
2160 __ movq(RCX, Address(RSP, +1 * kWordSize)); // Other. | 2072 __ movq(RCX, Address(RSP, +1 * kWordSize)); // Other. |
2161 | 2073 |
2162 // Are identical? | 2074 // Are identical? |
2163 __ cmpq(RAX, RCX); | 2075 __ cmpq(RAX, RCX); |
2164 __ j(EQUAL, &is_true, Assembler::kNearJump); | 2076 __ j(EQUAL, &is_true, Assembler::kNearJump); |
2165 | 2077 |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2202 __ LoadObject(RAX, Bool::True()); | 2114 __ LoadObject(RAX, Bool::True()); |
2203 __ ret(); | 2115 __ ret(); |
2204 | 2116 |
2205 __ Bind(&is_false); | 2117 __ Bind(&is_false); |
2206 __ LoadObject(RAX, Bool::False()); | 2118 __ LoadObject(RAX, Bool::False()); |
2207 __ ret(); | 2119 __ ret(); |
2208 | 2120 |
2209 __ Bind(&fall_through); | 2121 __ Bind(&fall_through); |
2210 } | 2122 } |
2211 | 2123 |
2212 | |
2213 void Intrinsifier::OneByteString_equality(Assembler* assembler) { | 2124 void Intrinsifier::OneByteString_equality(Assembler* assembler) { |
2214 StringEquality(assembler, kOneByteStringCid); | 2125 StringEquality(assembler, kOneByteStringCid); |
2215 } | 2126 } |
2216 | 2127 |
2217 | |
2218 void Intrinsifier::TwoByteString_equality(Assembler* assembler) { | 2128 void Intrinsifier::TwoByteString_equality(Assembler* assembler) { |
2219 StringEquality(assembler, kTwoByteStringCid); | 2129 StringEquality(assembler, kTwoByteStringCid); |
2220 } | 2130 } |
2221 | 2131 |
2222 | |
2223 void Intrinsifier::IntrinsifyRegExpExecuteMatch(Assembler* assembler, | 2132 void Intrinsifier::IntrinsifyRegExpExecuteMatch(Assembler* assembler, |
2224 bool sticky) { | 2133 bool sticky) { |
2225 if (FLAG_interpret_irregexp) return; | 2134 if (FLAG_interpret_irregexp) return; |
2226 | 2135 |
2227 static const intptr_t kRegExpParamOffset = 3 * kWordSize; | 2136 static const intptr_t kRegExpParamOffset = 3 * kWordSize; |
2228 static const intptr_t kStringParamOffset = 2 * kWordSize; | 2137 static const intptr_t kStringParamOffset = 2 * kWordSize; |
2229 // start_index smi is located at offset 1. | 2138 // start_index smi is located at offset 1. |
2230 | 2139 |
2231 // Incoming registers: | 2140 // Incoming registers: |
2232 // RAX: Function. (Will be loaded with the specialized matcher function.) | 2141 // RAX: Function. (Will be loaded with the specialized matcher function.) |
2233 // RCX: Unknown. (Must be GC safe on tail call.) | 2142 // RCX: Unknown. (Must be GC safe on tail call.) |
2234 // R10: Arguments descriptor. (Will be preserved.) | 2143 // R10: Arguments descriptor. (Will be preserved.) |
2235 | 2144 |
2236 // Load the specialized function pointer into RAX. Leverage the fact the | 2145 // Load the specialized function pointer into RAX. Leverage the fact the |
2237 // string CIDs as well as stored function pointers are in sequence. | 2146 // string CIDs as well as stored function pointers are in sequence. |
2238 __ movq(RBX, Address(RSP, kRegExpParamOffset)); | 2147 __ movq(RBX, Address(RSP, kRegExpParamOffset)); |
2239 __ movq(RDI, Address(RSP, kStringParamOffset)); | 2148 __ movq(RDI, Address(RSP, kStringParamOffset)); |
2240 __ LoadClassId(RDI, RDI); | 2149 __ LoadClassId(RDI, RDI); |
2241 __ SubImmediate(RDI, Immediate(kOneByteStringCid)); | 2150 __ SubImmediate(RDI, Immediate(kOneByteStringCid)); |
2242 __ movq(RAX, FieldAddress(RBX, RDI, TIMES_8, RegExp::function_offset( | 2151 __ movq(RAX, |
2243 kOneByteStringCid, sticky))); | 2152 FieldAddress(RBX, RDI, TIMES_8, |
| 2153 RegExp::function_offset(kOneByteStringCid, sticky))); |
2244 | 2154 |
2245 // Registers are now set up for the lazy compile stub. It expects the function | 2155 // Registers are now set up for the lazy compile stub. It expects the function |
2246 // in RAX, the argument descriptor in R10, and IC-Data in RCX. | 2156 // in RAX, the argument descriptor in R10, and IC-Data in RCX. |
2247 __ xorq(RCX, RCX); | 2157 __ xorq(RCX, RCX); |
2248 | 2158 |
2249 // Tail-call the function. | 2159 // Tail-call the function. |
2250 __ movq(CODE_REG, FieldAddress(RAX, Function::code_offset())); | 2160 __ movq(CODE_REG, FieldAddress(RAX, Function::code_offset())); |
2251 __ movq(RDI, FieldAddress(RAX, Function::entry_point_offset())); | 2161 __ movq(RDI, FieldAddress(RAX, Function::entry_point_offset())); |
2252 __ jmp(RDI); | 2162 __ jmp(RDI); |
2253 } | 2163 } |
2254 | 2164 |
2255 | |
2256 // On stack: user tag (+1), return-address (+0). | 2165 // On stack: user tag (+1), return-address (+0). |
2257 void Intrinsifier::UserTag_makeCurrent(Assembler* assembler) { | 2166 void Intrinsifier::UserTag_makeCurrent(Assembler* assembler) { |
2258 // RBX: Isolate. | 2167 // RBX: Isolate. |
2259 __ LoadIsolate(RBX); | 2168 __ LoadIsolate(RBX); |
2260 // RAX: Current user tag. | 2169 // RAX: Current user tag. |
2261 __ movq(RAX, Address(RBX, Isolate::current_tag_offset())); | 2170 __ movq(RAX, Address(RBX, Isolate::current_tag_offset())); |
2262 // R10: UserTag. | 2171 // R10: UserTag. |
2263 __ movq(R10, Address(RSP, +1 * kWordSize)); | 2172 __ movq(R10, Address(RSP, +1 * kWordSize)); |
2264 // Set Isolate::current_tag_. | 2173 // Set Isolate::current_tag_. |
2265 __ movq(Address(RBX, Isolate::current_tag_offset()), R10); | 2174 __ movq(Address(RBX, Isolate::current_tag_offset()), R10); |
2266 // R10: UserTag's tag. | 2175 // R10: UserTag's tag. |
2267 __ movq(R10, FieldAddress(R10, UserTag::tag_offset())); | 2176 __ movq(R10, FieldAddress(R10, UserTag::tag_offset())); |
2268 // Set Isolate::user_tag_. | 2177 // Set Isolate::user_tag_. |
2269 __ movq(Address(RBX, Isolate::user_tag_offset()), R10); | 2178 __ movq(Address(RBX, Isolate::user_tag_offset()), R10); |
2270 __ ret(); | 2179 __ ret(); |
2271 } | 2180 } |
2272 | 2181 |
2273 | |
2274 void Intrinsifier::UserTag_defaultTag(Assembler* assembler) { | 2182 void Intrinsifier::UserTag_defaultTag(Assembler* assembler) { |
2275 __ LoadIsolate(RAX); | 2183 __ LoadIsolate(RAX); |
2276 __ movq(RAX, Address(RAX, Isolate::default_tag_offset())); | 2184 __ movq(RAX, Address(RAX, Isolate::default_tag_offset())); |
2277 __ ret(); | 2185 __ ret(); |
2278 } | 2186 } |
2279 | 2187 |
2280 | |
2281 void Intrinsifier::Profiler_getCurrentTag(Assembler* assembler) { | 2188 void Intrinsifier::Profiler_getCurrentTag(Assembler* assembler) { |
2282 __ LoadIsolate(RAX); | 2189 __ LoadIsolate(RAX); |
2283 __ movq(RAX, Address(RAX, Isolate::current_tag_offset())); | 2190 __ movq(RAX, Address(RAX, Isolate::current_tag_offset())); |
2284 __ ret(); | 2191 __ ret(); |
2285 } | 2192 } |
2286 | 2193 |
2287 | |
2288 void Intrinsifier::Timeline_isDartStreamEnabled(Assembler* assembler) { | 2194 void Intrinsifier::Timeline_isDartStreamEnabled(Assembler* assembler) { |
2289 if (!FLAG_support_timeline) { | 2195 if (!FLAG_support_timeline) { |
2290 __ LoadObject(RAX, Bool::False()); | 2196 __ LoadObject(RAX, Bool::False()); |
2291 __ ret(); | 2197 __ ret(); |
2292 return; | 2198 return; |
2293 } | 2199 } |
2294 Label true_label; | 2200 Label true_label; |
2295 // Load TimelineStream*. | 2201 // Load TimelineStream*. |
2296 __ movq(RAX, Address(THR, Thread::dart_stream_offset())); | 2202 __ movq(RAX, Address(THR, Thread::dart_stream_offset())); |
2297 // Load uintptr_t from TimelineStream*. | 2203 // Load uintptr_t from TimelineStream*. |
2298 __ movq(RAX, Address(RAX, TimelineStream::enabled_offset())); | 2204 __ movq(RAX, Address(RAX, TimelineStream::enabled_offset())); |
2299 __ cmpq(RAX, Immediate(0)); | 2205 __ cmpq(RAX, Immediate(0)); |
2300 __ j(NOT_ZERO, &true_label, Assembler::kNearJump); | 2206 __ j(NOT_ZERO, &true_label, Assembler::kNearJump); |
2301 // Not enabled. | 2207 // Not enabled. |
2302 __ LoadObject(RAX, Bool::False()); | 2208 __ LoadObject(RAX, Bool::False()); |
2303 __ ret(); | 2209 __ ret(); |
2304 // Enabled. | 2210 // Enabled. |
2305 __ Bind(&true_label); | 2211 __ Bind(&true_label); |
2306 __ LoadObject(RAX, Bool::True()); | 2212 __ LoadObject(RAX, Bool::True()); |
2307 __ ret(); | 2213 __ ret(); |
2308 } | 2214 } |
2309 | 2215 |
2310 | |
2311 void Intrinsifier::ClearAsyncThreadStackTrace(Assembler* assembler) { | 2216 void Intrinsifier::ClearAsyncThreadStackTrace(Assembler* assembler) { |
2312 __ LoadObject(RAX, Object::null_object()); | 2217 __ LoadObject(RAX, Object::null_object()); |
2313 __ movq(Address(THR, Thread::async_stack_trace_offset()), RAX); | 2218 __ movq(Address(THR, Thread::async_stack_trace_offset()), RAX); |
2314 __ ret(); | 2219 __ ret(); |
2315 } | 2220 } |
2316 | 2221 |
2317 | |
2318 void Intrinsifier::SetAsyncThreadStackTrace(Assembler* assembler) { | 2222 void Intrinsifier::SetAsyncThreadStackTrace(Assembler* assembler) { |
2319 __ movq(Address(THR, Thread::async_stack_trace_offset()), RAX); | 2223 __ movq(Address(THR, Thread::async_stack_trace_offset()), RAX); |
2320 __ LoadObject(RAX, Object::null_object()); | 2224 __ LoadObject(RAX, Object::null_object()); |
2321 __ ret(); | 2225 __ ret(); |
2322 } | 2226 } |
2323 | 2227 |
2324 #undef __ | 2228 #undef __ |
2325 | 2229 |
2326 } // namespace dart | 2230 } // namespace dart |
2327 | 2231 |
2328 #endif // defined TARGET_ARCH_X64 | 2232 #endif // defined TARGET_ARCH_X64 |
OLD | NEW |