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 // The intrinsic code below is executed before a method has built its frame. | 5 // The intrinsic code below is executed before a method has built its frame. |
6 // The return address is on the stack and the arguments below it. | 6 // The return address is on the stack and the arguments below it. |
7 // Registers EDX (arguments descriptor) and ECX (function) must be preserved. | 7 // Registers EDX (arguments descriptor) and ECX (function) must be preserved. |
8 // Each intrinsification method returns true if the corresponding | 8 // Each intrinsification method returns true if the corresponding |
9 // Dart method was intrinsified. | 9 // Dart method was intrinsified. |
10 | 10 |
(...skipping 18 matching lines...) Expand all Loading... |
29 // ECX: IC Data | 29 // ECX: IC Data |
30 // EDX: Arguments descriptor | 30 // EDX: Arguments descriptor |
31 // TOS: Return address | 31 // TOS: Return address |
32 // The ECX, EDX registers can be destroyed only if there is no slow-path, i.e. | 32 // The ECX, EDX registers can be destroyed only if there is no slow-path, i.e. |
33 // if the intrinsified method always executes a return. | 33 // if the intrinsified method always executes a return. |
34 // The EBP register should not be modified, because it is used by the profiler. | 34 // The EBP register should not be modified, because it is used by the profiler. |
35 // The THR register (see constants_ia32.h) must be preserved. | 35 // The THR register (see constants_ia32.h) must be preserved. |
36 | 36 |
37 #define __ assembler-> | 37 #define __ assembler-> |
38 | 38 |
39 | |
40 intptr_t Intrinsifier::ParameterSlotFromSp() { | 39 intptr_t Intrinsifier::ParameterSlotFromSp() { |
41 return 0; | 40 return 0; |
42 } | 41 } |
43 | 42 |
44 | |
45 void Intrinsifier::IntrinsicCallPrologue(Assembler* assembler) { | 43 void Intrinsifier::IntrinsicCallPrologue(Assembler* assembler) { |
46 COMPILE_ASSERT(CALLEE_SAVED_TEMP != ARGS_DESC_REG); | 44 COMPILE_ASSERT(CALLEE_SAVED_TEMP != ARGS_DESC_REG); |
47 | 45 |
48 assembler->Comment("IntrinsicCallPrologue"); | 46 assembler->Comment("IntrinsicCallPrologue"); |
49 assembler->movl(CALLEE_SAVED_TEMP, ARGS_DESC_REG); | 47 assembler->movl(CALLEE_SAVED_TEMP, ARGS_DESC_REG); |
50 } | 48 } |
51 | 49 |
52 | |
53 void Intrinsifier::IntrinsicCallEpilogue(Assembler* assembler) { | 50 void Intrinsifier::IntrinsicCallEpilogue(Assembler* assembler) { |
54 assembler->Comment("IntrinsicCallEpilogue"); | 51 assembler->Comment("IntrinsicCallEpilogue"); |
55 assembler->movl(ARGS_DESC_REG, CALLEE_SAVED_TEMP); | 52 assembler->movl(ARGS_DESC_REG, CALLEE_SAVED_TEMP); |
56 } | 53 } |
57 | 54 |
58 | |
59 static intptr_t ComputeObjectArrayTypeArgumentsOffset() { | 55 static intptr_t ComputeObjectArrayTypeArgumentsOffset() { |
60 const Library& core_lib = Library::Handle(Library::CoreLibrary()); | 56 const Library& core_lib = Library::Handle(Library::CoreLibrary()); |
61 const Class& cls = | 57 const Class& cls = |
62 Class::Handle(core_lib.LookupClassAllowPrivate(Symbols::_List())); | 58 Class::Handle(core_lib.LookupClassAllowPrivate(Symbols::_List())); |
63 ASSERT(!cls.IsNull()); | 59 ASSERT(!cls.IsNull()); |
64 ASSERT(cls.NumTypeArguments() == 1); | 60 ASSERT(cls.NumTypeArguments() == 1); |
65 const intptr_t field_offset = cls.type_arguments_field_offset(); | 61 const intptr_t field_offset = cls.type_arguments_field_offset(); |
66 ASSERT(field_offset != Class::kNoTypeArguments); | 62 ASSERT(field_offset != Class::kNoTypeArguments); |
67 return field_offset; | 63 return field_offset; |
68 } | 64 } |
69 | 65 |
70 | |
71 // Intrinsify only for Smi value and index. Non-smi values need a store buffer | 66 // Intrinsify only for Smi value and index. Non-smi values need a store buffer |
72 // update. Array length is always a Smi. | 67 // update. Array length is always a Smi. |
73 void Intrinsifier::ObjectArraySetIndexed(Assembler* assembler) { | 68 void Intrinsifier::ObjectArraySetIndexed(Assembler* assembler) { |
74 Label fall_through; | 69 Label fall_through; |
75 if (Isolate::Current()->type_checks()) { | 70 if (Isolate::Current()->type_checks()) { |
76 const intptr_t type_args_field_offset = | 71 const intptr_t type_args_field_offset = |
77 ComputeObjectArrayTypeArgumentsOffset(); | 72 ComputeObjectArrayTypeArgumentsOffset(); |
78 // Inline simple tests (Smi, null), fallthrough if not positive. | 73 // Inline simple tests (Smi, null), fallthrough if not positive. |
79 const Immediate& raw_null = | 74 const Immediate& raw_null = |
80 Immediate(reinterpret_cast<intptr_t>(Object::null())); | 75 Immediate(reinterpret_cast<intptr_t>(Object::null())); |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
116 ASSERT(kSmiTagShift == 1); | 111 ASSERT(kSmiTagShift == 1); |
117 // Destroy ECX (ic data) as we will not continue in the function. | 112 // Destroy ECX (ic data) as we will not continue in the function. |
118 __ movl(ECX, Address(ESP, +1 * kWordSize)); // Value. | 113 __ movl(ECX, Address(ESP, +1 * kWordSize)); // Value. |
119 __ StoreIntoObject(EAX, FieldAddress(EAX, EBX, TIMES_2, Array::data_offset()), | 114 __ StoreIntoObject(EAX, FieldAddress(EAX, EBX, TIMES_2, Array::data_offset()), |
120 ECX); | 115 ECX); |
121 // Caller is responsible of preserving the value if necessary. | 116 // Caller is responsible of preserving the value if necessary. |
122 __ ret(); | 117 __ ret(); |
123 __ Bind(&fall_through); | 118 __ Bind(&fall_through); |
124 } | 119 } |
125 | 120 |
126 | |
127 // Allocate a GrowableObjectArray using the backing array specified. | 121 // Allocate a GrowableObjectArray using the backing array specified. |
128 // On stack: type argument (+2), data (+1), return-address (+0). | 122 // On stack: type argument (+2), data (+1), return-address (+0). |
129 void Intrinsifier::GrowableArray_Allocate(Assembler* assembler) { | 123 void Intrinsifier::GrowableArray_Allocate(Assembler* assembler) { |
130 // This snippet of inlined code uses the following registers: | 124 // This snippet of inlined code uses the following registers: |
131 // EAX, EBX | 125 // EAX, EBX |
132 // and the newly allocated object is returned in EAX. | 126 // and the newly allocated object is returned in EAX. |
133 const intptr_t kTypeArgumentsOffset = 2 * kWordSize; | 127 const intptr_t kTypeArgumentsOffset = 2 * kWordSize; |
134 const intptr_t kArrayOffset = 1 * kWordSize; | 128 const intptr_t kArrayOffset = 1 * kWordSize; |
135 Label fall_through; | 129 Label fall_through; |
136 | 130 |
(...skipping 14 matching lines...) Expand all Loading... |
151 __ StoreIntoObjectNoBarrier( | 145 __ StoreIntoObjectNoBarrier( |
152 EAX, FieldAddress(EAX, GrowableObjectArray::type_arguments_offset()), | 146 EAX, FieldAddress(EAX, GrowableObjectArray::type_arguments_offset()), |
153 EBX); | 147 EBX); |
154 | 148 |
155 __ ZeroInitSmiField(FieldAddress(EAX, GrowableObjectArray::length_offset())); | 149 __ ZeroInitSmiField(FieldAddress(EAX, GrowableObjectArray::length_offset())); |
156 __ ret(); // returns the newly allocated object in EAX. | 150 __ ret(); // returns the newly allocated object in EAX. |
157 | 151 |
158 __ Bind(&fall_through); | 152 __ Bind(&fall_through); |
159 } | 153 } |
160 | 154 |
161 | |
162 // Add an element to growable array if it doesn't need to grow, otherwise | 155 // Add an element to growable array if it doesn't need to grow, otherwise |
163 // call into regular code. | 156 // call into regular code. |
164 // On stack: growable array (+2), value (+1), return-address (+0). | 157 // On stack: growable array (+2), value (+1), return-address (+0). |
165 void Intrinsifier::GrowableArray_add(Assembler* assembler) { | 158 void Intrinsifier::GrowableArray_add(Assembler* assembler) { |
166 // In checked mode we need to type-check the incoming argument. | 159 // In checked mode we need to type-check the incoming argument. |
167 if (Isolate::Current()->type_checks()) return; | 160 if (Isolate::Current()->type_checks()) return; |
168 | 161 |
169 Label fall_through; | 162 Label fall_through; |
170 __ movl(EAX, Address(ESP, +2 * kWordSize)); // Array. | 163 __ movl(EAX, Address(ESP, +2 * kWordSize)); // Array. |
171 __ movl(EBX, FieldAddress(EAX, GrowableObjectArray::length_offset())); | 164 __ movl(EBX, FieldAddress(EAX, GrowableObjectArray::length_offset())); |
172 // EBX: length. | 165 // EBX: length. |
173 __ movl(EDI, FieldAddress(EAX, GrowableObjectArray::data_offset())); | 166 __ movl(EDI, FieldAddress(EAX, GrowableObjectArray::data_offset())); |
174 // EDI: data. | 167 // EDI: data. |
175 // Compare length with capacity. | 168 // Compare length with capacity. |
176 __ cmpl(EBX, FieldAddress(EDI, Array::length_offset())); | 169 __ cmpl(EBX, FieldAddress(EDI, Array::length_offset())); |
177 __ j(EQUAL, &fall_through); // Must grow data. | 170 __ j(EQUAL, &fall_through); // Must grow data. |
178 __ IncrementSmiField(FieldAddress(EAX, GrowableObjectArray::length_offset()), | 171 __ IncrementSmiField(FieldAddress(EAX, GrowableObjectArray::length_offset()), |
179 1); | 172 1); |
180 __ movl(EAX, Address(ESP, +1 * kWordSize)); // Value | 173 __ movl(EAX, Address(ESP, +1 * kWordSize)); // Value |
181 ASSERT(kSmiTagShift == 1); | 174 ASSERT(kSmiTagShift == 1); |
182 __ StoreIntoObject(EDI, FieldAddress(EDI, EBX, TIMES_2, Array::data_offset()), | 175 __ StoreIntoObject(EDI, FieldAddress(EDI, EBX, TIMES_2, Array::data_offset()), |
183 EAX); | 176 EAX); |
184 const Immediate& raw_null = | 177 const Immediate& raw_null = |
185 Immediate(reinterpret_cast<int32_t>(Object::null())); | 178 Immediate(reinterpret_cast<int32_t>(Object::null())); |
186 __ movl(EAX, raw_null); | 179 __ movl(EAX, raw_null); |
187 __ ret(); | 180 __ ret(); |
188 __ Bind(&fall_through); | 181 __ Bind(&fall_through); |
189 } | 182 } |
190 | 183 |
191 | |
192 #define TYPED_ARRAY_ALLOCATION(type_name, cid, max_len, scale_factor) \ | 184 #define TYPED_ARRAY_ALLOCATION(type_name, cid, max_len, scale_factor) \ |
193 Label fall_through; \ | 185 Label fall_through; \ |
194 const intptr_t kArrayLengthStackOffset = 1 * kWordSize; \ | 186 const intptr_t kArrayLengthStackOffset = 1 * kWordSize; \ |
195 NOT_IN_PRODUCT(__ MaybeTraceAllocation(cid, EDI, &fall_through, false)); \ | 187 NOT_IN_PRODUCT(__ MaybeTraceAllocation(cid, EDI, &fall_through, false)); \ |
196 __ movl(EDI, Address(ESP, kArrayLengthStackOffset)); /* Array length. */ \ | 188 __ movl(EDI, Address(ESP, kArrayLengthStackOffset)); /* Array length. */ \ |
197 /* Check that length is a positive Smi. */ \ | 189 /* Check that length is a positive Smi. */ \ |
198 /* EDI: requested array length argument. */ \ | 190 /* EDI: requested array length argument. */ \ |
199 __ testl(EDI, Immediate(kSmiTagMask)); \ | 191 __ testl(EDI, Immediate(kSmiTagMask)); \ |
200 __ j(NOT_ZERO, &fall_through); \ | 192 __ j(NOT_ZERO, &fall_through); \ |
201 __ cmpl(EDI, Immediate(0)); \ | 193 __ cmpl(EDI, Immediate(0)); \ |
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
277 __ cmpl(EDI, EBX); \ | 269 __ cmpl(EDI, EBX); \ |
278 __ j(ABOVE_EQUAL, &done, Assembler::kNearJump); \ | 270 __ j(ABOVE_EQUAL, &done, Assembler::kNearJump); \ |
279 __ movl(Address(EDI, 0), ECX); \ | 271 __ movl(Address(EDI, 0), ECX); \ |
280 __ addl(EDI, Immediate(kWordSize)); \ | 272 __ addl(EDI, Immediate(kWordSize)); \ |
281 __ jmp(&init_loop, Assembler::kNearJump); \ | 273 __ jmp(&init_loop, Assembler::kNearJump); \ |
282 __ Bind(&done); \ | 274 __ Bind(&done); \ |
283 \ | 275 \ |
284 __ ret(); \ | 276 __ ret(); \ |
285 __ Bind(&fall_through); | 277 __ Bind(&fall_through); |
286 | 278 |
287 | |
288 static ScaleFactor GetScaleFactor(intptr_t size) { | 279 static ScaleFactor GetScaleFactor(intptr_t size) { |
289 switch (size) { | 280 switch (size) { |
290 case 1: | 281 case 1: |
291 return TIMES_1; | 282 return TIMES_1; |
292 case 2: | 283 case 2: |
293 return TIMES_2; | 284 return TIMES_2; |
294 case 4: | 285 case 4: |
295 return TIMES_4; | 286 return TIMES_4; |
296 case 8: | 287 case 8: |
297 return TIMES_8; | 288 return TIMES_8; |
298 case 16: | 289 case 16: |
299 return TIMES_16; | 290 return TIMES_16; |
300 } | 291 } |
301 UNREACHABLE(); | 292 UNREACHABLE(); |
302 return static_cast<ScaleFactor>(0); | 293 return static_cast<ScaleFactor>(0); |
303 } | 294 } |
304 | 295 |
305 | |
306 #define TYPED_DATA_ALLOCATOR(clazz) \ | 296 #define TYPED_DATA_ALLOCATOR(clazz) \ |
307 void Intrinsifier::TypedData_##clazz##_factory(Assembler* assembler) { \ | 297 void Intrinsifier::TypedData_##clazz##_factory(Assembler* assembler) { \ |
308 intptr_t size = TypedData::ElementSizeInBytes(kTypedData##clazz##Cid); \ | 298 intptr_t size = TypedData::ElementSizeInBytes(kTypedData##clazz##Cid); \ |
309 intptr_t max_len = TypedData::MaxElements(kTypedData##clazz##Cid); \ | 299 intptr_t max_len = TypedData::MaxElements(kTypedData##clazz##Cid); \ |
310 ScaleFactor scale = GetScaleFactor(size); \ | 300 ScaleFactor scale = GetScaleFactor(size); \ |
311 TYPED_ARRAY_ALLOCATION(TypedData, kTypedData##clazz##Cid, max_len, scale); \ | 301 TYPED_ARRAY_ALLOCATION(TypedData, kTypedData##clazz##Cid, max_len, scale); \ |
312 } | 302 } |
313 CLASS_LIST_TYPED_DATA(TYPED_DATA_ALLOCATOR) | 303 CLASS_LIST_TYPED_DATA(TYPED_DATA_ALLOCATOR) |
314 #undef TYPED_DATA_ALLOCATOR | 304 #undef TYPED_DATA_ALLOCATOR |
315 | 305 |
316 | |
317 // Tests if two top most arguments are smis, jumps to label not_smi if not. | 306 // Tests if two top most arguments are smis, jumps to label not_smi if not. |
318 // Topmost argument is in EAX. | 307 // Topmost argument is in EAX. |
319 static void TestBothArgumentsSmis(Assembler* assembler, Label* not_smi) { | 308 static void TestBothArgumentsSmis(Assembler* assembler, Label* not_smi) { |
320 __ movl(EAX, Address(ESP, +1 * kWordSize)); | 309 __ movl(EAX, Address(ESP, +1 * kWordSize)); |
321 __ movl(EBX, Address(ESP, +2 * kWordSize)); | 310 __ movl(EBX, Address(ESP, +2 * kWordSize)); |
322 __ orl(EBX, EAX); | 311 __ orl(EBX, EAX); |
323 __ testl(EBX, Immediate(kSmiTagMask)); | 312 __ testl(EBX, Immediate(kSmiTagMask)); |
324 __ j(NOT_ZERO, not_smi, Assembler::kNearJump); | 313 __ j(NOT_ZERO, not_smi, Assembler::kNearJump); |
325 } | 314 } |
326 | 315 |
327 | |
328 void Intrinsifier::Integer_addFromInteger(Assembler* assembler) { | 316 void Intrinsifier::Integer_addFromInteger(Assembler* assembler) { |
329 Label fall_through; | 317 Label fall_through; |
330 TestBothArgumentsSmis(assembler, &fall_through); | 318 TestBothArgumentsSmis(assembler, &fall_through); |
331 __ addl(EAX, Address(ESP, +2 * kWordSize)); | 319 __ addl(EAX, Address(ESP, +2 * kWordSize)); |
332 __ j(OVERFLOW, &fall_through, Assembler::kNearJump); | 320 __ j(OVERFLOW, &fall_through, Assembler::kNearJump); |
333 // Result is in EAX. | 321 // Result is in EAX. |
334 __ ret(); | 322 __ ret(); |
335 __ Bind(&fall_through); | 323 __ Bind(&fall_through); |
336 } | 324 } |
337 | 325 |
338 | |
339 void Intrinsifier::Integer_add(Assembler* assembler) { | 326 void Intrinsifier::Integer_add(Assembler* assembler) { |
340 Integer_addFromInteger(assembler); | 327 Integer_addFromInteger(assembler); |
341 } | 328 } |
342 | 329 |
343 | |
344 void Intrinsifier::Integer_subFromInteger(Assembler* assembler) { | 330 void Intrinsifier::Integer_subFromInteger(Assembler* assembler) { |
345 Label fall_through; | 331 Label fall_through; |
346 TestBothArgumentsSmis(assembler, &fall_through); | 332 TestBothArgumentsSmis(assembler, &fall_through); |
347 __ subl(EAX, Address(ESP, +2 * kWordSize)); | 333 __ subl(EAX, Address(ESP, +2 * kWordSize)); |
348 __ j(OVERFLOW, &fall_through, Assembler::kNearJump); | 334 __ j(OVERFLOW, &fall_through, Assembler::kNearJump); |
349 // Result is in EAX. | 335 // Result is in EAX. |
350 __ ret(); | 336 __ ret(); |
351 __ Bind(&fall_through); | 337 __ Bind(&fall_through); |
352 } | 338 } |
353 | 339 |
354 | |
355 void Intrinsifier::Integer_sub(Assembler* assembler) { | 340 void Intrinsifier::Integer_sub(Assembler* assembler) { |
356 Label fall_through; | 341 Label fall_through; |
357 TestBothArgumentsSmis(assembler, &fall_through); | 342 TestBothArgumentsSmis(assembler, &fall_through); |
358 __ movl(EBX, EAX); | 343 __ movl(EBX, EAX); |
359 __ movl(EAX, Address(ESP, +2 * kWordSize)); | 344 __ movl(EAX, Address(ESP, +2 * kWordSize)); |
360 __ subl(EAX, EBX); | 345 __ subl(EAX, EBX); |
361 __ j(OVERFLOW, &fall_through, Assembler::kNearJump); | 346 __ j(OVERFLOW, &fall_through, Assembler::kNearJump); |
362 // Result is in EAX. | 347 // Result is in EAX. |
363 __ ret(); | 348 __ ret(); |
364 __ Bind(&fall_through); | 349 __ Bind(&fall_through); |
365 } | 350 } |
366 | 351 |
367 | |
368 void Intrinsifier::Integer_mulFromInteger(Assembler* assembler) { | 352 void Intrinsifier::Integer_mulFromInteger(Assembler* assembler) { |
369 Label fall_through; | 353 Label fall_through; |
370 TestBothArgumentsSmis(assembler, &fall_through); | 354 TestBothArgumentsSmis(assembler, &fall_through); |
371 ASSERT(kSmiTag == 0); // Adjust code below if not the case. | 355 ASSERT(kSmiTag == 0); // Adjust code below if not the case. |
372 __ SmiUntag(EAX); | 356 __ SmiUntag(EAX); |
373 __ imull(EAX, Address(ESP, +2 * kWordSize)); | 357 __ imull(EAX, Address(ESP, +2 * kWordSize)); |
374 __ j(OVERFLOW, &fall_through, Assembler::kNearJump); | 358 __ j(OVERFLOW, &fall_through, Assembler::kNearJump); |
375 // Result is in EAX. | 359 // Result is in EAX. |
376 __ ret(); | 360 __ ret(); |
377 __ Bind(&fall_through); | 361 __ Bind(&fall_through); |
378 } | 362 } |
379 | 363 |
380 | |
381 void Intrinsifier::Integer_mul(Assembler* assembler) { | 364 void Intrinsifier::Integer_mul(Assembler* assembler) { |
382 Integer_mulFromInteger(assembler); | 365 Integer_mulFromInteger(assembler); |
383 } | 366 } |
384 | 367 |
385 | |
386 // Optimizations: | 368 // Optimizations: |
387 // - result is 0 if: | 369 // - result is 0 if: |
388 // - left is 0 | 370 // - left is 0 |
389 // - left equals right | 371 // - left equals right |
390 // - result is left if | 372 // - result is left if |
391 // - left > 0 && left < right | 373 // - left > 0 && left < right |
392 // EAX: Tagged left (dividend). | 374 // EAX: Tagged left (dividend). |
393 // EBX: Tagged right (divisor). | 375 // EBX: Tagged right (divisor). |
394 // Returns: | 376 // Returns: |
395 // EDX: Untagged fallthrough result (remainder to be adjusted), or | 377 // EDX: Untagged fallthrough result (remainder to be adjusted), or |
(...skipping 19 matching lines...) Expand all Loading... |
415 __ xorl(EAX, EAX); | 397 __ xorl(EAX, EAX); |
416 __ ret(); | 398 __ ret(); |
417 | 399 |
418 __ Bind(&modulo); | 400 __ Bind(&modulo); |
419 __ SmiUntag(EBX); | 401 __ SmiUntag(EBX); |
420 __ SmiUntag(EAX); | 402 __ SmiUntag(EAX); |
421 __ cdq(); | 403 __ cdq(); |
422 __ idivl(EBX); | 404 __ idivl(EBX); |
423 } | 405 } |
424 | 406 |
425 | |
426 // Implementation: | 407 // Implementation: |
427 // res = left % right; | 408 // res = left % right; |
428 // if (res < 0) { | 409 // if (res < 0) { |
429 // if (right < 0) { | 410 // if (right < 0) { |
430 // res = res - right; | 411 // res = res - right; |
431 // } else { | 412 // } else { |
432 // res = res + right; | 413 // res = res + right; |
433 // } | 414 // } |
434 // } | 415 // } |
435 void Intrinsifier::Integer_moduloFromInteger(Assembler* assembler) { | 416 void Intrinsifier::Integer_moduloFromInteger(Assembler* assembler) { |
(...skipping 22 matching lines...) Expand all Loading... |
458 __ subl(EAX, EBX); | 439 __ subl(EAX, EBX); |
459 | 440 |
460 __ Bind(&done); | 441 __ Bind(&done); |
461 // The remainder of two smis is always a smi, no overflow check needed. | 442 // The remainder of two smis is always a smi, no overflow check needed. |
462 __ SmiTag(EAX); | 443 __ SmiTag(EAX); |
463 __ ret(); | 444 __ ret(); |
464 | 445 |
465 __ Bind(&fall_through); | 446 __ Bind(&fall_through); |
466 } | 447 } |
467 | 448 |
468 | |
469 void Intrinsifier::Integer_truncDivide(Assembler* assembler) { | 449 void Intrinsifier::Integer_truncDivide(Assembler* assembler) { |
470 Label fall_through; | 450 Label fall_through; |
471 TestBothArgumentsSmis(assembler, &fall_through); | 451 TestBothArgumentsSmis(assembler, &fall_through); |
472 // EAX: right argument (divisor) | 452 // EAX: right argument (divisor) |
473 __ cmpl(EAX, Immediate(0)); | 453 __ cmpl(EAX, Immediate(0)); |
474 __ j(EQUAL, &fall_through, Assembler::kNearJump); | 454 __ j(EQUAL, &fall_through, Assembler::kNearJump); |
475 __ movl(EBX, EAX); | 455 __ movl(EBX, EAX); |
476 __ SmiUntag(EBX); | 456 __ SmiUntag(EBX); |
477 __ movl(EAX, Address(ESP, +2 * kWordSize)); // Left argument (dividend). | 457 __ movl(EAX, Address(ESP, +2 * kWordSize)); // Left argument (dividend). |
478 __ SmiUntag(EAX); | 458 __ SmiUntag(EAX); |
479 __ pushl(EDX); // Preserve EDX in case of 'fall_through'. | 459 __ pushl(EDX); // Preserve EDX in case of 'fall_through'. |
480 __ cdq(); | 460 __ cdq(); |
481 __ idivl(EBX); | 461 __ idivl(EBX); |
482 __ popl(EDX); | 462 __ popl(EDX); |
483 // Check the corner case of dividing the 'MIN_SMI' with -1, in which case we | 463 // Check the corner case of dividing the 'MIN_SMI' with -1, in which case we |
484 // cannot tag the result. | 464 // cannot tag the result. |
485 __ cmpl(EAX, Immediate(0x40000000)); | 465 __ cmpl(EAX, Immediate(0x40000000)); |
486 __ j(EQUAL, &fall_through); | 466 __ j(EQUAL, &fall_through); |
487 __ SmiTag(EAX); | 467 __ SmiTag(EAX); |
488 __ ret(); | 468 __ ret(); |
489 __ Bind(&fall_through); | 469 __ Bind(&fall_through); |
490 } | 470 } |
491 | 471 |
492 | |
493 void Intrinsifier::Integer_negate(Assembler* assembler) { | 472 void Intrinsifier::Integer_negate(Assembler* assembler) { |
494 Label fall_through; | 473 Label fall_through; |
495 __ movl(EAX, Address(ESP, +1 * kWordSize)); | 474 __ movl(EAX, Address(ESP, +1 * kWordSize)); |
496 __ testl(EAX, Immediate(kSmiTagMask)); | 475 __ testl(EAX, Immediate(kSmiTagMask)); |
497 __ j(NOT_ZERO, &fall_through, Assembler::kNearJump); // Non-smi value. | 476 __ j(NOT_ZERO, &fall_through, Assembler::kNearJump); // Non-smi value. |
498 __ negl(EAX); | 477 __ negl(EAX); |
499 __ j(OVERFLOW, &fall_through, Assembler::kNearJump); | 478 __ j(OVERFLOW, &fall_through, Assembler::kNearJump); |
500 // Result is in EAX. | 479 // Result is in EAX. |
501 __ ret(); | 480 __ ret(); |
502 __ Bind(&fall_through); | 481 __ Bind(&fall_through); |
503 } | 482 } |
504 | 483 |
505 | |
506 void Intrinsifier::Integer_bitAndFromInteger(Assembler* assembler) { | 484 void Intrinsifier::Integer_bitAndFromInteger(Assembler* assembler) { |
507 Label fall_through; | 485 Label fall_through; |
508 TestBothArgumentsSmis(assembler, &fall_through); | 486 TestBothArgumentsSmis(assembler, &fall_through); |
509 __ movl(EBX, Address(ESP, +2 * kWordSize)); | 487 __ movl(EBX, Address(ESP, +2 * kWordSize)); |
510 __ andl(EAX, EBX); | 488 __ andl(EAX, EBX); |
511 // Result is in EAX. | 489 // Result is in EAX. |
512 __ ret(); | 490 __ ret(); |
513 __ Bind(&fall_through); | 491 __ Bind(&fall_through); |
514 } | 492 } |
515 | 493 |
516 | |
517 void Intrinsifier::Integer_bitAnd(Assembler* assembler) { | 494 void Intrinsifier::Integer_bitAnd(Assembler* assembler) { |
518 Integer_bitAndFromInteger(assembler); | 495 Integer_bitAndFromInteger(assembler); |
519 } | 496 } |
520 | 497 |
521 | |
522 void Intrinsifier::Integer_bitOrFromInteger(Assembler* assembler) { | 498 void Intrinsifier::Integer_bitOrFromInteger(Assembler* assembler) { |
523 Label fall_through; | 499 Label fall_through; |
524 TestBothArgumentsSmis(assembler, &fall_through); | 500 TestBothArgumentsSmis(assembler, &fall_through); |
525 __ movl(EBX, Address(ESP, +2 * kWordSize)); | 501 __ movl(EBX, Address(ESP, +2 * kWordSize)); |
526 __ orl(EAX, EBX); | 502 __ orl(EAX, EBX); |
527 // Result is in EAX. | 503 // Result is in EAX. |
528 __ ret(); | 504 __ ret(); |
529 __ Bind(&fall_through); | 505 __ Bind(&fall_through); |
530 } | 506 } |
531 | 507 |
532 | |
533 void Intrinsifier::Integer_bitOr(Assembler* assembler) { | 508 void Intrinsifier::Integer_bitOr(Assembler* assembler) { |
534 Integer_bitOrFromInteger(assembler); | 509 Integer_bitOrFromInteger(assembler); |
535 } | 510 } |
536 | 511 |
537 | |
538 void Intrinsifier::Integer_bitXorFromInteger(Assembler* assembler) { | 512 void Intrinsifier::Integer_bitXorFromInteger(Assembler* assembler) { |
539 Label fall_through; | 513 Label fall_through; |
540 TestBothArgumentsSmis(assembler, &fall_through); | 514 TestBothArgumentsSmis(assembler, &fall_through); |
541 __ movl(EBX, Address(ESP, +2 * kWordSize)); | 515 __ movl(EBX, Address(ESP, +2 * kWordSize)); |
542 __ xorl(EAX, EBX); | 516 __ xorl(EAX, EBX); |
543 // Result is in EAX. | 517 // Result is in EAX. |
544 __ ret(); | 518 __ ret(); |
545 __ Bind(&fall_through); | 519 __ Bind(&fall_through); |
546 } | 520 } |
547 | 521 |
548 | |
549 void Intrinsifier::Integer_bitXor(Assembler* assembler) { | 522 void Intrinsifier::Integer_bitXor(Assembler* assembler) { |
550 Integer_bitXorFromInteger(assembler); | 523 Integer_bitXorFromInteger(assembler); |
551 } | 524 } |
552 | 525 |
553 | |
554 void Intrinsifier::Integer_shl(Assembler* assembler) { | 526 void Intrinsifier::Integer_shl(Assembler* assembler) { |
555 ASSERT(kSmiTagShift == 1); | 527 ASSERT(kSmiTagShift == 1); |
556 ASSERT(kSmiTag == 0); | 528 ASSERT(kSmiTag == 0); |
557 Label fall_through, overflow; | 529 Label fall_through, overflow; |
558 TestBothArgumentsSmis(assembler, &fall_through); | 530 TestBothArgumentsSmis(assembler, &fall_through); |
559 // Shift value is in EAX. Compare with tagged Smi. | 531 // Shift value is in EAX. Compare with tagged Smi. |
560 __ cmpl(EAX, Immediate(Smi::RawValue(Smi::kBits))); | 532 __ cmpl(EAX, Immediate(Smi::RawValue(Smi::kBits))); |
561 __ j(ABOVE_EQUAL, &fall_through, Assembler::kNearJump); | 533 __ j(ABOVE_EQUAL, &fall_through, Assembler::kNearJump); |
562 | 534 |
563 __ SmiUntag(EAX); | 535 __ SmiUntag(EAX); |
(...skipping 28 matching lines...) Expand all Loading... |
592 __ TryAllocate(mint_class, &fall_through, Assembler::kNearJump, | 564 __ TryAllocate(mint_class, &fall_through, Assembler::kNearJump, |
593 EAX, // Result register. | 565 EAX, // Result register. |
594 ECX); // temp | 566 ECX); // temp |
595 // EBX and EDI are not objects but integer values. | 567 // EBX and EDI are not objects but integer values. |
596 __ movl(FieldAddress(EAX, Mint::value_offset()), EBX); | 568 __ movl(FieldAddress(EAX, Mint::value_offset()), EBX); |
597 __ movl(FieldAddress(EAX, Mint::value_offset() + kWordSize), EDI); | 569 __ movl(FieldAddress(EAX, Mint::value_offset() + kWordSize), EDI); |
598 __ ret(); | 570 __ ret(); |
599 __ Bind(&fall_through); | 571 __ Bind(&fall_through); |
600 } | 572 } |
601 | 573 |
602 | |
603 static void Push64SmiOrMint(Assembler* assembler, | 574 static void Push64SmiOrMint(Assembler* assembler, |
604 Register reg, | 575 Register reg, |
605 Register tmp, | 576 Register tmp, |
606 Label* not_smi_or_mint) { | 577 Label* not_smi_or_mint) { |
607 Label not_smi, done; | 578 Label not_smi, done; |
608 __ testl(reg, Immediate(kSmiTagMask)); | 579 __ testl(reg, Immediate(kSmiTagMask)); |
609 __ j(NOT_ZERO, ¬_smi, Assembler::kNearJump); | 580 __ j(NOT_ZERO, ¬_smi, Assembler::kNearJump); |
610 __ SmiUntag(reg); | 581 __ SmiUntag(reg); |
611 // Sign extend to 64 bit | 582 // Sign extend to 64 bit |
612 __ movl(tmp, reg); | 583 __ movl(tmp, reg); |
613 __ sarl(tmp, Immediate(31)); | 584 __ sarl(tmp, Immediate(31)); |
614 __ pushl(tmp); | 585 __ pushl(tmp); |
615 __ pushl(reg); | 586 __ pushl(reg); |
616 __ jmp(&done); | 587 __ jmp(&done); |
617 __ Bind(¬_smi); | 588 __ Bind(¬_smi); |
618 __ CompareClassId(reg, kMintCid, tmp); | 589 __ CompareClassId(reg, kMintCid, tmp); |
619 __ j(NOT_EQUAL, not_smi_or_mint); | 590 __ j(NOT_EQUAL, not_smi_or_mint); |
620 // Mint. | 591 // Mint. |
621 __ pushl(FieldAddress(reg, Mint::value_offset() + kWordSize)); | 592 __ pushl(FieldAddress(reg, Mint::value_offset() + kWordSize)); |
622 __ pushl(FieldAddress(reg, Mint::value_offset())); | 593 __ pushl(FieldAddress(reg, Mint::value_offset())); |
623 __ Bind(&done); | 594 __ Bind(&done); |
624 } | 595 } |
625 | 596 |
626 | |
627 static void CompareIntegers(Assembler* assembler, Condition true_condition) { | 597 static void CompareIntegers(Assembler* assembler, Condition true_condition) { |
628 Label try_mint_smi, is_true, is_false, drop_two_fall_through, fall_through; | 598 Label try_mint_smi, is_true, is_false, drop_two_fall_through, fall_through; |
629 TestBothArgumentsSmis(assembler, &try_mint_smi); | 599 TestBothArgumentsSmis(assembler, &try_mint_smi); |
630 // EAX contains the right argument. | 600 // EAX contains the right argument. |
631 __ cmpl(Address(ESP, +2 * kWordSize), EAX); | 601 __ cmpl(Address(ESP, +2 * kWordSize), EAX); |
632 __ j(true_condition, &is_true, Assembler::kNearJump); | 602 __ j(true_condition, &is_true, Assembler::kNearJump); |
633 __ Bind(&is_false); | 603 __ Bind(&is_false); |
634 __ LoadObject(EAX, Bool::False()); | 604 __ LoadObject(EAX, Bool::False()); |
635 __ ret(); | 605 __ ret(); |
636 __ Bind(&is_true); | 606 __ Bind(&is_true); |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
675 __ cmpl(EAX, EBX); // cmpl left.LO, right.LO. | 645 __ cmpl(EAX, EBX); // cmpl left.LO, right.LO. |
676 __ j(lo_false_cond, &is_false, Assembler::kNearJump); | 646 __ j(lo_false_cond, &is_false, Assembler::kNearJump); |
677 // Else is true. | 647 // Else is true. |
678 __ jmp(&is_true); | 648 __ jmp(&is_true); |
679 | 649 |
680 __ Bind(&drop_two_fall_through); | 650 __ Bind(&drop_two_fall_through); |
681 __ Drop(2); | 651 __ Drop(2); |
682 __ Bind(&fall_through); | 652 __ Bind(&fall_through); |
683 } | 653 } |
684 | 654 |
685 | |
686 void Intrinsifier::Integer_greaterThanFromInt(Assembler* assembler) { | 655 void Intrinsifier::Integer_greaterThanFromInt(Assembler* assembler) { |
687 CompareIntegers(assembler, LESS); | 656 CompareIntegers(assembler, LESS); |
688 } | 657 } |
689 | 658 |
690 | |
691 void Intrinsifier::Integer_lessThan(Assembler* assembler) { | 659 void Intrinsifier::Integer_lessThan(Assembler* assembler) { |
692 Integer_greaterThanFromInt(assembler); | 660 Integer_greaterThanFromInt(assembler); |
693 } | 661 } |
694 | 662 |
695 | |
696 void Intrinsifier::Integer_greaterThan(Assembler* assembler) { | 663 void Intrinsifier::Integer_greaterThan(Assembler* assembler) { |
697 CompareIntegers(assembler, GREATER); | 664 CompareIntegers(assembler, GREATER); |
698 } | 665 } |
699 | 666 |
700 | |
701 void Intrinsifier::Integer_lessEqualThan(Assembler* assembler) { | 667 void Intrinsifier::Integer_lessEqualThan(Assembler* assembler) { |
702 CompareIntegers(assembler, LESS_EQUAL); | 668 CompareIntegers(assembler, LESS_EQUAL); |
703 } | 669 } |
704 | 670 |
705 | |
706 void Intrinsifier::Integer_greaterEqualThan(Assembler* assembler) { | 671 void Intrinsifier::Integer_greaterEqualThan(Assembler* assembler) { |
707 CompareIntegers(assembler, GREATER_EQUAL); | 672 CompareIntegers(assembler, GREATER_EQUAL); |
708 } | 673 } |
709 | 674 |
710 | |
711 // This is called for Smi, Mint and Bigint receivers. The right argument | 675 // This is called for Smi, Mint and Bigint receivers. The right argument |
712 // can be Smi, Mint, Bigint or double. | 676 // can be Smi, Mint, Bigint or double. |
713 void Intrinsifier::Integer_equalToInteger(Assembler* assembler) { | 677 void Intrinsifier::Integer_equalToInteger(Assembler* assembler) { |
714 Label fall_through, true_label, check_for_mint; | 678 Label fall_through, true_label, check_for_mint; |
715 // For integer receiver '===' check first. | 679 // For integer receiver '===' check first. |
716 __ movl(EAX, Address(ESP, +1 * kWordSize)); | 680 __ movl(EAX, Address(ESP, +1 * kWordSize)); |
717 __ cmpl(EAX, Address(ESP, +2 * kWordSize)); | 681 __ cmpl(EAX, Address(ESP, +2 * kWordSize)); |
718 __ j(EQUAL, &true_label, Assembler::kNearJump); | 682 __ j(EQUAL, &true_label, Assembler::kNearJump); |
719 __ movl(EBX, Address(ESP, +2 * kWordSize)); | 683 __ movl(EBX, Address(ESP, +2 * kWordSize)); |
720 __ orl(EAX, EBX); | 684 __ orl(EAX, EBX); |
(...skipping 30 matching lines...) Expand all Loading... |
751 __ movl(EAX, Address(ESP, +1 * kWordSize)); // Right argument. | 715 __ movl(EAX, Address(ESP, +1 * kWordSize)); // Right argument. |
752 __ testl(EAX, Immediate(kSmiTagMask)); | 716 __ testl(EAX, Immediate(kSmiTagMask)); |
753 __ j(NOT_ZERO, &fall_through); | 717 __ j(NOT_ZERO, &fall_through); |
754 __ LoadObject(EAX, Bool::False()); | 718 __ LoadObject(EAX, Bool::False()); |
755 __ ret(); | 719 __ ret(); |
756 // TODO(srdjan): Implement Mint == Mint comparison. | 720 // TODO(srdjan): Implement Mint == Mint comparison. |
757 | 721 |
758 __ Bind(&fall_through); | 722 __ Bind(&fall_through); |
759 } | 723 } |
760 | 724 |
761 | |
762 void Intrinsifier::Integer_equal(Assembler* assembler) { | 725 void Intrinsifier::Integer_equal(Assembler* assembler) { |
763 Integer_equalToInteger(assembler); | 726 Integer_equalToInteger(assembler); |
764 } | 727 } |
765 | 728 |
766 | |
767 void Intrinsifier::Integer_sar(Assembler* assembler) { | 729 void Intrinsifier::Integer_sar(Assembler* assembler) { |
768 Label fall_through, shift_count_ok; | 730 Label fall_through, shift_count_ok; |
769 TestBothArgumentsSmis(assembler, &fall_through); | 731 TestBothArgumentsSmis(assembler, &fall_through); |
770 // Can destroy ECX since we are not falling through. | 732 // Can destroy ECX since we are not falling through. |
771 const Immediate& count_limit = Immediate(0x1F); | 733 const Immediate& count_limit = Immediate(0x1F); |
772 // Check that the count is not larger than what the hardware can handle. | 734 // Check that the count is not larger than what the hardware can handle. |
773 // For shifting right a Smi the result is the same for all numbers | 735 // For shifting right a Smi the result is the same for all numbers |
774 // >= count_limit. | 736 // >= count_limit. |
775 __ SmiUntag(EAX); | 737 __ SmiUntag(EAX); |
776 // Negative counts throw exception. | 738 // Negative counts throw exception. |
777 __ cmpl(EAX, Immediate(0)); | 739 __ cmpl(EAX, Immediate(0)); |
778 __ j(LESS, &fall_through, Assembler::kNearJump); | 740 __ j(LESS, &fall_through, Assembler::kNearJump); |
779 __ cmpl(EAX, count_limit); | 741 __ cmpl(EAX, count_limit); |
780 __ j(LESS_EQUAL, &shift_count_ok, Assembler::kNearJump); | 742 __ j(LESS_EQUAL, &shift_count_ok, Assembler::kNearJump); |
781 __ movl(EAX, count_limit); | 743 __ movl(EAX, count_limit); |
782 __ Bind(&shift_count_ok); | 744 __ Bind(&shift_count_ok); |
783 __ movl(ECX, EAX); // Shift amount must be in ECX. | 745 __ movl(ECX, EAX); // Shift amount must be in ECX. |
784 __ movl(EAX, Address(ESP, +2 * kWordSize)); // Value. | 746 __ movl(EAX, Address(ESP, +2 * kWordSize)); // Value. |
785 __ SmiUntag(EAX); // Value. | 747 __ SmiUntag(EAX); // Value. |
786 __ sarl(EAX, ECX); | 748 __ sarl(EAX, ECX); |
787 __ SmiTag(EAX); | 749 __ SmiTag(EAX); |
788 __ ret(); | 750 __ ret(); |
789 __ Bind(&fall_through); | 751 __ Bind(&fall_through); |
790 } | 752 } |
791 | 753 |
792 | |
793 // Argument is Smi (receiver). | 754 // Argument is Smi (receiver). |
794 void Intrinsifier::Smi_bitNegate(Assembler* assembler) { | 755 void Intrinsifier::Smi_bitNegate(Assembler* assembler) { |
795 __ movl(EAX, Address(ESP, +1 * kWordSize)); // Receiver. | 756 __ movl(EAX, Address(ESP, +1 * kWordSize)); // Receiver. |
796 __ notl(EAX); | 757 __ notl(EAX); |
797 __ andl(EAX, Immediate(~kSmiTagMask)); // Remove inverted smi-tag. | 758 __ andl(EAX, Immediate(~kSmiTagMask)); // Remove inverted smi-tag. |
798 __ ret(); | 759 __ ret(); |
799 } | 760 } |
800 | 761 |
801 | |
802 void Intrinsifier::Smi_bitLength(Assembler* assembler) { | 762 void Intrinsifier::Smi_bitLength(Assembler* assembler) { |
803 ASSERT(kSmiTagShift == 1); | 763 ASSERT(kSmiTagShift == 1); |
804 __ movl(EAX, Address(ESP, +1 * kWordSize)); // Receiver. | 764 __ movl(EAX, Address(ESP, +1 * kWordSize)); // Receiver. |
805 // XOR with sign bit to complement bits if value is negative. | 765 // XOR with sign bit to complement bits if value is negative. |
806 __ movl(ECX, EAX); | 766 __ movl(ECX, EAX); |
807 __ sarl(ECX, Immediate(31)); // All 0 or all 1. | 767 __ sarl(ECX, Immediate(31)); // All 0 or all 1. |
808 __ xorl(EAX, ECX); | 768 __ xorl(EAX, ECX); |
809 // BSR does not write the destination register if source is zero. Put a 1 in | 769 // BSR does not write the destination register if source is zero. Put a 1 in |
810 // the Smi tag bit to ensure BSR writes to destination register. | 770 // the Smi tag bit to ensure BSR writes to destination register. |
811 __ orl(EAX, Immediate(kSmiTagMask)); | 771 __ orl(EAX, Immediate(kSmiTagMask)); |
812 __ bsrl(EAX, EAX); | 772 __ bsrl(EAX, EAX); |
813 __ SmiTag(EAX); | 773 __ SmiTag(EAX); |
814 __ ret(); | 774 __ ret(); |
815 } | 775 } |
816 | 776 |
817 | |
818 void Intrinsifier::Smi_bitAndFromSmi(Assembler* assembler) { | 777 void Intrinsifier::Smi_bitAndFromSmi(Assembler* assembler) { |
819 Integer_bitAndFromInteger(assembler); | 778 Integer_bitAndFromInteger(assembler); |
820 } | 779 } |
821 | 780 |
822 | |
823 void Intrinsifier::Bigint_lsh(Assembler* assembler) { | 781 void Intrinsifier::Bigint_lsh(Assembler* assembler) { |
824 // static void _lsh(Uint32List x_digits, int x_used, int n, | 782 // static void _lsh(Uint32List x_digits, int x_used, int n, |
825 // Uint32List r_digits) | 783 // Uint32List r_digits) |
826 | 784 |
827 // Preserve THR to free ESI. | 785 // Preserve THR to free ESI. |
828 __ pushl(THR); | 786 __ pushl(THR); |
829 ASSERT(THR == ESI); | 787 ASSERT(THR == ESI); |
830 | 788 |
831 __ movl(EDI, Address(ESP, 5 * kWordSize)); // x_digits | 789 __ movl(EDI, Address(ESP, 5 * kWordSize)); // x_digits |
832 __ movl(ECX, Address(ESP, 3 * kWordSize)); // n is Smi | 790 __ movl(ECX, Address(ESP, 3 * kWordSize)); // n is Smi |
(...skipping 24 matching lines...) Expand all Loading... |
857 __ Bind(&last); | 815 __ Bind(&last); |
858 __ shldl(EDX, ESI, ECX); // ESI == 0. | 816 __ shldl(EDX, ESI, ECX); // ESI == 0. |
859 __ movl(Address(EBX, 0), EDX); | 817 __ movl(Address(EBX, 0), EDX); |
860 | 818 |
861 // Restore THR and return. | 819 // Restore THR and return. |
862 __ popl(THR); | 820 __ popl(THR); |
863 // Returning Object::null() is not required, since this method is private. | 821 // Returning Object::null() is not required, since this method is private. |
864 __ ret(); | 822 __ ret(); |
865 } | 823 } |
866 | 824 |
867 | |
868 void Intrinsifier::Bigint_rsh(Assembler* assembler) { | 825 void Intrinsifier::Bigint_rsh(Assembler* assembler) { |
869 // static void _rsh(Uint32List x_digits, int x_used, int n, | 826 // static void _rsh(Uint32List x_digits, int x_used, int n, |
870 // Uint32List r_digits) | 827 // Uint32List r_digits) |
871 | 828 |
872 // Preserve THR to free ESI. | 829 // Preserve THR to free ESI. |
873 __ pushl(THR); | 830 __ pushl(THR); |
874 ASSERT(THR == ESI); | 831 ASSERT(THR == ESI); |
875 | 832 |
876 __ movl(EDI, Address(ESP, 5 * kWordSize)); // x_digits | 833 __ movl(EDI, Address(ESP, 5 * kWordSize)); // x_digits |
877 __ movl(ECX, Address(ESP, 3 * kWordSize)); // n is Smi | 834 __ movl(ECX, Address(ESP, 3 * kWordSize)); // n is Smi |
(...skipping 25 matching lines...) Expand all Loading... |
903 __ Bind(&last); | 860 __ Bind(&last); |
904 __ shrdl(EDX, ESI, ECX); // ESI == 0. | 861 __ shrdl(EDX, ESI, ECX); // ESI == 0. |
905 __ movl(Address(EBX, 0), EDX); | 862 __ movl(Address(EBX, 0), EDX); |
906 | 863 |
907 // Restore THR and return. | 864 // Restore THR and return. |
908 __ popl(THR); | 865 __ popl(THR); |
909 // Returning Object::null() is not required, since this method is private. | 866 // Returning Object::null() is not required, since this method is private. |
910 __ ret(); | 867 __ ret(); |
911 } | 868 } |
912 | 869 |
913 | |
914 void Intrinsifier::Bigint_absAdd(Assembler* assembler) { | 870 void Intrinsifier::Bigint_absAdd(Assembler* assembler) { |
915 // static void _absAdd(Uint32List digits, int used, | 871 // static void _absAdd(Uint32List digits, int used, |
916 // Uint32List a_digits, int a_used, | 872 // Uint32List a_digits, int a_used, |
917 // Uint32List r_digits) | 873 // Uint32List r_digits) |
918 | 874 |
919 // Preserve THR to free ESI. | 875 // Preserve THR to free ESI. |
920 __ pushl(THR); | 876 __ pushl(THR); |
921 ASSERT(THR == ESI); | 877 ASSERT(THR == ESI); |
922 | 878 |
923 __ movl(EDI, Address(ESP, 6 * kWordSize)); // digits | 879 __ movl(EDI, Address(ESP, 6 * kWordSize)); // digits |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
963 __ movl(EAX, Immediate(0)); | 919 __ movl(EAX, Immediate(0)); |
964 __ adcl(EAX, Immediate(0)); | 920 __ adcl(EAX, Immediate(0)); |
965 __ movl(FieldAddress(EBX, EDX, TIMES_4, TypedData::data_offset()), EAX); | 921 __ movl(FieldAddress(EBX, EDX, TIMES_4, TypedData::data_offset()), EAX); |
966 | 922 |
967 // Restore THR and return. | 923 // Restore THR and return. |
968 __ popl(THR); | 924 __ popl(THR); |
969 // Returning Object::null() is not required, since this method is private. | 925 // Returning Object::null() is not required, since this method is private. |
970 __ ret(); | 926 __ ret(); |
971 } | 927 } |
972 | 928 |
973 | |
974 void Intrinsifier::Bigint_absSub(Assembler* assembler) { | 929 void Intrinsifier::Bigint_absSub(Assembler* assembler) { |
975 // static void _absSub(Uint32List digits, int used, | 930 // static void _absSub(Uint32List digits, int used, |
976 // Uint32List a_digits, int a_used, | 931 // Uint32List a_digits, int a_used, |
977 // Uint32List r_digits) | 932 // Uint32List r_digits) |
978 | 933 |
979 // Preserve THR to free ESI. | 934 // Preserve THR to free ESI. |
980 __ pushl(THR); | 935 __ pushl(THR); |
981 ASSERT(THR == ESI); | 936 ASSERT(THR == ESI); |
982 | 937 |
983 __ movl(EDI, Address(ESP, 6 * kWordSize)); // digits | 938 __ movl(EDI, Address(ESP, 6 * kWordSize)); // digits |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1019 __ decl(ECX); // Does not affect carry flag. | 974 __ decl(ECX); // Does not affect carry flag. |
1020 __ j(NOT_ZERO, &carry_loop, Assembler::kNearJump); | 975 __ j(NOT_ZERO, &carry_loop, Assembler::kNearJump); |
1021 | 976 |
1022 __ Bind(&done); | 977 __ Bind(&done); |
1023 // Restore THR and return. | 978 // Restore THR and return. |
1024 __ popl(THR); | 979 __ popl(THR); |
1025 // Returning Object::null() is not required, since this method is private. | 980 // Returning Object::null() is not required, since this method is private. |
1026 __ ret(); | 981 __ ret(); |
1027 } | 982 } |
1028 | 983 |
1029 | |
1030 void Intrinsifier::Bigint_mulAdd(Assembler* assembler) { | 984 void Intrinsifier::Bigint_mulAdd(Assembler* assembler) { |
1031 // Pseudo code: | 985 // Pseudo code: |
1032 // static int _mulAdd(Uint32List x_digits, int xi, | 986 // static int _mulAdd(Uint32List x_digits, int xi, |
1033 // Uint32List m_digits, int i, | 987 // Uint32List m_digits, int i, |
1034 // Uint32List a_digits, int j, int n) { | 988 // Uint32List a_digits, int j, int n) { |
1035 // uint32_t x = x_digits[xi >> 1]; // xi is Smi. | 989 // uint32_t x = x_digits[xi >> 1]; // xi is Smi. |
1036 // if (x == 0 || n == 0) { | 990 // if (x == 0 || n == 0) { |
1037 // return 1; | 991 // return 1; |
1038 // } | 992 // } |
1039 // uint32_t* mip = &m_digits[i >> 1]; // i is Smi. | 993 // uint32_t* mip = &m_digits[i >> 1]; // i is Smi. |
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1139 __ Bind(&done); | 1093 __ Bind(&done); |
1140 __ Drop(1); // n | 1094 __ Drop(1); // n |
1141 // Restore THR and return. | 1095 // Restore THR and return. |
1142 __ popl(THR); | 1096 __ popl(THR); |
1143 | 1097 |
1144 __ Bind(&no_op); | 1098 __ Bind(&no_op); |
1145 __ movl(EAX, Immediate(Smi::RawValue(1))); // One digit processed. | 1099 __ movl(EAX, Immediate(Smi::RawValue(1))); // One digit processed. |
1146 __ ret(); | 1100 __ ret(); |
1147 } | 1101 } |
1148 | 1102 |
1149 | |
1150 void Intrinsifier::Bigint_sqrAdd(Assembler* assembler) { | 1103 void Intrinsifier::Bigint_sqrAdd(Assembler* assembler) { |
1151 // Pseudo code: | 1104 // Pseudo code: |
1152 // static int _sqrAdd(Uint32List x_digits, int i, | 1105 // static int _sqrAdd(Uint32List x_digits, int i, |
1153 // Uint32List a_digits, int used) { | 1106 // Uint32List a_digits, int used) { |
1154 // uint32_t* xip = &x_digits[i >> 1]; // i is Smi. | 1107 // uint32_t* xip = &x_digits[i >> 1]; // i is Smi. |
1155 // uint32_t x = *xip++; | 1108 // uint32_t x = *xip++; |
1156 // if (x == 0) return 1; | 1109 // if (x == 0) return 1; |
1157 // uint32_t* ajp = &a_digits[i]; // j == 2*i, i is Smi. | 1110 // uint32_t* ajp = &a_digits[i]; // j == 2*i, i is Smi. |
1158 // uint32_t aj = *ajp; | 1111 // uint32_t aj = *ajp; |
1159 // uint64_t t = x*x + aj; | 1112 // uint64_t t = x*x + aj; |
(...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1272 __ movl(Address(ESI, Bigint::kBytesPerDigit), EDX); | 1225 __ movl(Address(ESI, Bigint::kBytesPerDigit), EDX); |
1273 | 1226 |
1274 // Restore THR and return. | 1227 // Restore THR and return. |
1275 __ Drop(3); | 1228 __ Drop(3); |
1276 __ popl(THR); | 1229 __ popl(THR); |
1277 __ Bind(&x_zero); | 1230 __ Bind(&x_zero); |
1278 __ movl(EAX, Immediate(Smi::RawValue(1))); // One digit processed. | 1231 __ movl(EAX, Immediate(Smi::RawValue(1))); // One digit processed. |
1279 __ ret(); | 1232 __ ret(); |
1280 } | 1233 } |
1281 | 1234 |
1282 | |
1283 void Intrinsifier::Bigint_estQuotientDigit(Assembler* assembler) { | 1235 void Intrinsifier::Bigint_estQuotientDigit(Assembler* assembler) { |
1284 // Pseudo code: | 1236 // Pseudo code: |
1285 // static int _estQuotientDigit(Uint32List args, Uint32List digits, int i) { | 1237 // static int _estQuotientDigit(Uint32List args, Uint32List digits, int i) { |
1286 // uint32_t yt = args[_YT]; // _YT == 1. | 1238 // uint32_t yt = args[_YT]; // _YT == 1. |
1287 // uint32_t* dp = &digits[i >> 1]; // i is Smi. | 1239 // uint32_t* dp = &digits[i >> 1]; // i is Smi. |
1288 // uint32_t dh = dp[0]; // dh == digits[i >> 1]. | 1240 // uint32_t dh = dp[0]; // dh == digits[i >> 1]. |
1289 // uint32_t qd; | 1241 // uint32_t qd; |
1290 // if (dh == yt) { | 1242 // if (dh == yt) { |
1291 // qd = DIGIT_MASK; | 1243 // qd = DIGIT_MASK; |
1292 // } else { | 1244 // } else { |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1329 __ Bind(&return_qd); | 1281 __ Bind(&return_qd); |
1330 // args[2] = qd | 1282 // args[2] = qd |
1331 __ movl( | 1283 __ movl( |
1332 FieldAddress(EDI, TypedData::data_offset() + 2 * Bigint::kBytesPerDigit), | 1284 FieldAddress(EDI, TypedData::data_offset() + 2 * Bigint::kBytesPerDigit), |
1333 EAX); | 1285 EAX); |
1334 | 1286 |
1335 __ movl(EAX, Immediate(Smi::RawValue(1))); // One digit processed. | 1287 __ movl(EAX, Immediate(Smi::RawValue(1))); // One digit processed. |
1336 __ ret(); | 1288 __ ret(); |
1337 } | 1289 } |
1338 | 1290 |
1339 | |
1340 void Intrinsifier::Montgomery_mulMod(Assembler* assembler) { | 1291 void Intrinsifier::Montgomery_mulMod(Assembler* assembler) { |
1341 // Pseudo code: | 1292 // Pseudo code: |
1342 // static int _mulMod(Uint32List args, Uint32List digits, int i) { | 1293 // static int _mulMod(Uint32List args, Uint32List digits, int i) { |
1343 // uint32_t rho = args[_RHO]; // _RHO == 2. | 1294 // uint32_t rho = args[_RHO]; // _RHO == 2. |
1344 // uint32_t d = digits[i >> 1]; // i is Smi. | 1295 // uint32_t d = digits[i >> 1]; // i is Smi. |
1345 // uint64_t t = rho*d; | 1296 // uint64_t t = rho*d; |
1346 // args[_MU] = t mod DIGIT_BASE; // _MU == 4. | 1297 // args[_MU] = t mod DIGIT_BASE; // _MU == 4. |
1347 // return 1; | 1298 // return 1; |
1348 // } | 1299 // } |
1349 | 1300 |
(...skipping 14 matching lines...) Expand all Loading... |
1364 | 1315 |
1365 // args[4] = t mod DIGIT_BASE = low32(t) | 1316 // args[4] = t mod DIGIT_BASE = low32(t) |
1366 __ movl( | 1317 __ movl( |
1367 FieldAddress(EDI, TypedData::data_offset() + 4 * Bigint::kBytesPerDigit), | 1318 FieldAddress(EDI, TypedData::data_offset() + 4 * Bigint::kBytesPerDigit), |
1368 EAX); | 1319 EAX); |
1369 | 1320 |
1370 __ movl(EAX, Immediate(Smi::RawValue(1))); // One digit processed. | 1321 __ movl(EAX, Immediate(Smi::RawValue(1))); // One digit processed. |
1371 __ ret(); | 1322 __ ret(); |
1372 } | 1323 } |
1373 | 1324 |
1374 | |
1375 // Check if the last argument is a double, jump to label 'is_smi' if smi | 1325 // Check if the last argument is a double, jump to label 'is_smi' if smi |
1376 // (easy to convert to double), otherwise jump to label 'not_double_smi', | 1326 // (easy to convert to double), otherwise jump to label 'not_double_smi', |
1377 // Returns the last argument in EAX. | 1327 // Returns the last argument in EAX. |
1378 static void TestLastArgumentIsDouble(Assembler* assembler, | 1328 static void TestLastArgumentIsDouble(Assembler* assembler, |
1379 Label* is_smi, | 1329 Label* is_smi, |
1380 Label* not_double_smi) { | 1330 Label* not_double_smi) { |
1381 __ movl(EAX, Address(ESP, +1 * kWordSize)); | 1331 __ movl(EAX, Address(ESP, +1 * kWordSize)); |
1382 __ testl(EAX, Immediate(kSmiTagMask)); | 1332 __ testl(EAX, Immediate(kSmiTagMask)); |
1383 __ j(ZERO, is_smi, Assembler::kNearJump); // Jump if Smi. | 1333 __ j(ZERO, is_smi, Assembler::kNearJump); // Jump if Smi. |
1384 __ CompareClassId(EAX, kDoubleCid, EBX); | 1334 __ CompareClassId(EAX, kDoubleCid, EBX); |
1385 __ j(NOT_EQUAL, not_double_smi, Assembler::kNearJump); | 1335 __ j(NOT_EQUAL, not_double_smi, Assembler::kNearJump); |
1386 // Fall through if double. | 1336 // Fall through if double. |
1387 } | 1337 } |
1388 | 1338 |
1389 | |
1390 // Both arguments on stack, arg0 (left) is a double, arg1 (right) is of unknown | 1339 // Both arguments on stack, arg0 (left) is a double, arg1 (right) is of unknown |
1391 // type. Return true or false object in the register EAX. Any NaN argument | 1340 // type. Return true or false object in the register EAX. Any NaN argument |
1392 // returns false. Any non-double arg1 causes control flow to fall through to the | 1341 // returns false. Any non-double arg1 causes control flow to fall through to the |
1393 // slow case (compiled method body). | 1342 // slow case (compiled method body). |
1394 static void CompareDoubles(Assembler* assembler, Condition true_condition) { | 1343 static void CompareDoubles(Assembler* assembler, Condition true_condition) { |
1395 Label fall_through, is_false, is_true, is_smi, double_op; | 1344 Label fall_through, is_false, is_true, is_smi, double_op; |
1396 TestLastArgumentIsDouble(assembler, &is_smi, &fall_through); | 1345 TestLastArgumentIsDouble(assembler, &is_smi, &fall_through); |
1397 // Both arguments are double, right operand is in EAX. | 1346 // Both arguments are double, right operand is in EAX. |
1398 __ movsd(XMM1, FieldAddress(EAX, Double::value_offset())); | 1347 __ movsd(XMM1, FieldAddress(EAX, Double::value_offset())); |
1399 __ Bind(&double_op); | 1348 __ Bind(&double_op); |
1400 __ movl(EAX, Address(ESP, +2 * kWordSize)); // Left argument. | 1349 __ movl(EAX, Address(ESP, +2 * kWordSize)); // Left argument. |
1401 __ movsd(XMM0, FieldAddress(EAX, Double::value_offset())); | 1350 __ movsd(XMM0, FieldAddress(EAX, Double::value_offset())); |
1402 __ comisd(XMM0, XMM1); | 1351 __ comisd(XMM0, XMM1); |
1403 __ j(PARITY_EVEN, &is_false, Assembler::kNearJump); // NaN -> false; | 1352 __ j(PARITY_EVEN, &is_false, Assembler::kNearJump); // NaN -> false; |
1404 __ j(true_condition, &is_true, Assembler::kNearJump); | 1353 __ j(true_condition, &is_true, Assembler::kNearJump); |
1405 // Fall through false. | 1354 // Fall through false. |
1406 __ Bind(&is_false); | 1355 __ Bind(&is_false); |
1407 __ LoadObject(EAX, Bool::False()); | 1356 __ LoadObject(EAX, Bool::False()); |
1408 __ ret(); | 1357 __ ret(); |
1409 __ Bind(&is_true); | 1358 __ Bind(&is_true); |
1410 __ LoadObject(EAX, Bool::True()); | 1359 __ LoadObject(EAX, Bool::True()); |
1411 __ ret(); | 1360 __ ret(); |
1412 __ Bind(&is_smi); | 1361 __ Bind(&is_smi); |
1413 __ SmiUntag(EAX); | 1362 __ SmiUntag(EAX); |
1414 __ cvtsi2sd(XMM1, EAX); | 1363 __ cvtsi2sd(XMM1, EAX); |
1415 __ jmp(&double_op); | 1364 __ jmp(&double_op); |
1416 __ Bind(&fall_through); | 1365 __ Bind(&fall_through); |
1417 } | 1366 } |
1418 | 1367 |
1419 | |
1420 // arg0 is Double, arg1 is unknown. | 1368 // arg0 is Double, arg1 is unknown. |
1421 void Intrinsifier::Double_greaterThan(Assembler* assembler) { | 1369 void Intrinsifier::Double_greaterThan(Assembler* assembler) { |
1422 CompareDoubles(assembler, ABOVE); | 1370 CompareDoubles(assembler, ABOVE); |
1423 } | 1371 } |
1424 | 1372 |
1425 | |
1426 // arg0 is Double, arg1 is unknown. | 1373 // arg0 is Double, arg1 is unknown. |
1427 void Intrinsifier::Double_greaterEqualThan(Assembler* assembler) { | 1374 void Intrinsifier::Double_greaterEqualThan(Assembler* assembler) { |
1428 CompareDoubles(assembler, ABOVE_EQUAL); | 1375 CompareDoubles(assembler, ABOVE_EQUAL); |
1429 } | 1376 } |
1430 | 1377 |
1431 | |
1432 // arg0 is Double, arg1 is unknown. | 1378 // arg0 is Double, arg1 is unknown. |
1433 void Intrinsifier::Double_lessThan(Assembler* assembler) { | 1379 void Intrinsifier::Double_lessThan(Assembler* assembler) { |
1434 CompareDoubles(assembler, BELOW); | 1380 CompareDoubles(assembler, BELOW); |
1435 } | 1381 } |
1436 | 1382 |
1437 | |
1438 // arg0 is Double, arg1 is unknown. | 1383 // arg0 is Double, arg1 is unknown. |
1439 void Intrinsifier::Double_equal(Assembler* assembler) { | 1384 void Intrinsifier::Double_equal(Assembler* assembler) { |
1440 CompareDoubles(assembler, EQUAL); | 1385 CompareDoubles(assembler, EQUAL); |
1441 } | 1386 } |
1442 | 1387 |
1443 | |
1444 // arg0 is Double, arg1 is unknown. | 1388 // arg0 is Double, arg1 is unknown. |
1445 void Intrinsifier::Double_lessEqualThan(Assembler* assembler) { | 1389 void Intrinsifier::Double_lessEqualThan(Assembler* assembler) { |
1446 CompareDoubles(assembler, BELOW_EQUAL); | 1390 CompareDoubles(assembler, BELOW_EQUAL); |
1447 } | 1391 } |
1448 | 1392 |
1449 | |
1450 // Expects left argument to be double (receiver). Right argument is unknown. | 1393 // Expects left argument to be double (receiver). Right argument is unknown. |
1451 // Both arguments are on stack. | 1394 // Both arguments are on stack. |
1452 static void DoubleArithmeticOperations(Assembler* assembler, Token::Kind kind) { | 1395 static void DoubleArithmeticOperations(Assembler* assembler, Token::Kind kind) { |
1453 Label fall_through, is_smi, double_op; | 1396 Label fall_through, is_smi, double_op; |
1454 TestLastArgumentIsDouble(assembler, &is_smi, &fall_through); | 1397 TestLastArgumentIsDouble(assembler, &is_smi, &fall_through); |
1455 // Both arguments are double, right operand is in EAX. | 1398 // Both arguments are double, right operand is in EAX. |
1456 __ movsd(XMM1, FieldAddress(EAX, Double::value_offset())); | 1399 __ movsd(XMM1, FieldAddress(EAX, Double::value_offset())); |
1457 __ Bind(&double_op); | 1400 __ Bind(&double_op); |
1458 __ movl(EAX, Address(ESP, +2 * kWordSize)); // Left argument. | 1401 __ movl(EAX, Address(ESP, +2 * kWordSize)); // Left argument. |
1459 __ movsd(XMM0, FieldAddress(EAX, Double::value_offset())); | 1402 __ movsd(XMM0, FieldAddress(EAX, Double::value_offset())); |
(...skipping 20 matching lines...) Expand all Loading... |
1480 EBX); | 1423 EBX); |
1481 __ movsd(FieldAddress(EAX, Double::value_offset()), XMM0); | 1424 __ movsd(FieldAddress(EAX, Double::value_offset()), XMM0); |
1482 __ ret(); | 1425 __ ret(); |
1483 __ Bind(&is_smi); | 1426 __ Bind(&is_smi); |
1484 __ SmiUntag(EAX); | 1427 __ SmiUntag(EAX); |
1485 __ cvtsi2sd(XMM1, EAX); | 1428 __ cvtsi2sd(XMM1, EAX); |
1486 __ jmp(&double_op); | 1429 __ jmp(&double_op); |
1487 __ Bind(&fall_through); | 1430 __ Bind(&fall_through); |
1488 } | 1431 } |
1489 | 1432 |
1490 | |
1491 void Intrinsifier::Double_add(Assembler* assembler) { | 1433 void Intrinsifier::Double_add(Assembler* assembler) { |
1492 DoubleArithmeticOperations(assembler, Token::kADD); | 1434 DoubleArithmeticOperations(assembler, Token::kADD); |
1493 } | 1435 } |
1494 | 1436 |
1495 | |
1496 void Intrinsifier::Double_mul(Assembler* assembler) { | 1437 void Intrinsifier::Double_mul(Assembler* assembler) { |
1497 DoubleArithmeticOperations(assembler, Token::kMUL); | 1438 DoubleArithmeticOperations(assembler, Token::kMUL); |
1498 } | 1439 } |
1499 | 1440 |
1500 | |
1501 void Intrinsifier::Double_sub(Assembler* assembler) { | 1441 void Intrinsifier::Double_sub(Assembler* assembler) { |
1502 DoubleArithmeticOperations(assembler, Token::kSUB); | 1442 DoubleArithmeticOperations(assembler, Token::kSUB); |
1503 } | 1443 } |
1504 | 1444 |
1505 | |
1506 void Intrinsifier::Double_div(Assembler* assembler) { | 1445 void Intrinsifier::Double_div(Assembler* assembler) { |
1507 DoubleArithmeticOperations(assembler, Token::kDIV); | 1446 DoubleArithmeticOperations(assembler, Token::kDIV); |
1508 } | 1447 } |
1509 | 1448 |
1510 | |
1511 // Left is double right is integer (Bigint, Mint or Smi) | 1449 // Left is double right is integer (Bigint, Mint or Smi) |
1512 void Intrinsifier::Double_mulFromInteger(Assembler* assembler) { | 1450 void Intrinsifier::Double_mulFromInteger(Assembler* assembler) { |
1513 Label fall_through; | 1451 Label fall_through; |
1514 // Only smis allowed. | 1452 // Only smis allowed. |
1515 __ movl(EAX, Address(ESP, +1 * kWordSize)); | 1453 __ movl(EAX, Address(ESP, +1 * kWordSize)); |
1516 __ testl(EAX, Immediate(kSmiTagMask)); | 1454 __ testl(EAX, Immediate(kSmiTagMask)); |
1517 __ j(NOT_ZERO, &fall_through, Assembler::kNearJump); | 1455 __ j(NOT_ZERO, &fall_through, Assembler::kNearJump); |
1518 // Is Smi. | 1456 // Is Smi. |
1519 __ SmiUntag(EAX); | 1457 __ SmiUntag(EAX); |
1520 __ cvtsi2sd(XMM1, EAX); | 1458 __ cvtsi2sd(XMM1, EAX); |
1521 __ movl(EAX, Address(ESP, +2 * kWordSize)); | 1459 __ movl(EAX, Address(ESP, +2 * kWordSize)); |
1522 __ movsd(XMM0, FieldAddress(EAX, Double::value_offset())); | 1460 __ movsd(XMM0, FieldAddress(EAX, Double::value_offset())); |
1523 __ mulsd(XMM0, XMM1); | 1461 __ mulsd(XMM0, XMM1); |
1524 const Class& double_class = | 1462 const Class& double_class = |
1525 Class::Handle(Isolate::Current()->object_store()->double_class()); | 1463 Class::Handle(Isolate::Current()->object_store()->double_class()); |
1526 __ TryAllocate(double_class, &fall_through, Assembler::kNearJump, | 1464 __ TryAllocate(double_class, &fall_through, Assembler::kNearJump, |
1527 EAX, // Result register. | 1465 EAX, // Result register. |
1528 EBX); | 1466 EBX); |
1529 __ movsd(FieldAddress(EAX, Double::value_offset()), XMM0); | 1467 __ movsd(FieldAddress(EAX, Double::value_offset()), XMM0); |
1530 __ ret(); | 1468 __ ret(); |
1531 __ Bind(&fall_through); | 1469 __ Bind(&fall_through); |
1532 } | 1470 } |
1533 | 1471 |
1534 | |
1535 void Intrinsifier::DoubleFromInteger(Assembler* assembler) { | 1472 void Intrinsifier::DoubleFromInteger(Assembler* assembler) { |
1536 Label fall_through; | 1473 Label fall_through; |
1537 __ movl(EAX, Address(ESP, +1 * kWordSize)); | 1474 __ movl(EAX, Address(ESP, +1 * kWordSize)); |
1538 __ testl(EAX, Immediate(kSmiTagMask)); | 1475 __ testl(EAX, Immediate(kSmiTagMask)); |
1539 __ j(NOT_ZERO, &fall_through, Assembler::kNearJump); | 1476 __ j(NOT_ZERO, &fall_through, Assembler::kNearJump); |
1540 // Is Smi. | 1477 // Is Smi. |
1541 __ SmiUntag(EAX); | 1478 __ SmiUntag(EAX); |
1542 __ cvtsi2sd(XMM0, EAX); | 1479 __ cvtsi2sd(XMM0, EAX); |
1543 const Class& double_class = | 1480 const Class& double_class = |
1544 Class::Handle(Isolate::Current()->object_store()->double_class()); | 1481 Class::Handle(Isolate::Current()->object_store()->double_class()); |
1545 __ TryAllocate(double_class, &fall_through, Assembler::kNearJump, | 1482 __ TryAllocate(double_class, &fall_through, Assembler::kNearJump, |
1546 EAX, // Result register. | 1483 EAX, // Result register. |
1547 EBX); | 1484 EBX); |
1548 __ movsd(FieldAddress(EAX, Double::value_offset()), XMM0); | 1485 __ movsd(FieldAddress(EAX, Double::value_offset()), XMM0); |
1549 __ ret(); | 1486 __ ret(); |
1550 __ Bind(&fall_through); | 1487 __ Bind(&fall_through); |
1551 } | 1488 } |
1552 | 1489 |
1553 | |
1554 void Intrinsifier::Double_getIsNaN(Assembler* assembler) { | 1490 void Intrinsifier::Double_getIsNaN(Assembler* assembler) { |
1555 Label is_true; | 1491 Label is_true; |
1556 __ movl(EAX, Address(ESP, +1 * kWordSize)); | 1492 __ movl(EAX, Address(ESP, +1 * kWordSize)); |
1557 __ movsd(XMM0, FieldAddress(EAX, Double::value_offset())); | 1493 __ movsd(XMM0, FieldAddress(EAX, Double::value_offset())); |
1558 __ comisd(XMM0, XMM0); | 1494 __ comisd(XMM0, XMM0); |
1559 __ j(PARITY_EVEN, &is_true, Assembler::kNearJump); // NaN -> true; | 1495 __ j(PARITY_EVEN, &is_true, Assembler::kNearJump); // NaN -> true; |
1560 __ LoadObject(EAX, Bool::False()); | 1496 __ LoadObject(EAX, Bool::False()); |
1561 __ ret(); | 1497 __ ret(); |
1562 __ Bind(&is_true); | 1498 __ Bind(&is_true); |
1563 __ LoadObject(EAX, Bool::True()); | 1499 __ LoadObject(EAX, Bool::True()); |
1564 __ ret(); | 1500 __ ret(); |
1565 } | 1501 } |
1566 | 1502 |
1567 | |
1568 void Intrinsifier::Double_getIsInfinite(Assembler* assembler) { | 1503 void Intrinsifier::Double_getIsInfinite(Assembler* assembler) { |
1569 Label not_inf; | 1504 Label not_inf; |
1570 __ movl(EAX, Address(ESP, +1 * kWordSize)); | 1505 __ movl(EAX, Address(ESP, +1 * kWordSize)); |
1571 __ movl(EBX, FieldAddress(EAX, Double::value_offset())); | 1506 __ movl(EBX, FieldAddress(EAX, Double::value_offset())); |
1572 | 1507 |
1573 // If the low word isn't zero, then it isn't infinity. | 1508 // If the low word isn't zero, then it isn't infinity. |
1574 __ cmpl(EBX, Immediate(0)); | 1509 __ cmpl(EBX, Immediate(0)); |
1575 __ j(NOT_EQUAL, ¬_inf, Assembler::kNearJump); | 1510 __ j(NOT_EQUAL, ¬_inf, Assembler::kNearJump); |
1576 // Check the high word. | 1511 // Check the high word. |
1577 __ movl(EBX, FieldAddress(EAX, Double::value_offset() + kWordSize)); | 1512 __ movl(EBX, FieldAddress(EAX, Double::value_offset() + kWordSize)); |
1578 // Mask off sign bit. | 1513 // Mask off sign bit. |
1579 __ andl(EBX, Immediate(0x7FFFFFFF)); | 1514 __ andl(EBX, Immediate(0x7FFFFFFF)); |
1580 // Compare with +infinity. | 1515 // Compare with +infinity. |
1581 __ cmpl(EBX, Immediate(0x7FF00000)); | 1516 __ cmpl(EBX, Immediate(0x7FF00000)); |
1582 __ j(NOT_EQUAL, ¬_inf, Assembler::kNearJump); | 1517 __ j(NOT_EQUAL, ¬_inf, Assembler::kNearJump); |
1583 __ LoadObject(EAX, Bool::True()); | 1518 __ LoadObject(EAX, Bool::True()); |
1584 __ ret(); | 1519 __ ret(); |
1585 | 1520 |
1586 __ Bind(¬_inf); | 1521 __ Bind(¬_inf); |
1587 __ LoadObject(EAX, Bool::False()); | 1522 __ LoadObject(EAX, Bool::False()); |
1588 __ ret(); | 1523 __ ret(); |
1589 } | 1524 } |
1590 | 1525 |
1591 | |
1592 void Intrinsifier::Double_getIsNegative(Assembler* assembler) { | 1526 void Intrinsifier::Double_getIsNegative(Assembler* assembler) { |
1593 Label is_false, is_true, is_zero; | 1527 Label is_false, is_true, is_zero; |
1594 __ movl(EAX, Address(ESP, +1 * kWordSize)); | 1528 __ movl(EAX, Address(ESP, +1 * kWordSize)); |
1595 __ movsd(XMM0, FieldAddress(EAX, Double::value_offset())); | 1529 __ movsd(XMM0, FieldAddress(EAX, Double::value_offset())); |
1596 __ xorpd(XMM1, XMM1); // 0.0 -> XMM1. | 1530 __ xorpd(XMM1, XMM1); // 0.0 -> XMM1. |
1597 __ comisd(XMM0, XMM1); | 1531 __ comisd(XMM0, XMM1); |
1598 __ j(PARITY_EVEN, &is_false, Assembler::kNearJump); // NaN -> false. | 1532 __ j(PARITY_EVEN, &is_false, Assembler::kNearJump); // NaN -> false. |
1599 __ j(EQUAL, &is_zero, Assembler::kNearJump); // Check for negative zero. | 1533 __ j(EQUAL, &is_zero, Assembler::kNearJump); // Check for negative zero. |
1600 __ j(ABOVE_EQUAL, &is_false, Assembler::kNearJump); // >= 0 -> false. | 1534 __ j(ABOVE_EQUAL, &is_false, Assembler::kNearJump); // >= 0 -> false. |
1601 __ Bind(&is_true); | 1535 __ Bind(&is_true); |
1602 __ LoadObject(EAX, Bool::True()); | 1536 __ LoadObject(EAX, Bool::True()); |
1603 __ ret(); | 1537 __ ret(); |
1604 __ Bind(&is_false); | 1538 __ Bind(&is_false); |
1605 __ LoadObject(EAX, Bool::False()); | 1539 __ LoadObject(EAX, Bool::False()); |
1606 __ ret(); | 1540 __ ret(); |
1607 __ Bind(&is_zero); | 1541 __ Bind(&is_zero); |
1608 // Check for negative zero (get the sign bit). | 1542 // Check for negative zero (get the sign bit). |
1609 __ movmskpd(EAX, XMM0); | 1543 __ movmskpd(EAX, XMM0); |
1610 __ testl(EAX, Immediate(1)); | 1544 __ testl(EAX, Immediate(1)); |
1611 __ j(NOT_ZERO, &is_true, Assembler::kNearJump); | 1545 __ j(NOT_ZERO, &is_true, Assembler::kNearJump); |
1612 __ jmp(&is_false, Assembler::kNearJump); | 1546 __ jmp(&is_false, Assembler::kNearJump); |
1613 } | 1547 } |
1614 | 1548 |
1615 | |
1616 void Intrinsifier::DoubleToInteger(Assembler* assembler) { | 1549 void Intrinsifier::DoubleToInteger(Assembler* assembler) { |
1617 __ movl(EAX, Address(ESP, +1 * kWordSize)); | 1550 __ movl(EAX, Address(ESP, +1 * kWordSize)); |
1618 __ movsd(XMM0, FieldAddress(EAX, Double::value_offset())); | 1551 __ movsd(XMM0, FieldAddress(EAX, Double::value_offset())); |
1619 __ cvttsd2si(EAX, XMM0); | 1552 __ cvttsd2si(EAX, XMM0); |
1620 // Overflow is signalled with minint. | 1553 // Overflow is signalled with minint. |
1621 Label fall_through; | 1554 Label fall_through; |
1622 // Check for overflow and that it fits into Smi. | 1555 // Check for overflow and that it fits into Smi. |
1623 __ cmpl(EAX, Immediate(0xC0000000)); | 1556 __ cmpl(EAX, Immediate(0xC0000000)); |
1624 __ j(NEGATIVE, &fall_through, Assembler::kNearJump); | 1557 __ j(NEGATIVE, &fall_through, Assembler::kNearJump); |
1625 __ SmiTag(EAX); | 1558 __ SmiTag(EAX); |
1626 __ ret(); | 1559 __ ret(); |
1627 __ Bind(&fall_through); | 1560 __ Bind(&fall_through); |
1628 } | 1561 } |
1629 | 1562 |
1630 | |
1631 // Argument type is not known | 1563 // Argument type is not known |
1632 void Intrinsifier::MathSqrt(Assembler* assembler) { | 1564 void Intrinsifier::MathSqrt(Assembler* assembler) { |
1633 Label fall_through, is_smi, double_op; | 1565 Label fall_through, is_smi, double_op; |
1634 TestLastArgumentIsDouble(assembler, &is_smi, &fall_through); | 1566 TestLastArgumentIsDouble(assembler, &is_smi, &fall_through); |
1635 // Argument is double and is in EAX. | 1567 // Argument is double and is in EAX. |
1636 __ movsd(XMM1, FieldAddress(EAX, Double::value_offset())); | 1568 __ movsd(XMM1, FieldAddress(EAX, Double::value_offset())); |
1637 __ Bind(&double_op); | 1569 __ Bind(&double_op); |
1638 __ sqrtsd(XMM0, XMM1); | 1570 __ sqrtsd(XMM0, XMM1); |
1639 const Class& double_class = | 1571 const Class& double_class = |
1640 Class::Handle(Isolate::Current()->object_store()->double_class()); | 1572 Class::Handle(Isolate::Current()->object_store()->double_class()); |
1641 __ TryAllocate(double_class, &fall_through, Assembler::kNearJump, | 1573 __ TryAllocate(double_class, &fall_through, Assembler::kNearJump, |
1642 EAX, // Result register. | 1574 EAX, // Result register. |
1643 EBX); | 1575 EBX); |
1644 __ movsd(FieldAddress(EAX, Double::value_offset()), XMM0); | 1576 __ movsd(FieldAddress(EAX, Double::value_offset()), XMM0); |
1645 __ ret(); | 1577 __ ret(); |
1646 __ Bind(&is_smi); | 1578 __ Bind(&is_smi); |
1647 __ SmiUntag(EAX); | 1579 __ SmiUntag(EAX); |
1648 __ cvtsi2sd(XMM1, EAX); | 1580 __ cvtsi2sd(XMM1, EAX); |
1649 __ jmp(&double_op); | 1581 __ jmp(&double_op); |
1650 __ Bind(&fall_through); | 1582 __ Bind(&fall_through); |
1651 } | 1583 } |
1652 | 1584 |
1653 | |
1654 // var state = ((_A * (_state[kSTATE_LO])) + _state[kSTATE_HI]) & _MASK_64; | 1585 // var state = ((_A * (_state[kSTATE_LO])) + _state[kSTATE_HI]) & _MASK_64; |
1655 // _state[kSTATE_LO] = state & _MASK_32; | 1586 // _state[kSTATE_LO] = state & _MASK_32; |
1656 // _state[kSTATE_HI] = state >> 32; | 1587 // _state[kSTATE_HI] = state >> 32; |
1657 void Intrinsifier::Random_nextState(Assembler* assembler) { | 1588 void Intrinsifier::Random_nextState(Assembler* assembler) { |
1658 const Library& math_lib = Library::Handle(Library::MathLibrary()); | 1589 const Library& math_lib = Library::Handle(Library::MathLibrary()); |
1659 ASSERT(!math_lib.IsNull()); | 1590 ASSERT(!math_lib.IsNull()); |
1660 const Class& random_class = | 1591 const Class& random_class = |
1661 Class::Handle(math_lib.LookupClassAllowPrivate(Symbols::_Random())); | 1592 Class::Handle(math_lib.LookupClassAllowPrivate(Symbols::_Random())); |
1662 ASSERT(!random_class.IsNull()); | 1593 ASSERT(!random_class.IsNull()); |
1663 const Field& state_field = Field::ZoneHandle( | 1594 const Field& state_field = Field::ZoneHandle( |
(...skipping 25 matching lines...) Expand all Loading... |
1689 __ movl(EAX, Immediate(a_int32_value)); | 1620 __ movl(EAX, Immediate(a_int32_value)); |
1690 // 64-bit multiply EAX * value -> EDX:EAX. | 1621 // 64-bit multiply EAX * value -> EDX:EAX. |
1691 __ mull(addr_0); | 1622 __ mull(addr_0); |
1692 __ addl(EAX, addr_1); | 1623 __ addl(EAX, addr_1); |
1693 __ adcl(EDX, Immediate(0)); | 1624 __ adcl(EDX, Immediate(0)); |
1694 __ movl(addr_1, EDX); | 1625 __ movl(addr_1, EDX); |
1695 __ movl(addr_0, EAX); | 1626 __ movl(addr_0, EAX); |
1696 __ ret(); | 1627 __ ret(); |
1697 } | 1628 } |
1698 | 1629 |
1699 | |
1700 // Identity comparison. | 1630 // Identity comparison. |
1701 void Intrinsifier::ObjectEquals(Assembler* assembler) { | 1631 void Intrinsifier::ObjectEquals(Assembler* assembler) { |
1702 Label is_true; | 1632 Label is_true; |
1703 __ movl(EAX, Address(ESP, +1 * kWordSize)); | 1633 __ movl(EAX, Address(ESP, +1 * kWordSize)); |
1704 __ cmpl(EAX, Address(ESP, +2 * kWordSize)); | 1634 __ cmpl(EAX, Address(ESP, +2 * kWordSize)); |
1705 __ j(EQUAL, &is_true, Assembler::kNearJump); | 1635 __ j(EQUAL, &is_true, Assembler::kNearJump); |
1706 __ LoadObject(EAX, Bool::False()); | 1636 __ LoadObject(EAX, Bool::False()); |
1707 __ ret(); | 1637 __ ret(); |
1708 __ Bind(&is_true); | 1638 __ Bind(&is_true); |
1709 __ LoadObject(EAX, Bool::True()); | 1639 __ LoadObject(EAX, Bool::True()); |
1710 __ ret(); | 1640 __ ret(); |
1711 } | 1641 } |
1712 | 1642 |
1713 | |
1714 static void RangeCheck(Assembler* assembler, | 1643 static void RangeCheck(Assembler* assembler, |
1715 Register reg, | 1644 Register reg, |
1716 intptr_t low, | 1645 intptr_t low, |
1717 intptr_t high, | 1646 intptr_t high, |
1718 Condition cc, | 1647 Condition cc, |
1719 Label* target) { | 1648 Label* target) { |
1720 __ subl(reg, Immediate(low)); | 1649 __ subl(reg, Immediate(low)); |
1721 __ cmpl(reg, Immediate(high - low)); | 1650 __ cmpl(reg, Immediate(high - low)); |
1722 __ j(cc, target); | 1651 __ j(cc, target); |
1723 } | 1652 } |
1724 | 1653 |
1725 | |
1726 const Condition kIfNotInRange = ABOVE; | 1654 const Condition kIfNotInRange = ABOVE; |
1727 const Condition kIfInRange = BELOW_EQUAL; | 1655 const Condition kIfInRange = BELOW_EQUAL; |
1728 | 1656 |
1729 | |
1730 static void JumpIfInteger(Assembler* assembler, Register cid, Label* target) { | 1657 static void JumpIfInteger(Assembler* assembler, Register cid, Label* target) { |
1731 RangeCheck(assembler, cid, kSmiCid, kBigintCid, kIfInRange, target); | 1658 RangeCheck(assembler, cid, kSmiCid, kBigintCid, kIfInRange, target); |
1732 } | 1659 } |
1733 | 1660 |
1734 | |
1735 static void JumpIfNotInteger(Assembler* assembler, | 1661 static void JumpIfNotInteger(Assembler* assembler, |
1736 Register cid, | 1662 Register cid, |
1737 Label* target) { | 1663 Label* target) { |
1738 RangeCheck(assembler, cid, kSmiCid, kBigintCid, kIfNotInRange, target); | 1664 RangeCheck(assembler, cid, kSmiCid, kBigintCid, kIfNotInRange, target); |
1739 } | 1665 } |
1740 | 1666 |
1741 | |
1742 static void JumpIfString(Assembler* assembler, Register cid, Label* target) { | 1667 static void JumpIfString(Assembler* assembler, Register cid, Label* target) { |
1743 RangeCheck(assembler, cid, kOneByteStringCid, kExternalTwoByteStringCid, | 1668 RangeCheck(assembler, cid, kOneByteStringCid, kExternalTwoByteStringCid, |
1744 kIfInRange, target); | 1669 kIfInRange, target); |
1745 } | 1670 } |
1746 | 1671 |
1747 | |
1748 static void JumpIfNotString(Assembler* assembler, Register cid, Label* target) { | 1672 static void JumpIfNotString(Assembler* assembler, Register cid, Label* target) { |
1749 RangeCheck(assembler, cid, kOneByteStringCid, kExternalTwoByteStringCid, | 1673 RangeCheck(assembler, cid, kOneByteStringCid, kExternalTwoByteStringCid, |
1750 kIfNotInRange, target); | 1674 kIfNotInRange, target); |
1751 } | 1675 } |
1752 | 1676 |
1753 | |
1754 // Return type quickly for simple types (not parameterized and not signature). | 1677 // Return type quickly for simple types (not parameterized and not signature). |
1755 void Intrinsifier::ObjectRuntimeType(Assembler* assembler) { | 1678 void Intrinsifier::ObjectRuntimeType(Assembler* assembler) { |
1756 Label fall_through, use_canonical_type, not_double, not_integer; | 1679 Label fall_through, use_canonical_type, not_double, not_integer; |
1757 __ movl(EAX, Address(ESP, +1 * kWordSize)); | 1680 __ movl(EAX, Address(ESP, +1 * kWordSize)); |
1758 __ LoadClassIdMayBeSmi(EDI, EAX); | 1681 __ LoadClassIdMayBeSmi(EDI, EAX); |
1759 | 1682 |
1760 __ cmpl(EDI, Immediate(kClosureCid)); | 1683 __ cmpl(EDI, Immediate(kClosureCid)); |
1761 __ j(EQUAL, &fall_through); // Instance is a closure. | 1684 __ j(EQUAL, &fall_through); // Instance is a closure. |
1762 | 1685 |
1763 __ cmpl(EDI, Immediate(kNumPredefinedCids)); | 1686 __ cmpl(EDI, Immediate(kNumPredefinedCids)); |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1800 __ cmpl(EDI, Immediate(0)); | 1723 __ cmpl(EDI, Immediate(0)); |
1801 __ j(NOT_EQUAL, &fall_through, Assembler::kNearJump); | 1724 __ j(NOT_EQUAL, &fall_through, Assembler::kNearJump); |
1802 __ movl(EAX, FieldAddress(EBX, Class::canonical_type_offset())); | 1725 __ movl(EAX, FieldAddress(EBX, Class::canonical_type_offset())); |
1803 __ CompareObject(EAX, Object::null_object()); | 1726 __ CompareObject(EAX, Object::null_object()); |
1804 __ j(EQUAL, &fall_through, Assembler::kNearJump); // Not yet set. | 1727 __ j(EQUAL, &fall_through, Assembler::kNearJump); // Not yet set. |
1805 __ ret(); | 1728 __ ret(); |
1806 | 1729 |
1807 __ Bind(&fall_through); | 1730 __ Bind(&fall_through); |
1808 } | 1731 } |
1809 | 1732 |
1810 | |
1811 void Intrinsifier::ObjectHaveSameRuntimeType(Assembler* assembler) { | 1733 void Intrinsifier::ObjectHaveSameRuntimeType(Assembler* assembler) { |
1812 Label fall_through, different_cids, equal, not_equal, not_integer; | 1734 Label fall_through, different_cids, equal, not_equal, not_integer; |
1813 | 1735 |
1814 __ movl(EAX, Address(ESP, +1 * kWordSize)); | 1736 __ movl(EAX, Address(ESP, +1 * kWordSize)); |
1815 __ LoadClassIdMayBeSmi(EDI, EAX); | 1737 __ LoadClassIdMayBeSmi(EDI, EAX); |
1816 | 1738 |
1817 // Check if left hand size is a closure. Closures are handled in the runtime. | 1739 // Check if left hand size is a closure. Closures are handled in the runtime. |
1818 __ cmpl(EDI, Immediate(kClosureCid)); | 1740 __ cmpl(EDI, Immediate(kClosureCid)); |
1819 __ j(EQUAL, &fall_through); | 1741 __ j(EQUAL, &fall_through); |
1820 | 1742 |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1864 // Strings only have the same runtime type as other strings. | 1786 // Strings only have the same runtime type as other strings. |
1865 // Fall-through to the not equal case. | 1787 // Fall-through to the not equal case. |
1866 | 1788 |
1867 __ Bind(¬_equal); | 1789 __ Bind(¬_equal); |
1868 __ LoadObject(EAX, Bool::False()); | 1790 __ LoadObject(EAX, Bool::False()); |
1869 __ ret(); | 1791 __ ret(); |
1870 | 1792 |
1871 __ Bind(&fall_through); | 1793 __ Bind(&fall_through); |
1872 } | 1794 } |
1873 | 1795 |
1874 | |
1875 void Intrinsifier::String_getHashCode(Assembler* assembler) { | 1796 void Intrinsifier::String_getHashCode(Assembler* assembler) { |
1876 Label fall_through; | 1797 Label fall_through; |
1877 __ movl(EAX, Address(ESP, +1 * kWordSize)); // String object. | 1798 __ movl(EAX, Address(ESP, +1 * kWordSize)); // String object. |
1878 __ movl(EAX, FieldAddress(EAX, String::hash_offset())); | 1799 __ movl(EAX, FieldAddress(EAX, String::hash_offset())); |
1879 __ cmpl(EAX, Immediate(0)); | 1800 __ cmpl(EAX, Immediate(0)); |
1880 __ j(EQUAL, &fall_through, Assembler::kNearJump); | 1801 __ j(EQUAL, &fall_through, Assembler::kNearJump); |
1881 __ ret(); | 1802 __ ret(); |
1882 __ Bind(&fall_through); | 1803 __ Bind(&fall_through); |
1883 // Hash not yet computed. | 1804 // Hash not yet computed. |
1884 } | 1805 } |
1885 | 1806 |
1886 | |
1887 // bool _substringMatches(int start, String other) | 1807 // bool _substringMatches(int start, String other) |
1888 void Intrinsifier::StringBaseSubstringMatches(Assembler* assembler) { | 1808 void Intrinsifier::StringBaseSubstringMatches(Assembler* assembler) { |
1889 // For precompilation, not implemented on IA32. | 1809 // For precompilation, not implemented on IA32. |
1890 } | 1810 } |
1891 | 1811 |
1892 | |
1893 void Intrinsifier::Object_getHash(Assembler* assembler) { | 1812 void Intrinsifier::Object_getHash(Assembler* assembler) { |
1894 UNREACHABLE(); | 1813 UNREACHABLE(); |
1895 } | 1814 } |
1896 | 1815 |
1897 | |
1898 void Intrinsifier::Object_setHash(Assembler* assembler) { | 1816 void Intrinsifier::Object_setHash(Assembler* assembler) { |
1899 UNREACHABLE(); | 1817 UNREACHABLE(); |
1900 } | 1818 } |
1901 | 1819 |
1902 | |
1903 void Intrinsifier::StringBaseCharAt(Assembler* assembler) { | 1820 void Intrinsifier::StringBaseCharAt(Assembler* assembler) { |
1904 Label fall_through, try_two_byte_string; | 1821 Label fall_through, try_two_byte_string; |
1905 __ movl(EBX, Address(ESP, +1 * kWordSize)); // Index. | 1822 __ movl(EBX, Address(ESP, +1 * kWordSize)); // Index. |
1906 __ movl(EAX, Address(ESP, +2 * kWordSize)); // String. | 1823 __ movl(EAX, Address(ESP, +2 * kWordSize)); // String. |
1907 __ testl(EBX, Immediate(kSmiTagMask)); | 1824 __ testl(EBX, Immediate(kSmiTagMask)); |
1908 __ j(NOT_ZERO, &fall_through, Assembler::kNearJump); // Non-smi index. | 1825 __ j(NOT_ZERO, &fall_through, Assembler::kNearJump); // Non-smi index. |
1909 // Range check. | 1826 // Range check. |
1910 __ cmpl(EBX, FieldAddress(EAX, String::length_offset())); | 1827 __ cmpl(EBX, FieldAddress(EAX, String::length_offset())); |
1911 // Runtime throws exception. | 1828 // Runtime throws exception. |
1912 __ j(ABOVE_EQUAL, &fall_through, Assembler::kNearJump); | 1829 __ j(ABOVE_EQUAL, &fall_through, Assembler::kNearJump); |
(...skipping 18 matching lines...) Expand all Loading... |
1931 __ j(GREATER_EQUAL, &fall_through); | 1848 __ j(GREATER_EQUAL, &fall_through); |
1932 __ movl(EAX, | 1849 __ movl(EAX, |
1933 Immediate(reinterpret_cast<uword>(Symbols::PredefinedAddress()))); | 1850 Immediate(reinterpret_cast<uword>(Symbols::PredefinedAddress()))); |
1934 __ movl(EAX, Address(EAX, EBX, TIMES_4, | 1851 __ movl(EAX, Address(EAX, EBX, TIMES_4, |
1935 Symbols::kNullCharCodeSymbolOffset * kWordSize)); | 1852 Symbols::kNullCharCodeSymbolOffset * kWordSize)); |
1936 __ ret(); | 1853 __ ret(); |
1937 | 1854 |
1938 __ Bind(&fall_through); | 1855 __ Bind(&fall_through); |
1939 } | 1856 } |
1940 | 1857 |
1941 | |
1942 void Intrinsifier::StringBaseIsEmpty(Assembler* assembler) { | 1858 void Intrinsifier::StringBaseIsEmpty(Assembler* assembler) { |
1943 Label is_true; | 1859 Label is_true; |
1944 // Get length. | 1860 // Get length. |
1945 __ movl(EAX, Address(ESP, +1 * kWordSize)); // String object. | 1861 __ movl(EAX, Address(ESP, +1 * kWordSize)); // String object. |
1946 __ movl(EAX, FieldAddress(EAX, String::length_offset())); | 1862 __ movl(EAX, FieldAddress(EAX, String::length_offset())); |
1947 __ cmpl(EAX, Immediate(Smi::RawValue(0))); | 1863 __ cmpl(EAX, Immediate(Smi::RawValue(0))); |
1948 __ j(EQUAL, &is_true, Assembler::kNearJump); | 1864 __ j(EQUAL, &is_true, Assembler::kNearJump); |
1949 __ LoadObject(EAX, Bool::False()); | 1865 __ LoadObject(EAX, Bool::False()); |
1950 __ ret(); | 1866 __ ret(); |
1951 __ Bind(&is_true); | 1867 __ Bind(&is_true); |
1952 __ LoadObject(EAX, Bool::True()); | 1868 __ LoadObject(EAX, Bool::True()); |
1953 __ ret(); | 1869 __ ret(); |
1954 } | 1870 } |
1955 | 1871 |
1956 | |
1957 void Intrinsifier::OneByteString_getHashCode(Assembler* assembler) { | 1872 void Intrinsifier::OneByteString_getHashCode(Assembler* assembler) { |
1958 Label compute_hash; | 1873 Label compute_hash; |
1959 __ movl(EBX, Address(ESP, +1 * kWordSize)); // OneByteString object. | 1874 __ movl(EBX, Address(ESP, +1 * kWordSize)); // OneByteString object. |
1960 __ movl(EAX, FieldAddress(EBX, String::hash_offset())); | 1875 __ movl(EAX, FieldAddress(EBX, String::hash_offset())); |
1961 __ cmpl(EAX, Immediate(0)); | 1876 __ cmpl(EAX, Immediate(0)); |
1962 __ j(EQUAL, &compute_hash, Assembler::kNearJump); | 1877 __ j(EQUAL, &compute_hash, Assembler::kNearJump); |
1963 __ ret(); | 1878 __ ret(); |
1964 | 1879 |
1965 __ Bind(&compute_hash); | 1880 __ Bind(&compute_hash); |
1966 // Hash not yet computed, use algorithm of class StringHasher. | 1881 // Hash not yet computed, use algorithm of class StringHasher. |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2015 // return hash_ == 0 ? 1 : hash_; | 1930 // return hash_ == 0 ? 1 : hash_; |
2016 __ cmpl(EAX, Immediate(0)); | 1931 __ cmpl(EAX, Immediate(0)); |
2017 __ j(NOT_EQUAL, &set_hash_code, Assembler::kNearJump); | 1932 __ j(NOT_EQUAL, &set_hash_code, Assembler::kNearJump); |
2018 __ incl(EAX); | 1933 __ incl(EAX); |
2019 __ Bind(&set_hash_code); | 1934 __ Bind(&set_hash_code); |
2020 __ SmiTag(EAX); | 1935 __ SmiTag(EAX); |
2021 __ StoreIntoSmiField(FieldAddress(EBX, String::hash_offset()), EAX); | 1936 __ StoreIntoSmiField(FieldAddress(EBX, String::hash_offset()), EAX); |
2022 __ ret(); | 1937 __ ret(); |
2023 } | 1938 } |
2024 | 1939 |
2025 | |
2026 // Allocates one-byte string of length 'end - start'. The content is not | 1940 // Allocates one-byte string of length 'end - start'. The content is not |
2027 // initialized. 'length-reg' contains tagged length. | 1941 // initialized. 'length-reg' contains tagged length. |
2028 // Returns new string as tagged pointer in EAX. | 1942 // Returns new string as tagged pointer in EAX. |
2029 static void TryAllocateOnebyteString(Assembler* assembler, | 1943 static void TryAllocateOnebyteString(Assembler* assembler, |
2030 Label* ok, | 1944 Label* ok, |
2031 Label* failure, | 1945 Label* failure, |
2032 Register length_reg) { | 1946 Register length_reg) { |
2033 NOT_IN_PRODUCT( | 1947 NOT_IN_PRODUCT( |
2034 __ MaybeTraceAllocation(kOneByteStringCid, EAX, failure, false)); | 1948 __ MaybeTraceAllocation(kOneByteStringCid, EAX, failure, false)); |
2035 if (length_reg != EDI) { | 1949 if (length_reg != EDI) { |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2095 EDI); | 2009 EDI); |
2096 // Clear hash. | 2010 // Clear hash. |
2097 __ ZeroInitSmiField(FieldAddress(EAX, String::hash_offset())); | 2011 __ ZeroInitSmiField(FieldAddress(EAX, String::hash_offset())); |
2098 __ jmp(ok, Assembler::kNearJump); | 2012 __ jmp(ok, Assembler::kNearJump); |
2099 | 2013 |
2100 __ Bind(&pop_and_fail); | 2014 __ Bind(&pop_and_fail); |
2101 __ popl(EDI); | 2015 __ popl(EDI); |
2102 __ jmp(failure); | 2016 __ jmp(failure); |
2103 } | 2017 } |
2104 | 2018 |
2105 | |
2106 // Arg0: OneByteString (receiver) | 2019 // Arg0: OneByteString (receiver) |
2107 // Arg1: Start index as Smi. | 2020 // Arg1: Start index as Smi. |
2108 // Arg2: End index as Smi. | 2021 // Arg2: End index as Smi. |
2109 // The indexes must be valid. | 2022 // The indexes must be valid. |
2110 void Intrinsifier::OneByteString_substringUnchecked(Assembler* assembler) { | 2023 void Intrinsifier::OneByteString_substringUnchecked(Assembler* assembler) { |
2111 const intptr_t kStringOffset = 3 * kWordSize; | 2024 const intptr_t kStringOffset = 3 * kWordSize; |
2112 const intptr_t kStartIndexOffset = 2 * kWordSize; | 2025 const intptr_t kStartIndexOffset = 2 * kWordSize; |
2113 const intptr_t kEndIndexOffset = 1 * kWordSize; | 2026 const intptr_t kEndIndexOffset = 1 * kWordSize; |
2114 Label fall_through, ok; | 2027 Label fall_through, ok; |
2115 __ movl(EAX, Address(ESP, +kStartIndexOffset)); | 2028 __ movl(EAX, Address(ESP, +kStartIndexOffset)); |
(...skipping 28 matching lines...) Expand all Loading... |
2144 __ movzxb(EBX, Address(EDI, EDX, TIMES_1, 0)); | 2057 __ movzxb(EBX, Address(EDI, EDX, TIMES_1, 0)); |
2145 __ movb(FieldAddress(EAX, EDX, TIMES_1, OneByteString::data_offset()), BL); | 2058 __ movb(FieldAddress(EAX, EDX, TIMES_1, OneByteString::data_offset()), BL); |
2146 __ incl(EDX); | 2059 __ incl(EDX); |
2147 __ Bind(&check); | 2060 __ Bind(&check); |
2148 __ cmpl(EDX, ECX); | 2061 __ cmpl(EDX, ECX); |
2149 __ j(LESS, &loop, Assembler::kNearJump); | 2062 __ j(LESS, &loop, Assembler::kNearJump); |
2150 __ ret(); | 2063 __ ret(); |
2151 __ Bind(&fall_through); | 2064 __ Bind(&fall_through); |
2152 } | 2065 } |
2153 | 2066 |
2154 | |
2155 void Intrinsifier::OneByteStringSetAt(Assembler* assembler) { | 2067 void Intrinsifier::OneByteStringSetAt(Assembler* assembler) { |
2156 __ movl(ECX, Address(ESP, +1 * kWordSize)); // Value. | 2068 __ movl(ECX, Address(ESP, +1 * kWordSize)); // Value. |
2157 __ movl(EBX, Address(ESP, +2 * kWordSize)); // Index. | 2069 __ movl(EBX, Address(ESP, +2 * kWordSize)); // Index. |
2158 __ movl(EAX, Address(ESP, +3 * kWordSize)); // OneByteString. | 2070 __ movl(EAX, Address(ESP, +3 * kWordSize)); // OneByteString. |
2159 __ SmiUntag(EBX); | 2071 __ SmiUntag(EBX); |
2160 __ SmiUntag(ECX); | 2072 __ SmiUntag(ECX); |
2161 __ movb(FieldAddress(EAX, EBX, TIMES_1, OneByteString::data_offset()), CL); | 2073 __ movb(FieldAddress(EAX, EBX, TIMES_1, OneByteString::data_offset()), CL); |
2162 __ ret(); | 2074 __ ret(); |
2163 } | 2075 } |
2164 | 2076 |
2165 | |
2166 void Intrinsifier::OneByteString_allocate(Assembler* assembler) { | 2077 void Intrinsifier::OneByteString_allocate(Assembler* assembler) { |
2167 __ movl(EDI, Address(ESP, +1 * kWordSize)); // Length. | 2078 __ movl(EDI, Address(ESP, +1 * kWordSize)); // Length. |
2168 Label fall_through, ok; | 2079 Label fall_through, ok; |
2169 TryAllocateOnebyteString(assembler, &ok, &fall_through, EDI); | 2080 TryAllocateOnebyteString(assembler, &ok, &fall_through, EDI); |
2170 // EDI: Start address to copy from (untagged). | 2081 // EDI: Start address to copy from (untagged). |
2171 | 2082 |
2172 __ Bind(&ok); | 2083 __ Bind(&ok); |
2173 __ ret(); | 2084 __ ret(); |
2174 | 2085 |
2175 __ Bind(&fall_through); | 2086 __ Bind(&fall_through); |
2176 } | 2087 } |
2177 | 2088 |
2178 | |
2179 // TODO(srdjan): Add combinations (one-byte/two-byte/external strings). | 2089 // TODO(srdjan): Add combinations (one-byte/two-byte/external strings). |
2180 static void StringEquality(Assembler* assembler, intptr_t string_cid) { | 2090 static void StringEquality(Assembler* assembler, intptr_t string_cid) { |
2181 Label fall_through, is_true, is_false, loop; | 2091 Label fall_through, is_true, is_false, loop; |
2182 __ movl(EAX, Address(ESP, +2 * kWordSize)); // This. | 2092 __ movl(EAX, Address(ESP, +2 * kWordSize)); // This. |
2183 __ movl(EBX, Address(ESP, +1 * kWordSize)); // Other. | 2093 __ movl(EBX, Address(ESP, +1 * kWordSize)); // Other. |
2184 | 2094 |
2185 // Are identical? | 2095 // Are identical? |
2186 __ cmpl(EAX, EBX); | 2096 __ cmpl(EAX, EBX); |
2187 __ j(EQUAL, &is_true, Assembler::kNearJump); | 2097 __ j(EQUAL, &is_true, Assembler::kNearJump); |
2188 | 2098 |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2225 __ LoadObject(EAX, Bool::True()); | 2135 __ LoadObject(EAX, Bool::True()); |
2226 __ ret(); | 2136 __ ret(); |
2227 | 2137 |
2228 __ Bind(&is_false); | 2138 __ Bind(&is_false); |
2229 __ LoadObject(EAX, Bool::False()); | 2139 __ LoadObject(EAX, Bool::False()); |
2230 __ ret(); | 2140 __ ret(); |
2231 | 2141 |
2232 __ Bind(&fall_through); | 2142 __ Bind(&fall_through); |
2233 } | 2143 } |
2234 | 2144 |
2235 | |
2236 void Intrinsifier::OneByteString_equality(Assembler* assembler) { | 2145 void Intrinsifier::OneByteString_equality(Assembler* assembler) { |
2237 StringEquality(assembler, kOneByteStringCid); | 2146 StringEquality(assembler, kOneByteStringCid); |
2238 } | 2147 } |
2239 | 2148 |
2240 | |
2241 void Intrinsifier::TwoByteString_equality(Assembler* assembler) { | 2149 void Intrinsifier::TwoByteString_equality(Assembler* assembler) { |
2242 StringEquality(assembler, kTwoByteStringCid); | 2150 StringEquality(assembler, kTwoByteStringCid); |
2243 } | 2151 } |
2244 | 2152 |
2245 | |
2246 void Intrinsifier::IntrinsifyRegExpExecuteMatch(Assembler* assembler, | 2153 void Intrinsifier::IntrinsifyRegExpExecuteMatch(Assembler* assembler, |
2247 bool sticky) { | 2154 bool sticky) { |
2248 if (FLAG_interpret_irregexp) return; | 2155 if (FLAG_interpret_irregexp) return; |
2249 | 2156 |
2250 static const intptr_t kRegExpParamOffset = 3 * kWordSize; | 2157 static const intptr_t kRegExpParamOffset = 3 * kWordSize; |
2251 static const intptr_t kStringParamOffset = 2 * kWordSize; | 2158 static const intptr_t kStringParamOffset = 2 * kWordSize; |
2252 // start_index smi is located at offset 1. | 2159 // start_index smi is located at offset 1. |
2253 | 2160 |
2254 // Incoming registers: | 2161 // Incoming registers: |
2255 // EAX: Function. (Will be loaded with the specialized matcher function.) | 2162 // EAX: Function. (Will be loaded with the specialized matcher function.) |
2256 // ECX: Unknown. (Must be GC safe on tail call.) | 2163 // ECX: Unknown. (Must be GC safe on tail call.) |
2257 // EDX: Arguments descriptor. (Will be preserved.) | 2164 // EDX: Arguments descriptor. (Will be preserved.) |
2258 | 2165 |
2259 // Load the specialized function pointer into EAX. Leverage the fact the | 2166 // Load the specialized function pointer into EAX. Leverage the fact the |
2260 // string CIDs as well as stored function pointers are in sequence. | 2167 // string CIDs as well as stored function pointers are in sequence. |
2261 __ movl(EBX, Address(ESP, kRegExpParamOffset)); | 2168 __ movl(EBX, Address(ESP, kRegExpParamOffset)); |
2262 __ movl(EDI, Address(ESP, kStringParamOffset)); | 2169 __ movl(EDI, Address(ESP, kStringParamOffset)); |
2263 __ LoadClassId(EDI, EDI); | 2170 __ LoadClassId(EDI, EDI); |
2264 __ SubImmediate(EDI, Immediate(kOneByteStringCid)); | 2171 __ SubImmediate(EDI, Immediate(kOneByteStringCid)); |
2265 __ movl(EAX, FieldAddress(EBX, EDI, TIMES_4, RegExp::function_offset( | 2172 __ movl(EAX, |
2266 kOneByteStringCid, sticky))); | 2173 FieldAddress(EBX, EDI, TIMES_4, |
| 2174 RegExp::function_offset(kOneByteStringCid, sticky))); |
2267 | 2175 |
2268 // Registers are now set up for the lazy compile stub. It expects the function | 2176 // Registers are now set up for the lazy compile stub. It expects the function |
2269 // in EAX, the argument descriptor in EDX, and IC-Data in ECX. | 2177 // in EAX, the argument descriptor in EDX, and IC-Data in ECX. |
2270 __ xorl(ECX, ECX); | 2178 __ xorl(ECX, ECX); |
2271 | 2179 |
2272 // Tail-call the function. | 2180 // Tail-call the function. |
2273 __ movl(EDI, FieldAddress(EAX, Function::entry_point_offset())); | 2181 __ movl(EDI, FieldAddress(EAX, Function::entry_point_offset())); |
2274 __ jmp(EDI); | 2182 __ jmp(EDI); |
2275 } | 2183 } |
2276 | 2184 |
2277 | |
2278 // On stack: user tag (+1), return-address (+0). | 2185 // On stack: user tag (+1), return-address (+0). |
2279 void Intrinsifier::UserTag_makeCurrent(Assembler* assembler) { | 2186 void Intrinsifier::UserTag_makeCurrent(Assembler* assembler) { |
2280 // RDI: Isolate. | 2187 // RDI: Isolate. |
2281 __ LoadIsolate(EDI); | 2188 __ LoadIsolate(EDI); |
2282 // EAX: Current user tag. | 2189 // EAX: Current user tag. |
2283 __ movl(EAX, Address(EDI, Isolate::current_tag_offset())); | 2190 __ movl(EAX, Address(EDI, Isolate::current_tag_offset())); |
2284 // EAX: UserTag. | 2191 // EAX: UserTag. |
2285 __ movl(EBX, Address(ESP, +1 * kWordSize)); | 2192 __ movl(EBX, Address(ESP, +1 * kWordSize)); |
2286 // Set Isolate::current_tag_. | 2193 // Set Isolate::current_tag_. |
2287 __ movl(Address(EDI, Isolate::current_tag_offset()), EBX); | 2194 __ movl(Address(EDI, Isolate::current_tag_offset()), EBX); |
2288 // EAX: UserTag's tag. | 2195 // EAX: UserTag's tag. |
2289 __ movl(EBX, FieldAddress(EBX, UserTag::tag_offset())); | 2196 __ movl(EBX, FieldAddress(EBX, UserTag::tag_offset())); |
2290 // Set Isolate::user_tag_. | 2197 // Set Isolate::user_tag_. |
2291 __ movl(Address(EDI, Isolate::user_tag_offset()), EBX); | 2198 __ movl(Address(EDI, Isolate::user_tag_offset()), EBX); |
2292 __ ret(); | 2199 __ ret(); |
2293 } | 2200 } |
2294 | 2201 |
2295 | |
2296 void Intrinsifier::UserTag_defaultTag(Assembler* assembler) { | 2202 void Intrinsifier::UserTag_defaultTag(Assembler* assembler) { |
2297 __ LoadIsolate(EAX); | 2203 __ LoadIsolate(EAX); |
2298 __ movl(EAX, Address(EAX, Isolate::default_tag_offset())); | 2204 __ movl(EAX, Address(EAX, Isolate::default_tag_offset())); |
2299 __ ret(); | 2205 __ ret(); |
2300 } | 2206 } |
2301 | 2207 |
2302 | |
2303 void Intrinsifier::Profiler_getCurrentTag(Assembler* assembler) { | 2208 void Intrinsifier::Profiler_getCurrentTag(Assembler* assembler) { |
2304 __ LoadIsolate(EAX); | 2209 __ LoadIsolate(EAX); |
2305 __ movl(EAX, Address(EAX, Isolate::current_tag_offset())); | 2210 __ movl(EAX, Address(EAX, Isolate::current_tag_offset())); |
2306 __ ret(); | 2211 __ ret(); |
2307 } | 2212 } |
2308 | 2213 |
2309 | |
2310 void Intrinsifier::Timeline_isDartStreamEnabled(Assembler* assembler) { | 2214 void Intrinsifier::Timeline_isDartStreamEnabled(Assembler* assembler) { |
2311 if (!FLAG_support_timeline) { | 2215 if (!FLAG_support_timeline) { |
2312 __ LoadObject(EAX, Bool::False()); | 2216 __ LoadObject(EAX, Bool::False()); |
2313 __ ret(); | 2217 __ ret(); |
2314 return; | 2218 return; |
2315 } | 2219 } |
2316 Label true_label; | 2220 Label true_label; |
2317 // Load TimelineStream*. | 2221 // Load TimelineStream*. |
2318 __ movl(EAX, Address(THR, Thread::dart_stream_offset())); | 2222 __ movl(EAX, Address(THR, Thread::dart_stream_offset())); |
2319 // Load uintptr_t from TimelineStream*. | 2223 // Load uintptr_t from TimelineStream*. |
2320 __ movl(EAX, Address(EAX, TimelineStream::enabled_offset())); | 2224 __ movl(EAX, Address(EAX, TimelineStream::enabled_offset())); |
2321 __ cmpl(EAX, Immediate(0)); | 2225 __ cmpl(EAX, Immediate(0)); |
2322 __ j(NOT_ZERO, &true_label, Assembler::kNearJump); | 2226 __ j(NOT_ZERO, &true_label, Assembler::kNearJump); |
2323 // Not enabled. | 2227 // Not enabled. |
2324 __ LoadObject(EAX, Bool::False()); | 2228 __ LoadObject(EAX, Bool::False()); |
2325 __ ret(); | 2229 __ ret(); |
2326 // Enabled. | 2230 // Enabled. |
2327 __ Bind(&true_label); | 2231 __ Bind(&true_label); |
2328 __ LoadObject(EAX, Bool::True()); | 2232 __ LoadObject(EAX, Bool::True()); |
2329 __ ret(); | 2233 __ ret(); |
2330 } | 2234 } |
2331 | 2235 |
2332 | |
2333 void Intrinsifier::ClearAsyncThreadStackTrace(Assembler* assembler) { | 2236 void Intrinsifier::ClearAsyncThreadStackTrace(Assembler* assembler) { |
2334 __ LoadObject(EAX, Object::null_object()); | 2237 __ LoadObject(EAX, Object::null_object()); |
2335 __ movl(Address(THR, Thread::async_stack_trace_offset()), EAX); | 2238 __ movl(Address(THR, Thread::async_stack_trace_offset()), EAX); |
2336 __ ret(); | 2239 __ ret(); |
2337 } | 2240 } |
2338 | 2241 |
2339 | |
2340 void Intrinsifier::SetAsyncThreadStackTrace(Assembler* assembler) { | 2242 void Intrinsifier::SetAsyncThreadStackTrace(Assembler* assembler) { |
2341 __ movl(Address(THR, Thread::async_stack_trace_offset()), EAX); | 2243 __ movl(Address(THR, Thread::async_stack_trace_offset()), EAX); |
2342 __ LoadObject(EAX, Object::null_object()); | 2244 __ LoadObject(EAX, Object::null_object()); |
2343 __ ret(); | 2245 __ ret(); |
2344 } | 2246 } |
2345 | 2247 |
2346 #undef __ | 2248 #undef __ |
2347 | 2249 |
2348 } // namespace dart | 2250 } // namespace dart |
2349 | 2251 |
2350 #endif // defined TARGET_ARCH_IA32 | 2252 #endif // defined TARGET_ARCH_IA32 |
OLD | NEW |