55
void MacroAssembler::RecordWriteHelper(Register object,
58
if (emit_debug_code()) {
59
// Check that the object is not in new space.
60
Label not_in_new_space;
61
InNewSpace(object, scratch, not_equal, ¬_in_new_space);
62
Abort("new-space object passed to RecordWriteHelper");
63
bind(¬_in_new_space);
66
// Compute the page start address from the heap object pointer, and reuse
67
// the 'object' register for it.
68
and_(object, ~Page::kPageAlignmentMask);
70
// Compute number of region covering addr. See Page::GetRegionNumberForAddress
71
// method for more details.
72
shr(addr, Page::kRegionSizeLog2);
73
and_(addr, Page::kPageAlignmentMask >> Page::kRegionSizeLog2);
75
// Set dirty mark for region.
76
// Bit tests with a memory operand should be avoided on Intel processors,
77
// as they usually have long latency and multiple uops. We load the bit base
78
// operand to a register at first and store it back after bit set.
79
mov(scratch, Operand(object, Page::kDirtyFlagOffset));
80
bts(Operand(scratch), addr);
81
mov(Operand(object, Page::kDirtyFlagOffset), scratch);
56
void MacroAssembler::InNewSpace(
61
Label::Distance condition_met_distance) {
62
ASSERT(cc == equal || cc == not_equal);
63
if (scratch.is(object)) {
64
and_(scratch, Immediate(~Page::kPageAlignmentMask));
66
mov(scratch, Immediate(~Page::kPageAlignmentMask));
67
and_(scratch, object);
69
// Check that we can use a test_b.
70
ASSERT(MemoryChunk::IN_FROM_SPACE < 8);
71
ASSERT(MemoryChunk::IN_TO_SPACE < 8);
72
int mask = (1 << MemoryChunk::IN_FROM_SPACE)
73
| (1 << MemoryChunk::IN_TO_SPACE);
74
// If non-zero, the page belongs to new-space.
75
test_b(Operand(scratch, MemoryChunk::kFlagsOffset),
76
static_cast<uint8_t>(mask));
77
j(cc, condition_met, condition_met_distance);
81
void MacroAssembler::RememberedSetHelper(
82
Register object, // Only used for debug checks.
85
SaveFPRegsMode save_fp,
86
MacroAssembler::RememberedSetFinalAction and_then) {
88
if (FLAG_debug_code) {
90
JumpIfNotInNewSpace(object, scratch, &ok, Label::kNear);
94
// Load store buffer top.
95
ExternalReference store_buffer =
96
ExternalReference::store_buffer_top(isolate());
97
mov(scratch, Operand::StaticVariable(store_buffer));
98
// Store pointer to buffer.
99
mov(Operand(scratch, 0), addr);
100
// Increment buffer top.
101
add(scratch, Immediate(kPointerSize));
102
// Write back new top of buffer.
103
mov(Operand::StaticVariable(store_buffer), scratch);
104
// Call stub on end of buffer.
105
// Check for end of buffer.
106
test(scratch, Immediate(StoreBuffer::kStoreBufferOverflowBit));
107
if (and_then == kReturnAtEnd) {
108
Label buffer_overflowed;
109
j(not_equal, &buffer_overflowed, Label::kNear);
111
bind(&buffer_overflowed);
113
ASSERT(and_then == kFallThroughAtEnd);
114
j(equal, &done, Label::kNear);
116
StoreBufferOverflowStub store_buffer_overflow =
117
StoreBufferOverflowStub(save_fp);
118
CallStub(&store_buffer_overflow);
119
if (and_then == kReturnAtEnd) {
122
ASSERT(and_then == kFallThroughAtEnd);
115
void MacroAssembler::InNewSpace(Register object,
119
Label::Distance branch_near) {
120
ASSERT(cc == equal || cc == not_equal);
121
if (Serializer::enabled()) {
122
// Can't do arithmetic on external references if it might get serialized.
123
mov(scratch, Operand(object));
124
// The mask isn't really an address. We load it as an external reference in
125
// case the size of the new space is different between the snapshot maker
126
// and the running system.
127
and_(Operand(scratch),
128
Immediate(ExternalReference::new_space_mask(isolate())));
129
cmp(Operand(scratch),
130
Immediate(ExternalReference::new_space_start(isolate())));
131
j(cc, branch, branch_near);
133
int32_t new_space_start = reinterpret_cast<int32_t>(
134
ExternalReference::new_space_start(isolate()).address());
135
lea(scratch, Operand(object, -new_space_start));
136
and_(scratch, isolate()->heap()->NewSpaceMask());
137
j(cc, branch, branch_near);
158
void MacroAssembler::RecordWriteArray(Register object,
161
SaveFPRegsMode save_fp,
162
RememberedSetAction remembered_set_action,
163
SmiCheck smi_check) {
164
// First, check if a write barrier is even needed. The tests below
165
// catch stores of Smis.
168
// Skip barrier if writing a smi.
169
if (smi_check == INLINE_SMI_CHECK) {
170
ASSERT_EQ(0, kSmiTag);
171
test(value, Immediate(kSmiTagMask));
175
// Array access: calculate the destination address in the same manner as
176
// KeyedStoreIC::GenerateGeneric. Multiply a smi by 2 to get an offset
177
// into an array of words.
178
Register dst = index;
179
lea(dst, Operand(object, index, times_half_pointer_size,
180
FixedArray::kHeaderSize - kHeapObjectTag));
183
object, dst, value, save_fp, remembered_set_action, OMIT_SMI_CHECK);
187
// Clobber clobbered input registers when running with the debug-code flag
188
// turned on to provoke errors.
189
if (emit_debug_code()) {
190
mov(value, Immediate(BitCast<int32_t>(kZapValue)));
191
mov(index, Immediate(BitCast<int32_t>(kZapValue)));
196
void MacroAssembler::RecordWriteField(
201
SaveFPRegsMode save_fp,
202
RememberedSetAction remembered_set_action,
203
SmiCheck smi_check) {
204
// First, check if a write barrier is even needed. The tests below
205
// catch stores of Smis.
208
// Skip barrier if writing a smi.
209
if (smi_check == INLINE_SMI_CHECK) {
210
JumpIfSmi(value, &done, Label::kNear);
213
// Although the object register is tagged, the offset is relative to the start
214
// of the object, so so offset must be a multiple of kPointerSize.
215
ASSERT(IsAligned(offset, kPointerSize));
217
lea(dst, FieldOperand(object, offset));
218
if (emit_debug_code()) {
220
test_b(dst, (1 << kPointerSizeLog2) - 1);
221
j(zero, &ok, Label::kNear);
227
object, dst, value, save_fp, remembered_set_action, OMIT_SMI_CHECK);
231
// Clobber clobbered input registers when running with the debug-code flag
232
// turned on to provoke errors.
233
if (emit_debug_code()) {
234
mov(value, Immediate(BitCast<int32_t>(kZapValue)));
235
mov(dst, Immediate(BitCast<int32_t>(kZapValue)));
142
240
void MacroAssembler::RecordWrite(Register object,
146
// First, check if a write barrier is even needed. The tests below
147
// catch stores of Smis and stores into young gen.
150
// Skip barrier if writing a smi.
151
STATIC_ASSERT(kSmiTag == 0);
152
JumpIfSmi(value, &done, Label::kNear);
154
InNewSpace(object, value, equal, &done, Label::kNear);
156
// The offset is relative to a tagged or untagged HeapObject pointer,
157
// so either offset or offset + kHeapObjectTag must be a
158
// multiple of kPointerSize.
159
ASSERT(IsAligned(offset, kPointerSize) ||
160
IsAligned(offset + kHeapObjectTag, kPointerSize));
162
Register dst = scratch;
164
lea(dst, Operand(object, offset));
166
// Array access: calculate the destination address in the same manner as
167
// KeyedStoreIC::GenerateGeneric. Multiply a smi by 2 to get an offset
168
// into an array of words.
169
STATIC_ASSERT(kSmiTagSize == 1);
170
STATIC_ASSERT(kSmiTag == 0);
171
lea(dst, Operand(object, dst, times_half_pointer_size,
172
FixedArray::kHeaderSize - kHeapObjectTag));
174
RecordWriteHelper(object, dst, value);
178
// Clobber all input registers when running with the debug-code flag
179
// turned on to provoke errors.
180
if (emit_debug_code()) {
181
mov(object, Immediate(BitCast<int32_t>(kZapValue)));
182
mov(value, Immediate(BitCast<int32_t>(kZapValue)));
183
mov(scratch, Immediate(BitCast<int32_t>(kZapValue)));
188
void MacroAssembler::RecordWrite(Register object,
191
// First, check if a write barrier is even needed. The tests below
192
// catch stores of Smis and stores into young gen.
195
// Skip barrier if writing a smi.
196
STATIC_ASSERT(kSmiTag == 0);
197
JumpIfSmi(value, &done, Label::kNear);
199
InNewSpace(object, value, equal, &done);
201
RecordWriteHelper(object, address, value);
205
// Clobber all input registers when running with the debug-code flag
206
// turned on to provoke errors.
207
if (emit_debug_code()) {
208
mov(object, Immediate(BitCast<int32_t>(kZapValue)));
243
SaveFPRegsMode fp_mode,
244
RememberedSetAction remembered_set_action,
245
SmiCheck smi_check) {
246
ASSERT(!object.is(value));
247
ASSERT(!object.is(address));
248
ASSERT(!value.is(address));
249
if (emit_debug_code()) {
253
if (remembered_set_action == OMIT_REMEMBERED_SET &&
254
!FLAG_incremental_marking) {
258
if (FLAG_debug_code) {
260
cmp(value, Operand(address, 0));
261
j(equal, &ok, Label::kNear);
266
// First, check if a write barrier is even needed. The tests below
267
// catch stores of Smis and stores into young gen.
270
if (smi_check == INLINE_SMI_CHECK) {
271
// Skip barrier if writing a smi.
272
JumpIfSmi(value, &done, Label::kNear);
276
value, // Used as scratch.
277
MemoryChunk::kPointersToHereAreInterestingMask,
281
CheckPageFlag(object,
282
value, // Used as scratch.
283
MemoryChunk::kPointersFromHereAreInterestingMask,
288
RecordWriteStub stub(object, value, address, remembered_set_action, fp_mode);
293
// Clobber clobbered registers when running with the debug-code flag
294
// turned on to provoke errors.
295
if (emit_debug_code()) {
209
296
mov(address, Immediate(BitCast<int32_t>(kZapValue)));
210
297
mov(value, Immediate(BitCast<int32_t>(kZapValue)));
287
374
void MacroAssembler::CheckFastElements(Register map,
289
376
Label::Distance distance) {
290
STATIC_ASSERT(FAST_ELEMENTS == 0);
291
cmpb(FieldOperand(map, Map::kBitField2Offset),
292
Map::kMaximumBitField2FastElementValue);
293
j(above, fail, distance);
377
STATIC_ASSERT(FAST_SMI_ONLY_ELEMENTS == 0);
378
STATIC_ASSERT(FAST_ELEMENTS == 1);
379
cmpb(FieldOperand(map, Map::kBitField2Offset),
380
Map::kMaximumBitField2FastElementValue);
381
j(above, fail, distance);
385
void MacroAssembler::CheckFastObjectElements(Register map,
387
Label::Distance distance) {
388
STATIC_ASSERT(FAST_SMI_ONLY_ELEMENTS == 0);
389
STATIC_ASSERT(FAST_ELEMENTS == 1);
390
cmpb(FieldOperand(map, Map::kBitField2Offset),
391
Map::kMaximumBitField2FastSmiOnlyElementValue);
392
j(below_equal, fail, distance);
393
cmpb(FieldOperand(map, Map::kBitField2Offset),
394
Map::kMaximumBitField2FastElementValue);
395
j(above, fail, distance);
399
void MacroAssembler::CheckFastSmiOnlyElements(Register map,
401
Label::Distance distance) {
402
STATIC_ASSERT(FAST_SMI_ONLY_ELEMENTS == 0);
403
cmpb(FieldOperand(map, Map::kBitField2Offset),
404
Map::kMaximumBitField2FastSmiOnlyElementValue);
405
j(above, fail, distance);
409
void MacroAssembler::StoreNumberToDoubleElements(
410
Register maybe_number,
414
XMMRegister scratch2,
416
bool specialize_for_processor) {
417
Label smi_value, done, maybe_nan, not_nan, is_nan, have_double_value;
418
JumpIfSmi(maybe_number, &smi_value, Label::kNear);
420
CheckMap(maybe_number,
421
isolate()->factory()->heap_number_map(),
425
// Double value, canonicalize NaN.
426
uint32_t offset = HeapNumber::kValueOffset + sizeof(kHoleNanLower32);
427
cmp(FieldOperand(maybe_number, offset),
428
Immediate(kNaNOrInfinityLowerBoundUpper32));
429
j(greater_equal, &maybe_nan, Label::kNear);
432
ExternalReference canonical_nan_reference =
433
ExternalReference::address_of_canonical_non_hole_nan();
434
if (CpuFeatures::IsSupported(SSE2) && specialize_for_processor) {
435
CpuFeatures::Scope use_sse2(SSE2);
436
movdbl(scratch2, FieldOperand(maybe_number, HeapNumber::kValueOffset));
437
bind(&have_double_value);
438
movdbl(FieldOperand(elements, key, times_4, FixedDoubleArray::kHeaderSize),
441
fld_d(FieldOperand(maybe_number, HeapNumber::kValueOffset));
442
bind(&have_double_value);
443
fstp_d(FieldOperand(elements, key, times_4, FixedDoubleArray::kHeaderSize));
448
// Could be NaN or Infinity. If fraction is not zero, it's NaN, otherwise
449
// it's an Infinity, and the non-NaN code path applies.
450
j(greater, &is_nan, Label::kNear);
451
cmp(FieldOperand(maybe_number, HeapNumber::kValueOffset), Immediate(0));
454
if (CpuFeatures::IsSupported(SSE2) && specialize_for_processor) {
455
CpuFeatures::Scope use_sse2(SSE2);
456
movdbl(scratch2, Operand::StaticVariable(canonical_nan_reference));
458
fld_d(Operand::StaticVariable(canonical_nan_reference));
460
jmp(&have_double_value, Label::kNear);
463
// Value is a smi. Convert to a double and store.
464
// Preserve original value.
465
mov(scratch1, maybe_number);
467
if (CpuFeatures::IsSupported(SSE2) && specialize_for_processor) {
468
CpuFeatures::Scope fscope(SSE2);
469
cvtsi2sd(scratch2, scratch1);
470
movdbl(FieldOperand(elements, key, times_4, FixedDoubleArray::kHeaderSize),
474
fild_s(Operand(esp, 0));
476
fstp_d(FieldOperand(elements, key, times_4, FixedDoubleArray::kHeaderSize));
542
726
void MacroAssembler::PushTryHandler(CodeLocation try_location,
544
729
// Adjust this code if not the case.
545
730
STATIC_ASSERT(StackHandlerConstants::kSize == 5 * kPointerSize);
546
731
STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0);
547
STATIC_ASSERT(StackHandlerConstants::kContextOffset == 1 * kPointerSize);
548
STATIC_ASSERT(StackHandlerConstants::kFPOffset == 2 * kPointerSize);
549
STATIC_ASSERT(StackHandlerConstants::kStateOffset == 3 * kPointerSize);
550
STATIC_ASSERT(StackHandlerConstants::kPCOffset == 4 * kPointerSize);
551
// The pc (return address) is already on TOS.
732
STATIC_ASSERT(StackHandlerConstants::kCodeOffset == 1 * kPointerSize);
733
STATIC_ASSERT(StackHandlerConstants::kStateOffset == 2 * kPointerSize);
734
STATIC_ASSERT(StackHandlerConstants::kContextOffset == 3 * kPointerSize);
735
STATIC_ASSERT(StackHandlerConstants::kFPOffset == 4 * kPointerSize);
737
// We will build up the handler from the bottom by pushing on the stack.
738
// First compute the state and push the frame pointer and context.
739
unsigned state = StackHandler::OffsetField::encode(handler_index);
552
740
if (try_location == IN_JAVASCRIPT) {
553
if (type == TRY_CATCH_HANDLER) {
554
push(Immediate(StackHandler::TRY_CATCH));
556
push(Immediate(StackHandler::TRY_FINALLY));
743
state |= (type == TRY_CATCH_HANDLER)
744
? StackHandler::KindField::encode(StackHandler::TRY_CATCH)
745
: StackHandler::KindField::encode(StackHandler::TRY_FINALLY);
561
747
ASSERT(try_location == IN_JS_ENTRY);
562
// The frame pointer does not point to a JS frame so we save NULL
563
// for ebp. We expect the code throwing an exception to check ebp
564
// before dereferencing it to restore the context.
565
push(Immediate(StackHandler::ENTRY));
748
// The frame pointer does not point to a JS frame so we save NULL for
749
// ebp. We expect the code throwing an exception to check ebp before
750
// dereferencing it to restore the context.
566
751
push(Immediate(0)); // NULL frame pointer.
567
752
push(Immediate(Smi::FromInt(0))); // No context.
753
state |= StackHandler::KindField::encode(StackHandler::ENTRY);
569
// Save the current handler as the next handler.
570
push(Operand::StaticVariable(ExternalReference(Isolate::kHandlerAddress,
572
// Link this handler as the new current one.
573
mov(Operand::StaticVariable(ExternalReference(Isolate::kHandlerAddress,
756
// Push the state and the code object.
757
push(Immediate(state));
760
// Link the current handler as the next handler.
761
ExternalReference handler_address(Isolate::kHandlerAddress, isolate());
762
push(Operand::StaticVariable(handler_address));
763
// Set this new handler as the current one.
764
mov(Operand::StaticVariable(handler_address), esp);
579
768
void MacroAssembler::PopTryHandler() {
580
769
STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0);
581
pop(Operand::StaticVariable(ExternalReference(Isolate::kHandlerAddress,
583
add(Operand(esp), Immediate(StackHandlerConstants::kSize - kPointerSize));
770
ExternalReference handler_address(Isolate::kHandlerAddress, isolate());
771
pop(Operand::StaticVariable(handler_address));
772
add(esp, Immediate(StackHandlerConstants::kSize - kPointerSize));
776
void MacroAssembler::JumpToHandlerEntry() {
777
// Compute the handler entry address and jump to it. The handler table is
778
// a fixed array of (smi-tagged) code offsets.
779
// eax = exception, edi = code object, edx = state.
780
mov(ebx, FieldOperand(edi, Code::kHandlerTableOffset));
781
shr(edx, StackHandler::kKindWidth);
782
mov(edx, FieldOperand(ebx, edx, times_4, FixedArray::kHeaderSize));
784
lea(edi, FieldOperand(edi, edx, times_1, Code::kHeaderSize));
588
790
// Adjust this code if not the case.
589
791
STATIC_ASSERT(StackHandlerConstants::kSize == 5 * kPointerSize);
590
792
STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0);
591
STATIC_ASSERT(StackHandlerConstants::kContextOffset == 1 * kPointerSize);
592
STATIC_ASSERT(StackHandlerConstants::kFPOffset == 2 * kPointerSize);
593
STATIC_ASSERT(StackHandlerConstants::kStateOffset == 3 * kPointerSize);
594
STATIC_ASSERT(StackHandlerConstants::kPCOffset == 4 * kPointerSize);
595
// eax must hold the exception.
793
STATIC_ASSERT(StackHandlerConstants::kCodeOffset == 1 * kPointerSize);
794
STATIC_ASSERT(StackHandlerConstants::kStateOffset == 2 * kPointerSize);
795
STATIC_ASSERT(StackHandlerConstants::kContextOffset == 3 * kPointerSize);
796
STATIC_ASSERT(StackHandlerConstants::kFPOffset == 4 * kPointerSize);
798
// The exception is expected in eax.
596
799
if (!value.is(eax)) {
600
// Drop the sp to the top of the handler.
601
ExternalReference handler_address(Isolate::kHandlerAddress,
802
// Drop the stack pointer to the top of the top handler.
803
ExternalReference handler_address(Isolate::kHandlerAddress, isolate());
603
804
mov(esp, Operand::StaticVariable(handler_address));
605
// Restore next handler, context, and frame pointer; discard handler state.
805
// Restore the next handler.
606
806
pop(Operand::StaticVariable(handler_address));
808
// Remove the code object and state, compute the handler address in edi.
809
pop(edi); // Code object.
810
pop(edx); // Index and state.
812
// Restore the context and frame pointer.
607
813
pop(esi); // Context.
608
814
pop(ebp); // Frame pointer.
611
816
// If the handler is a JS frame, restore the context to the frame.
612
// (edx == ENTRY) == (ebp == 0) == (esi == 0), so we could test any
817
// (kind == ENTRY) == (ebp == 0) == (esi == 0), so we could test either
615
cmp(Operand(edx), Immediate(StackHandler::ENTRY));
616
j(equal, &skip, Label::kNear);
821
j(zero, &skip, Label::kNear);
617
822
mov(Operand(ebp, StandardFrameConstants::kContextOffset), esi);
825
JumpToHandlerEntry();
626
831
// Adjust this code if not the case.
627
832
STATIC_ASSERT(StackHandlerConstants::kSize == 5 * kPointerSize);
628
833
STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0);
629
STATIC_ASSERT(StackHandlerConstants::kContextOffset == 1 * kPointerSize);
630
STATIC_ASSERT(StackHandlerConstants::kFPOffset == 2 * kPointerSize);
631
STATIC_ASSERT(StackHandlerConstants::kStateOffset == 3 * kPointerSize);
632
STATIC_ASSERT(StackHandlerConstants::kPCOffset == 4 * kPointerSize);
634
// eax must hold the exception.
635
if (!value.is(eax)) {
639
// Drop sp to the top stack handler.
640
ExternalReference handler_address(Isolate::kHandlerAddress,
642
mov(esp, Operand::StaticVariable(handler_address));
644
// Unwind the handlers until the ENTRY handler is found.
647
// Load the type of the current stack handler.
648
const int kStateOffset = StackHandlerConstants::kStateOffset;
649
cmp(Operand(esp, kStateOffset), Immediate(StackHandler::ENTRY));
650
j(equal, &done, Label::kNear);
651
// Fetch the next handler in the list.
652
const int kNextOffset = StackHandlerConstants::kNextOffset;
653
mov(esp, Operand(esp, kNextOffset));
657
// Set the top handler address to next handler past the current ENTRY handler.
658
pop(Operand::StaticVariable(handler_address));
834
STATIC_ASSERT(StackHandlerConstants::kCodeOffset == 1 * kPointerSize);
835
STATIC_ASSERT(StackHandlerConstants::kStateOffset == 2 * kPointerSize);
836
STATIC_ASSERT(StackHandlerConstants::kContextOffset == 3 * kPointerSize);
837
STATIC_ASSERT(StackHandlerConstants::kFPOffset == 4 * kPointerSize);
839
// The exception is expected in eax.
660
840
if (type == OUT_OF_MEMORY) {
661
841
// Set external caught exception to false.
662
ExternalReference external_caught(
663
Isolate::kExternalCaughtExceptionAddress,
666
mov(Operand::StaticVariable(external_caught), eax);
842
ExternalReference external_caught(Isolate::kExternalCaughtExceptionAddress,
844
mov(Operand::StaticVariable(external_caught), Immediate(false));
668
846
// Set pending exception and eax to out of memory exception.
669
847
ExternalReference pending_exception(Isolate::kPendingExceptionAddress,
671
849
mov(eax, reinterpret_cast<int32_t>(Failure::OutOfMemoryException()));
672
850
mov(Operand::StaticVariable(pending_exception), eax);
851
} else if (!value.is(eax)) {
675
// Discard the context saved in the handler and clear the context pointer.
677
Set(esi, Immediate(0));
679
// Restore fp from handler and discard handler state.
855
// Drop the stack pointer to the top of the top stack handler.
856
ExternalReference handler_address(Isolate::kHandlerAddress, isolate());
857
mov(esp, Operand::StaticVariable(handler_address));
859
// Unwind the handlers until the top ENTRY handler is found.
860
Label fetch_next, check_kind;
861
jmp(&check_kind, Label::kNear);
863
mov(esp, Operand(esp, StackHandlerConstants::kNextOffset));
866
STATIC_ASSERT(StackHandler::ENTRY == 0);
867
test(Operand(esp, StackHandlerConstants::kStateOffset),
868
Immediate(StackHandler::KindField::kMask));
869
j(not_zero, &fetch_next);
871
// Set the top handler address to next handler past the top ENTRY handler.
872
pop(Operand::StaticVariable(handler_address));
874
// Remove the code object and state, compute the handler address in edi.
875
pop(edi); // Code object.
876
pop(edx); // Index and state.
878
// Clear the context pointer and frame pointer (0 was saved in the handler).
882
JumpToHandlerEntry();
1369
1605
void MacroAssembler::CallStub(CodeStub* stub, unsigned ast_id) {
1370
ASSERT(allow_stub_calls()); // Calls are not allowed in some stubs.
1606
ASSERT(AllowThisStubCall(stub)); // Calls are not allowed in some stubs.
1371
1607
call(stub->GetCode(), RelocInfo::CODE_TARGET, ast_id);
1375
MaybeObject* MacroAssembler::TryCallStub(CodeStub* stub) {
1376
ASSERT(allow_stub_calls()); // Calls are not allowed in some stubs.
1378
{ MaybeObject* maybe_result = stub->TryGetCode();
1379
if (!maybe_result->ToObject(&result)) return maybe_result;
1381
call(Handle<Code>(Code::cast(result)), RelocInfo::CODE_TARGET);
1386
1611
void MacroAssembler::TailCallStub(CodeStub* stub) {
1387
ASSERT(allow_stub_calls()); // Calls are not allowed in some stubs.
1612
ASSERT(allow_stub_calls_ || stub->CompilingCallsToThisStubIsGCSafe());
1388
1613
jmp(stub->GetCode(), RelocInfo::CODE_TARGET);
1392
MaybeObject* MacroAssembler::TryTailCallStub(CodeStub* stub) {
1393
ASSERT(allow_stub_calls()); // Calls are not allowed in some stubs.
1395
{ MaybeObject* maybe_result = stub->TryGetCode();
1396
if (!maybe_result->ToObject(&result)) return maybe_result;
1398
jmp(Handle<Code>(Code::cast(result)), RelocInfo::CODE_TARGET);
1403
1617
void MacroAssembler::StubReturn(int argc) {
1404
1618
ASSERT(argc >= 1 && generating_stub());
1405
1619
ret((argc - 1) * kPointerSize);
1623
bool MacroAssembler::AllowThisStubCall(CodeStub* stub) {
1624
if (!has_frame_ && stub->SometimesSetsUpAFrame()) return false;
1625
return allow_stub_calls_ || stub->CompilingCallsToThisStubIsGCSafe();
1409
1629
void MacroAssembler::IllegalOperation(int num_arguments) {
1410
1630
if (num_arguments > 0) {
1411
add(Operand(esp), Immediate(num_arguments * kPointerSize));
1631
add(esp, Immediate(num_arguments * kPointerSize));
1413
1633
mov(eax, Immediate(isolate()->factory()->undefined_value()));
1847
void MacroAssembler::InvokeFunction(JSFunction* function,
2016
void MacroAssembler::InvokeFunction(Handle<JSFunction> function,
1848
2017
const ParameterCount& actual,
1849
2018
InvokeFlag flag,
1850
2019
const CallWrapper& call_wrapper,
1851
2020
CallKind call_kind) {
1852
ASSERT(function->is_compiled());
2021
// You can't call a function without a valid frame.
2022
ASSERT(flag == JUMP_FUNCTION || has_frame());
1853
2024
// Get the function and setup the context.
1854
mov(edi, Immediate(Handle<JSFunction>(function)));
2025
mov(edi, Immediate(function));
1855
2026
mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
1857
2028
ParameterCount expected(function->shared()->formal_parameter_count());
1858
if (V8::UseCrankshaft()) {
1859
// TODO(kasperl): For now, we always call indirectly through the
1860
// code field in the function to allow recompilation to take effect
1861
// without changing any of the call sites.
1862
InvokeCode(FieldOperand(edi, JSFunction::kCodeEntryOffset),
1863
expected, actual, flag, call_wrapper, call_kind);
1865
Handle<Code> code(function->code());
1866
InvokeCode(code, expected, actual, RelocInfo::CODE_TARGET,
1867
flag, call_wrapper, call_kind);
2029
// We call indirectly through the code field in the function to
2030
// allow recompilation to take effect without changing any of the
2032
InvokeCode(FieldOperand(edi, JSFunction::kCodeEntryOffset),
2033
expected, actual, flag, call_wrapper, call_kind);
1872
2037
void MacroAssembler::InvokeBuiltin(Builtins::JavaScript id,
1873
2038
InvokeFlag flag,
1874
2039
const CallWrapper& call_wrapper) {
1875
// Calls are not allowed in some stubs.
1876
ASSERT(flag == JUMP_FUNCTION || allow_stub_calls());
2040
// You can't call a builtin without a valid frame.
2041
ASSERT(flag == JUMP_FUNCTION || has_frame());
1878
2043
// Rely on the assertion to check that the number of provided
1879
2044
// arguments match the expected number of arguments. Fake a
2474
void MacroAssembler::CheckPageFlag(
2479
Label* condition_met,
2480
Label::Distance condition_met_distance) {
2481
ASSERT(cc == zero || cc == not_zero);
2482
if (scratch.is(object)) {
2483
and_(scratch, Immediate(~Page::kPageAlignmentMask));
2485
mov(scratch, Immediate(~Page::kPageAlignmentMask));
2486
and_(scratch, object);
2488
if (mask < (1 << kBitsPerByte)) {
2489
test_b(Operand(scratch, MemoryChunk::kFlagsOffset),
2490
static_cast<uint8_t>(mask));
2492
test(Operand(scratch, MemoryChunk::kFlagsOffset), Immediate(mask));
2494
j(cc, condition_met, condition_met_distance);
2498
void MacroAssembler::JumpIfBlack(Register object,
2502
Label::Distance on_black_near) {
2503
HasColor(object, scratch0, scratch1,
2504
on_black, on_black_near,
2505
1, 0); // kBlackBitPattern.
2506
ASSERT(strcmp(Marking::kBlackBitPattern, "10") == 0);
2510
void MacroAssembler::HasColor(Register object,
2511
Register bitmap_scratch,
2512
Register mask_scratch,
2514
Label::Distance has_color_distance,
2517
ASSERT(!AreAliased(object, bitmap_scratch, mask_scratch, ecx));
2519
GetMarkBits(object, bitmap_scratch, mask_scratch);
2521
Label other_color, word_boundary;
2522
test(mask_scratch, Operand(bitmap_scratch, MemoryChunk::kHeaderSize));
2523
j(first_bit == 1 ? zero : not_zero, &other_color, Label::kNear);
2524
add(mask_scratch, mask_scratch); // Shift left 1 by adding.
2525
j(zero, &word_boundary, Label::kNear);
2526
test(mask_scratch, Operand(bitmap_scratch, MemoryChunk::kHeaderSize));
2527
j(second_bit == 1 ? not_zero : zero, has_color, has_color_distance);
2528
jmp(&other_color, Label::kNear);
2530
bind(&word_boundary);
2531
test_b(Operand(bitmap_scratch, MemoryChunk::kHeaderSize + kPointerSize), 1);
2533
j(second_bit == 1 ? not_zero : zero, has_color, has_color_distance);
2538
void MacroAssembler::GetMarkBits(Register addr_reg,
2539
Register bitmap_reg,
2540
Register mask_reg) {
2541
ASSERT(!AreAliased(addr_reg, mask_reg, bitmap_reg, ecx));
2542
mov(bitmap_reg, Immediate(~Page::kPageAlignmentMask));
2543
and_(bitmap_reg, addr_reg);
2546
Bitmap::kBitsPerCellLog2 + kPointerSizeLog2 - Bitmap::kBytesPerCellLog2;
2549
(Page::kPageAlignmentMask >> shift) & ~(Bitmap::kBytesPerCell - 1));
2551
add(bitmap_reg, ecx);
2553
shr(ecx, kPointerSizeLog2);
2554
and_(ecx, (1 << Bitmap::kBitsPerCellLog2) - 1);
2555
mov(mask_reg, Immediate(1));
2560
void MacroAssembler::EnsureNotWhite(
2562
Register bitmap_scratch,
2563
Register mask_scratch,
2564
Label* value_is_white_and_not_data,
2565
Label::Distance distance) {
2566
ASSERT(!AreAliased(value, bitmap_scratch, mask_scratch, ecx));
2567
GetMarkBits(value, bitmap_scratch, mask_scratch);
2569
// If the value is black or grey we don't need to do anything.
2570
ASSERT(strcmp(Marking::kWhiteBitPattern, "00") == 0);
2571
ASSERT(strcmp(Marking::kBlackBitPattern, "10") == 0);
2572
ASSERT(strcmp(Marking::kGreyBitPattern, "11") == 0);
2573
ASSERT(strcmp(Marking::kImpossibleBitPattern, "01") == 0);
2577
// Since both black and grey have a 1 in the first position and white does
2578
// not have a 1 there we only need to check one bit.
2579
test(mask_scratch, Operand(bitmap_scratch, MemoryChunk::kHeaderSize));
2580
j(not_zero, &done, Label::kNear);
2582
if (FLAG_debug_code) {
2583
// Check for impossible bit pattern.
2586
// shl. May overflow making the check conservative.
2587
add(mask_scratch, mask_scratch);
2588
test(mask_scratch, Operand(bitmap_scratch, MemoryChunk::kHeaderSize));
2589
j(zero, &ok, Label::kNear);
2595
// Value is white. We check whether it is data that doesn't need scanning.
2596
// Currently only checks for HeapNumber and non-cons strings.
2597
Register map = ecx; // Holds map while checking type.
2598
Register length = ecx; // Holds length of object after checking type.
2599
Label not_heap_number;
2600
Label is_data_object;
2602
// Check for heap-number
2603
mov(map, FieldOperand(value, HeapObject::kMapOffset));
2604
cmp(map, FACTORY->heap_number_map());
2605
j(not_equal, ¬_heap_number, Label::kNear);
2606
mov(length, Immediate(HeapNumber::kSize));
2607
jmp(&is_data_object, Label::kNear);
2609
bind(¬_heap_number);
2610
// Check for strings.
2611
ASSERT(kIsIndirectStringTag == 1 && kIsIndirectStringMask == 1);
2612
ASSERT(kNotStringTag == 0x80 && kIsNotStringMask == 0x80);
2613
// If it's a string and it's not a cons string then it's an object containing
2615
Register instance_type = ecx;
2616
movzx_b(instance_type, FieldOperand(map, Map::kInstanceTypeOffset));
2617
test_b(instance_type, kIsIndirectStringMask | kIsNotStringMask);
2618
j(not_zero, value_is_white_and_not_data);
2619
// It's a non-indirect (non-cons and non-slice) string.
2620
// If it's external, the length is just ExternalString::kSize.
2621
// Otherwise it's String::kHeaderSize + string->length() * (1 or 2).
2623
// External strings are the only ones with the kExternalStringTag bit
2625
ASSERT_EQ(0, kSeqStringTag & kExternalStringTag);
2626
ASSERT_EQ(0, kConsStringTag & kExternalStringTag);
2627
test_b(instance_type, kExternalStringTag);
2628
j(zero, ¬_external, Label::kNear);
2629
mov(length, Immediate(ExternalString::kSize));
2630
jmp(&is_data_object, Label::kNear);
2632
bind(¬_external);
2633
// Sequential string, either ASCII or UC16.
2634
ASSERT(kAsciiStringTag == 0x04);
2635
and_(length, Immediate(kStringEncodingMask));
2636
xor_(length, Immediate(kStringEncodingMask));
2637
add(length, Immediate(0x04));
2638
// Value now either 4 (if ASCII) or 8 (if UC16), i.e., char-size shifted
2639
// by 2. If we multiply the string length as smi by this, it still
2640
// won't overflow a 32-bit value.
2641
ASSERT_EQ(SeqAsciiString::kMaxSize, SeqTwoByteString::kMaxSize);
2642
ASSERT(SeqAsciiString::kMaxSize <=
2643
static_cast<int>(0xffffffffu >> (2 + kSmiTagSize)));
2644
imul(length, FieldOperand(value, String::kLengthOffset));
2645
shr(length, 2 + kSmiTagSize + kSmiShiftSize);
2646
add(length, Immediate(SeqString::kHeaderSize + kObjectAlignmentMask));
2647
and_(length, Immediate(~kObjectAlignmentMask));
2649
bind(&is_data_object);
2650
// Value is a data object, and it is white. Mark it black. Since we know
2651
// that the object is white we can make it black by flipping one bit.
2652
or_(Operand(bitmap_scratch, MemoryChunk::kHeaderSize), mask_scratch);
2654
and_(bitmap_scratch, Immediate(~Page::kPageAlignmentMask));
2655
add(Operand(bitmap_scratch, MemoryChunk::kLiveBytesOffset),
2657
if (FLAG_debug_code) {
2658
mov(length, Operand(bitmap_scratch, MemoryChunk::kLiveBytesOffset));
2659
cmp(length, Operand(bitmap_scratch, MemoryChunk::kSizeOffset));
2660
Check(less_equal, "Live Bytes Count overflow chunk size");
2289
2666
} } // namespace v8::internal
2291
2668
#endif // V8_TARGET_ARCH_IA32