~ubuntu-branches/ubuntu/trusty/libv8/trusty

« back to all changes in this revision

Viewing changes to src/ia32/macro-assembler-ia32.cc

  • Committer: Package Import Robot
  • Author(s): Jérémy Lal
  • Date: 2012-02-20 14:08:17 UTC
  • mfrom: (15.1.24 sid)
  • Revision ID: package-import@ubuntu.com-20120220140817-bsvmeoa4sxsj5hbz
Tags: 3.7.12.22-3
Fix mipsel build, allow test debug-step-3 to fail (non-crucial)

Show diffs side-by-side

added added

removed removed

Lines of Context:
44
44
MacroAssembler::MacroAssembler(Isolate* arg_isolate, void* buffer, int size)
45
45
    : Assembler(arg_isolate, buffer, size),
46
46
      generating_stub_(false),
47
 
      allow_stub_calls_(true) {
 
47
      allow_stub_calls_(true),
 
48
      has_frame_(false) {
48
49
  if (isolate() != NULL) {
49
50
    code_object_ = Handle<Object>(isolate()->heap()->undefined_value(),
50
51
                                  isolate());
52
53
}
53
54
 
54
55
 
55
 
void MacroAssembler::RecordWriteHelper(Register object,
56
 
                                       Register addr,
57
 
                                       Register scratch) {
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, &not_in_new_space);
62
 
    Abort("new-space object passed to RecordWriteHelper");
63
 
    bind(&not_in_new_space);
64
 
  }
65
 
 
66
 
  // Compute the page start address from the heap object pointer, and reuse
67
 
  // the 'object' register for it.
68
 
  and_(object, ~Page::kPageAlignmentMask);
69
 
 
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);
74
 
 
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(
 
57
    Register object,
 
58
    Register scratch,
 
59
    Condition cc,
 
60
    Label* condition_met,
 
61
    Label::Distance condition_met_distance) {
 
62
  ASSERT(cc == equal || cc == not_equal);
 
63
  if (scratch.is(object)) {
 
64
    and_(scratch, Immediate(~Page::kPageAlignmentMask));
 
65
  } else {
 
66
    mov(scratch, Immediate(~Page::kPageAlignmentMask));
 
67
    and_(scratch, object);
 
68
  }
 
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);
 
78
}
 
79
 
 
80
 
 
81
void MacroAssembler::RememberedSetHelper(
 
82
    Register object,  // Only used for debug checks.
 
83
    Register addr,
 
84
    Register scratch,
 
85
    SaveFPRegsMode save_fp,
 
86
    MacroAssembler::RememberedSetFinalAction and_then) {
 
87
  Label done;
 
88
  if (FLAG_debug_code) {
 
89
    Label ok;
 
90
    JumpIfNotInNewSpace(object, scratch, &ok, Label::kNear);
 
91
    int3();
 
92
    bind(&ok);
 
93
  }
 
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);
 
110
    ret(0);
 
111
    bind(&buffer_overflowed);
 
112
  } else {
 
113
    ASSERT(and_then == kFallThroughAtEnd);
 
114
    j(equal, &done, Label::kNear);
 
115
  }
 
116
  StoreBufferOverflowStub store_buffer_overflow =
 
117
      StoreBufferOverflowStub(save_fp);
 
118
  CallStub(&store_buffer_overflow);
 
119
  if (and_then == kReturnAtEnd) {
 
120
    ret(0);
 
121
  } else {
 
122
    ASSERT(and_then == kFallThroughAtEnd);
 
123
    bind(&done);
 
124
  }
82
125
}
83
126
 
84
127
 
112
155
}
113
156
 
114
157
 
115
 
void MacroAssembler::InNewSpace(Register object,
116
 
                                Register scratch,
117
 
                                Condition cc,
118
 
                                Label* branch,
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);
132
 
  } else {
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,
 
159
                                      Register value,
 
160
                                      Register index,
 
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.
 
166
  Label done;
 
167
 
 
168
  // Skip barrier if writing a smi.
 
169
  if (smi_check == INLINE_SMI_CHECK) {
 
170
    ASSERT_EQ(0, kSmiTag);
 
171
    test(value, Immediate(kSmiTagMask));
 
172
    j(zero, &done);
 
173
  }
 
174
 
 
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));
 
181
 
 
182
  RecordWrite(
 
183
      object, dst, value, save_fp, remembered_set_action, OMIT_SMI_CHECK);
 
184
 
 
185
  bind(&done);
 
186
 
 
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)));
 
192
  }
 
193
}
 
194
 
 
195
 
 
196
void MacroAssembler::RecordWriteField(
 
197
    Register object,
 
198
    int offset,
 
199
    Register value,
 
200
    Register dst,
 
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.
 
206
  Label done;
 
207
 
 
208
  // Skip barrier if writing a smi.
 
209
  if (smi_check == INLINE_SMI_CHECK) {
 
210
    JumpIfSmi(value, &done, Label::kNear);
 
211
  }
 
212
 
 
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));
 
216
 
 
217
  lea(dst, FieldOperand(object, offset));
 
218
  if (emit_debug_code()) {
 
219
    Label ok;
 
220
    test_b(dst, (1 << kPointerSizeLog2) - 1);
 
221
    j(zero, &ok, Label::kNear);
 
222
    int3();
 
223
    bind(&ok);
 
224
  }
 
225
 
 
226
  RecordWrite(
 
227
      object, dst, value, save_fp, remembered_set_action, OMIT_SMI_CHECK);
 
228
 
 
229
  bind(&done);
 
230
 
 
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)));
138
236
  }
139
237
}
140
238
 
141
239
 
142
240
void MacroAssembler::RecordWrite(Register object,
143
 
                                 int offset,
 
241
                                 Register address,
144
242
                                 Register value,
145
 
                                 Register scratch) {
146
 
  // First, check if a write barrier is even needed. The tests below
147
 
  // catch stores of Smis and stores into young gen.
148
 
  Label done;
149
 
 
150
 
  // Skip barrier if writing a smi.
151
 
  STATIC_ASSERT(kSmiTag == 0);
152
 
  JumpIfSmi(value, &done, Label::kNear);
153
 
 
154
 
  InNewSpace(object, value, equal, &done, Label::kNear);
155
 
 
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));
161
 
 
162
 
  Register dst = scratch;
163
 
  if (offset != 0) {
164
 
    lea(dst, Operand(object, offset));
165
 
  } else {
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));
173
 
  }
174
 
  RecordWriteHelper(object, dst, value);
175
 
 
176
 
  bind(&done);
177
 
 
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)));
184
 
  }
185
 
}
186
 
 
187
 
 
188
 
void MacroAssembler::RecordWrite(Register object,
189
 
                                 Register address,
190
 
                                 Register value) {
191
 
  // First, check if a write barrier is even needed. The tests below
192
 
  // catch stores of Smis and stores into young gen.
193
 
  Label done;
194
 
 
195
 
  // Skip barrier if writing a smi.
196
 
  STATIC_ASSERT(kSmiTag == 0);
197
 
  JumpIfSmi(value, &done, Label::kNear);
198
 
 
199
 
  InNewSpace(object, value, equal, &done);
200
 
 
201
 
  RecordWriteHelper(object, address, value);
202
 
 
203
 
  bind(&done);
204
 
 
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()) {
 
250
    AbortIfSmi(object);
 
251
  }
 
