OLD | NEW |
1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "v8.h" | 5 #include "v8.h" |
6 | 6 |
7 #if V8_TARGET_ARCH_IA32 | 7 #if V8_TARGET_ARCH_X87 |
8 | 8 |
9 #include "bootstrapper.h" | 9 #include "bootstrapper.h" |
10 #include "codegen.h" | 10 #include "codegen.h" |
11 #include "cpu-profiler.h" | 11 #include "cpu-profiler.h" |
12 #include "debug.h" | 12 #include "debug.h" |
13 #include "isolate-inl.h" | 13 #include "isolate-inl.h" |
14 #include "runtime.h" | 14 #include "runtime.h" |
15 #include "serialize.h" | 15 #include "serialize.h" |
16 | 16 |
17 namespace v8 { | 17 namespace v8 { |
(...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
136 test_b(Operand(scratch, MemoryChunk::kFlagsOffset), | 136 test_b(Operand(scratch, MemoryChunk::kFlagsOffset), |
137 static_cast<uint8_t>(mask)); | 137 static_cast<uint8_t>(mask)); |
138 j(cc, condition_met, condition_met_distance); | 138 j(cc, condition_met, condition_met_distance); |
139 } | 139 } |
140 | 140 |
141 | 141 |
142 void MacroAssembler::RememberedSetHelper( | 142 void MacroAssembler::RememberedSetHelper( |
143 Register object, // Only used for debug checks. | 143 Register object, // Only used for debug checks. |
144 Register addr, | 144 Register addr, |
145 Register scratch, | 145 Register scratch, |
146 SaveFPRegsMode save_fp, | |
147 MacroAssembler::RememberedSetFinalAction and_then) { | 146 MacroAssembler::RememberedSetFinalAction and_then) { |
148 Label done; | 147 Label done; |
149 if (emit_debug_code()) { | 148 if (emit_debug_code()) { |
150 Label ok; | 149 Label ok; |
151 JumpIfNotInNewSpace(object, scratch, &ok, Label::kNear); | 150 JumpIfNotInNewSpace(object, scratch, &ok, Label::kNear); |
152 int3(); | 151 int3(); |
153 bind(&ok); | 152 bind(&ok); |
154 } | 153 } |
155 // Load store buffer top. | 154 // Load store buffer top. |
156 ExternalReference store_buffer = | 155 ExternalReference store_buffer = |
(...skipping 11 matching lines...) Expand all Loading... |
168 if (and_then == kReturnAtEnd) { | 167 if (and_then == kReturnAtEnd) { |
169 Label buffer_overflowed; | 168 Label buffer_overflowed; |
170 j(not_equal, &buffer_overflowed, Label::kNear); | 169 j(not_equal, &buffer_overflowed, Label::kNear); |
171 ret(0); | 170 ret(0); |
172 bind(&buffer_overflowed); | 171 bind(&buffer_overflowed); |
173 } else { | 172 } else { |
174 ASSERT(and_then == kFallThroughAtEnd); | 173 ASSERT(and_then == kFallThroughAtEnd); |
175 j(equal, &done, Label::kNear); | 174 j(equal, &done, Label::kNear); |
176 } | 175 } |
177 StoreBufferOverflowStub store_buffer_overflow = | 176 StoreBufferOverflowStub store_buffer_overflow = |
178 StoreBufferOverflowStub(isolate(), save_fp); | 177 StoreBufferOverflowStub(isolate()); |
179 CallStub(&store_buffer_overflow); | 178 CallStub(&store_buffer_overflow); |
180 if (and_then == kReturnAtEnd) { | 179 if (and_then == kReturnAtEnd) { |
181 ret(0); | 180 ret(0); |
182 } else { | 181 } else { |
183 ASSERT(and_then == kFallThroughAtEnd); | 182 ASSERT(and_then == kFallThroughAtEnd); |
184 bind(&done); | 183 bind(&done); |
185 } | 184 } |
186 } | 185 } |
187 | 186 |
188 | 187 |
189 void MacroAssembler::ClampDoubleToUint8(XMMRegister input_reg, | |
190 XMMRegister scratch_reg, | |
191 Register result_reg) { | |
192 Label done; | |
193 Label conv_failure; | |
194 xorps(scratch_reg, scratch_reg); | |
195 cvtsd2si(result_reg, input_reg); | |
196 test(result_reg, Immediate(0xFFFFFF00)); | |
197 j(zero, &done, Label::kNear); | |
198 cmp(result_reg, Immediate(0x1)); | |
199 j(overflow, &conv_failure, Label::kNear); | |
200 mov(result_reg, Immediate(0)); | |
201 setcc(sign, result_reg); | |
202 sub(result_reg, Immediate(1)); | |
203 and_(result_reg, Immediate(255)); | |
204 jmp(&done, Label::kNear); | |
205 bind(&conv_failure); | |
206 Move(result_reg, Immediate(0)); | |
207 ucomisd(input_reg, scratch_reg); | |
208 j(below, &done, Label::kNear); | |
209 Move(result_reg, Immediate(255)); | |
210 bind(&done); | |
211 } | |
212 | |
213 | |
214 void MacroAssembler::ClampUint8(Register reg) { | 188 void MacroAssembler::ClampUint8(Register reg) { |
215 Label done; | 189 Label done; |
216 test(reg, Immediate(0xFFFFFF00)); | 190 test(reg, Immediate(0xFFFFFF00)); |
217 j(zero, &done, Label::kNear); | 191 j(zero, &done, Label::kNear); |
218 setcc(negative, reg); // 1 if negative, 0 if positive. | 192 setcc(negative, reg); // 1 if negative, 0 if positive. |
219 dec_b(reg); // 0 if negative, 255 if positive. | 193 dec_b(reg); // 0 if negative, 255 if positive. |
220 bind(&done); | 194 bind(&done); |
221 } | 195 } |
222 | 196 |
223 | 197 |
224 void MacroAssembler::SlowTruncateToI(Register result_reg, | 198 void MacroAssembler::SlowTruncateToI(Register result_reg, |
225 Register input_reg, | 199 Register input_reg, |
226 int offset) { | 200 int offset) { |
227 DoubleToIStub stub(isolate(), input_reg, result_reg, offset, true); | 201 DoubleToIStub stub(isolate(), input_reg, result_reg, offset, true); |
228 call(stub.GetCode(), RelocInfo::CODE_TARGET); | 202 call(stub.GetCode(), RelocInfo::CODE_TARGET); |
229 } | 203 } |
230 | 204 |
231 | 205 |
232 void MacroAssembler::TruncateDoubleToI(Register result_reg, | 206 void MacroAssembler::TruncateX87TOSToI(Register result_reg) { |
233 XMMRegister input_reg) { | |
234 Label done; | |
235 cvttsd2si(result_reg, Operand(input_reg)); | |
236 cmp(result_reg, 0x1); | |
237 j(no_overflow, &done, Label::kNear); | |
238 | |
239 sub(esp, Immediate(kDoubleSize)); | 207 sub(esp, Immediate(kDoubleSize)); |
240 movsd(MemOperand(esp, 0), input_reg); | 208 fst_d(MemOperand(esp, 0)); |
241 SlowTruncateToI(result_reg, esp, 0); | 209 SlowTruncateToI(result_reg, esp, 0); |
242 add(esp, Immediate(kDoubleSize)); | 210 add(esp, Immediate(kDoubleSize)); |
| 211 } |
| 212 |
| 213 |
| 214 void MacroAssembler::X87TOSToI(Register result_reg, |
| 215 MinusZeroMode minus_zero_mode, |
| 216 Label* conversion_failed, |
| 217 Label::Distance dst) { |
| 218 Label done; |
| 219 sub(esp, Immediate(kPointerSize)); |
| 220 fld(0); |
| 221 fist_s(MemOperand(esp, 0)); |
| 222 fild_s(MemOperand(esp, 0)); |
| 223 pop(result_reg); |
| 224 FCmp(); |
| 225 j(not_equal, conversion_failed, dst); |
| 226 j(parity_even, conversion_failed, dst); |
| 227 if (minus_zero_mode == FAIL_ON_MINUS_ZERO) { |
| 228 test(result_reg, Operand(result_reg)); |
| 229 j(not_zero, &done, Label::kNear); |
| 230 // To check for minus zero, we load the value again as float, and check |
| 231 // if that is still 0. |
| 232 sub(esp, Immediate(kPointerSize)); |
| 233 fst_s(MemOperand(esp, 0)); |
| 234 pop(result_reg); |
| 235 test(result_reg, Operand(result_reg)); |
| 236 j(not_zero, conversion_failed, dst); |
| 237 } |
243 bind(&done); | 238 bind(&done); |
244 } | 239 } |
245 | 240 |
246 | 241 |
247 void MacroAssembler::DoubleToI(Register result_reg, | |
248 XMMRegister input_reg, | |
249 XMMRegister scratch, | |
250 MinusZeroMode minus_zero_mode, | |
251 Label* conversion_failed, | |
252 Label::Distance dst) { | |
253 ASSERT(!input_reg.is(scratch)); | |
254 cvttsd2si(result_reg, Operand(input_reg)); | |
255 Cvtsi2sd(scratch, Operand(result_reg)); | |
256 ucomisd(scratch, input_reg); | |
257 j(not_equal, conversion_failed, dst); | |
258 j(parity_even, conversion_failed, dst); // NaN. | |
259 if (minus_zero_mode == FAIL_ON_MINUS_ZERO) { | |
260 Label done; | |
261 // The integer converted back is equal to the original. We | |
262 // only have to test if we got -0 as an input. | |
263 test(result_reg, Operand(result_reg)); | |
264 j(not_zero, &done, Label::kNear); | |
265 movmskpd(result_reg, input_reg); | |
266 // Bit 0 contains the sign of the double in input_reg. | |
267 // If input was positive, we are ok and return 0, otherwise | |
268 // jump to conversion_failed. | |
269 and_(result_reg, 1); | |
270 j(not_zero, conversion_failed, dst); | |
271 bind(&done); | |
272 } | |
273 } | |
274 | |
275 | |
276 void MacroAssembler::TruncateHeapNumberToI(Register result_reg, | 242 void MacroAssembler::TruncateHeapNumberToI(Register result_reg, |
277 Register input_reg) { | 243 Register input_reg) { |
278 Label done, slow_case; | 244 Label done, slow_case; |
279 | 245 |
280 if (CpuFeatures::IsSupported(SSE3)) { | 246 SlowTruncateToI(result_reg, input_reg); |
281 CpuFeatureScope scope(this, SSE3); | |
282 Label convert; | |
283 // Use more powerful conversion when sse3 is available. | |
284 // Load x87 register with heap number. | |
285 fld_d(FieldOperand(input_reg, HeapNumber::kValueOffset)); | |
286 // Get exponent alone and check for too-big exponent. | |
287 mov(result_reg, FieldOperand(input_reg, HeapNumber::kExponentOffset)); | |
288 and_(result_reg, HeapNumber::kExponentMask); | |
289 const uint32_t kTooBigExponent = | |
290 (HeapNumber::kExponentBias + 63) << HeapNumber::kExponentShift; | |
291 cmp(Operand(result_reg), Immediate(kTooBigExponent)); | |
292 j(greater_equal, &slow_case, Label::kNear); | |
293 | |
294 // Reserve space for 64 bit answer. | |
295 sub(Operand(esp), Immediate(kDoubleSize)); | |
296 // Do conversion, which cannot fail because we checked the exponent. | |
297 fisttp_d(Operand(esp, 0)); | |
298 mov(result_reg, Operand(esp, 0)); // Low word of answer is the result. | |
299 add(Operand(esp), Immediate(kDoubleSize)); | |
300 jmp(&done, Label::kNear); | |
301 | |
302 // Slow case. | |
303 bind(&slow_case); | |
304 if (input_reg.is(result_reg)) { | |
305 // Input is clobbered. Restore number from fpu stack | |
306 sub(Operand(esp), Immediate(kDoubleSize)); | |
307 fstp_d(Operand(esp, 0)); | |
308 SlowTruncateToI(result_reg, esp, 0); | |
309 add(esp, Immediate(kDoubleSize)); | |
310 } else { | |
311 fstp(0); | |
312 SlowTruncateToI(result_reg, input_reg); | |
313 } | |
314 } else { | |
315 movsd(xmm0, FieldOperand(input_reg, HeapNumber::kValueOffset)); | |
316 cvttsd2si(result_reg, Operand(xmm0)); | |
317 cmp(result_reg, 0x1); | |
318 j(no_overflow, &done, Label::kNear); | |
319 // Check if the input was 0x8000000 (kMinInt). | |
320 // If no, then we got an overflow and we deoptimize. | |
321 ExternalReference min_int = ExternalReference::address_of_min_int(); | |
322 ucomisd(xmm0, Operand::StaticVariable(min_int)); | |
323 j(not_equal, &slow_case, Label::kNear); | |
324 j(parity_even, &slow_case, Label::kNear); // NaN. | |
325 jmp(&done, Label::kNear); | |
326 | |
327 // Slow case. | |
328 bind(&slow_case); | |
329 if (input_reg.is(result_reg)) { | |
330 // Input is clobbered. Restore number from double scratch. | |
331 sub(esp, Immediate(kDoubleSize)); | |
332 movsd(MemOperand(esp, 0), xmm0); | |
333 SlowTruncateToI(result_reg, esp, 0); | |
334 add(esp, Immediate(kDoubleSize)); | |
335 } else { | |
336 SlowTruncateToI(result_reg, input_reg); | |
337 } | |
338 } | |
339 bind(&done); | 247 bind(&done); |
340 } | 248 } |
341 | 249 |
342 | 250 |
343 void MacroAssembler::TaggedToI(Register result_reg, | 251 void MacroAssembler::TaggedToI(Register result_reg, |
344 Register input_reg, | 252 Register input_reg, |
345 XMMRegister temp, | |
346 MinusZeroMode minus_zero_mode, | 253 MinusZeroMode minus_zero_mode, |
347 Label* lost_precision) { | 254 Label* lost_precision) { |
348 Label done; | 255 Label done; |
349 ASSERT(!temp.is(xmm0)); | |
350 | 256 |
351 cmp(FieldOperand(input_reg, HeapObject::kMapOffset), | 257 cmp(FieldOperand(input_reg, HeapObject::kMapOffset), |
352 isolate()->factory()->heap_number_map()); | 258 isolate()->factory()->heap_number_map()); |
353 j(not_equal, lost_precision, Label::kNear); | 259 j(not_equal, lost_precision, Label::kNear); |
354 | 260 |
355 ASSERT(!temp.is(no_xmm_reg)); | 261 // TODO(olivf) Converting a number on the fpu is actually quite slow. We |
356 | 262 // should first try a fast conversion and then bailout to this slow case. |
357 movsd(xmm0, FieldOperand(input_reg, HeapNumber::kValueOffset)); | 263 Label lost_precision_pop, zero_check; |
358 cvttsd2si(result_reg, Operand(xmm0)); | 264 Label* lost_precision_int = (minus_zero_mode == FAIL_ON_MINUS_ZERO) |
359 Cvtsi2sd(temp, Operand(result_reg)); | 265 ? &lost_precision_pop : lost_precision; |
360 ucomisd(xmm0, temp); | 266 sub(esp, Immediate(kPointerSize)); |
361 RecordComment("Deferred TaggedToI: lost precision"); | 267 fld_d(FieldOperand(input_reg, HeapNumber::kValueOffset)); |
362 j(not_equal, lost_precision, Label::kNear); | 268 if (minus_zero_mode == FAIL_ON_MINUS_ZERO) fld(0); |
363 RecordComment("Deferred TaggedToI: NaN"); | 269 fist_s(MemOperand(esp, 0)); |
364 j(parity_even, lost_precision, Label::kNear); | 270 fild_s(MemOperand(esp, 0)); |
| 271 FCmp(); |
| 272 pop(result_reg); |
| 273 j(not_equal, lost_precision_int, Label::kNear); |
| 274 j(parity_even, lost_precision_int, Label::kNear); // NaN. |
365 if (minus_zero_mode == FAIL_ON_MINUS_ZERO) { | 275 if (minus_zero_mode == FAIL_ON_MINUS_ZERO) { |
366 test(result_reg, Operand(result_reg)); | 276 test(result_reg, Operand(result_reg)); |
367 j(not_zero, &done, Label::kNear); | 277 j(zero, &zero_check, Label::kNear); |
368 movmskpd(result_reg, xmm0); | 278 fstp(0); |
369 and_(result_reg, 1); | 279 jmp(&done, Label::kNear); |
370 RecordComment("Deferred TaggedToI: minus zero"); | 280 bind(&zero_check); |
371 j(not_zero, lost_precision, Label::kNear); | 281 // To check for minus zero, we load the value again as float, and check |
| 282 // if that is still 0. |
| 283 sub(esp, Immediate(kPointerSize)); |
| 284 fstp_s(Operand(esp, 0)); |
| 285 pop(result_reg); |
| 286 test(result_reg, Operand(result_reg)); |
| 287 j(zero, &done, Label::kNear); |
| 288 jmp(lost_precision, Label::kNear); |
| 289 |
| 290 bind(&lost_precision_pop); |
| 291 fstp(0); |
| 292 jmp(lost_precision, Label::kNear); |
372 } | 293 } |
373 bind(&done); | 294 bind(&done); |
374 } | 295 } |
375 | 296 |
376 | 297 |
377 void MacroAssembler::LoadUint32(XMMRegister dst, | 298 void MacroAssembler::LoadUint32NoSSE2(Register src) { |
378 Register src, | |
379 XMMRegister scratch) { | |
380 Label done; | 299 Label done; |
| 300 push(src); |
| 301 fild_s(Operand(esp, 0)); |
381 cmp(src, Immediate(0)); | 302 cmp(src, Immediate(0)); |
| 303 j(not_sign, &done, Label::kNear); |
382 ExternalReference uint32_bias = | 304 ExternalReference uint32_bias = |
383 ExternalReference::address_of_uint32_bias(); | 305 ExternalReference::address_of_uint32_bias(); |
384 movsd(scratch, Operand::StaticVariable(uint32_bias)); | 306 fld_d(Operand::StaticVariable(uint32_bias)); |
385 Cvtsi2sd(dst, src); | 307 faddp(1); |
386 j(not_sign, &done, Label::kNear); | |
387 addsd(dst, scratch); | |
388 bind(&done); | 308 bind(&done); |
| 309 add(esp, Immediate(kPointerSize)); |
389 } | 310 } |
390 | 311 |
391 | 312 |
392 void MacroAssembler::RecordWriteArray(Register object, | 313 void MacroAssembler::RecordWriteArray(Register object, |
393 Register value, | 314 Register value, |
394 Register index, | 315 Register index, |
395 SaveFPRegsMode save_fp, | |
396 RememberedSetAction remembered_set_action, | 316 RememberedSetAction remembered_set_action, |
397 SmiCheck smi_check) { | 317 SmiCheck smi_check) { |
398 // First, check if a write barrier is even needed. The tests below | 318 // First, check if a write barrier is even needed. The tests below |
399 // catch stores of Smis. | 319 // catch stores of Smis. |
400 Label done; | 320 Label done; |
401 | 321 |
402 // Skip barrier if writing a smi. | 322 // Skip barrier if writing a smi. |
403 if (smi_check == INLINE_SMI_CHECK) { | 323 if (smi_check == INLINE_SMI_CHECK) { |
404 ASSERT_EQ(0, kSmiTag); | 324 ASSERT_EQ(0, kSmiTag); |
405 test(value, Immediate(kSmiTagMask)); | 325 test(value, Immediate(kSmiTagMask)); |
406 j(zero, &done); | 326 j(zero, &done); |
407 } | 327 } |
408 | 328 |
409 // Array access: calculate the destination address in the same manner as | 329 // Array access: calculate the destination address in the same manner as |
410 // KeyedStoreIC::GenerateGeneric. Multiply a smi by 2 to get an offset | 330 // KeyedStoreIC::GenerateGeneric. Multiply a smi by 2 to get an offset |
411 // into an array of words. | 331 // into an array of words. |
412 Register dst = index; | 332 Register dst = index; |
413 lea(dst, Operand(object, index, times_half_pointer_size, | 333 lea(dst, Operand(object, index, times_half_pointer_size, |
414 FixedArray::kHeaderSize - kHeapObjectTag)); | 334 FixedArray::kHeaderSize - kHeapObjectTag)); |
415 | 335 |
416 RecordWrite( | 336 RecordWrite( |
417 object, dst, value, save_fp, remembered_set_action, OMIT_SMI_CHECK); | 337 object, dst, value, remembered_set_action, OMIT_SMI_CHECK); |
418 | 338 |
419 bind(&done); | 339 bind(&done); |
420 | 340 |
421 // Clobber clobbered input registers when running with the debug-code flag | 341 // Clobber clobbered input registers when running with the debug-code flag |
422 // turned on to provoke errors. | 342 // turned on to provoke errors. |
423 if (emit_debug_code()) { | 343 if (emit_debug_code()) { |
424 mov(value, Immediate(BitCast<int32_t>(kZapValue))); | 344 mov(value, Immediate(BitCast<int32_t>(kZapValue))); |
425 mov(index, Immediate(BitCast<int32_t>(kZapValue))); | 345 mov(index, Immediate(BitCast<int32_t>(kZapValue))); |
426 } | 346 } |
427 } | 347 } |
428 | 348 |
429 | 349 |
430 void MacroAssembler::RecordWriteField( | 350 void MacroAssembler::RecordWriteField( |
431 Register object, | 351 Register object, |
432 int offset, | 352 int offset, |
433 Register value, | 353 Register value, |
434 Register dst, | 354 Register dst, |
435 SaveFPRegsMode save_fp, | |
436 RememberedSetAction remembered_set_action, | 355 RememberedSetAction remembered_set_action, |
437 SmiCheck smi_check) { | 356 SmiCheck smi_check) { |
438 // First, check if a write barrier is even needed. The tests below | 357 // First, check if a write barrier is even needed. The tests below |
439 // catch stores of Smis. | 358 // catch stores of Smis. |
440 Label done; | 359 Label done; |
441 | 360 |
442 // Skip barrier if writing a smi. | 361 // Skip barrier if writing a smi. |
443 if (smi_check == INLINE_SMI_CHECK) { | 362 if (smi_check == INLINE_SMI_CHECK) { |
444 JumpIfSmi(value, &done, Label::kNear); | 363 JumpIfSmi(value, &done, Label::kNear); |
445 } | 364 } |
446 | 365 |
447 // Although the object register is tagged, the offset is relative to the start | 366 // Although the object register is tagged, the offset is relative to the start |
448 // of the object, so so offset must be a multiple of kPointerSize. | 367 // of the object, so so offset must be a multiple of kPointerSize. |
449 ASSERT(IsAligned(offset, kPointerSize)); | 368 ASSERT(IsAligned(offset, kPointerSize)); |
450 | 369 |
451 lea(dst, FieldOperand(object, offset)); | 370 lea(dst, FieldOperand(object, offset)); |
452 if (emit_debug_code()) { | 371 if (emit_debug_code()) { |
453 Label ok; | 372 Label ok; |
454 test_b(dst, (1 << kPointerSizeLog2) - 1); | 373 test_b(dst, (1 << kPointerSizeLog2) - 1); |
455 j(zero, &ok, Label::kNear); | 374 j(zero, &ok, Label::kNear); |
456 int3(); | 375 int3(); |
457 bind(&ok); | 376 bind(&ok); |
458 } | 377 } |
459 | 378 |
460 RecordWrite( | 379 RecordWrite( |
461 object, dst, value, save_fp, remembered_set_action, OMIT_SMI_CHECK); | 380 object, dst, value, remembered_set_action, OMIT_SMI_CHECK); |
462 | 381 |
463 bind(&done); | 382 bind(&done); |
464 | 383 |
465 // Clobber clobbered input registers when running with the debug-code flag | 384 // Clobber clobbered input registers when running with the debug-code flag |
466 // turned on to provoke errors. | 385 // turned on to provoke errors. |
467 if (emit_debug_code()) { | 386 if (emit_debug_code()) { |
468 mov(value, Immediate(BitCast<int32_t>(kZapValue))); | 387 mov(value, Immediate(BitCast<int32_t>(kZapValue))); |
469 mov(dst, Immediate(BitCast<int32_t>(kZapValue))); | 388 mov(dst, Immediate(BitCast<int32_t>(kZapValue))); |
470 } | 389 } |
471 } | 390 } |
472 | 391 |
473 | 392 |
474 void MacroAssembler::RecordWriteForMap( | 393 void MacroAssembler::RecordWriteForMap( |
475 Register object, | 394 Register object, |
476 Handle<Map> map, | 395 Handle<Map> map, |
477 Register scratch1, | 396 Register scratch1, |
478 Register scratch2, | 397 Register scratch2) { |
479 SaveFPRegsMode save_fp) { | |
480 Label done; | 398 Label done; |
481 | 399 |
482 Register address = scratch1; | 400 Register address = scratch1; |
483 Register value = scratch2; | 401 Register value = scratch2; |
484 if (emit_debug_code()) { | 402 if (emit_debug_code()) { |
485 Label ok; | 403 Label ok; |
486 lea(address, FieldOperand(object, HeapObject::kMapOffset)); | 404 lea(address, FieldOperand(object, HeapObject::kMapOffset)); |
487 test_b(address, (1 << kPointerSizeLog2) - 1); | 405 test_b(address, (1 << kPointerSizeLog2) - 1); |
488 j(zero, &ok, Label::kNear); | 406 j(zero, &ok, Label::kNear); |
489 int3(); | 407 int3(); |
(...skipping 23 matching lines...) Expand all Loading... |
513 zero, | 431 zero, |
514 &done, | 432 &done, |
515 Label::kNear); | 433 Label::kNear); |
516 | 434 |
517 // Delay the initialization of |address| and |value| for the stub until it's | 435 // Delay the initialization of |address| and |value| for the stub until it's |
518 // known that the will be needed. Up until this point their values are not | 436 // known that the will be needed. Up until this point their values are not |
519 // needed since they are embedded in the operands of instructions that need | 437 // needed since they are embedded in the operands of instructions that need |
520 // them. | 438 // them. |
521 lea(address, FieldOperand(object, HeapObject::kMapOffset)); | 439 lea(address, FieldOperand(object, HeapObject::kMapOffset)); |
522 mov(value, Immediate(map)); | 440 mov(value, Immediate(map)); |
523 RecordWriteStub stub(isolate(), object, value, address, OMIT_REMEMBERED_SET, | 441 RecordWriteStub stub(isolate(), object, value, address, OMIT_REMEMBERED_SET); |
524 save_fp); | |
525 CallStub(&stub); | 442 CallStub(&stub); |
526 | 443 |
527 bind(&done); | 444 bind(&done); |
528 | 445 |
529 // Clobber clobbered input registers when running with the debug-code flag | 446 // Clobber clobbered input registers when running with the debug-code flag |
530 // turned on to provoke errors. | 447 // turned on to provoke errors. |
531 if (emit_debug_code()) { | 448 if (emit_debug_code()) { |
532 mov(value, Immediate(BitCast<int32_t>(kZapValue))); | 449 mov(value, Immediate(BitCast<int32_t>(kZapValue))); |
533 mov(scratch1, Immediate(BitCast<int32_t>(kZapValue))); | 450 mov(scratch1, Immediate(BitCast<int32_t>(kZapValue))); |
534 mov(scratch2, Immediate(BitCast<int32_t>(kZapValue))); | 451 mov(scratch2, Immediate(BitCast<int32_t>(kZapValue))); |
535 } | 452 } |
536 } | 453 } |
537 | 454 |
538 | 455 |
539 void MacroAssembler::RecordWrite(Register object, | 456 void MacroAssembler::RecordWrite(Register object, |
540 Register address, | 457 Register address, |
541 Register value, | 458 Register value, |
542 SaveFPRegsMode fp_mode, | |
543 RememberedSetAction remembered_set_action, | 459 RememberedSetAction remembered_set_action, |
544 SmiCheck smi_check) { | 460 SmiCheck smi_check) { |
545 ASSERT(!object.is(value)); | 461 ASSERT(!object.is(value)); |
546 ASSERT(!object.is(address)); | 462 ASSERT(!object.is(address)); |
547 ASSERT(!value.is(address)); | 463 ASSERT(!value.is(address)); |
548 AssertNotSmi(object); | 464 AssertNotSmi(object); |
549 | 465 |
550 if (remembered_set_action == OMIT_REMEMBERED_SET && | 466 if (remembered_set_action == OMIT_REMEMBERED_SET && |
551 !FLAG_incremental_marking) { | 467 !FLAG_incremental_marking) { |
552 return; | 468 return; |
(...skipping 26 matching lines...) Expand all Loading... |
579 zero, | 495 zero, |
580 &done, | 496 &done, |
581 Label::kNear); | 497 Label::kNear); |
582 CheckPageFlag(object, | 498 CheckPageFlag(object, |
583 value, // Used as scratch. | 499 value, // Used as scratch. |
584 MemoryChunk::kPointersFromHereAreInterestingMask, | 500 MemoryChunk::kPointersFromHereAreInterestingMask, |
585 zero, | 501 zero, |
586 &done, | 502 &done, |
587 Label::kNear); | 503 Label::kNear); |
588 | 504 |
589 RecordWriteStub stub(isolate(), object, value, address, remembered_set_action, | 505 RecordWriteStub stub(isolate(), object, value, address, |
590 fp_mode); | 506 remembered_set_action); |
591 CallStub(&stub); | 507 CallStub(&stub); |
592 | 508 |
593 bind(&done); | 509 bind(&done); |
594 | 510 |
595 // Clobber clobbered registers when running with the debug-code flag | 511 // Clobber clobbered registers when running with the debug-code flag |
596 // turned on to provoke errors. | 512 // turned on to provoke errors. |
597 if (emit_debug_code()) { | 513 if (emit_debug_code()) { |
598 mov(address, Immediate(BitCast<int32_t>(kZapValue))); | 514 mov(address, Immediate(BitCast<int32_t>(kZapValue))); |
599 mov(value, Immediate(BitCast<int32_t>(kZapValue))); | 515 mov(value, Immediate(BitCast<int32_t>(kZapValue))); |
600 } | 516 } |
601 } | 517 } |
602 | 518 |
603 | 519 |
604 void MacroAssembler::DebugBreak() { | 520 void MacroAssembler::DebugBreak() { |
605 Move(eax, Immediate(0)); | 521 Move(eax, Immediate(0)); |
606 mov(ebx, Immediate(ExternalReference(Runtime::kDebugBreak, isolate()))); | 522 mov(ebx, Immediate(ExternalReference(Runtime::kDebugBreak, isolate()))); |
607 CEntryStub ces(isolate(), 1); | 523 CEntryStub ces(isolate(), 1); |
608 call(ces.GetCode(), RelocInfo::DEBUG_BREAK); | 524 call(ces.GetCode(), RelocInfo::DEBUG_BREAK); |
609 } | 525 } |
610 | 526 |
611 | 527 |
612 void MacroAssembler::Cvtsi2sd(XMMRegister dst, const Operand& src) { | |
613 xorps(dst, dst); | |
614 cvtsi2sd(dst, src); | |
615 } | |
616 | |
617 | |
618 bool MacroAssembler::IsUnsafeImmediate(const Immediate& x) { | 528 bool MacroAssembler::IsUnsafeImmediate(const Immediate& x) { |
619 static const int kMaxImmediateBits = 17; | 529 static const int kMaxImmediateBits = 17; |
620 if (!RelocInfo::IsNone(x.rmode_)) return false; | 530 if (!RelocInfo::IsNone(x.rmode_)) return false; |
621 return !is_intn(x.x_, kMaxImmediateBits); | 531 return !is_intn(x.x_, kMaxImmediateBits); |
622 } | 532 } |
623 | 533 |
624 | 534 |
625 void MacroAssembler::SafeMove(Register dst, const Immediate& x) { | 535 void MacroAssembler::SafeMove(Register dst, const Immediate& x) { |
626 if (IsUnsafeImmediate(x) && jit_cookie() != 0) { | 536 if (IsUnsafeImmediate(x) && jit_cookie() != 0) { |
627 Move(dst, Immediate(x.x_ ^ jit_cookie())); | 537 Move(dst, Immediate(x.x_ ^ jit_cookie())); |
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
693 cmpb(FieldOperand(map, Map::kBitField2Offset), | 603 cmpb(FieldOperand(map, Map::kBitField2Offset), |
694 Map::kMaximumBitField2FastHoleySmiElementValue); | 604 Map::kMaximumBitField2FastHoleySmiElementValue); |
695 j(above, fail, distance); | 605 j(above, fail, distance); |
696 } | 606 } |
697 | 607 |
698 | 608 |
699 void MacroAssembler::StoreNumberToDoubleElements( | 609 void MacroAssembler::StoreNumberToDoubleElements( |
700 Register maybe_number, | 610 Register maybe_number, |
701 Register elements, | 611 Register elements, |
702 Register key, | 612 Register key, |
703 Register scratch1, | 613 Register scratch, |
704 XMMRegister scratch2, | |
705 Label* fail, | 614 Label* fail, |
706 int elements_offset) { | 615 int elements_offset) { |
707 Label smi_value, done, maybe_nan, not_nan, is_nan, have_double_value; | 616 Label smi_value, done, maybe_nan, not_nan, is_nan, have_double_value; |
708 JumpIfSmi(maybe_number, &smi_value, Label::kNear); | 617 JumpIfSmi(maybe_number, &smi_value, Label::kNear); |
709 | 618 |
710 CheckMap(maybe_number, | 619 CheckMap(maybe_number, |
711 isolate()->factory()->heap_number_map(), | 620 isolate()->factory()->heap_number_map(), |
712 fail, | 621 fail, |
713 DONT_DO_SMI_CHECK); | 622 DONT_DO_SMI_CHECK); |
714 | 623 |
715 // Double value, canonicalize NaN. | 624 // Double value, canonicalize NaN. |
716 uint32_t offset = HeapNumber::kValueOffset + sizeof(kHoleNanLower32); | 625 uint32_t offset = HeapNumber::kValueOffset + sizeof(kHoleNanLower32); |
717 cmp(FieldOperand(maybe_number, offset), | 626 cmp(FieldOperand(maybe_number, offset), |
718 Immediate(kNaNOrInfinityLowerBoundUpper32)); | 627 Immediate(kNaNOrInfinityLowerBoundUpper32)); |
719 j(greater_equal, &maybe_nan, Label::kNear); | 628 j(greater_equal, &maybe_nan, Label::kNear); |
720 | 629 |
721 bind(¬_nan); | 630 bind(¬_nan); |
722 ExternalReference canonical_nan_reference = | 631 ExternalReference canonical_nan_reference = |
723 ExternalReference::address_of_canonical_non_hole_nan(); | 632 ExternalReference::address_of_canonical_non_hole_nan(); |
724 movsd(scratch2, FieldOperand(maybe_number, HeapNumber::kValueOffset)); | 633 fld_d(FieldOperand(maybe_number, HeapNumber::kValueOffset)); |
725 bind(&have_double_value); | 634 bind(&have_double_value); |
726 movsd(FieldOperand(elements, key, times_4, | 635 fstp_d(FieldOperand(elements, key, times_4, |
727 FixedDoubleArray::kHeaderSize - elements_offset), | 636 FixedDoubleArray::kHeaderSize - elements_offset)); |
728 scratch2); | |
729 jmp(&done); | 637 jmp(&done); |
730 | 638 |
731 bind(&maybe_nan); | 639 bind(&maybe_nan); |
732 // Could be NaN or Infinity. If fraction is not zero, it's NaN, otherwise | 640 // Could be NaN or Infinity. If fraction is not zero, it's NaN, otherwise |
733 // it's an Infinity, and the non-NaN code path applies. | 641 // it's an Infinity, and the non-NaN code path applies. |
734 j(greater, &is_nan, Label::kNear); | 642 j(greater, &is_nan, Label::kNear); |
735 cmp(FieldOperand(maybe_number, HeapNumber::kValueOffset), Immediate(0)); | 643 cmp(FieldOperand(maybe_number, HeapNumber::kValueOffset), Immediate(0)); |
736 j(zero, ¬_nan); | 644 j(zero, ¬_nan); |
737 bind(&is_nan); | 645 bind(&is_nan); |
738 movsd(scratch2, Operand::StaticVariable(canonical_nan_reference)); | 646 fld_d(Operand::StaticVariable(canonical_nan_reference)); |
739 jmp(&have_double_value, Label::kNear); | 647 jmp(&have_double_value, Label::kNear); |
740 | 648 |
741 bind(&smi_value); | 649 bind(&smi_value); |
742 // Value is a smi. Convert to a double and store. | 650 // Value is a smi. Convert to a double and store. |
743 // Preserve original value. | 651 // Preserve original value. |
744 mov(scratch1, maybe_number); | 652 mov(scratch, maybe_number); |
745 SmiUntag(scratch1); | 653 SmiUntag(scratch); |
746 Cvtsi2sd(scratch2, scratch1); | 654 push(scratch); |
747 movsd(FieldOperand(elements, key, times_4, | 655 fild_s(Operand(esp, 0)); |
748 FixedDoubleArray::kHeaderSize - elements_offset), | 656 pop(scratch); |
749 scratch2); | 657 fstp_d(FieldOperand(elements, key, times_4, |
| 658 FixedDoubleArray::kHeaderSize - elements_offset)); |
750 bind(&done); | 659 bind(&done); |
751 } | 660 } |
752 | 661 |
753 | 662 |
754 void MacroAssembler::CompareMap(Register obj, Handle<Map> map) { | 663 void MacroAssembler::CompareMap(Register obj, Handle<Map> map) { |
755 cmp(FieldOperand(obj, HeapObject::kMapOffset), map); | 664 cmp(FieldOperand(obj, HeapObject::kMapOffset), map); |
756 } | 665 } |
757 | 666 |
758 | 667 |
759 void MacroAssembler::CheckMap(Register obj, | 668 void MacroAssembler::CheckMap(Register obj, |
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
820 Label* fail) { | 729 Label* fail) { |
821 movzx_b(scratch, FieldOperand(map, Map::kInstanceTypeOffset)); | 730 movzx_b(scratch, FieldOperand(map, Map::kInstanceTypeOffset)); |
822 sub(scratch, Immediate(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE)); | 731 sub(scratch, Immediate(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE)); |
823 cmp(scratch, | 732 cmp(scratch, |
824 LAST_NONCALLABLE_SPEC_OBJECT_TYPE - FIRST_NONCALLABLE_SPEC_OBJECT_TYPE); | 733 LAST_NONCALLABLE_SPEC_OBJECT_TYPE - FIRST_NONCALLABLE_SPEC_OBJECT_TYPE); |
825 j(above, fail); | 734 j(above, fail); |
826 } | 735 } |
827 | 736 |
828 | 737 |
829 void MacroAssembler::FCmp() { | 738 void MacroAssembler::FCmp() { |
830 fucomip(); | 739 fucompp(); |
831 fstp(0); | 740 push(eax); |
| 741 fnstsw_ax(); |
| 742 sahf(); |
| 743 pop(eax); |
832 } | 744 } |
833 | 745 |
834 | 746 |
835 void MacroAssembler::AssertNumber(Register object) { | 747 void MacroAssembler::AssertNumber(Register object) { |
836 if (emit_debug_code()) { | 748 if (emit_debug_code()) { |
837 Label ok; | 749 Label ok; |
838 JumpIfSmi(object, &ok); | 750 JumpIfSmi(object, &ok); |
839 cmp(FieldOperand(object, HeapObject::kMapOffset), | 751 cmp(FieldOperand(object, HeapObject::kMapOffset), |
840 isolate()->factory()->heap_number_map()); | 752 isolate()->factory()->heap_number_map()); |
841 Check(equal, kOperandNotANumber); | 753 Check(equal, kOperandNotANumber); |
(...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
962 push(Immediate(CodeObject())); // Accessed from ExitFrame::code_slot. | 874 push(Immediate(CodeObject())); // Accessed from ExitFrame::code_slot. |
963 | 875 |
964 // Save the frame pointer and the context in top. | 876 // Save the frame pointer and the context in top. |
965 ExternalReference c_entry_fp_address(Isolate::kCEntryFPAddress, isolate()); | 877 ExternalReference c_entry_fp_address(Isolate::kCEntryFPAddress, isolate()); |
966 ExternalReference context_address(Isolate::kContextAddress, isolate()); | 878 ExternalReference context_address(Isolate::kContextAddress, isolate()); |
967 mov(Operand::StaticVariable(c_entry_fp_address), ebp); | 879 mov(Operand::StaticVariable(c_entry_fp_address), ebp); |
968 mov(Operand::StaticVariable(context_address), esi); | 880 mov(Operand::StaticVariable(context_address), esi); |
969 } | 881 } |
970 | 882 |
971 | 883 |
972 void MacroAssembler::EnterExitFrameEpilogue(int argc, bool save_doubles) { | 884 void MacroAssembler::EnterExitFrameEpilogue(int argc) { |
973 // Optionally save all XMM registers. | 885 sub(esp, Immediate(argc * kPointerSize)); |
974 if (save_doubles) { | |
975 int space = XMMRegister::kMaxNumRegisters * kDoubleSize + | |
976 argc * kPointerSize; | |
977 sub(esp, Immediate(space)); | |
978 const int offset = -2 * kPointerSize; | |
979 for (int i = 0; i < XMMRegister::kMaxNumRegisters; i++) { | |
980 XMMRegister reg = XMMRegister::from_code(i); | |
981 movsd(Operand(ebp, offset - ((i + 1) * kDoubleSize)), reg); | |
982 } | |
983 } else { | |
984 sub(esp, Immediate(argc * kPointerSize)); | |
985 } | |
986 | 886 |
987 // Get the required frame alignment for the OS. | 887 // Get the required frame alignment for the OS. |
988 const int kFrameAlignment = OS::ActivationFrameAlignment(); | 888 const int kFrameAlignment = OS::ActivationFrameAlignment(); |
989 if (kFrameAlignment > 0) { | 889 if (kFrameAlignment > 0) { |
990 ASSERT(IsPowerOf2(kFrameAlignment)); | 890 ASSERT(IsPowerOf2(kFrameAlignment)); |
991 and_(esp, -kFrameAlignment); | 891 and_(esp, -kFrameAlignment); |
992 } | 892 } |
993 | 893 |
994 // Patch the saved entry sp. | 894 // Patch the saved entry sp. |
995 mov(Operand(ebp, ExitFrameConstants::kSPOffset), esp); | 895 mov(Operand(ebp, ExitFrameConstants::kSPOffset), esp); |
996 } | 896 } |
997 | 897 |
998 | 898 |
999 void MacroAssembler::EnterExitFrame(bool save_doubles) { | 899 void MacroAssembler::EnterExitFrame() { |
1000 EnterExitFramePrologue(); | 900 EnterExitFramePrologue(); |
1001 | 901 |
1002 // Set up argc and argv in callee-saved registers. | 902 // Set up argc and argv in callee-saved registers. |
1003 int offset = StandardFrameConstants::kCallerSPOffset - kPointerSize; | 903 int offset = StandardFrameConstants::kCallerSPOffset - kPointerSize; |
1004 mov(edi, eax); | 904 mov(edi, eax); |
1005 lea(esi, Operand(ebp, eax, times_4, offset)); | 905 lea(esi, Operand(ebp, eax, times_4, offset)); |
1006 | 906 |
1007 // Reserve space for argc, argv and isolate. | 907 // Reserve space for argc, argv and isolate. |
1008 EnterExitFrameEpilogue(3, save_doubles); | 908 EnterExitFrameEpilogue(3); |
1009 } | 909 } |
1010 | 910 |
1011 | 911 |
1012 void MacroAssembler::EnterApiExitFrame(int argc) { | 912 void MacroAssembler::EnterApiExitFrame(int argc) { |
1013 EnterExitFramePrologue(); | 913 EnterExitFramePrologue(); |
1014 EnterExitFrameEpilogue(argc, false); | 914 EnterExitFrameEpilogue(argc); |
1015 } | 915 } |
1016 | 916 |
1017 | 917 |
1018 void MacroAssembler::LeaveExitFrame(bool save_doubles) { | 918 void MacroAssembler::LeaveExitFrame() { |
1019 // Optionally restore all XMM registers. | |
1020 if (save_doubles) { | |
1021 const int offset = -2 * kPointerSize; | |
1022 for (int i = 0; i < XMMRegister::kMaxNumRegisters; i++) { | |
1023 XMMRegister reg = XMMRegister::from_code(i); | |
1024 movsd(reg, Operand(ebp, offset - ((i + 1) * kDoubleSize))); | |
1025 } | |
1026 } | |
1027 | |
1028 // Get the return address from the stack and restore the frame pointer. | 919 // Get the return address from the stack and restore the frame pointer. |
1029 mov(ecx, Operand(ebp, 1 * kPointerSize)); | 920 mov(ecx, Operand(ebp, 1 * kPointerSize)); |
1030 mov(ebp, Operand(ebp, 0 * kPointerSize)); | 921 mov(ebp, Operand(ebp, 0 * kPointerSize)); |
1031 | 922 |
1032 // Pop the arguments and the receiver from the caller stack. | 923 // Pop the arguments and the receiver from the caller stack. |
1033 lea(esp, Operand(esi, 1 * kPointerSize)); | 924 lea(esp, Operand(esi, 1 * kPointerSize)); |
1034 | 925 |
1035 // Push the return address to get ready to return. | 926 // Push the return address to get ready to return. |
1036 push(ecx); | 927 push(ecx); |
1037 | 928 |
(...skipping 1032 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2070 if (String::kHashShift > kSmiTagSize) { | 1961 if (String::kHashShift > kSmiTagSize) { |
2071 shr(hash, String::kHashShift - kSmiTagSize); | 1962 shr(hash, String::kHashShift - kSmiTagSize); |
2072 } | 1963 } |
2073 if (!index.is(hash)) { | 1964 if (!index.is(hash)) { |
2074 mov(index, hash); | 1965 mov(index, hash); |
2075 } | 1966 } |
2076 } | 1967 } |
2077 | 1968 |
2078 | 1969 |
2079 void MacroAssembler::CallRuntime(const Runtime::Function* f, | 1970 void MacroAssembler::CallRuntime(const Runtime::Function* f, |
2080 int num_arguments, | 1971 int num_arguments) { |
2081 SaveFPRegsMode save_doubles) { | |
2082 // If the expected number of arguments of the runtime function is | 1972 // If the expected number of arguments of the runtime function is |
2083 // constant, we check that the actual number of arguments match the | 1973 // constant, we check that the actual number of arguments match the |
2084 // expectation. | 1974 // expectation. |
2085 CHECK(f->nargs < 0 || f->nargs == num_arguments); | 1975 CHECK(f->nargs < 0 || f->nargs == num_arguments); |
2086 | 1976 |
2087 // TODO(1236192): Most runtime routines don't need the number of | 1977 // TODO(1236192): Most runtime routines don't need the number of |
2088 // arguments passed in because it is constant. At some point we | 1978 // arguments passed in because it is constant. At some point we |
2089 // should remove this need and make the runtime routine entry code | 1979 // should remove this need and make the runtime routine entry code |
2090 // smarter. | 1980 // smarter. |
2091 Move(eax, Immediate(num_arguments)); | 1981 Move(eax, Immediate(num_arguments)); |
2092 mov(ebx, Immediate(ExternalReference(f, isolate()))); | 1982 mov(ebx, Immediate(ExternalReference(f, isolate()))); |
2093 CEntryStub ces(isolate(), 1, save_doubles); | 1983 CEntryStub ces(isolate(), 1); |
2094 CallStub(&ces); | 1984 CallStub(&ces); |
2095 } | 1985 } |
2096 | 1986 |
2097 | 1987 |
2098 void MacroAssembler::CallExternalReference(ExternalReference ref, | 1988 void MacroAssembler::CallExternalReference(ExternalReference ref, |
2099 int num_arguments) { | 1989 int num_arguments) { |
2100 mov(eax, Immediate(num_arguments)); | 1990 mov(eax, Immediate(num_arguments)); |
2101 mov(ebx, Immediate(ref)); | 1991 mov(ebx, Immediate(ref)); |
2102 | 1992 |
2103 CEntryStub stub(isolate(), 1); | 1993 CEntryStub stub(isolate(), 1); |
(...skipping 528 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2632 ret(bytes_dropped); | 2522 ret(bytes_dropped); |
2633 } else { | 2523 } else { |
2634 pop(scratch); | 2524 pop(scratch); |
2635 add(esp, Immediate(bytes_dropped)); | 2525 add(esp, Immediate(bytes_dropped)); |
2636 push(scratch); | 2526 push(scratch); |
2637 ret(0); | 2527 ret(0); |
2638 } | 2528 } |
2639 } | 2529 } |
2640 | 2530 |
2641 | 2531 |
| 2532 void MacroAssembler::VerifyX87StackDepth(uint32_t depth) { |
| 2533 // Make sure the floating point stack is either empty or has depth items. |
| 2534 ASSERT(depth <= 7); |
| 2535 // This is very expensive. |
| 2536 ASSERT(FLAG_debug_code && FLAG_enable_slow_asserts); |
| 2537 |
| 2538 // The top-of-stack (tos) is 7 if there is one item pushed. |
| 2539 int tos = (8 - depth) % 8; |
| 2540 const int kTopMask = 0x3800; |
| 2541 push(eax); |
| 2542 fwait(); |
| 2543 fnstsw_ax(); |
| 2544 and_(eax, kTopMask); |
| 2545 shr(eax, 11); |
| 2546 cmp(eax, Immediate(tos)); |
| 2547 Check(equal, kUnexpectedFPUStackDepthAfterInstruction); |
| 2548 fnclex(); |
| 2549 pop(eax); |
| 2550 } |
| 2551 |
| 2552 |
2642 void MacroAssembler::Drop(int stack_elements) { | 2553 void MacroAssembler::Drop(int stack_elements) { |
2643 if (stack_elements > 0) { | 2554 if (stack_elements > 0) { |
2644 add(esp, Immediate(stack_elements * kPointerSize)); | 2555 add(esp, Immediate(stack_elements * kPointerSize)); |
2645 } | 2556 } |
2646 } | 2557 } |
2647 | 2558 |
2648 | 2559 |
2649 void MacroAssembler::Move(Register dst, Register src) { | 2560 void MacroAssembler::Move(Register dst, Register src) { |
2650 if (!dst.is(src)) { | 2561 if (!dst.is(src)) { |
2651 mov(dst, src); | 2562 mov(dst, src); |
2652 } | 2563 } |
2653 } | 2564 } |
2654 | 2565 |
2655 | 2566 |
2656 void MacroAssembler::Move(Register dst, const Immediate& x) { | 2567 void MacroAssembler::Move(Register dst, const Immediate& x) { |
2657 if (x.is_zero()) { | 2568 if (x.is_zero()) { |
2658 xor_(dst, dst); // Shorter than mov of 32-bit immediate 0. | 2569 xor_(dst, dst); // Shorter than mov of 32-bit immediate 0. |
2659 } else { | 2570 } else { |
2660 mov(dst, x); | 2571 mov(dst, x); |
2661 } | 2572 } |
2662 } | 2573 } |
2663 | 2574 |
2664 | 2575 |
2665 void MacroAssembler::Move(const Operand& dst, const Immediate& x) { | 2576 void MacroAssembler::Move(const Operand& dst, const Immediate& x) { |
2666 mov(dst, x); | 2577 mov(dst, x); |
2667 } | 2578 } |
2668 | 2579 |
2669 | 2580 |
2670 void MacroAssembler::Move(XMMRegister dst, double val) { | |
2671 // TODO(titzer): recognize double constants with ExternalReferences. | |
2672 uint64_t int_val = BitCast<uint64_t, double>(val); | |
2673 if (int_val == 0) { | |
2674 xorps(dst, dst); | |
2675 } else { | |
2676 int32_t lower = static_cast<int32_t>(int_val); | |
2677 int32_t upper = static_cast<int32_t>(int_val >> kBitsPerInt); | |
2678 push(Immediate(upper)); | |
2679 push(Immediate(lower)); | |
2680 movsd(dst, Operand(esp, 0)); | |
2681 add(esp, Immediate(kDoubleSize)); | |
2682 } | |
2683 } | |
2684 | |
2685 | |
2686 void MacroAssembler::SetCounter(StatsCounter* counter, int value) { | 2581 void MacroAssembler::SetCounter(StatsCounter* counter, int value) { |
2687 if (FLAG_native_code_counters && counter->Enabled()) { | 2582 if (FLAG_native_code_counters && counter->Enabled()) { |
2688 mov(Operand::StaticVariable(ExternalReference(counter)), Immediate(value)); | 2583 mov(Operand::StaticVariable(ExternalReference(counter)), Immediate(value)); |
2689 } | 2584 } |
2690 } | 2585 } |
2691 | 2586 |
2692 | 2587 |
2693 void MacroAssembler::IncrementCounter(StatsCounter* counter, int value) { | 2588 void MacroAssembler::IncrementCounter(StatsCounter* counter, int value) { |
2694 ASSERT(value > 0); | 2589 ASSERT(value > 0); |
2695 if (FLAG_native_code_counters && counter->Enabled()) { | 2590 if (FLAG_native_code_counters && counter->Enabled()) { |
(...skipping 167 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2863 mov(descriptors, FieldOperand(map, Map::kDescriptorsOffset)); | 2758 mov(descriptors, FieldOperand(map, Map::kDescriptorsOffset)); |
2864 } | 2759 } |
2865 | 2760 |
2866 | 2761 |
2867 void MacroAssembler::NumberOfOwnDescriptors(Register dst, Register map) { | 2762 void MacroAssembler::NumberOfOwnDescriptors(Register dst, Register map) { |
2868 mov(dst, FieldOperand(map, Map::kBitField3Offset)); | 2763 mov(dst, FieldOperand(map, Map::kBitField3Offset)); |
2869 DecodeField<Map::NumberOfOwnDescriptorsBits>(dst); | 2764 DecodeField<Map::NumberOfOwnDescriptorsBits>(dst); |
2870 } | 2765 } |
2871 | 2766 |
2872 | 2767 |
2873 void MacroAssembler::LoadPowerOf2(XMMRegister dst, | |
2874 Register scratch, | |
2875 int power) { | |
2876 ASSERT(is_uintn(power + HeapNumber::kExponentBias, | |
2877 HeapNumber::kExponentBits)); | |
2878 mov(scratch, Immediate(power + HeapNumber::kExponentBias)); | |
2879 movd(dst, scratch); | |
2880 psllq(dst, HeapNumber::kMantissaBits); | |
2881 } | |
2882 | |
2883 | |
2884 void MacroAssembler::LookupNumberStringCache(Register object, | 2768 void MacroAssembler::LookupNumberStringCache(Register object, |
2885 Register result, | 2769 Register result, |
2886 Register scratch1, | 2770 Register scratch1, |
2887 Register scratch2, | 2771 Register scratch2, |
2888 Label* not_found) { | 2772 Label* not_found) { |
2889 // Use of registers. Register result is used as a temporary. | 2773 // Use of registers. Register result is used as a temporary. |
2890 Register number_string_cache = result; | 2774 Register number_string_cache = result; |
2891 Register mask = scratch1; | 2775 Register mask = scratch1; |
2892 Register scratch = scratch2; | 2776 Register scratch = scratch2; |
2893 | 2777 |
(...skipping 27 matching lines...) Expand all Loading... |
2921 // Object is heap number and hash is now in scratch. Calculate cache index. | 2805 // Object is heap number and hash is now in scratch. Calculate cache index. |
2922 and_(scratch, mask); | 2806 and_(scratch, mask); |
2923 Register index = scratch; | 2807 Register index = scratch; |
2924 Register probe = mask; | 2808 Register probe = mask; |
2925 mov(probe, | 2809 mov(probe, |
2926 FieldOperand(number_string_cache, | 2810 FieldOperand(number_string_cache, |
2927 index, | 2811 index, |
2928 times_twice_pointer_size, | 2812 times_twice_pointer_size, |
2929 FixedArray::kHeaderSize)); | 2813 FixedArray::kHeaderSize)); |
2930 JumpIfSmi(probe, not_found); | 2814 JumpIfSmi(probe, not_found); |
2931 movsd(xmm0, FieldOperand(object, HeapNumber::kValueOffset)); | 2815 fld_d(FieldOperand(object, HeapNumber::kValueOffset)); |
2932 ucomisd(xmm0, FieldOperand(probe, HeapNumber::kValueOffset)); | 2816 fld_d(FieldOperand(probe, HeapNumber::kValueOffset)); |
| 2817 FCmp(); |
2933 j(parity_even, not_found); // Bail out if NaN is involved. | 2818 j(parity_even, not_found); // Bail out if NaN is involved. |
2934 j(not_equal, not_found); // The cache did not contain this value. | 2819 j(not_equal, not_found); // The cache did not contain this value. |
2935 jmp(&load_result_from_cache, Label::kNear); | 2820 jmp(&load_result_from_cache, Label::kNear); |
2936 | 2821 |
2937 bind(&smi_hash_calculated); | 2822 bind(&smi_hash_calculated); |
2938 // Object is smi and hash is now in scratch. Calculate cache index. | 2823 // Object is smi and hash is now in scratch. Calculate cache index. |
2939 and_(scratch, mask); | 2824 and_(scratch, mask); |
2940 // Check if the entry is the smi we are looking for. | 2825 // Check if the entry is the smi we are looking for. |
2941 cmp(object, | 2826 cmp(object, |
2942 FieldOperand(number_string_cache, | 2827 FieldOperand(number_string_cache, |
(...skipping 515 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3458 if (divisor < 0 && ms.multiplier() > 0) sub(edx, dividend); | 3343 if (divisor < 0 && ms.multiplier() > 0) sub(edx, dividend); |
3459 if (ms.shift() > 0) sar(edx, ms.shift()); | 3344 if (ms.shift() > 0) sar(edx, ms.shift()); |
3460 mov(eax, dividend); | 3345 mov(eax, dividend); |
3461 shr(eax, 31); | 3346 shr(eax, 31); |
3462 add(edx, eax); | 3347 add(edx, eax); |
3463 } | 3348 } |
3464 | 3349 |
3465 | 3350 |
3466 } } // namespace v8::internal | 3351 } } // namespace v8::internal |
3467 | 3352 |
3468 #endif // V8_TARGET_ARCH_IA32 | 3353 #endif // V8_TARGET_ARCH_X87 |
OLD | NEW |