diff options
Diffstat (limited to 'deps/v8/src/ia32/macro-assembler-ia32.cc')
-rw-r--r-- | deps/v8/src/ia32/macro-assembler-ia32.cc | 737 |
1 files changed, 155 insertions, 582 deletions
diff --git a/deps/v8/src/ia32/macro-assembler-ia32.cc b/deps/v8/src/ia32/macro-assembler-ia32.cc index 3aaa22acc..837112a55 100644 --- a/deps/v8/src/ia32/macro-assembler-ia32.cc +++ b/deps/v8/src/ia32/macro-assembler-ia32.cc @@ -44,8 +44,7 @@ namespace internal { MacroAssembler::MacroAssembler(Isolate* arg_isolate, void* buffer, int size) : Assembler(arg_isolate, buffer, size), generating_stub_(false), - allow_stub_calls_(true), - has_frame_(false) { + allow_stub_calls_(true) { if (isolate() != NULL) { code_object_ = Handle<Object>(isolate()->heap()->undefined_value(), isolate()); @@ -53,75 +52,33 @@ MacroAssembler::MacroAssembler(Isolate* arg_isolate, void* buffer, int size) } -void MacroAssembler::InNewSpace( - Register object, - Register scratch, - Condition cc, - Label* condition_met, - Label::Distance condition_met_distance) { - ASSERT(cc == equal || cc == not_equal); - if (scratch.is(object)) { - and_(scratch, Immediate(~Page::kPageAlignmentMask)); - } else { - mov(scratch, Immediate(~Page::kPageAlignmentMask)); - and_(scratch, object); +void MacroAssembler::RecordWriteHelper(Register object, + Register addr, + Register scratch) { + if (emit_debug_code()) { + // Check that the object is not in new space. + Label not_in_new_space; + InNewSpace(object, scratch, not_equal, ¬_in_new_space); + Abort("new-space object passed to RecordWriteHelper"); + bind(¬_in_new_space); } - // Check that we can use a test_b. - ASSERT(MemoryChunk::IN_FROM_SPACE < 8); - ASSERT(MemoryChunk::IN_TO_SPACE < 8); - int mask = (1 << MemoryChunk::IN_FROM_SPACE) - | (1 << MemoryChunk::IN_TO_SPACE); - // If non-zero, the page belongs to new-space. - test_b(Operand(scratch, MemoryChunk::kFlagsOffset), - static_cast<uint8_t>(mask)); - j(cc, condition_met, condition_met_distance); -} + // Compute the page start address from the heap object pointer, and reuse + // the 'object' register for it. + and_(object, ~Page::kPageAlignmentMask); -void MacroAssembler::RememberedSetHelper( - Register object, // Only used for debug checks. - Register addr, - Register scratch, - SaveFPRegsMode save_fp, - MacroAssembler::RememberedSetFinalAction and_then) { - Label done; - if (FLAG_debug_code) { - Label ok; - JumpIfNotInNewSpace(object, scratch, &ok, Label::kNear); - int3(); - bind(&ok); - } - // Load store buffer top. - ExternalReference store_buffer = - ExternalReference::store_buffer_top(isolate()); - mov(scratch, Operand::StaticVariable(store_buffer)); - // Store pointer to buffer. - mov(Operand(scratch, 0), addr); - // Increment buffer top. - add(scratch, Immediate(kPointerSize)); - // Write back new top of buffer. - mov(Operand::StaticVariable(store_buffer), scratch); - // Call stub on end of buffer. - // Check for end of buffer. - test(scratch, Immediate(StoreBuffer::kStoreBufferOverflowBit)); - if (and_then == kReturnAtEnd) { - Label buffer_overflowed; - j(not_equal, &buffer_overflowed, Label::kNear); - ret(0); - bind(&buffer_overflowed); - } else { - ASSERT(and_then == kFallThroughAtEnd); - j(equal, &done, Label::kNear); - } - StoreBufferOverflowStub store_buffer_overflow = - StoreBufferOverflowStub(save_fp); - CallStub(&store_buffer_overflow); - if (and_then == kReturnAtEnd) { - ret(0); - } else { - ASSERT(and_then == kFallThroughAtEnd); - bind(&done); - } + // Compute number of region covering addr. See Page::GetRegionNumberForAddress + // method for more details. + shr(addr, Page::kRegionSizeLog2); + and_(addr, Page::kPageAlignmentMask >> Page::kRegionSizeLog2); + + // Set dirty mark for region. + // Bit tests with a memory operand should be avoided on Intel processors, + // as they usually have long latency and multiple uops. We load the bit base + // operand to a register at first and store it back after bit set. + mov(scratch, Operand(object, Page::kDirtyFlagOffset)); + bts(Operand(scratch), addr); + mov(Operand(object, Page::kDirtyFlagOffset), scratch); } @@ -155,144 +112,100 @@ void MacroAssembler::ClampUint8(Register reg) { } -void MacroAssembler::RecordWriteArray(Register object, - Register value, - Register index, - SaveFPRegsMode save_fp, - RememberedSetAction remembered_set_action, - SmiCheck smi_check) { - // First, check if a write barrier is even needed. The tests below - // catch stores of Smis. - Label done; - - // Skip barrier if writing a smi. - if (smi_check == INLINE_SMI_CHECK) { - ASSERT_EQ(0, kSmiTag); - test(value, Immediate(kSmiTagMask)); - j(zero, &done); - } - - // Array access: calculate the destination address in the same manner as - // KeyedStoreIC::GenerateGeneric. Multiply a smi by 2 to get an offset - // into an array of words. - Register dst = index; - lea(dst, Operand(object, index, times_half_pointer_size, - FixedArray::kHeaderSize - kHeapObjectTag)); - - RecordWrite( - object, dst, value, save_fp, remembered_set_action, OMIT_SMI_CHECK); - - bind(&done); - - // Clobber clobbered input registers when running with the debug-code flag - // turned on to provoke errors. - if (emit_debug_code()) { - mov(value, Immediate(BitCast<int32_t>(kZapValue))); - mov(index, Immediate(BitCast<int32_t>(kZapValue))); +void MacroAssembler::InNewSpace(Register object, + Register scratch, + Condition cc, + Label* branch, + Label::Distance branch_near) { + ASSERT(cc == equal || cc == not_equal); + if (Serializer::enabled()) { + // Can't do arithmetic on external references if it might get serialized. + mov(scratch, Operand(object)); + // The mask isn't really an address. We load it as an external reference in + // case the size of the new space is different between the snapshot maker + // and the running system. + and_(Operand(scratch), + Immediate(ExternalReference::new_space_mask(isolate()))); + cmp(Operand(scratch), + Immediate(ExternalReference::new_space_start(isolate()))); + j(cc, branch, branch_near); + } else { + int32_t new_space_start = reinterpret_cast<int32_t>( + ExternalReference::new_space_start(isolate()).address()); + lea(scratch, Operand(object, -new_space_start)); + and_(scratch, isolate()->heap()->NewSpaceMask()); + j(cc, branch, branch_near); } } -void MacroAssembler::RecordWriteField( - Register object, - int offset, - Register value, - Register dst, - SaveFPRegsMode save_fp, - RememberedSetAction remembered_set_action, - SmiCheck smi_check) { +void MacroAssembler::RecordWrite(Register object, + int offset, + Register value, + Register scratch) { // First, check if a write barrier is even needed. The tests below - // catch stores of Smis. + // catch stores of Smis and stores into young gen. Label done; // Skip barrier if writing a smi. - if (smi_check == INLINE_SMI_CHECK) { - JumpIfSmi(value, &done, Label::kNear); - } + STATIC_ASSERT(kSmiTag == 0); + JumpIfSmi(value, &done, Label::kNear); - // Although the object register is tagged, the offset is relative to the start - // of the object, so so offset must be a multiple of kPointerSize. - ASSERT(IsAligned(offset, kPointerSize)); + InNewSpace(object, value, equal, &done, Label::kNear); - lea(dst, FieldOperand(object, offset)); - if (emit_debug_code()) { - Label ok; - test_b(dst, (1 << kPointerSizeLog2) - 1); - j(zero, &ok, Label::kNear); - int3(); - bind(&ok); - } + // The offset is relative to a tagged or untagged HeapObject pointer, + // so either offset or offset + kHeapObjectTag must be a + // multiple of kPointerSize. + ASSERT(IsAligned(offset, kPointerSize) || + IsAligned(offset + kHeapObjectTag, kPointerSize)); - RecordWrite( - object, dst, value, save_fp, remembered_set_action, OMIT_SMI_CHECK); + Register dst = scratch; + if (offset != 0) { + lea(dst, Operand(object, offset)); + } else { + // Array access: calculate the destination address in the same manner as + // KeyedStoreIC::GenerateGeneric. Multiply a smi by 2 to get an offset + // into an array of words. + STATIC_ASSERT(kSmiTagSize == 1); + STATIC_ASSERT(kSmiTag == 0); + lea(dst, Operand(object, dst, times_half_pointer_size, + FixedArray::kHeaderSize - kHeapObjectTag)); + } + RecordWriteHelper(object, dst, value); bind(&done); - // Clobber clobbered input registers when running with the debug-code flag + // Clobber all input registers when running with the debug-code flag // turned on to provoke errors. if (emit_debug_code()) { + mov(object, Immediate(BitCast<int32_t>(kZapValue))); mov(value, Immediate(BitCast<int32_t>(kZapValue))); - mov(dst, Immediate(BitCast<int32_t>(kZapValue))); + mov(scratch, Immediate(BitCast<int32_t>(kZapValue))); } } void MacroAssembler::RecordWrite(Register object, Register address, - Register value, - SaveFPRegsMode fp_mode, - RememberedSetAction remembered_set_action, - SmiCheck smi_check) { - ASSERT(!object.is(value)); - ASSERT(!object.is(address)); - ASSERT(!value.is(address)); - if (emit_debug_code()) { - AbortIfSmi(object); - } - - if (remembered_set_action == OMIT_REMEMBERED_SET && - !FLAG_incremental_marking) { - return; - } - - if (FLAG_debug_code) { - Label ok; - cmp(value, Operand(address, 0)); - j(equal, &ok, Label::kNear); - int3(); - bind(&ok); - } - + Register value) { // First, check if a write barrier is even needed. The tests below // catch stores of Smis and stores into young gen. Label done; - if (smi_check == INLINE_SMI_CHECK) { - // Skip barrier if writing a smi. - JumpIfSmi(value, &done, Label::kNear); - } - - CheckPageFlag(value, - value, // Used as scratch. - MemoryChunk::kPointersToHereAreInterestingMask, - zero, - &done, - Label::kNear); - CheckPageFlag(object, - value, // Used as scratch. - MemoryChunk::kPointersFromHereAreInterestingMask, - zero, - &done, - Label::kNear); - - RecordWriteStub stub(object, value, address, remembered_set_action, fp_mode); - CallStub(&stub); + // Skip barrier if writing a smi. + STATIC_ASSERT(kSmiTag == 0); + JumpIfSmi(value, &done, Label::kNear); + + InNewSpace(object, value, equal, &done); + + RecordWriteHelper(object, address, value); bind(&done); - // Clobber clobbered registers when running with the debug-code flag + // Clobber all input registers when running with the debug-code flag // turned on to provoke errors. if (emit_debug_code()) { + mov(object, Immediate(BitCast<int32_t>(kZapValue))); mov(address, Immediate(BitCast<int32_t>(kZapValue))); mov(value, Immediate(BitCast<int32_t>(kZapValue))); } @@ -311,7 +224,7 @@ void MacroAssembler::DebugBreak() { void MacroAssembler::Set(Register dst, const Immediate& x) { if (x.is_zero()) { - xor_(dst, dst); // Shorter than mov. + xor_(dst, Operand(dst)); // Shorter than mov. } else { mov(dst, x); } @@ -374,111 +287,13 @@ void MacroAssembler::CmpInstanceType(Register map, InstanceType type) { void MacroAssembler::CheckFastElements(Register map, Label* fail, Label::Distance distance) { - STATIC_ASSERT(FAST_SMI_ONLY_ELEMENTS == 0); - STATIC_ASSERT(FAST_ELEMENTS == 1); - cmpb(FieldOperand(map, Map::kBitField2Offset), - Map::kMaximumBitField2FastElementValue); - j(above, fail, distance); -} - - -void MacroAssembler::CheckFastObjectElements(Register map, - Label* fail, - Label::Distance distance) { - STATIC_ASSERT(FAST_SMI_ONLY_ELEMENTS == 0); - STATIC_ASSERT(FAST_ELEMENTS == 1); - cmpb(FieldOperand(map, Map::kBitField2Offset), - Map::kMaximumBitField2FastSmiOnlyElementValue); - j(below_equal, fail, distance); + STATIC_ASSERT(FAST_ELEMENTS == 0); cmpb(FieldOperand(map, Map::kBitField2Offset), Map::kMaximumBitField2FastElementValue); j(above, fail, distance); } -void MacroAssembler::CheckFastSmiOnlyElements(Register map, - Label* fail, - Label::Distance distance) { - STATIC_ASSERT(FAST_SMI_ONLY_ELEMENTS == 0); - cmpb(FieldOperand(map, Map::kBitField2Offset), - Map::kMaximumBitField2FastSmiOnlyElementValue); - j(above, fail, distance); -} - - -void MacroAssembler::StoreNumberToDoubleElements( - Register maybe_number, - Register elements, - Register key, - Register scratch1, - XMMRegister scratch2, - Label* fail, - bool specialize_for_processor) { - Label smi_value, done, maybe_nan, not_nan, is_nan, have_double_value; - JumpIfSmi(maybe_number, &smi_value, Label::kNear); - - CheckMap(maybe_number, - isolate()->factory()->heap_number_map(), - fail, - DONT_DO_SMI_CHECK); - - // Double value, canonicalize NaN. - uint32_t offset = HeapNumber::kValueOffset + sizeof(kHoleNanLower32); - cmp(FieldOperand(maybe_number, offset), - Immediate(kNaNOrInfinityLowerBoundUpper32)); - j(greater_equal, &maybe_nan, Label::kNear); - - bind(¬_nan); - ExternalReference canonical_nan_reference = - ExternalReference::address_of_canonical_non_hole_nan(); - if (CpuFeatures::IsSupported(SSE2) && specialize_for_processor) { - CpuFeatures::Scope use_sse2(SSE2); - movdbl(scratch2, FieldOperand(maybe_number, HeapNumber::kValueOffset)); - bind(&have_double_value); - movdbl(FieldOperand(elements, key, times_4, FixedDoubleArray::kHeaderSize), - scratch2); - } else { - fld_d(FieldOperand(maybe_number, HeapNumber::kValueOffset)); - bind(&have_double_value); - fstp_d(FieldOperand(elements, key, times_4, FixedDoubleArray::kHeaderSize)); - } - jmp(&done); - - bind(&maybe_nan); - // Could be NaN or Infinity. If fraction is not zero, it's NaN, otherwise - // it's an Infinity, and the non-NaN code path applies. - j(greater, &is_nan, Label::kNear); - cmp(FieldOperand(maybe_number, HeapNumber::kValueOffset), Immediate(0)); - j(zero, ¬_nan); - bind(&is_nan); - if (CpuFeatures::IsSupported(SSE2) && specialize_for_processor) { - CpuFeatures::Scope use_sse2(SSE2); - movdbl(scratch2, Operand::StaticVariable(canonical_nan_reference)); - } else { - fld_d(Operand::StaticVariable(canonical_nan_reference)); - } - jmp(&have_double_value, Label::kNear); - - bind(&smi_value); - // Value is a smi. Convert to a double and store. - // Preserve original value. - mov(scratch1, maybe_number); - SmiUntag(scratch1); - if (CpuFeatures::IsSupported(SSE2) && specialize_for_processor) { - CpuFeatures::Scope fscope(SSE2); - cvtsi2sd(scratch2, scratch1); - movdbl(FieldOperand(elements, key, times_4, FixedDoubleArray::kHeaderSize), - scratch2); - } else { - push(scratch1); - fild_s(Operand(esp, 0)); - pop(scratch1); - fstp_d(FieldOperand(elements, key, times_4, FixedDoubleArray::kHeaderSize)); - } - bind(&done); -} - - void MacroAssembler::CheckMap(Register obj, Handle<Map> map, Label* fail, @@ -530,7 +345,7 @@ void MacroAssembler::IsInstanceJSObjectType(Register map, Register scratch, Label* fail) { movzx_b(scratch, FieldOperand(map, Map::kInstanceTypeOffset)); - sub(scratch, Immediate(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE)); + sub(Operand(scratch), Immediate(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE)); cmp(scratch, LAST_NONCALLABLE_SPEC_OBJECT_TYPE - FIRST_NONCALLABLE_SPEC_OBJECT_TYPE); j(above, fail); @@ -587,7 +402,7 @@ void MacroAssembler::AbortIfSmi(Register object) { void MacroAssembler::EnterFrame(StackFrame::Type type) { push(ebp); - mov(ebp, esp); + mov(ebp, Operand(esp)); push(esi); push(Immediate(Smi::FromInt(type))); push(Immediate(CodeObject())); @@ -614,7 +429,7 @@ void MacroAssembler::EnterExitFramePrologue() { ASSERT(ExitFrameConstants::kCallerPCOffset == +1 * kPointerSize); ASSERT(ExitFrameConstants::kCallerFPOffset == 0 * kPointerSize); push(ebp); - mov(ebp, esp); + mov(ebp, Operand(esp)); // Reserve room for entry stack pointer and push the code object. ASSERT(ExitFrameConstants::kSPOffset == -1 * kPointerSize); @@ -636,14 +451,14 @@ void MacroAssembler::EnterExitFrameEpilogue(int argc, bool save_doubles) { if (save_doubles) { CpuFeatures::Scope scope(SSE2); int space = XMMRegister::kNumRegisters * kDoubleSize + argc * kPointerSize; - sub(esp, Immediate(space)); + sub(Operand(esp), Immediate(space)); const int offset = -2 * kPointerSize; for (int i = 0; i < XMMRegister::kNumRegisters; i++) { XMMRegister reg = XMMRegister::from_code(i); movdbl(Operand(ebp, offset - ((i + 1) * kDoubleSize)), reg); } } else { - sub(esp, Immediate(argc * kPointerSize)); + sub(Operand(esp), Immediate(argc * kPointerSize)); } // Get the required frame alignment for the OS. @@ -663,7 +478,7 @@ void MacroAssembler::EnterExitFrame(bool save_doubles) { // Setup argc and argv in callee-saved registers. int offset = StandardFrameConstants::kCallerSPOffset - kPointerSize; - mov(edi, eax); + mov(edi, Operand(eax)); lea(esi, Operand(ebp, eax, times_4, offset)); // Reserve space for argc, argv and isolate. @@ -717,7 +532,7 @@ void MacroAssembler::LeaveExitFrameEpilogue() { void MacroAssembler::LeaveApiExitFrame() { - mov(esp, ebp); + mov(esp, Operand(ebp)); pop(ebp); LeaveExitFrameEpilogue(); @@ -765,7 +580,7 @@ void MacroAssembler::PopTryHandler() { STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0); pop(Operand::StaticVariable(ExternalReference(Isolate::kHandlerAddress, isolate()))); - add(esp, Immediate(StackHandlerConstants::kSize - kPointerSize)); + add(Operand(esp), Immediate(StackHandlerConstants::kSize - kPointerSize)); } @@ -797,7 +612,7 @@ void MacroAssembler::Throw(Register value) { // (edx == ENTRY) == (ebp == 0) == (esi == 0), so we could test any // of them. Label skip; - cmp(edx, Immediate(StackHandler::ENTRY)); + cmp(Operand(edx), Immediate(StackHandler::ENTRY)); j(equal, &skip, Label::kNear); mov(Operand(ebp, StandardFrameConstants::kContextOffset), esi); bind(&skip); @@ -881,7 +696,7 @@ void MacroAssembler::CheckAccessGlobalProxy(Register holder_reg, // When generating debug code, make sure the lexical context is set. if (emit_debug_code()) { - cmp(scratch, Immediate(0)); + cmp(Operand(scratch), Immediate(0)); Check(not_equal, "we should not have an empty lexical context"); } // Load the global context of the current context. @@ -969,23 +784,23 @@ void MacroAssembler::LoadFromNumberDictionary(Label* miss, mov(r1, r0); not_(r0); shl(r1, 15); - add(r0, r1); + add(r0, Operand(r1)); // hash = hash ^ (hash >> 12); mov(r1, r0); shr(r1, 12); - xor_(r0, r1); + xor_(r0, Operand(r1)); // hash = hash + (hash << 2); lea(r0, Operand(r0, r0, times_4, 0)); // hash = hash ^ (hash >> 4); mov(r1, r0); shr(r1, 4); - xor_(r0, r1); + xor_(r0, Operand(r1)); // hash = hash * 2057; imul(r0, r0, 2057); // hash = hash ^ (hash >> 16); mov(r1, r0); shr(r1, 16); - xor_(r0, r1); + xor_(r0, Operand(r1)); // Compute capacity mask. mov(r1, FieldOperand(elements, NumberDictionary::kCapacityOffset)); @@ -999,9 +814,9 @@ void MacroAssembler::LoadFromNumberDictionary(Label* miss, mov(r2, r0); // Compute the masked index: (hash + i + i * i) & mask. if (i > 0) { - add(r2, Immediate(NumberDictionary::GetProbeOffset(i))); + add(Operand(r2), Immediate(NumberDictionary::GetProbeOffset(i))); } - and_(r2, r1); + and_(r2, Operand(r1)); // Scale the index by multiplying by the entry size. ASSERT(NumberDictionary::kEntrySize == 3); @@ -1057,7 +872,7 @@ void MacroAssembler::LoadAllocationTopHelper(Register result, if (scratch.is(no_reg)) { mov(result, Operand::StaticVariable(new_space_allocation_top)); } else { - mov(scratch, Immediate(new_space_allocation_top)); + mov(Operand(scratch), Immediate(new_space_allocation_top)); mov(result, Operand(scratch, 0)); } } @@ -1116,7 +931,7 @@ void MacroAssembler::AllocateInNewSpace(int object_size, if (!top_reg.is(result)) { mov(top_reg, result); } - add(top_reg, Immediate(object_size)); + add(Operand(top_reg), Immediate(object_size)); j(carry, gc_required); cmp(top_reg, Operand::StaticVariable(new_space_allocation_limit)); j(above, gc_required); @@ -1127,12 +942,12 @@ void MacroAssembler::AllocateInNewSpace(int object_size, // Tag result if requested. if (top_reg.is(result)) { if ((flags & TAG_OBJECT) != 0) { - sub(result, Immediate(object_size - kHeapObjectTag)); + sub(Operand(result), Immediate(object_size - kHeapObjectTag)); } else { - sub(result, Immediate(object_size)); + sub(Operand(result), Immediate(object_size)); } } else if ((flags & TAG_OBJECT) != 0) { - add(result, Immediate(kHeapObjectTag)); + add(Operand(result), Immediate(kHeapObjectTag)); } } @@ -1170,7 +985,7 @@ void MacroAssembler::AllocateInNewSpace(int header_size, // We assume that element_count*element_size + header_size does not // overflow. lea(result_end, Operand(element_count, element_size, header_size)); - add(result_end, result); + add(result_end, Operand(result)); j(carry, gc_required); cmp(result_end, Operand::StaticVariable(new_space_allocation_limit)); j(above, gc_required); @@ -1215,7 +1030,7 @@ void MacroAssembler::AllocateInNewSpace(Register object_size, if (!object_size.is(result_end)) { mov(result_end, object_size); } - add(result_end, result); + add(result_end, Operand(result)); j(carry, gc_required); cmp(result_end, Operand::StaticVariable(new_space_allocation_limit)); j(above, gc_required); @@ -1235,7 +1050,7 @@ void MacroAssembler::UndoAllocationInNewSpace(Register object) { ExternalReference::new_space_allocation_top_address(isolate()); // Make sure the object has no tag before resetting top. - and_(object, Immediate(~kHeapObjectTagMask)); + and_(Operand(object), Immediate(~kHeapObjectTagMask)); #ifdef DEBUG cmp(object, Operand::StaticVariable(new_space_allocation_top)); Check(below, "Undo allocation of non allocated memory"); @@ -1274,7 +1089,7 @@ void MacroAssembler::AllocateTwoByteString(Register result, ASSERT(kShortSize == 2); // scratch1 = length * 2 + kObjectAlignmentMask. lea(scratch1, Operand(length, length, times_1, kObjectAlignmentMask)); - and_(scratch1, Immediate(~kObjectAlignmentMask)); + and_(Operand(scratch1), Immediate(~kObjectAlignmentMask)); // Allocate two byte string in new space. AllocateInNewSpace(SeqTwoByteString::kHeaderSize, @@ -1308,8 +1123,8 @@ void MacroAssembler::AllocateAsciiString(Register result, ASSERT((SeqAsciiString::kHeaderSize & kObjectAlignmentMask) == 0); mov(scratch1, length); ASSERT(kCharSize == 1); - add(scratch1, Immediate(kObjectAlignmentMask)); - and_(scratch1, Immediate(~kObjectAlignmentMask)); + add(Operand(scratch1), Immediate(kObjectAlignmentMask)); + and_(Operand(scratch1), Immediate(~kObjectAlignmentMask)); // Allocate ascii string in new space. AllocateInNewSpace(SeqAsciiString::kHeaderSize, @@ -1443,7 +1258,7 @@ void MacroAssembler::CopyBytes(Register source, Register scratch) { Label loop, done, short_string, short_loop; // Experimentation shows that the short string loop is faster if length < 10. - cmp(length, Immediate(10)); + cmp(Operand(length), Immediate(10)); j(less_equal, &short_string); ASSERT(source.is(esi)); @@ -1458,12 +1273,12 @@ void MacroAssembler::CopyBytes(Register source, mov(scratch, ecx); shr(ecx, 2); rep_movs(); - and_(scratch, Immediate(0x3)); - add(destination, scratch); + and_(Operand(scratch), Immediate(0x3)); + add(destination, Operand(scratch)); jmp(&done); bind(&short_string); - test(length, length); + test(length, Operand(length)); j(zero, &done); bind(&short_loop); @@ -1478,27 +1293,13 @@ void MacroAssembler::CopyBytes(Register source, } -void MacroAssembler::InitializeFieldsWithFiller(Register start_offset, - Register end_offset, - Register filler) { - Label loop, entry; - jmp(&entry); - bind(&loop); - mov(Operand(start_offset, 0), filler); - add(start_offset, Immediate(kPointerSize)); - bind(&entry); - cmp(start_offset, end_offset); - j(less, &loop); -} - - void MacroAssembler::NegativeZeroTest(Register result, Register op, Label* then_label) { Label ok; - test(result, result); + test(result, Operand(result)); j(not_zero, &ok); - test(op, op); + test(op, Operand(op)); j(sign, then_label); bind(&ok); } @@ -1510,10 +1311,10 @@ void MacroAssembler::NegativeZeroTest(Register result, Register scratch, Label* then_label) { Label ok; - test(result, result); + test(result, Operand(result)); j(not_zero, &ok); - mov(scratch, op1); - or_(scratch, op2); + mov(scratch, Operand(op1)); + or_(scratch, Operand(op2)); j(sign, then_label); bind(&ok); } @@ -1543,7 +1344,7 @@ void MacroAssembler::TryGetFunctionPrototype(Register function, // If the prototype or initial map is the hole, don't return it and // simply miss the cache instead. This will allow us to allocate a // prototype object on-demand in the runtime system. - cmp(result, Immediate(isolate()->factory()->the_hole_value())); + cmp(Operand(result), Immediate(isolate()->factory()->the_hole_value())); j(equal, miss); // If the function does not have an initial map, we're done. @@ -1566,13 +1367,13 @@ void MacroAssembler::TryGetFunctionPrototype(Register function, void MacroAssembler::CallStub(CodeStub* stub, unsigned ast_id) { - ASSERT(AllowThisStubCall(stub)); // Calls are not allowed in some stubs. + ASSERT(allow_stub_calls()); // Calls are not allowed in some stubs. call(stub->GetCode(), RelocInfo::CODE_TARGET, ast_id); } MaybeObject* MacroAssembler::TryCallStub(CodeStub* stub) { - ASSERT(AllowThisStubCall(stub)); // Calls are not allowed in some stubs. + ASSERT(allow_stub_calls()); // Calls are not allowed in some stubs. Object* result; { MaybeObject* maybe_result = stub->TryGetCode(); if (!maybe_result->ToObject(&result)) return maybe_result; @@ -1583,12 +1384,13 @@ MaybeObject* MacroAssembler::TryCallStub(CodeStub* stub) { void MacroAssembler::TailCallStub(CodeStub* stub) { - ASSERT(allow_stub_calls_ || stub->CompilingCallsToThisStubIsGCSafe()); + ASSERT(allow_stub_calls()); // Calls are not allowed in some stubs. jmp(stub->GetCode(), RelocInfo::CODE_TARGET); } MaybeObject* MacroAssembler::TryTailCallStub(CodeStub* stub) { + ASSERT(allow_stub_calls()); // Calls are not allowed in some stubs. Object* result; { MaybeObject* maybe_result = stub->TryGetCode(); if (!maybe_result->ToObject(&result)) return maybe_result; @@ -1604,15 +1406,9 @@ void MacroAssembler::StubReturn(int argc) { } -bool MacroAssembler::AllowThisStubCall(CodeStub* stub) { - if (!has_frame_ && stub->SometimesSetsUpAFrame()) return false; - return allow_stub_calls_ || stub->CompilingCallsToThisStubIsGCSafe(); -} - - void MacroAssembler::IllegalOperation(int num_arguments) { if (num_arguments > 0) { - add(esp, Immediate(num_arguments * kPointerSize)); + add(Operand(esp), Immediate(num_arguments * kPointerSize)); } mov(eax, Immediate(isolate()->factory()->undefined_value())); } @@ -1646,7 +1442,8 @@ void MacroAssembler::CallRuntimeSaveDoubles(Runtime::FunctionId id) { const Runtime::Function* function = Runtime::FunctionForId(id); Set(eax, Immediate(function->nargs)); mov(ebx, Immediate(ExternalReference(function, isolate()))); - CEntryStub ces(1, kSaveFPRegs); + CEntryStub ces(1); + ces.SaveDoubles(); CallStub(&ces); } @@ -1826,7 +1623,7 @@ MaybeObject* MacroAssembler::TryCallApiFunctionAndReturn(ApiFunction* function, Label leave_exit_frame; // Check if the result handle holds 0. - test(eax, eax); + test(eax, Operand(eax)); j(zero, &empty_handle); // It was non-zero. Dereference to get the result value. mov(eax, Operand(eax, 0)); @@ -1867,7 +1664,7 @@ MaybeObject* MacroAssembler::TryCallApiFunctionAndReturn(ApiFunction* function, mov(edi, eax); mov(Operand(esp, 0), Immediate(ExternalReference::isolate_address())); mov(eax, Immediate(delete_extensions)); - call(eax); + call(Operand(eax)); mov(eax, edi); jmp(&leave_exit_frame); @@ -1901,10 +1698,10 @@ void MacroAssembler::SetCallKind(Register dst, CallKind call_kind) { if (call_kind == CALL_AS_FUNCTION) { // Set to some non-zero smi by updating the least significant // byte. - mov_b(dst, 1 << kSmiTagSize); + mov_b(Operand(dst), 1 << kSmiTagSize); } else { // Set to smi zero by clearing the register. - xor_(dst, dst); + xor_(dst, Operand(dst)); } } @@ -1949,7 +1746,7 @@ void MacroAssembler::InvokePrologue(const ParameterCount& expected, } else if (!expected.reg().is(actual.reg())) { // Both expected and actual are in (different) registers. This // is the case when we invoke functions using call and apply. - cmp(expected.reg(), actual.reg()); + cmp(expected.reg(), Operand(actual.reg())); j(equal, &invoke); ASSERT(actual.reg().is(eax)); ASSERT(expected.reg().is(ebx)); @@ -1961,7 +1758,7 @@ void MacroAssembler::InvokePrologue(const ParameterCount& expected, isolate()->builtins()->ArgumentsAdaptorTrampoline(); if (!code_constant.is_null()) { mov(edx, Immediate(code_constant)); - add(edx, Immediate(Code::kHeaderSize - kHeapObjectTag)); + add(Operand(edx), Immediate(Code::kHeaderSize - kHeapObjectTag)); } else if (!code_operand.is_reg(edx)) { mov(edx, code_operand); } @@ -1987,9 +1784,6 @@ void MacroAssembler::InvokeCode(const Operand& code, InvokeFlag flag, const CallWrapper& call_wrapper, CallKind call_kind) { - // You can't call a function without a valid frame. - ASSERT(flag == JUMP_FUNCTION || has_frame()); - Label done; InvokePrologue(expected, actual, Handle<Code>::null(), code, &done, flag, Label::kNear, call_wrapper, @@ -2015,11 +1809,8 @@ void MacroAssembler::InvokeCode(Handle<Code> code, InvokeFlag flag, const CallWrapper& call_wrapper, CallKind call_kind) { - // You can't call a function without a valid frame. - ASSERT(flag == JUMP_FUNCTION || has_frame()); - Label done; - Operand dummy(eax, 0); + Operand dummy(eax); InvokePrologue(expected, actual, code, dummy, &done, flag, Label::kNear, call_wrapper, call_kind); if (flag == CALL_FUNCTION) { @@ -2041,9 +1832,6 @@ void MacroAssembler::InvokeFunction(Register fun, InvokeFlag flag, const CallWrapper& call_wrapper, CallKind call_kind) { - // You can't call a function without a valid frame. - ASSERT(flag == JUMP_FUNCTION || has_frame()); - ASSERT(fun.is(edi)); mov(edx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset)); mov(esi, FieldOperand(edi, JSFunction::kContextOffset)); @@ -2061,9 +1849,6 @@ void MacroAssembler::InvokeFunction(JSFunction* function, InvokeFlag flag, const CallWrapper& call_wrapper, CallKind call_kind) { - // You can't call a function without a valid frame. - ASSERT(flag == JUMP_FUNCTION || has_frame()); - ASSERT(function->is_compiled()); // Get the function and setup the context. mov(edi, Immediate(Handle<JSFunction>(function))); @@ -2087,8 +1872,8 @@ void MacroAssembler::InvokeFunction(JSFunction* function, void MacroAssembler::InvokeBuiltin(Builtins::JavaScript id, InvokeFlag flag, const CallWrapper& call_wrapper) { - // You can't call a builtin without a valid frame. - ASSERT(flag == JUMP_FUNCTION || has_frame()); + // Calls are not allowed in some stubs. + ASSERT(flag == JUMP_FUNCTION || allow_stub_calls()); // Rely on the assertion to check that the number of provided // arguments match the expected number of arguments. Fake a @@ -2099,7 +1884,6 @@ void MacroAssembler::InvokeBuiltin(Builtins::JavaScript id, expected, expected, flag, call_wrapper, CALL_AS_METHOD); } - void MacroAssembler::GetBuiltinFunction(Register target, Builtins::JavaScript id) { // Load the JavaScript builtin function from the builtins object. @@ -2109,7 +1893,6 @@ void MacroAssembler::GetBuiltinFunction(Register target, JSBuiltinsObject::OffsetOfFunctionWithId(id))); } - void MacroAssembler::GetBuiltinEntry(Register target, Builtins::JavaScript id) { ASSERT(!target.is(edi)); // Load the JavaScript builtin function from the builtins object. @@ -2211,7 +1994,7 @@ void MacroAssembler::Ret(int bytes_dropped, Register scratch) { ret(bytes_dropped); } else { pop(scratch); - add(esp, Immediate(bytes_dropped)); + add(Operand(esp), Immediate(bytes_dropped)); push(scratch); ret(0); } @@ -2222,7 +2005,7 @@ void MacroAssembler::Ret(int bytes_dropped, Register scratch) { void MacroAssembler::Drop(int stack_elements) { if (stack_elements > 0) { - add(esp, Immediate(stack_elements * kPointerSize)); + add(Operand(esp), Immediate(stack_elements * kPointerSize)); } } @@ -2365,19 +2148,13 @@ void MacroAssembler::Abort(const char* msg) { RecordComment(msg); } #endif + // Disable stub call restrictions to always allow calls to abort. + AllowStubCallsScope allow_scope(this, true); push(eax); push(Immediate(p0)); push(Immediate(reinterpret_cast<intptr_t>(Smi::FromInt(p1 - p0)))); - // Disable stub call restrictions to always allow calls to abort. - if (!has_frame_) { - // We don't actually want to generate a pile of code for this, so just - // claim there is a stack frame, without generating one. - FrameScope scope(this, StackFrame::NONE); - CallRuntime(Runtime::kAbort, 2); - } else { - CallRuntime(Runtime::kAbort, 2); - } + CallRuntime(Runtime::kAbort, 2); // will not return here int3(); } @@ -2400,7 +2177,7 @@ void MacroAssembler::LoadPowerOf2(XMMRegister dst, ASSERT(is_uintn(power + HeapNumber::kExponentBias, HeapNumber::kExponentBits)); mov(scratch, Immediate(power + HeapNumber::kExponentBias)); - movd(dst, scratch); + movd(dst, Operand(scratch)); psllq(dst, HeapNumber::kMantissaBits); } @@ -2426,8 +2203,8 @@ void MacroAssembler::JumpIfNotBothSequentialAsciiStrings(Register object1, Label* failure) { // Check that both objects are not smis. STATIC_ASSERT(kSmiTag == 0); - mov(scratch1, object1); - and_(scratch1, object2); + mov(scratch1, Operand(object1)); + and_(scratch1, Operand(object2)); JumpIfSmi(scratch1, failure); // Load instance type for both strings. @@ -2456,12 +2233,12 @@ void MacroAssembler::PrepareCallCFunction(int num_arguments, Register scratch) { // Make stack end at alignment and make room for num_arguments words // and the original value of esp. mov(scratch, esp); - sub(esp, Immediate((num_arguments + 1) * kPointerSize)); + sub(Operand(esp), Immediate((num_arguments + 1) * kPointerSize)); ASSERT(IsPowerOf2(frame_alignment)); and_(esp, -frame_alignment); mov(Operand(esp, num_arguments * kPointerSize), scratch); } else { - sub(esp, Immediate(num_arguments * kPointerSize)); + sub(Operand(esp), Immediate(num_arguments * kPointerSize)); } } @@ -2469,39 +2246,27 @@ void MacroAssembler::PrepareCallCFunction(int num_arguments, Register scratch) { void MacroAssembler::CallCFunction(ExternalReference function, int num_arguments) { // Trashing eax is ok as it will be the return value. - mov(eax, Immediate(function)); + mov(Operand(eax), Immediate(function)); CallCFunction(eax, num_arguments); } void MacroAssembler::CallCFunction(Register function, int num_arguments) { - ASSERT(has_frame()); // Check stack alignment. if (emit_debug_code()) { CheckStackAlignment(); } - call(function); + call(Operand(function)); if (OS::ActivationFrameAlignment() != 0) { mov(esp, Operand(esp, num_arguments * kPointerSize)); } else { - add(esp, Immediate(num_arguments * kPointerSize)); + add(Operand(esp), Immediate(num_arguments * kPointerSize)); } } -bool AreAliased(Register r1, Register r2, Register r3, Register r4) { - if (r1.is(r2)) return true; - if (r1.is(r3)) return true; - if (r1.is(r4)) return true; - if (r2.is(r3)) return true; - if (r2.is(r4)) return true; - if (r3.is(r4)) return true; - return false; -} - - CodePatcher::CodePatcher(byte* address, int size) : address_(address), size_(size), @@ -2523,198 +2288,6 @@ CodePatcher::~CodePatcher() { } -void MacroAssembler::CheckPageFlag( - Register object, - Register scratch, - int mask, - Condition cc, - Label* condition_met, - Label::Distance condition_met_distance) { - ASSERT(cc == zero || cc == not_zero); - if (scratch.is(object)) { - and_(scratch, Immediate(~Page::kPageAlignmentMask)); - } else { - mov(scratch, Immediate(~Page::kPageAlignmentMask)); - and_(scratch, object); - } - if (mask < (1 << kBitsPerByte)) { - test_b(Operand(scratch, MemoryChunk::kFlagsOffset), - static_cast<uint8_t>(mask)); - } else { - test(Operand(scratch, MemoryChunk::kFlagsOffset), Immediate(mask)); - } - j(cc, condition_met, condition_met_distance); -} - - -void MacroAssembler::JumpIfBlack(Register object, - Register scratch0, - Register scratch1, - Label* on_black, - Label::Distance on_black_near) { - HasColor(object, scratch0, scratch1, - on_black, on_black_near, - 1, 0); // kBlackBitPattern. - ASSERT(strcmp(Marking::kBlackBitPattern, "10") == 0); -} - - -void MacroAssembler::HasColor(Register object, - Register bitmap_scratch, - Register mask_scratch, - Label* has_color, - Label::Distance has_color_distance, - int first_bit, - int second_bit) { - ASSERT(!AreAliased(object, bitmap_scratch, mask_scratch, ecx)); - - GetMarkBits(object, bitmap_scratch, mask_scratch); - - Label other_color, word_boundary; - test(mask_scratch, Operand(bitmap_scratch, MemoryChunk::kHeaderSize)); - j(first_bit == 1 ? zero : not_zero, &other_color, Label::kNear); - add(mask_scratch, mask_scratch); // Shift left 1 by adding. - j(zero, &word_boundary, Label::kNear); - test(mask_scratch, Operand(bitmap_scratch, MemoryChunk::kHeaderSize)); - j(second_bit == 1 ? not_zero : zero, has_color, has_color_distance); - jmp(&other_color, Label::kNear); - - bind(&word_boundary); - test_b(Operand(bitmap_scratch, MemoryChunk::kHeaderSize + kPointerSize), 1); - - j(second_bit == 1 ? not_zero : zero, has_color, has_color_distance); - bind(&other_color); -} - - -void MacroAssembler::GetMarkBits(Register addr_reg, - Register bitmap_reg, - Register mask_reg) { - ASSERT(!AreAliased(addr_reg, mask_reg, bitmap_reg, ecx)); - mov(bitmap_reg, Immediate(~Page::kPageAlignmentMask)); - and_(bitmap_reg, addr_reg); - mov(ecx, addr_reg); - int shift = - Bitmap::kBitsPerCellLog2 + kPointerSizeLog2 - Bitmap::kBytesPerCellLog2; - shr(ecx, shift); - and_(ecx, - (Page::kPageAlignmentMask >> shift) & ~(Bitmap::kBytesPerCell - 1)); - - add(bitmap_reg, ecx); - mov(ecx, addr_reg); - shr(ecx, kPointerSizeLog2); - and_(ecx, (1 << Bitmap::kBitsPerCellLog2) - 1); - mov(mask_reg, Immediate(1)); - shl_cl(mask_reg); -} - - -void MacroAssembler::EnsureNotWhite( - Register value, - Register bitmap_scratch, - Register mask_scratch, - Label* value_is_white_and_not_data, - Label::Distance distance) { - ASSERT(!AreAliased(value, bitmap_scratch, mask_scratch, ecx)); - GetMarkBits(value, bitmap_scratch, mask_scratch); - - // If the value is black or grey we don't need to do anything. - ASSERT(strcmp(Marking::kWhiteBitPattern, "00") == 0); - ASSERT(strcmp(Marking::kBlackBitPattern, "10") == 0); - ASSERT(strcmp(Marking::kGreyBitPattern, "11") == 0); - ASSERT(strcmp(Marking::kImpossibleBitPattern, "01") == 0); - - Label done; - - // Since both black and grey have a 1 in the first position and white does - // not have a 1 there we only need to check one bit. - test(mask_scratch, Operand(bitmap_scratch, MemoryChunk::kHeaderSize)); - j(not_zero, &done, Label::kNear); - - if (FLAG_debug_code) { - // Check for impossible bit pattern. - Label ok; - push(mask_scratch); - // shl. May overflow making the check conservative. - add(mask_scratch, mask_scratch); - test(mask_scratch, Operand(bitmap_scratch, MemoryChunk::kHeaderSize)); - j(zero, &ok, Label::kNear); - int3(); - bind(&ok); - pop(mask_scratch); - } - - // Value is white. We check whether it is data that doesn't need scanning. - // Currently only checks for HeapNumber and non-cons strings. - Register map = ecx; // Holds map while checking type. - Register length = ecx; // Holds length of object after checking type. - Label not_heap_number; - Label is_data_object; - - // Check for heap-number - mov(map, FieldOperand(value, HeapObject::kMapOffset)); - cmp(map, FACTORY->heap_number_map()); - j(not_equal, ¬_heap_number, Label::kNear); - mov(length, Immediate(HeapNumber::kSize)); - jmp(&is_data_object, Label::kNear); - - bind(¬_heap_number); - // Check for strings. - ASSERT(kIsIndirectStringTag == 1 && kIsIndirectStringMask == 1); - ASSERT(kNotStringTag == 0x80 && kIsNotStringMask == 0x80); - // If it's a string and it's not a cons string then it's an object containing - // no GC pointers. - Register instance_type = ecx; - movzx_b(instance_type, FieldOperand(map, Map::kInstanceTypeOffset)); - test_b(instance_type, kIsIndirectStringMask | kIsNotStringMask); - j(not_zero, value_is_white_and_not_data); - // It's a non-indirect (non-cons and non-slice) string. - // If it's external, the length is just ExternalString::kSize. - // Otherwise it's String::kHeaderSize + string->length() * (1 or 2). - Label not_external; - // External strings are the only ones with the kExternalStringTag bit - // set. - ASSERT_EQ(0, kSeqStringTag & kExternalStringTag); - ASSERT_EQ(0, kConsStringTag & kExternalStringTag); - test_b(instance_type, kExternalStringTag); - j(zero, ¬_external, Label::kNear); - mov(length, Immediate(ExternalString::kSize)); - jmp(&is_data_object, Label::kNear); - - bind(¬_external); - // Sequential string, either ASCII or UC16. - ASSERT(kAsciiStringTag == 0x04); - and_(length, Immediate(kStringEncodingMask)); - xor_(length, Immediate(kStringEncodingMask)); - add(length, Immediate(0x04)); - // Value now either 4 (if ASCII) or 8 (if UC16), i.e., char-size shifted - // by 2. If we multiply the string length as smi by this, it still - // won't overflow a 32-bit value. - ASSERT_EQ(SeqAsciiString::kMaxSize, SeqTwoByteString::kMaxSize); - ASSERT(SeqAsciiString::kMaxSize <= - static_cast<int>(0xffffffffu >> (2 + kSmiTagSize))); - imul(length, FieldOperand(value, String::kLengthOffset)); - shr(length, 2 + kSmiTagSize + kSmiShiftSize); - add(length, Immediate(SeqString::kHeaderSize + kObjectAlignmentMask)); - and_(length, Immediate(~kObjectAlignmentMask)); - - bind(&is_data_object); - // Value is a data object, and it is white. Mark it black. Since we know - // that the object is white we can make it black by flipping one bit. - or_(Operand(bitmap_scratch, MemoryChunk::kHeaderSize), mask_scratch); - - and_(bitmap_scratch, Immediate(~Page::kPageAlignmentMask)); - add(Operand(bitmap_scratch, MemoryChunk::kLiveBytesOffset), - length); - if (FLAG_debug_code) { - mov(length, Operand(bitmap_scratch, MemoryChunk::kLiveBytesOffset)); - cmp(length, Operand(bitmap_scratch, MemoryChunk::kSizeOffset)); - Check(less_equal, "Live Bytes Count overflow chunk size"); - } - - bind(&done); -} - } } // namespace v8::internal #endif // V8_TARGET_ARCH_IA32 |