252
 
 
253
  if (remembered_set_action == OMIT_REMEMBERED_SET &&
 
254
      !FLAG_incremental_marking) {
 
255
    return;
 
256
  }
 
257
 
 
258
  if (FLAG_debug_code) {
 
259
    Label ok;
 
260
    cmp(value, Operand(address, 0));
 
261
    j(equal, &ok, Label::kNear);
 
262
    int3();
 
263
    bind(&ok);
 
264
  }
 
265
 
 
266
  // First, check if a write barrier is even needed. The tests below
 
267
  // catch stores of Smis and stores into young gen.
 
268
  Label done;
 
269
 
 
270
  if (smi_check == INLINE_SMI_CHECK) {
 
271
    // Skip barrier if writing a smi.
 
272
    JumpIfSmi(value, &done, Label::kNear);
 
273
  }
 
274
 
 
275
  CheckPageFlag(value,
 
276
                value,  // Used as scratch.
 
277
                MemoryChunk::kPointersToHereAreInterestingMask,
 
278
                zero,
 
279
                &done,
 
280
                Label::kNear);
 
281
  CheckPageFlag(object,
 
282
                value,  // Used as scratch.
 
283
                MemoryChunk::kPointersFromHereAreInterestingMask,
 
284
                zero,
 
285
                &done,
 
286
                Label::kNear);
 
287
 
 
288
  RecordWriteStub stub(object, value, address, remembered_set_action, fp_mode);
 
289
  CallStub(&stub);
 
290
 
 
291
  bind(&done);
 
292
 
 
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)));
211
298
  }
224
311
 
225
312
void MacroAssembler::Set(Register dst, const Immediate& x) {
226
313
  if (x.is_zero()) {
227
 
    xor_(dst, Operand(dst));  // Shorter than mov.
 
314
    xor_(dst, dst);  // Shorter than mov.
228
315
  } else {
229
316
    mov(dst, x);
230
317
  }
265
352
 
266
353
void MacroAssembler::CompareRoot(Register with, Heap::RootListIndex index) {
267
354
  // see ROOT_ACCESSOR macro in factory.h
268
 
  Handle<Object> value(&isolate()->heap()->roots_address()[index]);
 
355
  Handle<Object> value(&isolate()->heap()->roots_array_start()[index]);
269
356
  cmp(with, value);
270
357
}
271
358
 
287
374
void MacroAssembler::CheckFastElements(Register map,
288
375
                                       Label* fail,
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);
 
382
}
 
383
 
 
384
 
 
385
void MacroAssembler::CheckFastObjectElements(Register map,
 
386
                                             Label* fail,
 
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);
 
396
}
 
397
 
 
398
 
 
399
void MacroAssembler::CheckFastSmiOnlyElements(Register map,
 
400
                                              Label* fail,
 
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);
 
406
}
 
407
 
 
408
 
 
409
void MacroAssembler::StoreNumberToDoubleElements(
 
410
    Register maybe_number,
 
411
    Register elements,
 
412
    Register key,
 
413
    Register scratch1,
 
414
    XMMRegister scratch2,
 
415
    Label* fail,
 
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);
 
419
 
 
420
  CheckMap(maybe_number,
 
421
           isolate()->factory()->heap_number_map(),
 
422
           fail,
 
423
           DONT_DO_SMI_CHECK);
 
424
 
 
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);
 
430
 
 
431
  bind(&not_nan);
 
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),
 
439
           scratch2);
 
440
  } else {
 
441
    fld_d(FieldOperand(maybe_number, HeapNumber::kValueOffset));
 
442
    bind(&have_double_value);
 
443
    fstp_d(FieldOperand(elements, key, times_4, FixedDoubleArray::kHeaderSize));
 
444
  }
 
445
  jmp(&done);
 
446
 
 
447
  bind(&maybe_nan);
 
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));
 
452
  j(zero, &not_nan);
 
453
  bind(&is_nan);
 
454
  if (CpuFeatures::IsSupported(SSE2) && specialize_for_processor) {
 
455
    CpuFeatures::Scope use_sse2(SSE2);
 
456
    movdbl(scratch2, Operand::StaticVariable(canonical_nan_reference));
 
457
  } else {
 
458
    fld_d(Operand::StaticVariable(canonical_nan_reference));
 
459
  }
 
460
  jmp(&have_double_value, Label::kNear);
 
461
 
 
462
  bind(&smi_value);
 
463
  // Value is a smi. Convert to a double and store.
 
464
  // Preserve original value.
 
465
  mov(scratch1, maybe_number);
 
466
  SmiUntag(scratch1);
 
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),
 
471
           scratch2);
 
472
  } else {
 
473
    push(scratch1);
 
474
    fild_s(Operand(esp, 0));
 
475
    pop(scratch1);
 
476
    fstp_d(FieldOperand(elements, key, times_4, FixedDoubleArray::kHeaderSize));
 
477
  }
 
478
  bind(&done);
294
479
}
295
480
 
296
481
 
345
530
                                            Register scratch,
346
531
                                            Label* fail) {
347
532
  movzx_b(scratch, FieldOperand(map, Map::kInstanceTypeOffset));
348
 
  sub(Operand(scratch), Immediate(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE));
 
533
  sub(scratch, Immediate(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE));
349
534
  cmp(scratch,
350
535
      LAST_NONCALLABLE_SPEC_OBJECT_TYPE - FIRST_NONCALLABLE_SPEC_OBJECT_TYPE);
351
536
  j(above, fail);
355
540
void MacroAssembler::FCmp() {
356
541
  if (CpuFeatures::IsSupported(CMOV)) {
357
542
    fucomip();
358
 
    ffree(0);
359
 
    fincstp();
 
543
    fstp(0);
360
544
  } else {
361
545
    fucompp();
362
546
    push(eax);
402
586
 
403
587
void MacroAssembler::EnterFrame(StackFrame::Type type) {
404
588
  push(ebp);
405
 
  mov(ebp, Operand(esp));
 
589
  mov(ebp, esp);
406
590
  push(esi);
407
591
  push(Immediate(Smi::FromInt(type)));
408
592
  push(Immediate(CodeObject()));
429
613
  ASSERT(ExitFrameConstants::kCallerPCOffset == +1 * kPointerSize);
430
614
  ASSERT(ExitFrameConstants::kCallerFPOffset ==  0 * kPointerSize);
431
615
  push(ebp);
432
 
  mov(ebp, Operand(esp));
 
616
  mov(ebp, esp);
433
617
 
434
618
  // Reserve room for entry stack pointer and push the code object.
435
619
  ASSERT(ExitFrameConstants::kSPOffset  == -1 * kPointerSize);
451
635
  if (save_doubles) {
452
636
    CpuFeatures::Scope scope(SSE2);
453
637
    int space = XMMRegister::kNumRegisters * kDoubleSize + argc * kPointerSize;
454
 
    sub(Operand(esp), Immediate(space));
 
638
    sub(esp, Immediate(space));
455
639
    const int offset = -2 * kPointerSize;
456
640
    for (int i = 0; i < XMMRegister::kNumRegisters; i++) {
457
641
      XMMRegister reg = XMMRegister::from_code(i);
458
642
      movdbl(Operand(ebp, offset - ((i + 1) * kDoubleSize)), reg);
459
643
    }
460
644
  } else {
461
 
    sub(Operand(esp), Immediate(argc * kPointerSize));
 
645
    sub(esp, Immediate(argc * kPointerSize));
462
646
  }
463
647
 
464
648
  // Get the required frame alignment for the OS.
478
662
 
479
663
  // Setup argc and argv in callee-saved registers.
480
664
  int offset = StandardFrameConstants::kCallerSPOffset - kPointerSize;
481
 
  mov(edi, Operand(eax));
 
665
  mov(edi, eax);
482
666
  lea(esi, Operand(ebp, eax, times_4, offset));
483
667
 
484
668
  // Reserve space for argc, argv and isolate.
532
716
 
533
717
 
534
718
void MacroAssembler::LeaveApiExitFrame() {
535
 
  mov(esp, Operand(ebp));
 
719
  mov(esp, ebp);
536
720
  pop(ebp);
537
721
 
538
722
  LeaveExitFrameEpilogue();
540
724
 
541
725
 
542
726
void MacroAssembler::PushTryHandler(CodeLocation try_location,
543
 
                                    HandlerType type) {
 
727
                                    HandlerType type,
 
728
                                    int handler_index) {
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);
 
736
 
 
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));
555
 
    } else {
556
 
      push(Immediate(StackHandler::TRY_FINALLY));
557
 
    }
558
741
    push(ebp);
559
742
    push(esi);
 
743
    state |= (type == TRY_CATCH_HANDLER)
 
744
        ? StackHandler::KindField::encode(StackHandler::TRY_CATCH)
 
745
        : StackHandler::KindField::encode(StackHandler::TRY_FINALLY);
560
746
  } else {
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);
568
754
  }
