| 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 "src/v8.h" | 5 #include "src/v8.h" |
| 6 | 6 |
| 7 #if V8_TARGET_ARCH_X64 | 7 #if V8_TARGET_ARCH_X64 |
| 8 | 8 |
| 9 #include "src/bootstrapper.h" | 9 #include "src/bootstrapper.h" |
| 10 #include "src/codegen.h" | 10 #include "src/codegen.h" |
| (...skipping 274 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 285 } | 285 } |
| 286 | 286 |
| 287 | 287 |
| 288 void MacroAssembler::RecordWriteField( | 288 void MacroAssembler::RecordWriteField( |
| 289 Register object, | 289 Register object, |
| 290 int offset, | 290 int offset, |
| 291 Register value, | 291 Register value, |
| 292 Register dst, | 292 Register dst, |
| 293 SaveFPRegsMode save_fp, | 293 SaveFPRegsMode save_fp, |
| 294 RememberedSetAction remembered_set_action, | 294 RememberedSetAction remembered_set_action, |
| 295 SmiCheck smi_check) { | 295 SmiCheck smi_check, |
| 296 PointersToHereCheck pointers_to_here_check_for_value) { |
| 296 // First, check if a write barrier is even needed. The tests below | 297 // First, check if a write barrier is even needed. The tests below |
| 297 // catch stores of Smis. | 298 // catch stores of Smis. |
| 298 Label done; | 299 Label done; |
| 299 | 300 |
| 300 // Skip barrier if writing a smi. | 301 // Skip barrier if writing a smi. |
| 301 if (smi_check == INLINE_SMI_CHECK) { | 302 if (smi_check == INLINE_SMI_CHECK) { |
| 302 JumpIfSmi(value, &done); | 303 JumpIfSmi(value, &done); |
| 303 } | 304 } |
| 304 | 305 |
| 305 // Although the object register is tagged, the offset is relative to the start | 306 // Although the object register is tagged, the offset is relative to the start |
| 306 // of the object, so so offset must be a multiple of kPointerSize. | 307 // of the object, so so offset must be a multiple of kPointerSize. |
| 307 ASSERT(IsAligned(offset, kPointerSize)); | 308 ASSERT(IsAligned(offset, kPointerSize)); |
| 308 | 309 |
| 309 leap(dst, FieldOperand(object, offset)); | 310 leap(dst, FieldOperand(object, offset)); |
| 310 if (emit_debug_code()) { | 311 if (emit_debug_code()) { |
| 311 Label ok; | 312 Label ok; |
| 312 testb(dst, Immediate((1 << kPointerSizeLog2) - 1)); | 313 testb(dst, Immediate((1 << kPointerSizeLog2) - 1)); |
| 313 j(zero, &ok, Label::kNear); | 314 j(zero, &ok, Label::kNear); |
| 314 int3(); | 315 int3(); |
| 315 bind(&ok); | 316 bind(&ok); |
| 316 } | 317 } |
| 317 | 318 |
| 318 RecordWrite( | 319 RecordWrite(object, dst, value, save_fp, remembered_set_action, |
| 319 object, dst, value, save_fp, remembered_set_action, OMIT_SMI_CHECK); | 320 OMIT_SMI_CHECK, pointers_to_here_check_for_value); |
| 320 | 321 |
| 321 bind(&done); | 322 bind(&done); |
| 322 | 323 |
| 323 // Clobber clobbered input registers when running with the debug-code flag | 324 // Clobber clobbered input registers when running with the debug-code flag |
| 324 // turned on to provoke errors. | 325 // turned on to provoke errors. |
| 325 if (emit_debug_code()) { | 326 if (emit_debug_code()) { |
| 326 Move(value, kZapValue, Assembler::RelocInfoNone()); | 327 Move(value, kZapValue, Assembler::RelocInfoNone()); |
| 327 Move(dst, kZapValue, Assembler::RelocInfoNone()); | 328 Move(dst, kZapValue, Assembler::RelocInfoNone()); |
| 328 } | 329 } |
| 329 } | 330 } |
| 330 | 331 |
| 331 | 332 |
| 332 void MacroAssembler::RecordWriteArray(Register object, | 333 void MacroAssembler::RecordWriteArray( |
| 333 Register value, | 334 Register object, |
| 334 Register index, | 335 Register value, |
| 335 SaveFPRegsMode save_fp, | 336 Register index, |
| 336 RememberedSetAction remembered_set_action, | 337 SaveFPRegsMode save_fp, |
| 337 SmiCheck smi_check) { | 338 RememberedSetAction remembered_set_action, |
| 339 SmiCheck smi_check, |
| 340 PointersToHereCheck pointers_to_here_check_for_value) { |
| 338 // First, check if a write barrier is even needed. The tests below | 341 // First, check if a write barrier is even needed. The tests below |
| 339 // catch stores of Smis. | 342 // catch stores of Smis. |
| 340 Label done; | 343 Label done; |
| 341 | 344 |
| 342 // Skip barrier if writing a smi. | 345 // Skip barrier if writing a smi. |
| 343 if (smi_check == INLINE_SMI_CHECK) { | 346 if (smi_check == INLINE_SMI_CHECK) { |
| 344 JumpIfSmi(value, &done); | 347 JumpIfSmi(value, &done); |
| 345 } | 348 } |
| 346 | 349 |
| 347 // Array access: calculate the destination address. Index is not a smi. | 350 // Array access: calculate the destination address. Index is not a smi. |
| 348 Register dst = index; | 351 Register dst = index; |
| 349 leap(dst, Operand(object, index, times_pointer_size, | 352 leap(dst, Operand(object, index, times_pointer_size, |
| 350 FixedArray::kHeaderSize - kHeapObjectTag)); | 353 FixedArray::kHeaderSize - kHeapObjectTag)); |
| 351 | 354 |
| 352 RecordWrite( | 355 RecordWrite(object, dst, value, save_fp, remembered_set_action, |
| 353 object, dst, value, save_fp, remembered_set_action, OMIT_SMI_CHECK); | 356 OMIT_SMI_CHECK, pointers_to_here_check_for_value); |
| 354 | 357 |
| 355 bind(&done); | 358 bind(&done); |
| 356 | 359 |
| 357 // Clobber clobbered input registers when running with the debug-code flag | 360 // Clobber clobbered input registers when running with the debug-code flag |
| 358 // turned on to provoke errors. | 361 // turned on to provoke errors. |
| 359 if (emit_debug_code()) { | 362 if (emit_debug_code()) { |
| 360 Move(value, kZapValue, Assembler::RelocInfoNone()); | 363 Move(value, kZapValue, Assembler::RelocInfoNone()); |
| 361 Move(index, kZapValue, Assembler::RelocInfoNone()); | 364 Move(index, kZapValue, Assembler::RelocInfoNone()); |
| 362 } | 365 } |
| 363 } | 366 } |
| 364 | 367 |
| 365 | 368 |
| 366 void MacroAssembler::RecordWrite(Register object, | 369 void MacroAssembler::RecordWriteForMap(Register object, |
| 367 Register address, | 370 Register map, |
| 368 Register value, | 371 Register dst, |
| 369 SaveFPRegsMode fp_mode, | 372 SaveFPRegsMode fp_mode) { |
| 370 RememberedSetAction remembered_set_action, | 373 ASSERT(!object.is(kScratchRegister)); |
| 371 SmiCheck smi_check) { | 374 ASSERT(!object.is(map)); |
| 375 ASSERT(!object.is(dst)); |
| 376 ASSERT(!map.is(dst)); |
| 377 AssertNotSmi(object); |
| 378 |
| 379 if (emit_debug_code()) { |
| 380 Label ok; |
| 381 if (map.is(kScratchRegister)) pushq(map); |
| 382 CompareMap(map, isolate()->factory()->meta_map()); |
| 383 if (map.is(kScratchRegister)) popq(map); |
| 384 j(equal, &ok, Label::kNear); |
| 385 int3(); |
| 386 bind(&ok); |
| 387 } |
| 388 |
| 389 if (!FLAG_incremental_marking) { |
| 390 return; |
| 391 } |
| 392 |
| 393 if (emit_debug_code()) { |
| 394 Label ok; |
| 395 if (map.is(kScratchRegister)) pushq(map); |
| 396 cmpp(map, FieldOperand(object, HeapObject::kMapOffset)); |
| 397 if (map.is(kScratchRegister)) popq(map); |
| 398 j(equal, &ok, Label::kNear); |
| 399 int3(); |
| 400 bind(&ok); |
| 401 } |
| 402 |
| 403 // Compute the address. |
| 404 leap(dst, FieldOperand(object, HeapObject::kMapOffset)); |
| 405 |
| 406 // Count number of write barriers in generated code. |
| 407 isolate()->counters()->write_barriers_static()->Increment(); |
| 408 IncrementCounter(isolate()->counters()->write_barriers_dynamic(), 1); |
| 409 |
| 410 // First, check if a write barrier is even needed. The tests below |
| 411 // catch stores of smis and stores into the young generation. |
| 412 Label done; |
| 413 |
| 414 // A single check of the map's pages interesting flag suffices, since it is |
| 415 // only set during incremental collection, and then it's also guaranteed that |
| 416 // the from object's page's interesting flag is also set. This optimization |
| 417 // relies on the fact that maps can never be in new space. |
| 418 CheckPageFlag(map, |
| 419 map, // Used as scratch. |
| 420 MemoryChunk::kPointersToHereAreInterestingMask, |
| 421 zero, |
| 422 &done, |
| 423 Label::kNear); |
| 424 |
| 425 RecordWriteStub stub(isolate(), object, map, dst, OMIT_REMEMBERED_SET, |
| 426 fp_mode); |
| 427 CallStub(&stub); |
| 428 |
| 429 bind(&done); |
| 430 |
| 431 // Clobber clobbered registers when running with the debug-code flag |
| 432 // turned on to provoke errors. |
| 433 if (emit_debug_code()) { |
| 434 Move(dst, kZapValue, Assembler::RelocInfoNone()); |
| 435 Move(map, kZapValue, Assembler::RelocInfoNone()); |
| 436 } |
| 437 } |
| 438 |
| 439 |
| 440 void MacroAssembler::RecordWrite( |
| 441 Register object, |
| 442 Register address, |
| 443 Register value, |
| 444 SaveFPRegsMode fp_mode, |
| 445 RememberedSetAction remembered_set_action, |
| 446 SmiCheck smi_check, |
| 447 PointersToHereCheck pointers_to_here_check_for_value) { |
| 372 ASSERT(!object.is(value)); | 448 ASSERT(!object.is(value)); |
| 373 ASSERT(!object.is(address)); | 449 ASSERT(!object.is(address)); |
| 374 ASSERT(!value.is(address)); | 450 ASSERT(!value.is(address)); |
| 375 AssertNotSmi(object); | 451 AssertNotSmi(object); |
| 376 | 452 |
| 377 if (remembered_set_action == OMIT_REMEMBERED_SET && | 453 if (remembered_set_action == OMIT_REMEMBERED_SET && |
| 378 !FLAG_incremental_marking) { | 454 !FLAG_incremental_marking) { |
| 379 return; | 455 return; |
| 380 } | 456 } |
| 381 | 457 |
| (...skipping 11 matching lines...) Expand all Loading... |
| 393 | 469 |
| 394 // First, check if a write barrier is even needed. The tests below | 470 // First, check if a write barrier is even needed. The tests below |
| 395 // catch stores of smis and stores into the young generation. | 471 // catch stores of smis and stores into the young generation. |
| 396 Label done; | 472 Label done; |
| 397 | 473 |
| 398 if (smi_check == INLINE_SMI_CHECK) { | 474 if (smi_check == INLINE_SMI_CHECK) { |
| 399 // Skip barrier if writing a smi. | 475 // Skip barrier if writing a smi. |
| 400 JumpIfSmi(value, &done); | 476 JumpIfSmi(value, &done); |
| 401 } | 477 } |
| 402 | 478 |
| 403 CheckPageFlag(value, | 479 if (pointers_to_here_check_for_value != kPointersToHereAreAlwaysInteresting) { |
| 404 value, // Used as scratch. | 480 CheckPageFlag(value, |
| 405 MemoryChunk::kPointersToHereAreInterestingMask, | 481 value, // Used as scratch. |
| 406 zero, | 482 MemoryChunk::kPointersToHereAreInterestingMask, |
| 407 &done, | 483 zero, |
| 408 Label::kNear); | 484 &done, |
| 485 Label::kNear); |
| 486 } |
| 409 | 487 |
| 410 CheckPageFlag(object, | 488 CheckPageFlag(object, |
| 411 value, // Used as scratch. | 489 value, // Used as scratch. |
| 412 MemoryChunk::kPointersFromHereAreInterestingMask, | 490 MemoryChunk::kPointersFromHereAreInterestingMask, |
| 413 zero, | 491 zero, |
| 414 &done, | 492 &done, |
| 415 Label::kNear); | 493 Label::kNear); |
| 416 | 494 |
| 417 RecordWriteStub stub(isolate(), object, value, address, remembered_set_action, | 495 RecordWriteStub stub(isolate(), object, value, address, remembered_set_action, |
| 418 fp_mode); | 496 fp_mode); |
| (...skipping 4758 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5177 if (ms.shift() > 0) sarl(rdx, Immediate(ms.shift())); | 5255 if (ms.shift() > 0) sarl(rdx, Immediate(ms.shift())); |
| 5178 movl(rax, dividend); | 5256 movl(rax, dividend); |
| 5179 shrl(rax, Immediate(31)); | 5257 shrl(rax, Immediate(31)); |
| 5180 addl(rdx, rax); | 5258 addl(rdx, rax); |
| 5181 } | 5259 } |
| 5182 | 5260 |
| 5183 | 5261 |
| 5184 } } // namespace v8::internal | 5262 } } // namespace v8::internal |
| 5185 | 5263 |
| 5186 #endif // V8_TARGET_ARCH_X64 | 5264 #endif // V8_TARGET_ARCH_X64 |
| OLD | NEW |