| OLD | NEW |
| 1 // Copyright 2011 the V8 project authors. All rights reserved. | 1 // Copyright 2011 the V8 project authors. All rights reserved. |
| 2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
| 3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
| 4 // met: | 4 // met: |
| 5 // | 5 // |
| 6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
| 7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
| 8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
| 9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
| 10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
| (...skipping 179 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 190 | 190 |
| 191 void MacroAssembler::CompareRoot(const Operand& with, | 191 void MacroAssembler::CompareRoot(const Operand& with, |
| 192 Heap::RootListIndex index) { | 192 Heap::RootListIndex index) { |
| 193 ASSERT(root_array_available_); | 193 ASSERT(root_array_available_); |
| 194 ASSERT(!with.AddressUsesRegister(kScratchRegister)); | 194 ASSERT(!with.AddressUsesRegister(kScratchRegister)); |
| 195 LoadRoot(kScratchRegister, index); | 195 LoadRoot(kScratchRegister, index); |
| 196 cmpq(with, kScratchRegister); | 196 cmpq(with, kScratchRegister); |
| 197 } | 197 } |
| 198 | 198 |
| 199 | 199 |
| 200 void MacroAssembler::RecordWriteHelper(Register object, | 200 void MacroAssembler::RememberedSetHelper(Register addr, |
| 201 Register addr, | 201 Register scratch, |
| 202 Register scratch) { | 202 SaveFPRegsMode save_fp, |
| 203 if (emit_debug_code()) { | 203 RememberedSetFinalAction and_then) { |
| 204 // Check that the object is not in new space. | 204 if (FLAG_debug_code) { |
| 205 Label not_in_new_space; | 205 Label ok; |
| 206 InNewSpace(object, scratch, not_equal, ¬_in_new_space, Label::kNear); | 206 JumpIfNotInNewSpace(addr, scratch, &ok, Label::kNear); |
| 207 Abort("new-space object passed to RecordWriteHelper"); | 207 int3(); |
| 208 bind(¬_in_new_space); | 208 bind(&ok); |
| 209 } | 209 } |
| 210 | 210 // Load store buffer top. |
| 211 // Compute the page start address from the heap object pointer, and reuse | 211 LoadRoot(scratch, Heap::kStoreBufferTopRootIndex); |
| 212 // the 'object' register for it. | 212 // Store pointer to buffer. |
| 213 and_(object, Immediate(~Page::kPageAlignmentMask)); | 213 movq(Operand(scratch, 0), addr); |
| 214 | 214 // Increment buffer top. |
| 215 // Compute number of region covering addr. See Page::GetRegionNumberForAddress | 215 addq(scratch, Immediate(kPointerSize)); |
| 216 // method for more details. | 216 // Write back new top of buffer. |
| 217 shrl(addr, Immediate(Page::kRegionSizeLog2)); | 217 StoreRoot(scratch, Heap::kStoreBufferTopRootIndex); |
| 218 andl(addr, Immediate(Page::kPageAlignmentMask >> Page::kRegionSizeLog2)); | 218 // Call stub on end of buffer. |
| 219 | 219 Label done; |
| 220 // Set dirty mark for region. | 220 // Check for end of buffer. |
| 221 bts(Operand(object, Page::kDirtyFlagOffset), addr); | 221 testq(scratch, Immediate(StoreBuffer::kStoreBufferOverflowBit)); |
| 222 if (and_then == kReturnAtEnd) { |
| 223 Label buffer_overflowed; |
| 224 j(not_equal, &buffer_overflowed, Label::kNear); |
| 225 ret(0); |
| 226 bind(&buffer_overflowed); |
| 227 } else { |
| 228 ASSERT(and_then == kFallThroughAtEnd); |
| 229 j(equal, &done, Label::kNear); |
| 230 } |
| 231 StoreBufferOverflowStub store_buffer_overflow = |
| 232 StoreBufferOverflowStub(save_fp); |
| 233 CallStub(&store_buffer_overflow); |
| 234 if (and_then == kReturnAtEnd) { |
| 235 ret(0); |
| 236 } else { |
| 237 ASSERT(and_then == kFallThroughAtEnd); |
| 238 bind(&done); |
| 239 } |
| 222 } | 240 } |
| 223 | 241 |
| 224 | 242 |
| 225 void MacroAssembler::InNewSpace(Register object, | 243 void MacroAssembler::InNewSpace(Register object, |
| 226 Register scratch, | 244 Register scratch, |
| 227 Condition cc, | 245 Condition cc, |
| 228 Label* branch, | 246 Label* branch, |
| 229 Label::Distance near_jump) { | 247 Label::Distance distance) { |
| 230 if (Serializer::enabled()) { | 248 if (Serializer::enabled()) { |
| 231 // Can't do arithmetic on external references if it might get serialized. | 249 // Can't do arithmetic on external references if it might get serialized. |
| 232 // The mask isn't really an address. We load it as an external reference in | 250 // The mask isn't really an address. We load it as an external reference in |
| 233 // case the size of the new space is different between the snapshot maker | 251 // case the size of the new space is different between the snapshot maker |
| 234 // and the running system. | 252 // and the running system. |
| 235 if (scratch.is(object)) { | 253 if (scratch.is(object)) { |
| 236 movq(kScratchRegister, ExternalReference::new_space_mask(isolate())); | 254 movq(kScratchRegister, ExternalReference::new_space_mask(isolate())); |
| 237 and_(scratch, kScratchRegister); | 255 and_(scratch, kScratchRegister); |
| 238 } else { | 256 } else { |
| 239 movq(scratch, ExternalReference::new_space_mask(isolate())); | 257 movq(scratch, ExternalReference::new_space_mask(isolate())); |
| 240 and_(scratch, object); | 258 and_(scratch, object); |
| 241 } | 259 } |
| 242 movq(kScratchRegister, ExternalReference::new_space_start(isolate())); | 260 movq(kScratchRegister, ExternalReference::new_space_start(isolate())); |
| 243 cmpq(scratch, kScratchRegister); | 261 cmpq(scratch, kScratchRegister); |
| 244 j(cc, branch, near_jump); | 262 j(cc, branch, distance); |
| 245 } else { | 263 } else { |
| 246 ASSERT(is_int32(static_cast<int64_t>(HEAP->NewSpaceMask()))); | 264 ASSERT(is_int32(static_cast<int64_t>(HEAP->NewSpaceMask()))); |
| 247 intptr_t new_space_start = | 265 intptr_t new_space_start = |
| 248 reinterpret_cast<intptr_t>(HEAP->NewSpaceStart()); | 266 reinterpret_cast<intptr_t>(HEAP->NewSpaceStart()); |
| 249 movq(kScratchRegister, -new_space_start, RelocInfo::NONE); | 267 movq(kScratchRegister, -new_space_start, RelocInfo::NONE); |
| 250 if (scratch.is(object)) { | 268 if (scratch.is(object)) { |
| 251 addq(scratch, kScratchRegister); | 269 addq(scratch, kScratchRegister); |
| 252 } else { | 270 } else { |
| 253 lea(scratch, Operand(object, kScratchRegister, times_1, 0)); | 271 lea(scratch, Operand(object, kScratchRegister, times_1, 0)); |
| 254 } | 272 } |
| 255 and_(scratch, Immediate(static_cast<int32_t>(HEAP->NewSpaceMask()))); | 273 and_(scratch, Immediate(static_cast<int32_t>(HEAP->NewSpaceMask()))); |
| 256 j(cc, branch, near_jump); | 274 j(cc, branch, distance); |
| 257 } | 275 } |
| 258 } | 276 } |
| 259 | 277 |
| 260 | 278 |
| 261 void MacroAssembler::RecordWrite(Register object, | 279 void MacroAssembler::RecordWriteField( |
| 262 int offset, | 280 Register object, |
| 263 Register value, | 281 int offset, |
| 264 Register index) { | 282 Register value, |
| 283 Register dst, |
| 284 SaveFPRegsMode save_fp, |
| 285 RememberedSetAction remembered_set_action, |
| 286 SmiCheck smi_check) { |
| 265 // The compiled code assumes that record write doesn't change the | 287 // The compiled code assumes that record write doesn't change the |
| 266 // context register, so we check that none of the clobbered | 288 // context register, so we check that none of the clobbered |
| 267 // registers are rsi. | 289 // registers are rsi. |
| 268 ASSERT(!object.is(rsi) && !value.is(rsi) && !index.is(rsi)); | 290 ASSERT(!value.is(rsi) && !dst.is(rsi)); |
| 269 | 291 |
| 270 // First, check if a write barrier is even needed. The tests below | 292 // First, check if a write barrier is even needed. The tests below |
| 271 // catch stores of smis and stores into the young generation. | 293 // catch stores of Smis. |
| 272 Label done; | 294 Label done; |
| 273 JumpIfSmi(value, &done); | |
| 274 | 295 |
| 275 RecordWriteNonSmi(object, offset, value, index); | 296 // Skip barrier if writing a smi. |
| 297 if (smi_check == INLINE_SMI_CHECK) { |
| 298 JumpIfSmi(value, &done); |
| 299 } |
| 300 |
| 301 // Although the object register is tagged, the offset is relative to the start |
| 302 // of the object, so so offset must be a multiple of kPointerSize. |
| 303 ASSERT(IsAligned(offset, kPointerSize)); |
| 304 |
| 305 lea(dst, FieldOperand(object, offset)); |
| 306 if (emit_debug_code()) { |
| 307 Label ok; |
| 308 testb(dst, Immediate((1 << kPointerSizeLog2) - 1)); |
| 309 j(zero, &ok, Label::kNear); |
| 310 int3(); |
| 311 bind(&ok); |
| 312 } |
| 313 |
| 314 RecordWrite( |
| 315 object, dst, value, save_fp, remembered_set_action, OMIT_SMI_CHECK); |
| 316 |
| 276 bind(&done); | 317 bind(&done); |
| 277 | 318 |
| 278 // Clobber all input registers when running with the debug-code flag | 319 // Clobber clobbered input registers when running with the debug-code flag |
| 279 // turned on to provoke errors. This clobbering repeats the | 320 // turned on to provoke errors. |
| 280 // clobbering done inside RecordWriteNonSmi but it's necessary to | |
| 281 // avoid having the fast case for smis leave the registers | |
| 282 // unchanged. | |
| 283 if (emit_debug_code()) { | 321 if (emit_debug_code()) { |
| 284 movq(object, BitCast<int64_t>(kZapValue), RelocInfo::NONE); | |
| 285 movq(value, BitCast<int64_t>(kZapValue), RelocInfo::NONE); | 322 movq(value, BitCast<int64_t>(kZapValue), RelocInfo::NONE); |
| 286 movq(index, BitCast<int64_t>(kZapValue), RelocInfo::NONE); | 323 movq(dst, BitCast<int64_t>(kZapValue), RelocInfo::NONE); |
| 287 } | 324 } |
| 288 } | 325 } |
| 289 | 326 |
| 290 | 327 |
| 291 void MacroAssembler::RecordWrite(Register object, | 328 void MacroAssembler::RecordWrite(Register object, |
| 292 Register address, | 329 Register address, |
| 293 Register value) { | 330 Register value, |
| 331 SaveFPRegsMode fp_mode, |
| 332 RememberedSetAction remembered_set_action, |
| 333 SmiCheck smi_check) { |
| 294 // The compiled code assumes that record write doesn't change the | 334 // The compiled code assumes that record write doesn't change the |
| 295 // context register, so we check that none of the clobbered | 335 // context register, so we check that none of the clobbered |
| 296 // registers are rsi. | 336 // registers are rsi. |
| 297 ASSERT(!object.is(rsi) && !value.is(rsi) && !address.is(rsi)); | 337 ASSERT(!value.is(rsi) && !address.is(rsi)); |
| 338 |
| 339 ASSERT(!object.is(value)); |
| 340 ASSERT(!object.is(address)); |
| 341 ASSERT(!value.is(address)); |
| 342 if (emit_debug_code()) { |
| 343 AbortIfSmi(object); |
| 344 } |
| 345 |
| 346 if (remembered_set_action == OMIT_REMEMBERED_SET && |
| 347 !FLAG_incremental_marking) { |
| 348 return; |
| 349 } |
| 350 |
| 351 if (FLAG_debug_code) { |
| 352 Label ok; |
| 353 cmpq(value, Operand(address, 0)); |
| 354 j(equal, &ok, Label::kNear); |
| 355 int3(); |
| 356 bind(&ok); |
| 357 } |
| 298 | 358 |
| 299 // First, check if a write barrier is even needed. The tests below | 359 // First, check if a write barrier is even needed. The tests below |
| 300 // catch stores of smis and stores into the young generation. | 360 // catch stores of smis and stores into the young generation. |
| 301 Label done; | 361 Label done; |
| 302 JumpIfSmi(value, &done); | |
| 303 | 362 |
| 304 InNewSpace(object, value, equal, &done); | 363 if (smi_check == INLINE_SMI_CHECK) { |
| 364 // Skip barrier if writing a smi. |
| 365 JumpIfSmi(value, &done); |
| 366 } |
| 305 | 367 |
| 306 RecordWriteHelper(object, address, value); | 368 CheckPageFlag(value, |
| 369 value, // Used as scratch. |
| 370 MemoryChunk::kPointersToHereAreInterestingMask, |
| 371 zero, |
| 372 &done, |
| 373 Label::kNear); |
| 374 |
| 375 CheckPageFlag(object, |
| 376 value, // Used as scratch. |
| 377 MemoryChunk::kPointersFromHereAreInterestingMask, |
| 378 zero, |
| 379 &done, |
| 380 Label::kNear); |
| 381 |
| 382 RecordWriteStub stub(object, value, address, remembered_set_action, fp_mode); |
| 383 CallStub(&stub); |
| 307 | 384 |
| 308 bind(&done); | 385 bind(&done); |
| 309 | 386 |
| 310 // Clobber all input registers when running with the debug-code flag | 387 // Clobber clobbered registers when running with the debug-code flag |
| 311 // turned on to provoke errors. | 388 // turned on to provoke errors. |
| 312 if (emit_debug_code()) { | 389 if (emit_debug_code()) { |
| 313 movq(object, BitCast<int64_t>(kZapValue), RelocInfo::NONE); | |
| 314 movq(address, BitCast<int64_t>(kZapValue), RelocInfo::NONE); | 390 movq(address, BitCast<int64_t>(kZapValue), RelocInfo::NONE); |
| 315 movq(value, BitCast<int64_t>(kZapValue), RelocInfo::NONE); | 391 movq(value, BitCast<int64_t>(kZapValue), RelocInfo::NONE); |
| 316 } | 392 } |
| 317 } | 393 } |
| 318 | 394 |
| 319 | 395 |
| 320 void MacroAssembler::RecordWriteNonSmi(Register object, | |
| 321 int offset, | |
| 322 Register scratch, | |
| 323 Register index) { | |
| 324 Label done; | |
| 325 | |
| 326 if (emit_debug_code()) { | |
| 327 Label okay; | |
| 328 JumpIfNotSmi(object, &okay, Label::kNear); | |
| 329 Abort("MacroAssembler::RecordWriteNonSmi cannot deal with smis"); | |
| 330 bind(&okay); | |
| 331 | |
| 332 if (offset == 0) { | |
| 333 // index must be int32. | |
| 334 Register tmp = index.is(rax) ? rbx : rax; | |
| 335 push(tmp); | |
| 336 movl(tmp, index); | |
| 337 cmpq(tmp, index); | |
| 338 Check(equal, "Index register for RecordWrite must be untagged int32."); | |
| 339 pop(tmp); | |
| 340 } | |
| 341 } | |
| 342 | |
| 343 // Test that the object address is not in the new space. We cannot | |
| 344 // update page dirty marks for new space pages. | |
| 345 InNewSpace(object, scratch, equal, &done); | |
| 346 | |
| 347 // The offset is relative to a tagged or untagged HeapObject pointer, | |
| 348 // so either offset or offset + kHeapObjectTag must be a | |
| 349 // multiple of kPointerSize. | |
| 350 ASSERT(IsAligned(offset, kPointerSize) || | |
| 351 IsAligned(offset + kHeapObjectTag, kPointerSize)); | |
| 352 | |
| 353 Register dst = index; | |
| 354 if (offset != 0) { | |
| 355 lea(dst, Operand(object, offset)); | |
| 356 } else { | |
| 357 // array access: calculate the destination address in the same manner as | |
| 358 // KeyedStoreIC::GenerateGeneric. | |
| 359 lea(dst, FieldOperand(object, | |
| 360 index, | |
| 361 times_pointer_size, | |
| 362 FixedArray::kHeaderSize)); | |
| 363 } | |
| 364 RecordWriteHelper(object, dst, scratch); | |
| 365 | |
| 366 bind(&done); | |
| 367 | |
| 368 // Clobber all input registers when running with the debug-code flag | |
| 369 // turned on to provoke errors. | |
| 370 if (emit_debug_code()) { | |
| 371 movq(object, BitCast<int64_t>(kZapValue), RelocInfo::NONE); | |
| 372 movq(scratch, BitCast<int64_t>(kZapValue), RelocInfo::NONE); | |
| 373 movq(index, BitCast<int64_t>(kZapValue), RelocInfo::NONE); | |
| 374 } | |
| 375 } | |
| 376 | |
| 377 void MacroAssembler::Assert(Condition cc, const char* msg) { | 396 void MacroAssembler::Assert(Condition cc, const char* msg) { |
| 378 if (emit_debug_code()) Check(cc, msg); | 397 if (emit_debug_code()) Check(cc, msg); |
| 379 } | 398 } |
| 380 | 399 |
| 381 | 400 |
| 382 void MacroAssembler::AssertFastElements(Register elements) { | 401 void MacroAssembler::AssertFastElements(Register elements) { |
| 383 if (emit_debug_code()) { | 402 if (emit_debug_code()) { |
| 384 Label ok; | 403 Label ok; |
| 385 CompareRoot(FieldOperand(elements, HeapObject::kMapOffset), | 404 CompareRoot(FieldOperand(elements, HeapObject::kMapOffset), |
| 386 Heap::kFixedArrayMapRootIndex); | 405 Heap::kFixedArrayMapRootIndex); |
| (...skipping 157 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 544 | 563 |
| 545 void MacroAssembler::CallRuntime(Runtime::FunctionId id, int num_arguments) { | 564 void MacroAssembler::CallRuntime(Runtime::FunctionId id, int num_arguments) { |
| 546 CallRuntime(Runtime::FunctionForId(id), num_arguments); | 565 CallRuntime(Runtime::FunctionForId(id), num_arguments); |
| 547 } | 566 } |
| 548 | 567 |
| 549 | 568 |
| 550 void MacroAssembler::CallRuntimeSaveDoubles(Runtime::FunctionId id) { | 569 void MacroAssembler::CallRuntimeSaveDoubles(Runtime::FunctionId id) { |
| 551 const Runtime::Function* function = Runtime::FunctionForId(id); | 570 const Runtime::Function* function = Runtime::FunctionForId(id); |
| 552 Set(rax, function->nargs); | 571 Set(rax, function->nargs); |
| 553 LoadAddress(rbx, ExternalReference(function, isolate())); | 572 LoadAddress(rbx, ExternalReference(function, isolate())); |
| 554 CEntryStub ces(1); | 573 CEntryStub ces(1, kSaveFPRegs); |
| 555 ces.SaveDoubles(); | |
| 556 CallStub(&ces); | 574 CallStub(&ces); |
| 557 } | 575 } |
| 558 | 576 |
| 559 | 577 |
| 560 MaybeObject* MacroAssembler::TryCallRuntime(Runtime::FunctionId id, | 578 MaybeObject* MacroAssembler::TryCallRuntime(Runtime::FunctionId id, |
| 561 int num_arguments) { | 579 int num_arguments) { |
| 562 return TryCallRuntime(Runtime::FunctionForId(id), num_arguments); | 580 return TryCallRuntime(Runtime::FunctionForId(id), num_arguments); |
| 563 } | 581 } |
| 564 | 582 |
| 565 | 583 |
| (...skipping 263 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 829 | 847 |
| 830 | 848 |
| 831 void MacroAssembler::GetBuiltinEntry(Register target, Builtins::JavaScript id) { | 849 void MacroAssembler::GetBuiltinEntry(Register target, Builtins::JavaScript id) { |
| 832 ASSERT(!target.is(rdi)); | 850 ASSERT(!target.is(rdi)); |
| 833 // Load the JavaScript builtin function from the builtins object. | 851 // Load the JavaScript builtin function from the builtins object. |
| 834 GetBuiltinFunction(rdi, id); | 852 GetBuiltinFunction(rdi, id); |
| 835 movq(target, FieldOperand(rdi, JSFunction::kCodeEntryOffset)); | 853 movq(target, FieldOperand(rdi, JSFunction::kCodeEntryOffset)); |
| 836 } | 854 } |
| 837 | 855 |
| 838 | 856 |
| 857 static const Register saved_regs[] = |
| 858 { rax, rcx, rdx, rbx, rbp, rsi, rdi, r8, r9, r10, r11 }; |
| 859 static const int kNumberOfSavedRegs = sizeof(saved_regs) / sizeof(Register); |
| 860 |
| 861 |
| 862 void MacroAssembler::PushCallerSaved(SaveFPRegsMode fp_mode, |
| 863 Register exclusion1, |
| 864 Register exclusion2, |
| 865 Register exclusion3) { |
| 866 // We don't allow a GC during a store buffer overflow so there is no need to |
| 867 // store the registers in any particular way, but we do have to store and |
| 868 // restore them. |
| 869 for (int i = 0; i < kNumberOfSavedRegs; i++) { |
| 870 Register reg = saved_regs[i]; |
| 871 if (!reg.is(exclusion1) && !reg.is(exclusion2) && !reg.is(exclusion3)) { |
| 872 push(reg); |
| 873 } |
| 874 } |
| 875 // R12 to r15 are callee save on all platforms. |
| 876 if (fp_mode == kSaveFPRegs) { |
| 877 CpuFeatures::Scope scope(SSE2); |
| 878 subq(rsp, Immediate(kDoubleSize * XMMRegister::kNumRegisters)); |
| 879 for (int i = 0; i < XMMRegister::kNumRegisters; i++) { |
| 880 XMMRegister reg = XMMRegister::from_code(i); |
| 881 movsd(Operand(rsp, i * kDoubleSize), reg); |
| 882 } |
| 883 } |
| 884 } |
| 885 |
| 886 |
| 887 void MacroAssembler::PopCallerSaved(SaveFPRegsMode fp_mode, |
| 888 Register exclusion1, |
| 889 Register exclusion2, |
| 890 Register exclusion3) { |
| 891 if (fp_mode == kSaveFPRegs) { |
| 892 CpuFeatures::Scope scope(SSE2); |
| 893 for (int i = 0; i < XMMRegister::kNumRegisters; i++) { |
| 894 XMMRegister reg = XMMRegister::from_code(i); |
| 895 movsd(reg, Operand(rsp, i * kDoubleSize)); |
| 896 } |
| 897 addq(rsp, Immediate(kDoubleSize * XMMRegister::kNumRegisters)); |
| 898 } |
| 899 for (int i = kNumberOfSavedRegs - 1; i >= 0; i--) { |
| 900 Register reg = saved_regs[i]; |
| 901 if (!reg.is(exclusion1) && !reg.is(exclusion2) && !reg.is(exclusion3)) { |
| 902 pop(reg); |
| 903 } |
| 904 } |
| 905 } |
| 906 |
| 907 |
| 839 void MacroAssembler::Set(Register dst, int64_t x) { | 908 void MacroAssembler::Set(Register dst, int64_t x) { |
| 840 if (x == 0) { | 909 if (x == 0) { |
| 841 xorl(dst, dst); | 910 xorl(dst, dst); |
| 842 } else if (is_uint32(x)) { | 911 } else if (is_uint32(x)) { |
| 843 movl(dst, Immediate(static_cast<uint32_t>(x))); | 912 movl(dst, Immediate(static_cast<uint32_t>(x))); |
| 844 } else if (is_int32(x)) { | 913 } else if (is_int32(x)) { |
| 845 movq(dst, Immediate(static_cast<int32_t>(x))); | 914 movq(dst, Immediate(static_cast<int32_t>(x))); |
| 846 } else { | 915 } else { |
| 847 movq(dst, x, RelocInfo::NONE); | 916 movq(dst, x, RelocInfo::NONE); |
| 848 } | 917 } |
| (...skipping 3040 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3889 | 3958 |
| 3890 call(function); | 3959 call(function); |
| 3891 ASSERT(OS::ActivationFrameAlignment() != 0); | 3960 ASSERT(OS::ActivationFrameAlignment() != 0); |
| 3892 ASSERT(num_arguments >= 0); | 3961 ASSERT(num_arguments >= 0); |
| 3893 int argument_slots_on_stack = | 3962 int argument_slots_on_stack = |
| 3894 ArgumentStackSlotsForCFunctionCall(num_arguments); | 3963 ArgumentStackSlotsForCFunctionCall(num_arguments); |
| 3895 movq(rsp, Operand(rsp, argument_slots_on_stack * kPointerSize)); | 3964 movq(rsp, Operand(rsp, argument_slots_on_stack * kPointerSize)); |
| 3896 } | 3965 } |
| 3897 | 3966 |
| 3898 | 3967 |
| 3968 bool AreAliased(Register r1, Register r2, Register r3, Register r4) { |
| 3969 if (r1.is(r2)) return true; |
| 3970 if (r1.is(r3)) return true; |
| 3971 if (r1.is(r4)) return true; |
| 3972 if (r2.is(r3)) return true; |
| 3973 if (r2.is(r4)) return true; |
| 3974 if (r3.is(r4)) return true; |
| 3975 return false; |
| 3976 } |
| 3977 |
| 3978 |
| 3899 CodePatcher::CodePatcher(byte* address, int size) | 3979 CodePatcher::CodePatcher(byte* address, int size) |
| 3900 : address_(address), | 3980 : address_(address), |
| 3901 size_(size), | 3981 size_(size), |
| 3902 masm_(Isolate::Current(), address, size + Assembler::kGap) { | 3982 masm_(Isolate::Current(), address, size + Assembler::kGap) { |
| 3903 // Create a new macro assembler pointing to the address of the code to patch. | 3983 // Create a new macro assembler pointing to the address of the code to patch. |
| 3904 // The size is adjusted with kGap on order for the assembler to generate size | 3984 // The size is adjusted with kGap on order for the assembler to generate size |
| 3905 // bytes of instructions without failing with buffer size constraints. | 3985 // bytes of instructions without failing with buffer size constraints. |
| 3906 ASSERT(masm_.reloc_info_writer.pos() == address_ + size_ + Assembler::kGap); | 3986 ASSERT(masm_.reloc_info_writer.pos() == address_ + size_ + Assembler::kGap); |
| 3907 } | 3987 } |
| 3908 | 3988 |
| 3909 | 3989 |
| 3910 CodePatcher::~CodePatcher() { | 3990 CodePatcher::~CodePatcher() { |
| 3911 // Indicate that code has changed. | 3991 // Indicate that code has changed. |
| 3912 CPU::FlushICache(address_, size_); | 3992 CPU::FlushICache(address_, size_); |
| 3913 | 3993 |
| 3914 // Check that the code was patched as expected. | 3994 // Check that the code was patched as expected. |
| 3915 ASSERT(masm_.pc_ == address_ + size_); | 3995 ASSERT(masm_.pc_ == address_ + size_); |
| 3916 ASSERT(masm_.reloc_info_writer.pos() == address_ + size_ + Assembler::kGap); | 3996 ASSERT(masm_.reloc_info_writer.pos() == address_ + size_ + Assembler::kGap); |
| 3917 } | 3997 } |
| 3918 | 3998 |
| 3999 |
| 4000 void MacroAssembler::CheckPageFlag( |
| 4001 Register object, |
| 4002 Register scratch, |
| 4003 int mask, |
| 4004 Condition cc, |
| 4005 Label* condition_met, |
| 4006 Label::Distance condition_met_distance) { |
| 4007 ASSERT(cc == zero || cc == not_zero); |
| 4008 if (scratch.is(object)) { |
| 4009 and_(scratch, Immediate(~Page::kPageAlignmentMask)); |
| 4010 } else { |
| 4011 movq(scratch, Immediate(~Page::kPageAlignmentMask)); |
| 4012 and_(scratch, object); |
| 4013 } |
| 4014 if (mask < (1 << kBitsPerByte)) { |
| 4015 testb(Operand(scratch, MemoryChunk::kFlagsOffset), |
| 4016 Immediate(static_cast<uint8_t>(mask))); |
| 4017 } else { |
| 4018 testl(Operand(scratch, MemoryChunk::kFlagsOffset), Immediate(mask)); |
| 4019 } |
| 4020 j(cc, condition_met, condition_met_distance); |
| 4021 } |
| 4022 |
| 4023 |
| 4024 void MacroAssembler::JumpIfBlack(Register object, |
| 4025 Register bitmap_scratch, |
| 4026 Register mask_scratch, |
| 4027 Label* on_black, |
| 4028 Label::Distance on_black_distance) { |
| 4029 ASSERT(!AreAliased(object, bitmap_scratch, mask_scratch, rcx)); |
| 4030 GetMarkBits(object, bitmap_scratch, mask_scratch); |
| 4031 |
| 4032 ASSERT(strcmp(Marking::kBlackBitPattern, "10") == 0); |
| 4033 // The mask_scratch register contains a 1 at the position of the first bit |
| 4034 // and a 0 at all other positions, including the position of the second bit. |
| 4035 movq(rcx, mask_scratch); |
| 4036 // Make rcx into a mask that covers both marking bits using the operation |
| 4037 // rcx = mask | (mask << 1). |
| 4038 lea(rcx, Operand(mask_scratch, mask_scratch, times_2, 0)); |
| 4039 // Note that we are using a 4-byte aligned 8-byte load. |
| 4040 and_(rcx, Operand(bitmap_scratch, MemoryChunk::kHeaderSize)); |
| 4041 cmpq(mask_scratch, rcx); |
| 4042 j(equal, on_black, on_black_distance); |
| 4043 } |
| 4044 |
| 4045 |
| 4046 // Detect some, but not all, common pointer-free objects. This is used by the |
| 4047 // incremental write barrier which doesn't care about oddballs (they are always |
| 4048 // marked black immediately so this code is not hit). |
| 4049 void MacroAssembler::JumpIfDataObject( |
| 4050 Register value, |
| 4051 Register scratch, |
| 4052 Label* not_data_object, |
| 4053 Label::Distance not_data_object_distance) { |
| 4054 Label is_data_object; |
| 4055 movq(scratch, FieldOperand(value, HeapObject::kMapOffset)); |
| 4056 CompareRoot(scratch, Heap::kHeapNumberMapRootIndex); |
| 4057 j(equal, &is_data_object, Label::kNear); |
| 4058 ASSERT(kIsIndirectStringTag == 1 && kIsIndirectStringMask == 1); |
| 4059 ASSERT(kNotStringTag == 0x80 && kIsNotStringMask == 0x80); |
| 4060 // If it's a string and it's not a cons string then it's an object containing |
| 4061 // no GC pointers. |
| 4062 testb(FieldOperand(scratch, Map::kInstanceTypeOffset), |
| 4063 Immediate(kIsIndirectStringMask | kIsNotStringMask)); |
| 4064 j(not_zero, not_data_object, not_data_object_distance); |
| 4065 bind(&is_data_object); |
| 4066 } |
| 4067 |
| 4068 |
| 4069 void MacroAssembler::GetMarkBits(Register addr_reg, |
| 4070 Register bitmap_reg, |
| 4071 Register mask_reg) { |
| 4072 ASSERT(!AreAliased(addr_reg, bitmap_reg, mask_reg, rcx)); |
| 4073 movq(bitmap_reg, addr_reg); |
| 4074 // Sign extended 32 bit immediate. |
| 4075 and_(bitmap_reg, Immediate(~Page::kPageAlignmentMask)); |
| 4076 movq(rcx, addr_reg); |
| 4077 int shift = |
| 4078 Bitmap::kBitsPerCellLog2 + kPointerSizeLog2 - Bitmap::kBytesPerCellLog2; |
| 4079 shrl(rcx, Immediate(shift)); |
| 4080 and_(rcx, |
| 4081 Immediate((Page::kPageAlignmentMask >> shift) & |
| 4082 ~(Bitmap::kBytesPerCell - 1))); |
| 4083 |
| 4084 addq(bitmap_reg, rcx); |
| 4085 movq(rcx, addr_reg); |
| 4086 shrl(rcx, Immediate(kPointerSizeLog2)); |
| 4087 and_(rcx, Immediate((1 << Bitmap::kBitsPerCellLog2) - 1)); |
| 4088 movl(mask_reg, Immediate(1)); |
| 4089 shl_cl(mask_reg); |
| 4090 } |
| 4091 |
| 4092 |
| 4093 void MacroAssembler::EnsureNotWhite( |
| 4094 Register value, |
| 4095 Register bitmap_scratch, |
| 4096 Register mask_scratch, |
| 4097 Label* value_is_white_and_not_data, |
| 4098 Label::Distance distance) { |
| 4099 ASSERT(!AreAliased(value, bitmap_scratch, mask_scratch, rcx)); |
| 4100 GetMarkBits(value, bitmap_scratch, mask_scratch); |
| 4101 |
| 4102 // If the value is black or grey we don't need to do anything. |
| 4103 ASSERT(strcmp(Marking::kWhiteBitPattern, "00") == 0); |
| 4104 ASSERT(strcmp(Marking::kBlackBitPattern, "10") == 0); |
| 4105 ASSERT(strcmp(Marking::kGreyBitPattern, "11") == 0); |
| 4106 ASSERT(strcmp(Marking::kImpossibleBitPattern, "01") == 0); |
| 4107 |
| 4108 Label done; |
| 4109 |
| 4110 // Since both black and grey have a 1 in the first position and white does |
| 4111 // not have a 1 there we only need to check one bit. |
| 4112 testq(Operand(bitmap_scratch, MemoryChunk::kHeaderSize), mask_scratch); |
| 4113 j(not_zero, &done, Label::kNear); |
| 4114 |
| 4115 if (FLAG_debug_code) { |
| 4116 // Check for impossible bit pattern. |
| 4117 Label ok; |
| 4118 push(mask_scratch); |
| 4119 // shl. May overflow making the check conservative. |
| 4120 addq(mask_scratch, mask_scratch); |
| 4121 testq(Operand(bitmap_scratch, MemoryChunk::kHeaderSize), mask_scratch); |
| 4122 j(zero, &ok, Label::kNear); |
| 4123 int3(); |
| 4124 bind(&ok); |
| 4125 pop(mask_scratch); |
| 4126 } |
| 4127 |
| 4128 // Value is white. We check whether it is data that doesn't need scanning. |
| 4129 // Currently only checks for HeapNumber and non-cons strings. |
| 4130 Register map = rcx; // Holds map while checking type. |
| 4131 Register length = rcx; // Holds length of object after checking type. |
| 4132 Label not_heap_number; |
| 4133 Label is_data_object; |
| 4134 |
| 4135 // Check for heap-number |
| 4136 movq(map, FieldOperand(value, HeapObject::kMapOffset)); |
| 4137 CompareRoot(map, Heap::kHeapNumberMapRootIndex); |
| 4138 j(not_equal, ¬_heap_number, Label::kNear); |
| 4139 movq(length, Immediate(HeapNumber::kSize)); |
| 4140 jmp(&is_data_object, Label::kNear); |
| 4141 |
| 4142 bind(¬_heap_number); |
| 4143 // Check for strings. |
| 4144 ASSERT(kIsIndirectStringTag == 1 && kIsIndirectStringMask == 1); |
| 4145 ASSERT(kNotStringTag == 0x80 && kIsNotStringMask == 0x80); |
| 4146 // If it's a string and it's not a cons string then it's an object containing |
| 4147 // no GC pointers. |
| 4148 Register instance_type = rcx; |
| 4149 movzxbl(instance_type, FieldOperand(map, Map::kInstanceTypeOffset)); |
| 4150 testb(instance_type, Immediate(kIsIndirectStringMask | kIsNotStringMask)); |
| 4151 j(not_zero, value_is_white_and_not_data); |
| 4152 // It's a non-indirect (non-cons and non-slice) string. |
| 4153 // If it's external, the length is just ExternalString::kSize. |
| 4154 // Otherwise it's String::kHeaderSize + string->length() * (1 or 2). |
| 4155 Label not_external; |
| 4156 // External strings are the only ones with the kExternalStringTag bit |
| 4157 // set. |
| 4158 ASSERT_EQ(0, kSeqStringTag & kExternalStringTag); |
| 4159 ASSERT_EQ(0, kConsStringTag & kExternalStringTag); |
| 4160 testb(instance_type, Immediate(kExternalStringTag)); |
| 4161 j(zero, ¬_external, Label::kNear); |
| 4162 movq(length, Immediate(ExternalString::kSize)); |
| 4163 jmp(&is_data_object, Label::kNear); |
| 4164 |
| 4165 bind(¬_external); |
| 4166 // Sequential string, either ASCII or UC16. |
| 4167 ASSERT(kAsciiStringTag == 0x04); |
| 4168 and_(length, Immediate(kStringEncodingMask)); |
| 4169 xor_(length, Immediate(kStringEncodingMask)); |
| 4170 addq(length, Immediate(0x04)); |
| 4171 // Value now either 4 (if ASCII) or 8 (if UC16), i.e. char-size shifted by 2. |
| 4172 imul(length, FieldOperand(value, String::kLengthOffset)); |
| 4173 shr(length, Immediate(2 + kSmiTagSize)); |
| 4174 addq(length, Immediate(SeqString::kHeaderSize + kObjectAlignmentMask)); |
| 4175 and_(length, Immediate(~kObjectAlignmentMask)); |
| 4176 |
| 4177 bind(&is_data_object); |
| 4178 // Value is a data object, and it is white. Mark it black. Since we know |
| 4179 // that the object is white we can make it black by flipping one bit. |
| 4180 or_(Operand(bitmap_scratch, MemoryChunk::kHeaderSize), mask_scratch); |
| 4181 |
| 4182 and_(bitmap_scratch, Immediate(~Page::kPageAlignmentMask)); |
| 4183 addl(Operand(bitmap_scratch, MemoryChunk::kLiveBytesOffset), length); |
| 4184 |
| 4185 bind(&done); |
| 4186 } |
| 4187 |
| 3919 } } // namespace v8::internal | 4188 } } // namespace v8::internal |
| 3920 | 4189 |
| 3921 #endif // V8_TARGET_ARCH_X64 | 4190 #endif // V8_TARGET_ARCH_X64 |
| OLD | NEW |