569
 
  // Save the current handler as the next handler.
570
 
  push(Operand::StaticVariable(ExternalReference(Isolate::kHandlerAddress,
571
 
                                                 isolate())));
572
 
  // Link this handler as the new current one.
573
 
  mov(Operand::StaticVariable(ExternalReference(Isolate::kHandlerAddress,
574
 
                                                isolate())),
575
 
      esp);
 
755
 
 
756
  // Push the state and the code object.
 
757
  push(Immediate(state));
 
758
  push(CodeObject());
 
759
 
 
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);
576
765
}
577
766
 
578
767
 
579
768
void MacroAssembler::PopTryHandler() {
580
769
  STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0);
581
 
  pop(Operand::StaticVariable(ExternalReference(Isolate::kHandlerAddress,
582
 
                                                isolate())));
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));
 
773
}
 
774
 
 
775
 
 
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));
 
783
  SmiUntag(edx);
 
784
  lea(edi, FieldOperand(edi, edx, times_1, Code::kHeaderSize));
 
785
  jmp(edi);
584
786
}
585
787
 
586
788
 
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);
 
797
 
 
798
  // The exception is expected in eax.
596
799
  if (!value.is(eax)) {
597
800
    mov(eax, value);
598
801
  }
599
 
 
600
 
  // Drop the sp to the top of the handler.
601
 
  ExternalReference handler_address(Isolate::kHandlerAddress,
602
 
                                    isolate());
 
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));
604
 
 
605
 
  // Restore next handler, context, and frame pointer; discard handler state.
 
805
  // Restore the next handler.
606
806
  pop(Operand::StaticVariable(handler_address));
 
807
 
 
808
  // Remove the code object and state, compute the handler address in edi.
 
809
  pop(edi);  // Code object.
 
810
  pop(edx);  // Index and state.
 
811
 
 
812
  // Restore the context and frame pointer.
607
813
  pop(esi);  // Context.
608
814
  pop(ebp);  // Frame pointer.
609
 
  pop(edx);  // State.
610
815
 
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
613
 
  // of them.
 
817
  // (kind == ENTRY) == (ebp == 0) == (esi == 0), so we could test either
 
818
  // ebp or esi.
614
819
  Label skip;
615
 
  cmp(Operand(edx), Immediate(StackHandler::ENTRY));
616
 
  j(equal, &skip, Label::kNear);
 
820
  test(esi, esi);
 
821
  j(zero, &skip, Label::kNear);
617
822
  mov(Operand(ebp, StandardFrameConstants::kContextOffset), esi);
618
823
  bind(&skip);
619
824
 
620
 
  ret(0);
 
825
  JumpToHandlerEntry();
621
826
}
622
827
 
623
828
 
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);
633
 
 
634
 
  // eax must hold the exception.
635
 
  if (!value.is(eax)) {
636
 
    mov(eax, value);
637
 
  }
638
 
 
639
 
  // Drop sp to the top stack handler.
640
 
  ExternalReference handler_address(Isolate::kHandlerAddress,
641
 
                                    isolate());
642
 
  mov(esp, Operand::StaticVariable(handler_address));
643
 
 
644
 
  // Unwind the handlers until the ENTRY handler is found.
645
 
  Label loop, done;
646
 
  bind(&loop);
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));
654
 
  jmp(&loop);
655
 
  bind(&done);
656
 
 
657
 
  // Set the top handler address to next handler past the current ENTRY handler.
658
 
  pop(Operand::StaticVariable(handler_address));
659
 
 
 
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);
 
838
 
 
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,
664
 
        isolate());
665
 
    mov(eax, false);
666
 
    mov(Operand::StaticVariable(external_caught), eax);
 
842
    ExternalReference external_caught(Isolate::kExternalCaughtExceptionAddress,
 
843
                                      isolate());
 
844
    mov(Operand::StaticVariable(external_caught), Immediate(false));
667
845
 
668
846
    // Set pending exception and eax to out of memory exception.
669
847
    ExternalReference pending_exception(Isolate::kPendingExceptionAddress,
670
848
                                        isolate());
671
849
    mov(eax, reinterpret_cast<int32_t>(Failure::OutOfMemoryException()));
672
850
    mov(Operand::StaticVariable(pending_exception), eax);
 
851
  } else if (!value.is(eax)) {
 
852
    mov(eax, value);
673
853
  }
674
854
 
675
 
  // Discard the context saved in the handler and clear the context pointer.
676
 
  pop(edx);
677
 
  Set(esi, Immediate(0));
678
 
 
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));
 
858
 
 
859
  // Unwind the handlers until the top ENTRY handler is found.
 
860
  Label fetch_next, check_kind;
 
861
  jmp(&check_kind, Label::kNear);
 
862
  bind(&fetch_next);
 
863
  mov(esp, Operand(esp, StackHandlerConstants::kNextOffset));
 
864
 
 
865
  bind(&check_kind);
 
866
  STATIC_ASSERT(StackHandler::ENTRY == 0);
 
867
  test(Operand(esp, StackHandlerConstants::kStateOffset),
 
868
       Immediate(StackHandler::KindField::kMask));
 
869
  j(not_zero, &fetch_next);
 
870
 
 
871
  // Set the top handler address to next handler past the top ENTRY handler.
 
872
  pop(Operand::StaticVariable(handler_address));
 
873
 
 
874
  // Remove the code object and state, compute the handler address in edi.
 
875
  pop(edi);  // Code object.
 
876
  pop(edx);  // Index and state.
 
877
 
 
878
  // Clear the context pointer and frame pointer (0 was saved in the handler).
 
879
  pop(esi);
680
880
  pop(ebp);
681
 
  pop(edx);  // State.
682
881
 
683
 
  ret(0);
 
882
  JumpToHandlerEntry();
684
883
}
685
884
 
686
885
 
696
895
 
697
896
  // When generating debug code, make sure the lexical context is set.
698
897
  if (emit_debug_code()) {
699
 
    cmp(Operand(scratch), Immediate(0));
 
898
    cmp(scratch, Immediate(0));
700
899
    Check(not_equal, "we should not have an empty lexical context");
701
900
  }
702
901
  // Load the global context of the current context.
784
983
  mov(r1, r0);
785
984
  not_(r0);
786
985
  shl(r1, 15);
787
 
  add(r0, Operand(r1));
 
986
  add(r0, r1);
788
987
  // hash = hash ^ (hash >> 12);
789
988
  mov(r1, r0);
790
989
  shr(r1, 12);
791
 
  xor_(r0, Operand(r1));
 
990
  xor_(r0, r1);
792
991
  // hash = hash + (hash << 2);
793
992
  lea(r0, Operand(r0, r0, times_4, 0));
794
993
  // hash = hash ^ (hash >> 4);
795
994
  mov(r1, r0);
796
995
  shr(r1, 4);
797
 
  xor_(r0, Operand(r1));
 
996
  xor_(r0, r1);
798
997
  // hash = hash * 2057;
799
998
  imul(r0, r0, 2057);
800
999
  // hash = hash ^ (hash >> 16);
801
1000
  mov(r1, r0);
802
1001
  shr(r1, 16);
803
 
  xor_(r0, Operand(r1));
 
1002
  xor_(r0, r1);
804
1003
 
805
1004
  // Compute capacity mask.
806
1005
  mov(r1, FieldOperand(elements, NumberDictionary::kCapacityOffset));
814
1013
    mov(r2, r0);
815
1014
    // Compute the masked index: (hash + i + i * i) & mask.
816
1015
    if (i > 0) {
817
 
      add(Operand(r2), Immediate(NumberDictionary::GetProbeOffset(i)));
 
1016
      add(r2, Immediate(NumberDictionary::GetProbeOffset(i)));
818
1017
    }
819
 
    and_(r2, Operand(r1));
 
1018
    and_(r2, r1);
820
1019
 
821
1020
    // Scale the index by multiplying by the entry size.
822
1021
    ASSERT(NumberDictionary::kEntrySize == 3);
872
1071
  if (scratch.is(no_reg)) {
873
1072
    mov(result, Operand::StaticVariable(new_space_allocation_top));
874
1073
  } else {
875
 
    mov(Operand(scratch), Immediate(new_space_allocation_top));
 
1074
    mov(scratch, Immediate(new_space_allocation_top));
876
1075
    mov(result, Operand(scratch, 0));
877
1076
  }
878
1077
}
931
1130
  if (!top_reg.is(result)) {
932
1131
    mov(top_reg, result);
933
1132
  }
934
 
  add(Operand(top_reg), Immediate(object_size));
 
1133
  add(top_reg, Immediate(object_size));
935
1134
  j(carry, gc_required);
936
1135
  cmp(top_reg, Operand::StaticVariable(new_space_allocation_limit));
937
1136
  j(above, gc_required);
942
1141
  // Tag result if requested.
943
1142
  if (top_reg.is(result)) {
944
1143
    if ((flags & TAG_OBJECT) != 0) {
945
 
      sub(Operand(result), Immediate(object_size - kHeapObjectTag));
 
1144
      sub(result, Immediate(object_size - kHeapObjectTag));
946
1145
    } else {
947
 
      sub(Operand(result), Immediate(object_size));
 
1146
      sub(result, Immediate(object_size));
948
1147
    }
949
1148
  } else if ((flags & TAG_OBJECT) != 0) {
950
 
    add(Operand(result), Immediate(kHeapObjectTag));
 
1149
    add(result, Immediate(kHeapObjectTag));
951
1150
  }
952
1151
}
953
1152
 
985
1184
  // We assume that element_count*element_size + header_size does not
986
1185
  // overflow.
987
1186
  lea(result_end, Operand(element_count, element_size, header_size));
988
 
  add(result_end, Operand(result));
 
1187
  add(result_end, result);
989
1188
  j(carry, gc_required);
990
1189
  cmp(result_end, Operand::StaticVariable(new_space_allocation_limit));
991
1190
  j(above, gc_required);
1030
1229
  if (!object_size.is(result_end)) {
1031
1230
    mov(result_end, object_size);
1032
1231
  }
1033
 
  add(result_end, Operand(result));
 
1232
  add(result_end, result);
1034
1233
  j(carry, gc_required);
1035
1234
  cmp(result_end, Operand::StaticVariable(new_space_allocation_limit));
1036
1235
  j(above, gc_required);
1050
1249
      ExternalReference::new_space_allocation_top_address(isolate());
1051
1250
 
1052
1251
  // Make sure the object has no tag before resetting top.
1053
 
  and_(Operand(object), Immediate(~kHeapObjectTagMask));
 
1252
  and_(object, Immediate(~kHeapObjectTagMask));
1054
1253
#ifdef DEBUG
1055
1254
  cmp(object, Operand::StaticVariable(new_space_allocation_top));
1056
1255
  Check(below, "Undo allocation of non allocated memory");
1089
1288
  ASSERT(kShortSize == 2);
1090
1289
  // scratch1 = length * 2 + kObjectAlignmentMask.
1091
1290
  lea(scratch1, Operand(length, length, times_1, kObjectAlignmentMask));
1092
 
  and_(Operand(scratch1), Immediate(~kObjectAlignmentMask));
 
1291
  and_(scratch1, Immediate(~kObjectAlignmentMask));
1093
1292
 
1094
1293
  // Allocate two byte string in new space.
1095
1294
  AllocateInNewSpace(SeqTwoByteString::kHeaderSize,
1123
1322
  ASSERT((SeqAsciiString::kHeaderSize & kObjectAlignmentMask) == 0);
1124
1323
  mov(scratch1, length);
1125
1324
  ASSERT(kCharSize == 1);
1126
 
  add(Operand(scratch1), Immediate(kObjectAlignmentMask));
1127
 
  and_(Operand(scratch1), Immediate(~kObjectAlignmentMask));
 
1325
  add(scratch1, Immediate(kObjectAlignmentMask));
 
1326
  and_(scratch1, Immediate(~kObjectAlignmentMask));
1128
1327
 
1129
1328
  // Allocate ascii string in new space.
1130
1329
  AllocateInNewSpace(SeqAsciiString::kHeaderSize,
1258
1457
                               Register scratch) {
1259
1458
  Label loop, done, short_string, short_loop;
1260
1459
  // Experimentation shows that the short string loop is faster if length < 10.
1261
 
  cmp(Operand(length), Immediate(10));
 
1460
  cmp(length, Immediate(10));
1262
1461
  j(less_equal, &short_string);
1263
1462
 
1264
1463
  ASSERT(source.is(esi));
1273
1472
  mov(scratch, ecx);
1274
1473
  shr(ecx, 2);
1275
1474
  rep_movs();
1276
 
  and_(Operand(scratch), Immediate(0x3));
1277
 
  add(destination, Operand(scratch));
 
1475
  and_(scratch, Immediate(0x3));
 
1476
  add(destination, scratch);
1278
1477
  jmp(&done);
1279
1478
 
1280
1479
  bind(&short_string);
1281
 
  test(length, Operand(length));
 
1480
  test(length, length);
1282
1481
  j(zero, &done);
1283
1482
 
1284
1483
  bind(&short_loop);
1293
1492
}
1294
1493
 
1295
1494
 
 
1495
void MacroAssembler::InitializeFieldsWithFiller(Register start_offset,
 
1496
                                                Register end_offset,
 
1497
                                                Register filler) {
 
1498
  Label loop, entry;
 
1499
  jmp(&entry);
 
1500
  bind(&loop);
 
1501
  mov(Operand(start_offset, 0), filler);
 
1502
  add(start_offset, Immediate(kPointerSize));
 
1503
  bind(&entry);
 
1504
  cmp(start_offset, end_offset);
 
1505
  j(less, &loop);
 
1506
}
 
1507
 
 
1508
 
 
1509
void MacroAssembler::BooleanBitTest(Register object,
 
1510
                                    int field_offset,
 
1511
                                    int bit_index) {
 
1512
  bit_index += kSmiTagSize + kSmiShiftSize;
 
1513
  ASSERT(IsPowerOf2(kBitsPerByte));
 
1514
  int byte_index = bit_index / kBitsPerByte;
 
1515
  int byte_bit_index = bit_index & (kBitsPerByte - 1);
 
1516
  test_b(FieldOperand(object, field_offset + byte_index),
 
1517
         static_cast<byte>(1 << byte_bit_index));
 
1518
}
 
1519
 
 
1520
 
 
1521
 
1296
1522
void MacroAssembler::NegativeZeroTest(Register result,
1297
1523
                                      Register op,
1298
1524
                                      Label* then_label) {
1299
1525
  Label ok;
1300
 
  test(result, Operand(result));
 
1526
  test(result, result);
1301
1527
  j(not_zero, &ok);
1302
 
  test(op, Operand(op));
 
1528
  test(op, op);
1303
1529
  j(sign, then_label);
1304
1530
  bind(&ok);
1305
1531
}
1311
1537
                                      Register scratch,
1312
1538
                                      Label* then_label) {
1313
1539
  Label ok;
1314
 
  test(result, Operand(result));
 
1540
  test(result, result);
1315
1541
  j(not_zero, &ok);
1316
 
  mov(scratch, Operand(op1));
1317
 
  or_(scratch, Operand(op2));
 
1542
  mov(scratch, op1);
 
1543
  or_(scratch, op2);
1318
1544
  j(sign, then_label);
1319
1545
  bind(&ok);
1320
1546
}
1323
1549
void MacroAssembler::TryGetFunctionPrototype(Register function,
1324
1550
                                             Register result,
1325
1551
                                             Register scratch,
1326
 
                                             Label* miss) {
 
1552
                                             Label* miss,
 
1553
                                             bool miss_on_bound_function) {
1327
1554
  // Check that the receiver isn't a smi.
1328
1555
  JumpIfSmi(function, miss);
1329
1556
 
1331
1558
  CmpObjectType(function, JS_FUNCTION_TYPE, result);
1332
1559
  j(not_equal, miss);
1333
1560
 
 
1561
  if (miss_on_bound_function) {
 
1562
    // If a bound function, go to miss label.
 
1563
    mov(scratch,
 
1564
        FieldOperand(function, JSFunction::kSharedFunctionInfoOffset));
 
1565
    BooleanBitTest(scratch, SharedFunctionInfo::kCompilerHintsOffset,
 
1566
                   SharedFunctionInfo::kBoundFunction);
 
1567
    j(not_zero, miss);
 
1568
  }
 
1569
 
1334
1570
  // Make sure that the function has an instance prototype.
1335
1571
  Label non_instance;
1336
1572
  movzx_b(scratch, FieldOperand(result, Map::kBitFieldOffset));
1344
1580
  // If the prototype or initial map is the hole, don't return it and
1345
1581
  // simply miss the cache instead. This will allow us to allocate a
1346
1582
  // prototype object on-demand in the runtime system.
1347
 
  cmp(Operand(result), Immediate(isolate()->factory()->the_hole_value()));
 
1583
  cmp(result, Immediate(isolate()->factory()->the_hole_value()));
1348
1584
  j(equal, miss);
1349
1585
 
1350
1586
  // If the function does not have an initial map, we're done.
1367
1603
 
1368
1604
 
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);
1372
1608
}
1373
1609
 
1374
1610
 
1375
 
MaybeObject* MacroAssembler::TryCallStub(CodeStub* stub) {
1376
 
  ASSERT(allow_stub_calls());  // Calls are not allowed in some stubs.
1377
 
  Object* result;
1378
 
  { MaybeObject* maybe_result = stub->TryGetCode();
1379
 
    if (!maybe_result->ToObject(&result)) return maybe_result;
1380
 
  }
1381
 
  call(Handle<Code>(Code::cast(result)), RelocInfo::CODE_TARGET);
1382
 
  return result;
1383
 
}
1384
 
 
1385
 
 
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);
1389
1614
}
1390
1615
 
1391
1616
 
1392
 
MaybeObject* MacroAssembler::TryTailCallStub(CodeStub* stub) {
1393
 
  ASSERT(allow_stub_calls());  // Calls are not allowed in some stubs.
1394
 
  Object* result;
1395
 
  { MaybeObject* maybe_result = stub->TryGetCode();
1396
 
    if (!maybe_result->ToObject(&result)) return maybe_result;
1397
 
  }
1398
 
  jmp(Handle<Code>(Code::cast(result)), RelocInfo::CODE_TARGET);
1399
 
  return result;
1400
 
}
1401
 
 
1402
 
 
1403
1617
void MacroAssembler::StubReturn(int argc) {
1404
1618
  ASSERT(argc >= 1 && generating_stub());
1405
1619
  ret((argc - 1) * kPointerSize);
1406
1620
}
1407
1621
 
1408
1622
 
 
1623
bool MacroAssembler::AllowThisStubCall(CodeStub* stub) {
 
1624
  if (!has_frame_ && stub->SometimesSetsUpAFrame()) return false;
 
1625
  return allow_stub_calls_ || stub->CompilingCallsToThisStubIsGCSafe();
 
1626
}
 
1627
 
 
1628
 
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));
1412
1632
  }
1413
1633
  mov(eax, Immediate(isolate()->factory()->undefined_value()));
1414
1634
}
1442
1662
  const Runtime::Function* function = Runtime::FunctionForId(id);
1443
1663
  Set(eax, Immediate(function->nargs));
1444
1664
  mov(ebx, Immediate(ExternalReference(function, isolate())));
1445
 
  CEntryStub ces(1);
1446
 
  ces.SaveDoubles();
 
1665
  CEntryStub ces(1, kSaveFPRegs);
1447
1666
  CallStub(&ces);
1448
1667
}
1449
1668
 
1450
1669
 
1451
 
MaybeObject* MacroAssembler::TryCallRuntime(Runtime::FunctionId id,
1452
 
                                            int num_arguments) {
1453
 
  return TryCallRuntime(Runtime::FunctionForId(id), num_arguments);
1454
 
}
1455
 
 
1456
 
 
1457
1670
void MacroAssembler::CallRuntime(const Runtime::Function* f,
1458
1671
                                 int num_arguments) {
1459
1672
  // If the expected number of arguments of the runtime function is
1475
1688
}
1476
1689
 
1477
1690
 
1478
 
MaybeObject* MacroAssembler::TryCallRuntime(const Runtime::Function* f,
1479
 
                                            int num_arguments) {
1480
 
  if (f->nargs >= 0 && f->nargs != num_arguments) {
1481
 
    IllegalOperation(num_arguments);
1482
 
    // Since we did not call the stub, there was no allocation failure.
1483
 
    // Return some non-failure object.
1484
 
    return isolate()->heap()->undefined_value();
1485
 
  }
1486
 
 
1487
 
  // TODO(1236192): Most runtime routines don't need the number of
1488
 
  // arguments passed in because it is constant. At some point we
1489
 
  // should remove this need and make the runtime routine entry code
1490
 
  // smarter.
1491
 
  Set(eax, Immediate(num_arguments));
1492
 
  mov(ebx, Immediate(ExternalReference(f, isolate())));
1493
 
  CEntryStub ces(1);
1494
 
  return TryCallStub(&ces);
1495
 
}
1496
 
 
1497
 
 
1498
1691
void MacroAssembler::CallExternalReference(ExternalReference ref,
1499
1692
                                           int num_arguments) {
1500
1693
  mov(eax, Immediate(num_arguments));
1517
1710
}
1518
1711
 
1519
1712
 
1520
 
MaybeObject* MacroAssembler::TryTailCallExternalReference(
1521
 
    const ExternalReference& ext, int num_arguments, int result_size) {
1522
 
  // TODO(1236192): Most runtime routines don't need the number of
1523
 
  // arguments passed in because it is constant. At some point we
1524
 
  // should remove this need and make the runtime routine entry code
1525
 
  // smarter.
1526
 
  Set(eax, Immediate(num_arguments));
1527
 
  return TryJumpToExternalReference(ext);
1528
 
}
1529
 
 
1530
 
 
1531
1713
void MacroAssembler::TailCallRuntime(Runtime::FunctionId fid,
1532
1714
                                     int num_arguments,
1533
1715
                                     int result_size) {
1537
1719
}
1538
1720
 
1539
1721
 
1540
 
MaybeObject* MacroAssembler::TryTailCallRuntime(Runtime::FunctionId fid,
1541
 
                                                int num_arguments,
1542
 
                                                int result_size) {
1543
 
  return TryTailCallExternalReference(
1544
 
      ExternalReference(fid, isolate()), num_arguments, result_size);
1545
 
}
1546
 
 
1547
 
 
1548
1722
// If true, a Handle<T> returned by value from a function with cdecl calling
1549
1723
// convention will be returned directly as a value of location_ field in a
1550
1724
// register eax.
1593
1767
}
1594
1768
 
1595
1769
 
1596
 
MaybeObject* MacroAssembler::TryCallApiFunctionAndReturn(ApiFunction* function,
1597
 
                                                         int stack_space) {
 
1770
void MacroAssembler::CallApiFunctionAndReturn(Address function_address,
 
1771
                                              int stack_space) {
1598
1772
  ExternalReference next_address =
1599
1773
      ExternalReference::handle_scope_next_address();
1600
1774
  ExternalReference limit_address =
1607
1781
  mov(edi, Operand::StaticVariable(limit_address));
1608
1782
  add(Operand::StaticVariable(level_address), Immediate(1));
1609
1783
 
1610
 
  // Call the api function!
1611
 
  call(function->address(), RelocInfo::RUNTIME_ENTRY);
 
1784
  // Call the api function.
 
1785
  call(function_address, RelocInfo::RUNTIME_ENTRY);
1612
1786
 
1613
1787
  if (!kReturnHandlesDirectly) {
1614
1788
    // PrepareCallApiFunction saved pointer to the output slot into
1623
1797
  Label leave_exit_frame;
1624
1798
 
1625
1799
  // Check if the result handle holds 0.
1626
 
  test(eax, Operand(eax));
 
1800
  test(eax, eax);
1627
1801
  j(zero, &empty_handle);
1628
1802
  // It was non-zero.  Dereference to get the result value.
1629
1803
  mov(eax, Operand(eax, 0));
1646
1820
  LeaveApiExitFrame();
1647
1821
  ret(stack_space * kPointerSize);
1648
1822
  bind(&promote_scheduled_exception);
1649
 
  MaybeObject* result =
1650
 
      TryTailCallRuntime(Runtime::kPromoteScheduledException, 0, 1);
1651
 
  if (result->IsFailure()) {
1652
 
    return result;
1653
 
  }
 
1823
  TailCallRuntime(Runtime::kPromoteScheduledException, 0, 1);
 
1824
 
1654
1825
  bind(&empty_handle);
1655
1826
  // It was zero; the result is undefined.
1656
1827
  mov(eax, isolate()->factory()->undefined_value());
1664
1835
  mov(edi, eax);
1665
1836
  mov(Operand(esp, 0), Immediate(ExternalReference::isolate_address()));
1666
1837
  mov(eax, Immediate(delete_extensions));
1667
 
  call(Operand(eax));
 
1838
  call(eax);
1668
1839
  mov(eax, edi);
1669
1840
  jmp(&leave_exit_frame);
1670
 
 
1671
 
  return result;
1672
1841
}
1673
1842
 
1674
1843
 
1680
1849
}
1681
1850
 
1682
1851
 
1683
 
MaybeObject* MacroAssembler::TryJumpToExternalReference(
1684
 
    const ExternalReference& ext) {
1685
 
  // Set the entry point and jump to the C entry runtime stub.
1686
 
  mov(ebx, Immediate(ext));
1687
 
  CEntryStub ces(1);
1688
 
  return TryTailCallStub(&ces);
1689
 
}
1690
 
 
1691
 
 
1692
1852
void MacroAssembler::SetCallKind(Register dst, CallKind call_kind) {
1693
1853
  // This macro takes the dst register to make the code more readable
1694
1854
  // at the call sites. However, the dst register has to be ecx to
1698
1858
  if (call_kind == CALL_AS_FUNCTION) {
1699
1859
    // Set to some non-zero smi by updating the least significant
1700
1860
    // byte.
1701
 
    mov_b(Operand(dst), 1 << kSmiTagSize);
 
1861
    mov_b(dst, 1 << kSmiTagSize);
1702
1862
  } else {
1703
1863
    // Set to smi zero by clearing the register.
1704
 
    xor_(dst, Operand(dst));
 
1864
    xor_(dst, dst);
1705
1865
  }
1706
1866
}
1707
1867
 
1746
1906
    } else if (!expected.reg().is(actual.reg())) {
1747
1907
      // Both expected and actual are in (different) registers. This
1748
1908
      // is the case when we invoke functions using call and apply.
1749
 
      cmp(expected.reg(), Operand(actual.reg()));
 
1909
      cmp(expected.reg(), actual.reg());
1750
1910
      j(equal, &invoke);
1751
1911
      ASSERT(actual.reg().is(eax));
1752
1912
      ASSERT(expected.reg().is(ebx));
1758
1918
        isolate()->builtins()->ArgumentsAdaptorTrampoline();
1759
1919
    if (!code_constant.is_null()) {
1760
1920
      mov(edx, Immediate(code_constant));
1761
 
      add(Operand(edx), Immediate(Code::kHeaderSize - kHeapObjectTag));
 
1921
      add(edx, Immediate(Code::kHeaderSize - kHeapObjectTag));
1762
1922
    } else if (!code_operand.is_reg(edx)) {
1763
1923
      mov(edx, code_operand);
1764
1924
    }
1784
1944
                                InvokeFlag flag,
1785
1945
                                const CallWrapper& call_wrapper,
1786
1946
                                CallKind call_kind) {
 
1947
  // You can't call a function without a valid frame.
 
1948
  ASSERT(flag == JUMP_FUNCTION || has_frame());
 
1949
 
1787
1950
  Label done;
1788
1951
  InvokePrologue(expected, actual, Handle<Code>::null(), code,
1789
1952
                 &done, flag, Label::kNear, call_wrapper,
1809
1972
                                InvokeFlag flag,
1810
1973
                                const CallWrapper& call_wrapper,
1811
1974
                                CallKind call_kind) {
 
1975
  // You can't call a function without a valid frame.
 
1976
  ASSERT(flag == JUMP_FUNCTION || has_frame());
 
1977
 
1812
1978
  Label done;
1813
 
  Operand dummy(eax);
 
1979
  Operand dummy(eax, 0);
1814
1980
  InvokePrologue(expected, actual, code, dummy, &done, flag, Label::kNear,
1815
1981
                 call_wrapper, call_kind);
1816
1982
  if (flag == CALL_FUNCTION) {
1832
1998
                                    InvokeFlag flag,
1833
1999
                                    const CallWrapper& call_wrapper,
1834
2000
                                    CallKind call_kind) {
 
2001
  // You can't call a function without a valid frame.
 
2002
  ASSERT(flag == JUMP_FUNCTION || has_frame());
 
2003
 
1835
2004
  ASSERT(fun.is(edi));
1836
2005
  mov(edx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
1837
2006
  mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
1844
2013
}
1845
2014
 
1846
2015
 
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());
 
2023
 
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));
1856
2027
 
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);
1864
 
  } else {
1865
 
    Handle<Code> code(function->code());
1866
 
    InvokeCode(code, expected, actual, RelocInfo::CODE_TARGET,
1867
 
               flag, call_wrapper, call_kind);
1868
 
  }
 
2029
  // We call indirectly through the code field in the function to
 
2030
  // allow recompilation to take effect without changing any of the
 
2031
  // call sites.
 
2032
  InvokeCode(FieldOperand(edi, JSFunction::kCodeEntryOffset),
 
2033
             expected, actual, flag, call_wrapper, call_kind);
1869
2034
}
1870
2035
 
1871
2036
 
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());
1877
2042
 
1878
2043
  // Rely on the assertion to check that the number of provided
1879
2044
  // arguments match the expected number of arguments. Fake a
1884
2049
             expected, expected, flag, call_wrapper, CALL_AS_METHOD);
1885
2050
}
1886
2051
 
 
2052
 
1887
2053
void MacroAssembler::GetBuiltinFunction(Register target,
1888
2054
                                        Builtins::JavaScript id) {
1889
2055
  // Load the JavaScript builtin function from the builtins object.
1893
2059
                           JSBuiltinsObject::OffsetOfFunctionWithId(id)));
1894
2060
}
1895
2061
 
 
2062
 
1896
2063
void MacroAssembler::GetBuiltinEntry(Register target, Builtins::JavaScript id) {
1897
2064
  ASSERT(!target.is(edi));
1898
2065
  // Load the JavaScript builtin function from the builtins object.
1994
2161
    ret(bytes_dropped);
1995
2162
  } else {
1996
2163
    pop(scratch);
1997
 
    add(Operand(esp), Immediate(bytes_dropped));
 
2164
    add(esp, Immediate(bytes_dropped));
1998
2165
    push(scratch);
1999
2166
    ret(0);
2000
2167
  }
2003
2170
 
2004
2171
void MacroAssembler::Drop(int stack_elements) {
2005
2172
  if (stack_elements > 0) {
2006
 
    add(Operand(esp), Immediate(stack_elements * kPointerSize));
 
2173
    add(esp, Immediate(stack_elements * kPointerSize));
2007
2174
  }
2008
2175
}
2009
2176
 
2146
2313
    RecordComment(msg);
2147
2314
  }
2148
2315
#endif
2149
 
  // Disable stub call restrictions to always allow calls to abort.
2150
 
  AllowStubCallsScope allow_scope(this, true);
2151
2316
 
2152
2317
  push(eax);
2153
2318
  push(Immediate(p0));
2154
2319
  push(Immediate(reinterpret_cast<intptr_t>(Smi::FromInt(p1 - p0))));
2155
 
  CallRuntime(Runtime::kAbort, 2);
 
2320
  // Disable stub call restrictions to always allow calls to abort.
 
2321
  if (!has_frame_) {
 
2322
    // We don't actually want to generate a pile of code for this, so just
 
2323
    // claim there is a stack frame, without generating one.
 
2324
    FrameScope scope(this, StackFrame::NONE);
 
2325
    CallRuntime(Runtime::kAbort, 2);
 
2326
  } else {
 
2327
    CallRuntime(Runtime::kAbort, 2);
 
2328
  }
2156
2329
  // will not return here
2157
2330
  int3();
2158
2331
}
2175
2348
  ASSERT(is_uintn(power + HeapNumber::kExponentBias,
2176
2349
                  HeapNumber::kExponentBits));
2177
2350
  mov(scratch, Immediate(power + HeapNumber::kExponentBias));
2178
 
  movd(dst, Operand(scratch));
 
2351
  movd(dst, scratch);
2179
2352
  psllq(dst, HeapNumber::kMantissaBits);
2180
2353
}
2181
2354
 
2201
2374
                                                         Label* failure) {
2202
2375
  // Check that both objects are not smis.
2203
2376
  STATIC_ASSERT(kSmiTag == 0);
2204
 
  mov(scratch1, Operand(object1));
2205
 
  and_(scratch1, Operand(object2));
 
2377
  mov(scratch1, object1);
 
2378
  and_(scratch1, object2);
2206
2379
  JumpIfSmi(scratch1, failure);
2207
2380
 
2208
2381
  // Load instance type for both strings.
2231
2404
    // Make stack end at alignment and make room for num_arguments words
2232
2405
    // and the original value of esp.
2233
2406
    mov(scratch, esp);
2234
 
    sub(Operand(esp), Immediate((num_arguments + 1) * kPointerSize));
 
2407
    sub(esp, Immediate((num_arguments + 1) * kPointerSize));
2235
2408
    ASSERT(IsPowerOf2(frame_alignment));
2236
2409
    and_(esp, -frame_alignment);
2237
2410
    mov(Operand(esp, num_arguments * kPointerSize), scratch);
2238
2411
  } else {
2239
 
    sub(Operand(esp), Immediate(num_arguments * kPointerSize));
 
2412
    sub(esp, Immediate(num_arguments * kPointerSize));
2240
2413
  }
2241
2414
}
2242
2415
 
2244
2417
void MacroAssembler::CallCFunction(ExternalReference function,
2245
2418
                                   int num_arguments) {
2246
2419
  // Trashing eax is ok as it will be the return value.
2247
 
  mov(Operand(eax), Immediate(function));
 
2420
  mov(eax, Immediate(function));
2248
2421
  CallCFunction(eax, num_arguments);
2249
2422
}
2250
2423
 
2251
2424
 
2252
2425
void MacroAssembler::CallCFunction(Register function,
2253
2426
                                   int num_arguments) {
 
2427
  ASSERT(has_frame());
2254
2428
  // Check stack alignment.
2255
2429
  if (emit_debug_code()) {
2256
2430
    CheckStackAlignment();
2257
2431
  }
2258
2432
 
2259
 
  call(Operand(function));
 
2433
  call(function);
2260
2434
  if (OS::ActivationFrameAlignment() != 0) {
2261
2435
    mov(esp, Operand(esp, num_arguments * kPointerSize));
2262
2436
  } else {
2263
 
    add(Operand(esp), Immediate(num_arguments * kPointerSize));
 
2437
    add(esp, Immediate(num_arguments * kPointerSize));
2264
2438
  }
2265
2439
}
2266
2440
 
2267
2441
 
 
2442
bool AreAliased(Register r1, Register r2, Register r3, Register r4) {
 
2443
  if (r1.is(r2)) return true;
 
2444
  if (r1.is(r3)) return true;
 
2445
  if (r1.is(r4)) return true;
 
2446
  if (r2.is(r3)) return true;
 
2447
  if (r2.is(r4)) return true;
 
2448
  if (r3.is(r4)) return true;
 
2449
  return false;
 
2450
}
 
2451
 
 
2452
 
2268
2453
CodePatcher::CodePatcher(byte* address, int size)
2269
2454
    : address_(address),
2270
2455
      size_(size),
2286
2471
}
2287
2472
 
2288
2473
 
 
2474
void MacroAssembler::CheckPageFlag(
 
2475
    Register object,
 
2476
    Register scratch,
 
2477
    int mask,
 
2478
    Condition cc,
 
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));
 
2484
  } else {
 
2485
    mov(scratch, Immediate(~Page::kPageAlignmentMask));
 
2486
    and_(scratch, object);
 
2487
  }
 
2488
  if (mask < (1 << kBitsPerByte)) {
 
2489
    test_b(Operand(scratch, MemoryChunk::kFlagsOffset),
 
2490
           static_cast<uint8_t>(mask));
 
2491
  } else {
 
2492
    test(Operand(scratch, MemoryChunk::kFlagsOffset), Immediate(mask));
 
2493
  }
 
2494
  j(cc, condition_met, condition_met_distance);
 
2495
}
 
2496
 
 
2497
 
 
2498
void MacroAssembler::JumpIfBlack(Register object,
 
2499
                                 Register scratch0,
 
2500
                                 Register scratch1,
 
2501
                                 Label* on_black,
 
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);
 
2507
}
 
2508
 
 
2509
 
 
2510
void MacroAssembler::HasColor(Register object,
 
2511
                              Register bitmap_scratch,
 
2512
                              Register mask_scratch,
 
2513
                              Label* has_color,
 
2514
                              Label::Distance has_color_distance,
 
2515
                              int first_bit,
 
2516
                              int second_bit) {
 
2517
  ASSERT(!AreAliased(object, bitmap_scratch, mask_scratch, ecx));
 
2518
 
 
2519
  GetMarkBits(object, bitmap_scratch, mask_scratch);
 
2520
 
 
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);
 
2529
 
 
2530
  bind(&word_boundary);
 
2531
  test_b(Operand(bitmap_scratch, MemoryChunk::kHeaderSize + kPointerSize), 1);
 
2532
 
 
2533
  j(second_bit == 1 ? not_zero : zero, has_color, has_color_distance);
 
2534
  bind(&other_color);
 
2535
}
 
2536
 
 
2537
 
 
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);
 
2544
  mov(ecx, addr_reg);
 
2545
  int shift =
 
2546
      Bitmap::kBitsPerCellLog2 + kPointerSizeLog2 - Bitmap::kBytesPerCellLog2;
 
2547
  shr(ecx, shift);
 
2548
  and_(ecx,
 
2549
       (Page::kPageAlignmentMask >> shift) & ~(Bitmap::kBytesPerCell - 1));
 
2550
 
 
2551
  add(bitmap_reg, ecx);
 
2552
  mov(ecx, addr_reg);
 
2553
  shr(ecx, kPointerSizeLog2);
 
2554
  and_(ecx, (1 << Bitmap::kBitsPerCellLog2) - 1);
 
2555
  mov(mask_reg, Immediate(1));
 
2556
  shl_cl(mask_reg);
 
2557
}
 
2558
 
 
2559
 
 
2560
void MacroAssembler::EnsureNotWhite(
 
2561
    Register value,
 
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);
 
2568
 
 
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);
 
2574
 
 
2575
  Label done;
 
2576
 
 
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);
 
2581
 
 
2582
  if (FLAG_debug_code) {
 
2583
    // Check for impossible bit pattern.
 
2584
    Label ok;
 
2585
    push(mask_scratch);
 
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);
 
2590
    int3();
 
2591
    bind(&ok);
 
2592
    pop(mask_scratch);
 
2593
  }
 
2594
 
 
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;
 
2601
 
 
2602
  // Check for heap-number
 
2603
  mov(map, FieldOperand(value, HeapObject::kMapOffset));
 
2604
  cmp(map, FACTORY->heap_number_map());
 
2605
  j(not_equal, &not_heap_number, Label::kNear);
 
2606
  mov(length, Immediate(HeapNumber::kSize));
 
2607
  jmp(&is_data_object, Label::kNear);
 
2608
 
 
2609
  bind(&not_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
 
2614
  // no GC pointers.
 
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).
 
2622
  Label not_external;
 
2623
  // External strings are the only ones with the kExternalStringTag bit
 
2624
  // set.
 
2625
  ASSERT_EQ(0, kSeqStringTag & kExternalStringTag);
 
2626
  ASSERT_EQ(0, kConsStringTag & kExternalStringTag);
 
2627
  test_b(instance_type, kExternalStringTag);
 
2628
  j(zero, &not_external, Label::kNear);
 
2629
  mov(length, Immediate(ExternalString::kSize));
 
2630
  jmp(&is_data_object, Label::kNear);
 
2631
 
 
2632
  bind(&not_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));
 
2648
 
 
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);
 
2653
 
 
2654
  and_(bitmap_scratch, Immediate(~Page::kPageAlignmentMask));
 
2655
  add(Operand(bitmap_scratch, MemoryChunk::kLiveBytesOffset),
 
2656
      length);
 
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");
 
2661
  }
 
2662
 
 
2663
  bind(&done);
 
2664
}
 
2665
 
2289
2666
} }  // namespace v8::internal
2290
2667
 
2291
2668
#endif  // V8_TARGET_ARCH_IA32