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

« back to all changes in this revision

Viewing changes to .pc/0015_hash-collision-fix-v8-3.6.patch/src/arm/macro-assembler-arm.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:
1
 
// Copyright 2011 the V8 project authors. All rights reserved.
2
 
// Redistribution and use in source and binary forms, with or without
3
 
// modification, are permitted provided that the following conditions are
4
 
// met:
5
 
//
6
 
//     * Redistributions of source code must retain the above copyright
7
 
//       notice, this list of conditions and the following disclaimer.
8
 
//     * Redistributions in binary form must reproduce the above
9
 
//       copyright notice, this list of conditions and the following
10
 
//       disclaimer in the documentation and/or other materials provided
11
 
//       with the distribution.
12
 
//     * Neither the name of Google Inc. nor the names of its
13
 
//       contributors may be used to endorse or promote products derived
14
 
//       from this software without specific prior written permission.
15
 
//
16
 
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17
 
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18
 
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19
 
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20
 
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21
 
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22
 
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23
 
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24
 
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25
 
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26
 
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
 
 
28
 
#include <limits.h>  // For LONG_MIN, LONG_MAX.
29
 
 
30
 
#include "v8.h"
31
 
 
32
 
#if defined(V8_TARGET_ARCH_ARM)
33
 
 
34
 
#include "bootstrapper.h"
35
 
#include "codegen.h"
36
 
#include "debug.h"
37
 
#include "runtime.h"
38
 
 
39
 
namespace v8 {
40
 
namespace internal {
41
 
 
42
 
MacroAssembler::MacroAssembler(Isolate* arg_isolate, void* buffer, int size)
43
 
    : Assembler(arg_isolate, buffer, size),
44
 
      generating_stub_(false),
45
 
      allow_stub_calls_(true) {
46
 
  if (isolate() != NULL) {
47
 
    code_object_ = Handle<Object>(isolate()->heap()->undefined_value(),
48
 
                                  isolate());
49
 
  }
50
 
}
51
 
 
52
 
 
53
 
// We always generate arm code, never thumb code, even if V8 is compiled to
54
 
// thumb, so we require inter-working support
55
 
#if defined(__thumb__) && !defined(USE_THUMB_INTERWORK)
56
 
#error "flag -mthumb-interwork missing"
57
 
#endif
58
 
 
59
 
 
60
 
// We do not support thumb inter-working with an arm architecture not supporting
61
 
// the blx instruction (below v5t).  If you know what CPU you are compiling for
62
 
// you can use -march=armv7 or similar.
63
 
#if defined(USE_THUMB_INTERWORK) && !defined(CAN_USE_THUMB_INSTRUCTIONS)
64
 
# error "For thumb inter-working we require an architecture which supports blx"
65
 
#endif
66
 
 
67
 
 
68
 
// Using bx does not yield better code, so use it only when required
69
 
#if defined(USE_THUMB_INTERWORK)
70
 
#define USE_BX 1
71
 
#endif
72
 
 
73
 
 
74
 
void MacroAssembler::Jump(Register target, Condition cond) {
75
 
#if USE_BX
76
 
  bx(target, cond);
77
 
#else
78
 
  mov(pc, Operand(target), LeaveCC, cond);
79
 
#endif
80
 
}
81
 
 
82
 
 
83
 
void MacroAssembler::Jump(intptr_t target, RelocInfo::Mode rmode,
84
 
                          Condition cond) {
85
 
#if USE_BX
86
 
  mov(ip, Operand(target, rmode));
87
 
  bx(ip, cond);
88
 
#else
89
 
  mov(pc, Operand(target, rmode), LeaveCC, cond);
90
 
#endif
91
 
}
92
 
 
93
 
 
94
 
void MacroAssembler::Jump(Address target, RelocInfo::Mode rmode,
95
 
                          Condition cond) {
96
 
  ASSERT(!RelocInfo::IsCodeTarget(rmode));
97
 
  Jump(reinterpret_cast<intptr_t>(target), rmode, cond);
98
 
}
99
 
 
100
 
 
101
 
void MacroAssembler::Jump(Handle<Code> code, RelocInfo::Mode rmode,
102
 
                          Condition cond) {
103
 
  ASSERT(RelocInfo::IsCodeTarget(rmode));
104
 
  // 'code' is always generated ARM code, never THUMB code
105
 
  Jump(reinterpret_cast<intptr_t>(code.location()), rmode, cond);
106
 
}
107
 
 
108
 
 
109
 
int MacroAssembler::CallSize(Register target, Condition cond) {
110
 
#if USE_BLX
111
 
  return kInstrSize;
112
 
#else
113
 
  return 2 * kInstrSize;
114
 
#endif
115
 
}
116
 
 
117
 
 
118
 
void MacroAssembler::Call(Register target, Condition cond) {
119
 
  // Block constant pool for the call instruction sequence.
120
 
  BlockConstPoolScope block_const_pool(this);
121
 
  Label start;
122
 
  bind(&start);
123
 
#if USE_BLX
124
 
  blx(target, cond);
125
 
#else
126
 
  // set lr for return at current pc + 8
127
 
  mov(lr, Operand(pc), LeaveCC, cond);
128
 
  mov(pc, Operand(target), LeaveCC, cond);
129
 
#endif
130
 
  ASSERT_EQ(CallSize(target, cond), SizeOfCodeGeneratedSince(&start));
131
 
}
132
 
 
133
 
 
134
 
int MacroAssembler::CallSize(
135
 
    Address target, RelocInfo::Mode rmode, Condition cond) {
136
 
  int size = 2 * kInstrSize;
137
 
  Instr mov_instr = cond | MOV | LeaveCC;
138
 
  intptr_t immediate = reinterpret_cast<intptr_t>(target);
139
 
  if (!Operand(immediate, rmode).is_single_instruction(mov_instr)) {
140
 
    size += kInstrSize;
141
 
  }
142
 
  return size;
143
 
}
144
 
 
145
 
 
146
 
void MacroAssembler::Call(Address target,
147
 
                          RelocInfo::Mode rmode,
148
 
                          Condition cond) {
149
 
  // Block constant pool for the call instruction sequence.
150
 
  BlockConstPoolScope block_const_pool(this);
151
 
  Label start;
152
 
  bind(&start);
153
 
#if USE_BLX
154
 
  // On ARMv5 and after the recommended call sequence is:
155
 
  //  ldr ip, [pc, #...]
156
 
  //  blx ip
157
 
 
158
 
  // Statement positions are expected to be recorded when the target
159
 
  // address is loaded. The mov method will automatically record
160
 
  // positions when pc is the target, since this is not the case here
161
 
  // we have to do it explicitly.
162
 
  positions_recorder()->WriteRecordedPositions();
163
 
 
164
 
  mov(ip, Operand(reinterpret_cast<int32_t>(target), rmode));
165
 
  blx(ip, cond);
166
 
 
167
 
  ASSERT(kCallTargetAddressOffset == 2 * kInstrSize);
168
 
#else
169
 
  // Set lr for return at current pc + 8.
170
 
  mov(lr, Operand(pc), LeaveCC, cond);
171
 
  // Emit a ldr<cond> pc, [pc + offset of target in constant pool].
172
 
  mov(pc, Operand(reinterpret_cast<int32_t>(target), rmode), LeaveCC, cond);
173
 
  ASSERT(kCallTargetAddressOffset == kInstrSize);
174
 
#endif
175
 
  ASSERT_EQ(CallSize(target, rmode, cond), SizeOfCodeGeneratedSince(&start));
176
 
}
177
 
 
178
 
 
179
 
int MacroAssembler::CallSize(Handle<Code> code,
180
 
                             RelocInfo::Mode rmode,
181
 
                             unsigned ast_id,
182
 
                             Condition cond) {
183
 
  return CallSize(reinterpret_cast<Address>(code.location()), rmode, cond);
184
 
}
185
 
 
186
 
 
187
 
void MacroAssembler::Call(Handle<Code> code,
188
 
                          RelocInfo::Mode rmode,
189
 
                          unsigned ast_id,
190
 
                          Condition cond) {
191
 
  Label start;
192
 
  bind(&start);
193
 
  ASSERT(RelocInfo::IsCodeTarget(rmode));
194
 
  if (rmode == RelocInfo::CODE_TARGET && ast_id != kNoASTId) {
195
 
    SetRecordedAstId(ast_id);
196
 
    rmode = RelocInfo::CODE_TARGET_WITH_ID;
197
 
  }
198
 
  // 'code' is always generated ARM code, never THUMB code
199
 
  Call(reinterpret_cast<Address>(code.location()), rmode, cond);
200
 
  ASSERT_EQ(CallSize(code, rmode, ast_id, cond),
201
 
            SizeOfCodeGeneratedSince(&start));
202
 
}
203
 
 
204
 
 
205
 
void MacroAssembler::Ret(Condition cond) {
206
 
#if USE_BX
207
 
  bx(lr, cond);
208
 
#else
209
 
  mov(pc, Operand(lr), LeaveCC, cond);
210
 
#endif
211
 
}
212
 
 
213
 
 
214
 
void MacroAssembler::Drop(int count, Condition cond) {
215
 
  if (count > 0) {
216
 
    add(sp, sp, Operand(count * kPointerSize), LeaveCC, cond);
217
 
  }
218
 
}
219
 
 
220
 
 
221
 
void MacroAssembler::Ret(int drop, Condition cond) {
222
 
  Drop(drop, cond);
223
 
  Ret(cond);
224
 
}
225
 
 
226
 
 
227
 
void MacroAssembler::Swap(Register reg1,
228
 
                          Register reg2,
229
 
                          Register scratch,
230
 
                          Condition cond) {
231
 
  if (scratch.is(no_reg)) {
232
 
    eor(reg1, reg1, Operand(reg2), LeaveCC, cond);
233
 
    eor(reg2, reg2, Operand(reg1), LeaveCC, cond);
234
 
    eor(reg1, reg1, Operand(reg2), LeaveCC, cond);
235
 
  } else {
236
 
    mov(scratch, reg1, LeaveCC, cond);
237
 
    mov(reg1, reg2, LeaveCC, cond);
238
 
    mov(reg2, scratch, LeaveCC, cond);
239
 
  }
240
 
}
241
 
 
242
 
 
243
 
void MacroAssembler::Call(Label* target) {
244
 
  bl(target);
245
 
}
246
 
 
247
 
 
248
 
void MacroAssembler::Push(Handle<Object> handle) {
249
 
  mov(ip, Operand(handle));
250
 
  push(ip);
251
 
}
252
 
 
253
 
 
254
 
void MacroAssembler::Move(Register dst, Handle<Object> value) {
255
 
  mov(dst, Operand(value));
256
 
}
257
 
 
258
 
 
259
 
void MacroAssembler::Move(Register dst, Register src, Condition cond) {
260
 
  if (!dst.is(src)) {
261
 
    mov(dst, src, LeaveCC, cond);
262
 
  }
263
 
}
264
 
 
265
 
 
266
 
void MacroAssembler::Move(DoubleRegister dst, DoubleRegister src) {
267
 
  ASSERT(CpuFeatures::IsSupported(VFP3));
268
 
  CpuFeatures::Scope scope(VFP3);
269
 
  if (!dst.is(src)) {
270
 
    vmov(dst, src);
271
 
  }
272
 
}
273
 
 
274
 
 
275
 
void MacroAssembler::And(Register dst, Register src1, const Operand& src2,
276
 
                         Condition cond) {
277
 
  if (!src2.is_reg() &&
278
 
      !src2.must_use_constant_pool() &&
279
 
      src2.immediate() == 0) {
280
 
    mov(dst, Operand(0, RelocInfo::NONE), LeaveCC, cond);
281
 
 
282
 
  } else if (!src2.is_single_instruction() &&
283
 
             !src2.must_use_constant_pool() &&
284
 
             CpuFeatures::IsSupported(ARMv7) &&
285
 
             IsPowerOf2(src2.immediate() + 1)) {
286
 
    ubfx(dst, src1, 0,
287
 
        WhichPowerOf2(static_cast<uint32_t>(src2.immediate()) + 1), cond);
288
 
 
289
 
  } else {
290
 
    and_(dst, src1, src2, LeaveCC, cond);
291
 
  }
292
 
}
293
 
 
294
 
 
295
 
void MacroAssembler::Ubfx(Register dst, Register src1, int lsb, int width,
296
 
                          Condition cond) {
297
 
  ASSERT(lsb < 32);
298
 
  if (!CpuFeatures::IsSupported(ARMv7)) {
299
 
    int mask = (1 << (width + lsb)) - 1 - ((1 << lsb) - 1);
300
 
    and_(dst, src1, Operand(mask), LeaveCC, cond);
301
 
    if (lsb != 0) {
302
 
      mov(dst, Operand(dst, LSR, lsb), LeaveCC, cond);
303
 
    }
304
 
  } else {
305
 
    ubfx(dst, src1, lsb, width, cond);
306
 
  }
307
 
}
308
 
 
309
 
 
310
 
void MacroAssembler::Sbfx(Register dst, Register src1, int lsb, int width,
311
 
                          Condition cond) {
312
 
  ASSERT(lsb < 32);
313
 
  if (!CpuFeatures::IsSupported(ARMv7)) {
314
 
    int mask = (1 << (width + lsb)) - 1 - ((1 << lsb) - 1);
315
 
    and_(dst, src1, Operand(mask), LeaveCC, cond);
316
 
    int shift_up = 32 - lsb - width;
317
 
    int shift_down = lsb + shift_up;
318
 
    if (shift_up != 0) {
319
 
      mov(dst, Operand(dst, LSL, shift_up), LeaveCC, cond);
320
 
    }
321
 
    if (shift_down != 0) {
322
 
      mov(dst, Operand(dst, ASR, shift_down), LeaveCC, cond);
323
 
    }
324
 
  } else {
325
 
    sbfx(dst, src1, lsb, width, cond);
326
 
  }
327
 
}
328
 
 
329
 
 
330
 
void MacroAssembler::Bfi(Register dst,
331
 
                         Register src,
332
 
                         Register scratch,
333
 
                         int lsb,
334
 
                         int width,
335
 
                         Condition cond) {
336
 
  ASSERT(0 <= lsb && lsb < 32);
337
 
  ASSERT(0 <= width && width < 32);
338
 
  ASSERT(lsb + width < 32);
339
 
  ASSERT(!scratch.is(dst));
340
 
  if (width == 0) return;
341
 
  if (!CpuFeatures::IsSupported(ARMv7)) {
342
 
    int mask = (1 << (width + lsb)) - 1 - ((1 << lsb) - 1);
343
 
    bic(dst, dst, Operand(mask));
344
 
    and_(scratch, src, Operand((1 << width) - 1));
345
 
    mov(scratch, Operand(scratch, LSL, lsb));
346
 
    orr(dst, dst, scratch);
347
 
  } else {
348
 
    bfi(dst, src, lsb, width, cond);
349
 
  }
350
 
}
351
 
 
352
 
 
353
 
void MacroAssembler::Bfc(Register dst, int lsb, int width, Condition cond) {
354
 
  ASSERT(lsb < 32);
355
 
  if (!CpuFeatures::IsSupported(ARMv7)) {
356
 
    int mask = (1 << (width + lsb)) - 1 - ((1 << lsb) - 1);
357
 
    bic(dst, dst, Operand(mask));
358
 
  } else {
359
 
    bfc(dst, lsb, width, cond);
360
 
  }
361
 
}
362
 
 
363
 
 
364
 
void MacroAssembler::Usat(Register dst, int satpos, const Operand& src,
365
 
                          Condition cond) {
366
 
  if (!CpuFeatures::IsSupported(ARMv7)) {
367
 
    ASSERT(!dst.is(pc) && !src.rm().is(pc));
368
 
    ASSERT((satpos >= 0) && (satpos <= 31));
369
 
 
370
 
    // These asserts are required to ensure compatibility with the ARMv7
371
 
    // implementation.
372
 
    ASSERT((src.shift_op() == ASR) || (src.shift_op() == LSL));
373
 
    ASSERT(src.rs().is(no_reg));
374
 
 
375
 
    Label done;
376
 
    int satval = (1 << satpos) - 1;
377
 
 
378
 
    if (cond != al) {
379
 
      b(NegateCondition(cond), &done);  // Skip saturate if !condition.
380
 
    }
381
 
    if (!(src.is_reg() && dst.is(src.rm()))) {
382
 
      mov(dst, src);
383
 
    }
384
 
    tst(dst, Operand(~satval));
385
 
    b(eq, &done);
386
 
    mov(dst, Operand(0, RelocInfo::NONE), LeaveCC, mi);  // 0 if negative.
387
 
    mov(dst, Operand(satval), LeaveCC, pl);  // satval if positive.
388
 
    bind(&done);
389
 
  } else {
390
 
    usat(dst, satpos, src, cond);
391
 
  }
392
 
}
393
 
 
394
 
 
395
 
void MacroAssembler::LoadRoot(Register destination,
396
 
                              Heap::RootListIndex index,
397
 
                              Condition cond) {
398
 
  ldr(destination, MemOperand(roots, index << kPointerSizeLog2), cond);
399
 
}
400
 
 
401
 
 
402
 
void MacroAssembler::StoreRoot(Register source,
403
 
                               Heap::RootListIndex index,
404
 
                               Condition cond) {
405
 
  str(source, MemOperand(roots, index << kPointerSizeLog2), cond);
406
 
}
407
 
 
408
 
 
409
 
void MacroAssembler::RecordWriteHelper(Register object,
410
 
                                       Register address,
411
 
                                       Register scratch) {
412
 
  if (emit_debug_code()) {
413
 
    // Check that the object is not in new space.
414
 
    Label not_in_new_space;
415
 
    InNewSpace(object, scratch, ne, &not_in_new_space);
416
 
    Abort("new-space object passed to RecordWriteHelper");
417
 
    bind(&not_in_new_space);
418
 
  }
419
 
 
420
 
  // Calculate page address.
421
 
  Bfc(object, 0, kPageSizeBits);
422
 
 
423
 
  // Calculate region number.
424
 
  Ubfx(address, address, Page::kRegionSizeLog2,
425
 
       kPageSizeBits - Page::kRegionSizeLog2);
426
 
 
427
 
  // Mark region dirty.
428
 
  ldr(scratch, MemOperand(object, Page::kDirtyFlagOffset));
429
 
  mov(ip, Operand(1));
430
 
  orr(scratch, scratch, Operand(ip, LSL, address));
431
 
  str(scratch, MemOperand(object, Page::kDirtyFlagOffset));
432
 
}
433
 
 
434
 
 
435
 
void MacroAssembler::InNewSpace(Register object,
436
 
                                Register scratch,
437
 
                                Condition cond,
438
 
                                Label* branch) {
439
 
  ASSERT(cond == eq || cond == ne);
440
 
  and_(scratch, object, Operand(ExternalReference::new_space_mask(isolate())));
441
 
  cmp(scratch, Operand(ExternalReference::new_space_start(isolate())));
442
 
  b(cond, branch);
443
 
}
444
 
 
445
 
 
446
 
// Will clobber 4 registers: object, offset, scratch, ip.  The
447
 
// register 'object' contains a heap object pointer.  The heap object
448
 
// tag is shifted away.
449
 
void MacroAssembler::RecordWrite(Register object,
450
 
                                 Operand offset,
451
 
                                 Register scratch0,
452
 
                                 Register scratch1) {
453
 
  // The compiled code assumes that record write doesn't change the
454
 
  // context register, so we check that none of the clobbered
455
 
  // registers are cp.
456
 
  ASSERT(!object.is(cp) && !scratch0.is(cp) && !scratch1.is(cp));
457
 
 
458
 
  Label done;
459
 
 
460
 
  // First, test that the object is not in the new space.  We cannot set
461
 
  // region marks for new space pages.
462
 
  InNewSpace(object, scratch0, eq, &done);
463
 
 
464
 
  // Add offset into the object.
465
 
  add(scratch0, object, offset);
466
 
 
467
 
  // Record the actual write.
468
 
  RecordWriteHelper(object, scratch0, scratch1);
469
 
 
470
 
  bind(&done);
471
 
 
472
 
  // Clobber all input registers when running with the debug-code flag
473
 
  // turned on to provoke errors.
474
 
  if (emit_debug_code()) {
475
 
    mov(object, Operand(BitCast<int32_t>(kZapValue)));
476
 
    mov(scratch0, Operand(BitCast<int32_t>(kZapValue)));
477
 
    mov(scratch1, Operand(BitCast<int32_t>(kZapValue)));
478
 
  }
479
 
}
480
 
 
481
 
 
482
 
// Will clobber 4 registers: object, address, scratch, ip.  The
483
 
// register 'object' contains a heap object pointer.  The heap object
484
 
// tag is shifted away.
485
 
void MacroAssembler::RecordWrite(Register object,
486
 
                                 Register address,
487
 
                                 Register scratch) {
488
 
  // The compiled code assumes that record write doesn't change the
489
 
  // context register, so we check that none of the clobbered
490
 
  // registers are cp.
491
 
  ASSERT(!object.is(cp) && !address.is(cp) && !scratch.is(cp));
492
 
 
493
 
  Label done;
494
 
 
495
 
  // First, test that the object is not in the new space.  We cannot set
496
 
  // region marks for new space pages.
497
 
  InNewSpace(object, scratch, eq, &done);
498
 
 
499
 
  // Record the actual write.
500
 
  RecordWriteHelper(object, address, scratch);
501
 
 
502
 
  bind(&done);
503
 
 
504
 
  // Clobber all input registers when running with the debug-code flag
505
 
  // turned on to provoke errors.
506
 
  if (emit_debug_code()) {
507
 
    mov(object, Operand(BitCast<int32_t>(kZapValue)));
508
 
    mov(address, Operand(BitCast<int32_t>(kZapValue)));
509
 
    mov(scratch, Operand(BitCast<int32_t>(kZapValue)));
510
 
  }
511
 
}
512
 
 
513
 
 
514
 
// Push and pop all registers that can hold pointers.
515
 
void MacroAssembler::PushSafepointRegisters() {
516
 
  // Safepoints expect a block of contiguous register values starting with r0:
517
 
  ASSERT(((1 << kNumSafepointSavedRegisters) - 1) == kSafepointSavedRegisters);
518
 
  // Safepoints expect a block of kNumSafepointRegisters values on the
519
 
  // stack, so adjust the stack for unsaved registers.
520
 
  const int num_unsaved = kNumSafepointRegisters - kNumSafepointSavedRegisters;
521
 
  ASSERT(num_unsaved >= 0);
522
 
  sub(sp, sp, Operand(num_unsaved * kPointerSize));
523
 
  stm(db_w, sp, kSafepointSavedRegisters);
524
 
}
525
 
 
526
 
 
527
 
void MacroAssembler::PopSafepointRegisters() {
528
 
  const int num_unsaved = kNumSafepointRegisters - kNumSafepointSavedRegisters;
529
 
  ldm(ia_w, sp, kSafepointSavedRegisters);
530
 
  add(sp, sp, Operand(num_unsaved * kPointerSize));
531
 
}
532
 
 
533
 
 
534
 
void MacroAssembler::PushSafepointRegistersAndDoubles() {
535
 
  PushSafepointRegisters();
536
 
  sub(sp, sp, Operand(DwVfpRegister::kNumAllocatableRegisters *
537
 
                      kDoubleSize));
538
 
  for (int i = 0; i < DwVfpRegister::kNumAllocatableRegisters; i++) {
539
 
    vstr(DwVfpRegister::FromAllocationIndex(i), sp, i * kDoubleSize);
540
 
  }
541
 
}
542
 
 
543
 
 
544
 
void MacroAssembler::PopSafepointRegistersAndDoubles() {
545
 
  for (int i = 0; i < DwVfpRegister::kNumAllocatableRegisters; i++) {
546
 
    vldr(DwVfpRegister::FromAllocationIndex(i), sp, i * kDoubleSize);
547
 
  }
548
 
  add(sp, sp, Operand(DwVfpRegister::kNumAllocatableRegisters *
549
 
                      kDoubleSize));
550
 
  PopSafepointRegisters();
551
 
}
552
 
 
553
 
void MacroAssembler::StoreToSafepointRegistersAndDoublesSlot(Register src,
554
 
                                                             Register dst) {
555
 
  str(src, SafepointRegistersAndDoublesSlot(dst));
556
 
}
557
 
 
558
 
 
559
 
void MacroAssembler::StoreToSafepointRegisterSlot(Register src, Register dst) {
560
 
  str(src, SafepointRegisterSlot(dst));
561
 
}
562
 
 
563
 
 
564
 
void MacroAssembler::LoadFromSafepointRegisterSlot(Register dst, Register src) {
565
 
  ldr(dst, SafepointRegisterSlot(src));
566
 
}
567
 
 
568
 
 
569
 
int MacroAssembler::SafepointRegisterStackIndex(int reg_code) {
570
 
  // The registers are pushed starting with the highest encoding,
571
 
  // which means that lowest encodings are closest to the stack pointer.
572
 
  ASSERT(reg_code >= 0 && reg_code < kNumSafepointRegisters);
573
 
  return reg_code;
574
 
}
575
 
 
576
 
 
577
 
MemOperand MacroAssembler::SafepointRegisterSlot(Register reg) {
578
 
  return MemOperand(sp, SafepointRegisterStackIndex(reg.code()) * kPointerSize);
579
 
}
580
 
 
581
 
 
582
 
MemOperand MacroAssembler::SafepointRegistersAndDoublesSlot(Register reg) {
583
 
  // General purpose registers are pushed last on the stack.
584
 
  int doubles_size = DwVfpRegister::kNumAllocatableRegisters * kDoubleSize;
585
 
  int register_offset = SafepointRegisterStackIndex(reg.code()) * kPointerSize;
586
 
  return MemOperand(sp, doubles_size + register_offset);
587
 
}
588
 
 
589
 
 
590
 
void MacroAssembler::Ldrd(Register dst1, Register dst2,
591
 
                          const MemOperand& src, Condition cond) {
592
 
  ASSERT(src.rm().is(no_reg));
593
 
  ASSERT(!dst1.is(lr));  // r14.
594
 
  ASSERT_EQ(0, dst1.code() % 2);
595
 
  ASSERT_EQ(dst1.code() + 1, dst2.code());
596
 
 
597
 
  // V8 does not use this addressing mode, so the fallback code
598
 
  // below doesn't support it yet.
599
 
  ASSERT((src.am() != PreIndex) && (src.am() != NegPreIndex));
600
 
 
601
 
  // Generate two ldr instructions if ldrd is not available.
602
 
  if (CpuFeatures::IsSupported(ARMv7)) {
603
 
    CpuFeatures::Scope scope(ARMv7);
604
 
    ldrd(dst1, dst2, src, cond);
605
 
  } else {
606
 
    if ((src.am() == Offset) || (src.am() == NegOffset)) {
607
 
      MemOperand src2(src);
608
 
      src2.set_offset(src2.offset() + 4);
609
 
      if (dst1.is(src.rn())) {
610
 
        ldr(dst2, src2, cond);
611
 
        ldr(dst1, src, cond);
612
 
      } else {
613
 
        ldr(dst1, src, cond);
614
 
        ldr(dst2, src2, cond);
615
 
      }
616
 
    } else {  // PostIndex or NegPostIndex.
617
 
      ASSERT((src.am() == PostIndex) || (src.am() == NegPostIndex));
618
 
      if (dst1.is(src.rn())) {
619
 
        ldr(dst2, MemOperand(src.rn(), 4, Offset), cond);
620
 
        ldr(dst1, src, cond);
621
 
      } else {
622
 
        MemOperand src2(src);
623
 
        src2.set_offset(src2.offset() - 4);
624
 
        ldr(dst1, MemOperand(src.rn(), 4, PostIndex), cond);
625
 
        ldr(dst2, src2, cond);
626
 
      }
627
 
    }
628
 
  }
629
 
}
630
 
 
631
 
 
632
 
void MacroAssembler::Strd(Register src1, Register src2,
633
 
                          const MemOperand& dst, Condition cond) {
634
 
  ASSERT(dst.rm().is(no_reg));
635
 
  ASSERT(!src1.is(lr));  // r14.
636
 
  ASSERT_EQ(0, src1.code() % 2);
637
 
  ASSERT_EQ(src1.code() + 1, src2.code());
638
 
 
639
 
  // V8 does not use this addressing mode, so the fallback code
640
 
  // below doesn't support it yet.
641
 
  ASSERT((dst.am() != PreIndex) && (dst.am() != NegPreIndex));
642
 
 
643
 
  // Generate two str instructions if strd is not available.
644
 
  if (CpuFeatures::IsSupported(ARMv7)) {
645
 
    CpuFeatures::Scope scope(ARMv7);
646
 
    strd(src1, src2, dst, cond);
647
 
  } else {
648
 
    MemOperand dst2(dst);
649
 
    if ((dst.am() == Offset) || (dst.am() == NegOffset)) {
650
 
      dst2.set_offset(dst2.offset() + 4);
651
 
      str(src1, dst, cond);
652
 
      str(src2, dst2, cond);
653
 
    } else {  // PostIndex or NegPostIndex.
654
 
      ASSERT((dst.am() == PostIndex) || (dst.am() == NegPostIndex));
655
 
      dst2.set_offset(dst2.offset() - 4);
656
 
      str(src1, MemOperand(dst.rn(), 4, PostIndex), cond);
657
 
      str(src2, dst2, cond);
658
 
    }
659
 
  }
660
 
}
661
 
 
662
 
 
663
 
void MacroAssembler::ClearFPSCRBits(const uint32_t bits_to_clear,
664
 
                                    const Register scratch,
665
 
                                    const Condition cond) {
666
 
  vmrs(scratch, cond);
667
 
  bic(scratch, scratch, Operand(bits_to_clear), LeaveCC, cond);
668
 
  vmsr(scratch, cond);
669
 
}
670
 
 
671
 
 
672
 
void MacroAssembler::VFPCompareAndSetFlags(const DwVfpRegister src1,
673
 
                                           const DwVfpRegister src2,
674
 
                                           const Condition cond) {
675
 
  // Compare and move FPSCR flags to the normal condition flags.
676
 
  VFPCompareAndLoadFlags(src1, src2, pc, cond);
677
 
}
678
 
 
679
 
void MacroAssembler::VFPCompareAndSetFlags(const DwVfpRegister src1,
680
 
                                           const double src2,
681
 
                                           const Condition cond) {
682
 
  // Compare and move FPSCR flags to the normal condition flags.
683
 
  VFPCompareAndLoadFlags(src1, src2, pc, cond);
684
 
}
685
 
 
686
 
 
687
 
void MacroAssembler::VFPCompareAndLoadFlags(const DwVfpRegister src1,
688
 
                                            const DwVfpRegister src2,
689
 
                                            const Register fpscr_flags,
690
 
                                            const Condition cond) {
691
 
  // Compare and load FPSCR.
692
 
  vcmp(src1, src2, cond);
693
 
  vmrs(fpscr_flags, cond);
694
 
}
695
 
 
696
 
void MacroAssembler::VFPCompareAndLoadFlags(const DwVfpRegister src1,
697
 
                                            const double src2,
698
 
                                            const Register fpscr_flags,
699
 
                                            const Condition cond) {
700
 
  // Compare and load FPSCR.
701
 
  vcmp(src1, src2, cond);
702
 
  vmrs(fpscr_flags, cond);
703
 
}
704
 
 
705
 
void MacroAssembler::Vmov(const DwVfpRegister dst,
706
 
                          const double imm,
707
 
                          const Condition cond) {
708
 
  ASSERT(CpuFeatures::IsEnabled(VFP3));
709
 
  static const DoubleRepresentation minus_zero(-0.0);
710
 
  static const DoubleRepresentation zero(0.0);
711
 
  DoubleRepresentation value(imm);
712
 
  // Handle special values first.
713
 
  if (value.bits == zero.bits) {
714
 
    vmov(dst, kDoubleRegZero, cond);
715
 
  } else if (value.bits == minus_zero.bits) {
716
 
    vneg(dst, kDoubleRegZero, cond);
717
 
  } else {
718
 
    vmov(dst, imm, cond);
719
 
  }
720
 
}
721
 
 
722
 
 
723
 
void MacroAssembler::EnterFrame(StackFrame::Type type) {
724
 
  // r0-r3: preserved
725
 
  stm(db_w, sp, cp.bit() | fp.bit() | lr.bit());
726
 
  mov(ip, Operand(Smi::FromInt(type)));
727
 
  push(ip);
728
 
  mov(ip, Operand(CodeObject()));
729
 
  push(ip);
730
 
  add(fp, sp, Operand(3 * kPointerSize));  // Adjust FP to point to saved FP.
731
 
}
732
 
 
733
 
 
734
 
void MacroAssembler::LeaveFrame(StackFrame::Type type) {
735
 
  // r0: preserved
736
 
  // r1: preserved
737
 
  // r2: preserved
738
 
 
739
 
  // Drop the execution stack down to the frame pointer and restore
740
 
  // the caller frame pointer and return address.
741
 
  mov(sp, fp);
742
 
  ldm(ia_w, sp, fp.bit() | lr.bit());
743
 
}
744
 
 
745
 
 
746
 
void MacroAssembler::EnterExitFrame(bool save_doubles, int stack_space) {
747
 
  // Setup the frame structure on the stack.
748
 
  ASSERT_EQ(2 * kPointerSize, ExitFrameConstants::kCallerSPDisplacement);
749
 
  ASSERT_EQ(1 * kPointerSize, ExitFrameConstants::kCallerPCOffset);
750
 
  ASSERT_EQ(0 * kPointerSize, ExitFrameConstants::kCallerFPOffset);
751
 
  Push(lr, fp);
752
 
  mov(fp, Operand(sp));  // Setup new frame pointer.
753
 
  // Reserve room for saved entry sp and code object.
754
 
  sub(sp, sp, Operand(2 * kPointerSize));
755
 
  if (emit_debug_code()) {
756
 
    mov(ip, Operand(0));
757
 
    str(ip, MemOperand(fp, ExitFrameConstants::kSPOffset));
758
 
  }
759
 
  mov(ip, Operand(CodeObject()));
760
 
  str(ip, MemOperand(fp, ExitFrameConstants::kCodeOffset));
761
 
 
762
 
  // Save the frame pointer and the context in top.
763
 
  mov(ip, Operand(ExternalReference(Isolate::kCEntryFPAddress, isolate())));
764
 
  str(fp, MemOperand(ip));
765
 
  mov(ip, Operand(ExternalReference(Isolate::kContextAddress, isolate())));
766
 
  str(cp, MemOperand(ip));
767
 
 
768
 
  // Optionally save all double registers.
769
 
  if (save_doubles) {
770
 
    DwVfpRegister first = d0;
771
 
    DwVfpRegister last =
772
 
        DwVfpRegister::from_code(DwVfpRegister::kNumRegisters - 1);
773
 
    vstm(db_w, sp, first, last);
774
 
    // Note that d0 will be accessible at
775
 
    //   fp - 2 * kPointerSize - DwVfpRegister::kNumRegisters * kDoubleSize,
776
 
    // since the sp slot and code slot were pushed after the fp.
777
 
  }
778
 
 
779
 
  // Reserve place for the return address and stack space and align the frame
780
 
  // preparing for calling the runtime function.
781
 
  const int frame_alignment = MacroAssembler::ActivationFrameAlignment();
782
 
  sub(sp, sp, Operand((stack_space + 1) * kPointerSize));
783
 
  if (frame_alignment > 0) {
784
 
    ASSERT(IsPowerOf2(frame_alignment));
785
 
    and_(sp, sp, Operand(-frame_alignment));
786
 
  }
787
 
 
788
 
  // Set the exit frame sp value to point just before the return address
789
 
  // location.
790
 
  add(ip, sp, Operand(kPointerSize));
791
 
  str(ip, MemOperand(fp, ExitFrameConstants::kSPOffset));
792
 
}
793
 
 
794
 
 
795
 
void MacroAssembler::InitializeNewString(Register string,
796
 
                                         Register length,
797
 
                                         Heap::RootListIndex map_index,
798
 
                                         Register scratch1,
799
 
                                         Register scratch2) {
800
 
  mov(scratch1, Operand(length, LSL, kSmiTagSize));
801
 
  LoadRoot(scratch2, map_index);
802
 
  str(scratch1, FieldMemOperand(string, String::kLengthOffset));
803
 
  mov(scratch1, Operand(String::kEmptyHashField));
804
 
  str(scratch2, FieldMemOperand(string, HeapObject::kMapOffset));
805
 
  str(scratch1, FieldMemOperand(string, String::kHashFieldOffset));
806
 
}
807
 
 
808
 
 
809
 
int MacroAssembler::ActivationFrameAlignment() {
810
 
#if defined(V8_HOST_ARCH_ARM)
811
 
  // Running on the real platform. Use the alignment as mandated by the local
812
 
  // environment.
813
 
  // Note: This will break if we ever start generating snapshots on one ARM
814
 
  // platform for another ARM platform with a different alignment.
815
 
  return OS::ActivationFrameAlignment();
816
 
#else  // defined(V8_HOST_ARCH_ARM)
817
 
  // If we are using the simulator then we should always align to the expected
818
 
  // alignment. As the simulator is used to generate snapshots we do not know
819
 
  // if the target platform will need alignment, so this is controlled from a
820
 
  // flag.
821
 
  return FLAG_sim_stack_alignment;
822
 
#endif  // defined(V8_HOST_ARCH_ARM)
823
 
}
824
 
 
825
 
 
826
 
void MacroAssembler::LeaveExitFrame(bool save_doubles,
827
 
                                    Register argument_count) {
828
 
  // Optionally restore all double registers.
829
 
  if (save_doubles) {
830
 
    // Calculate the stack location of the saved doubles and restore them.
831
 
    const int offset = 2 * kPointerSize;
832
 
    sub(r3, fp, Operand(offset + DwVfpRegister::kNumRegisters * kDoubleSize));
833
 
    DwVfpRegister first = d0;
834
 
    DwVfpRegister last =
835
 
        DwVfpRegister::from_code(DwVfpRegister::kNumRegisters - 1);
836
 
    vldm(ia, r3, first, last);
837
 
  }
838
 
 
839
 
  // Clear top frame.
840
 
  mov(r3, Operand(0, RelocInfo::NONE));
841
 
  mov(ip, Operand(ExternalReference(Isolate::kCEntryFPAddress, isolate())));
842
 
  str(r3, MemOperand(ip));
843
 
 
844
 
  // Restore current context from top and clear it in debug mode.
845
 
  mov(ip, Operand(ExternalReference(Isolate::kContextAddress, isolate())));
846
 
  ldr(cp, MemOperand(ip));
847
 
#ifdef DEBUG
848
 
  str(r3, MemOperand(ip));
849
 
#endif
850
 
 
851
 
  // Tear down the exit frame, pop the arguments, and return.
852
 
  mov(sp, Operand(fp));
853
 
  ldm(ia_w, sp, fp.bit() | lr.bit());
854
 
  if (argument_count.is_valid()) {
855
 
    add(sp, sp, Operand(argument_count, LSL, kPointerSizeLog2));
856
 
  }
857
 
}
858
 
 
859
 
void MacroAssembler::GetCFunctionDoubleResult(const DoubleRegister dst) {
860
 
  if (use_eabi_hardfloat()) {
861
 
    Move(dst, d0);
862
 
  } else {
863
 
    vmov(dst, r0, r1);
864
 
  }
865
 
}
866
 
 
867
 
 
868
 
void MacroAssembler::SetCallKind(Register dst, CallKind call_kind) {
869
 
  // This macro takes the dst register to make the code more readable
870
 
  // at the call sites. However, the dst register has to be r5 to
871
 
  // follow the calling convention which requires the call type to be
872
 
  // in r5.
873
 
  ASSERT(dst.is(r5));
874
 
  if (call_kind == CALL_AS_FUNCTION) {
875
 
    mov(dst, Operand(Smi::FromInt(1)));
876
 
  } else {
877
 
    mov(dst, Operand(Smi::FromInt(0)));
878
 
  }
879
 
}
880
 
 
881
 
 
882
 
void MacroAssembler::InvokePrologue(const ParameterCount& expected,
883
 
                                    const ParameterCount& actual,
884
 
                                    Handle<Code> code_constant,
885
 
                                    Register code_reg,
886
 
                                    Label* done,
887
 
                                    InvokeFlag flag,
888
 
                                    const CallWrapper& call_wrapper,
889
 
                                    CallKind call_kind) {
890
 
  bool definitely_matches = false;
891
 
  Label regular_invoke;
892
 
 
893
 
  // Check whether the expected and actual arguments count match. If not,
894
 
  // setup registers according to contract with ArgumentsAdaptorTrampoline:
895
 
  //  r0: actual arguments count
896
 
  //  r1: function (passed through to callee)
897
 
  //  r2: expected arguments count
898
 
  //  r3: callee code entry
899
 
 
900
 
  // The code below is made a lot easier because the calling code already sets
901
 
  // up actual and expected registers according to the contract if values are
902
 
  // passed in registers.
903
 
  ASSERT(actual.is_immediate() || actual.reg().is(r0));
904
 
  ASSERT(expected.is_immediate() || expected.reg().is(r2));
905
 
  ASSERT((!code_constant.is_null() && code_reg.is(no_reg)) || code_reg.is(r3));
906
 
 
907
 
  if (expected.is_immediate()) {
908
 
    ASSERT(actual.is_immediate());
909
 
    if (expected.immediate() == actual.immediate()) {
910
 
      definitely_matches = true;
911
 
    } else {
912
 
      mov(r0, Operand(actual.immediate()));
913
 
      const int sentinel = SharedFunctionInfo::kDontAdaptArgumentsSentinel;
914
 
      if (expected.immediate() == sentinel) {
915
 
        // Don't worry about adapting arguments for builtins that
916
 
        // don't want that done. Skip adaption code by making it look
917
 
        // like we have a match between expected and actual number of
918
 
        // arguments.
919
 
        definitely_matches = true;
920
 
      } else {
921
 
        mov(r2, Operand(expected.immediate()));
922
 
      }
923
 
    }
924
 
  } else {
925
 
    if (actual.is_immediate()) {
926
 
      cmp(expected.reg(), Operand(actual.immediate()));
927
 
      b(eq, &regular_invoke);
928
 
      mov(r0, Operand(actual.immediate()));
929
 
    } else {
930
 
      cmp(expected.reg(), Operand(actual.reg()));
931
 
      b(eq, &regular_invoke);
932
 
    }
933
 
  }
934
 
 
935
 
  if (!definitely_matches) {
936
 
    if (!code_constant.is_null()) {
937
 
      mov(r3, Operand(code_constant));
938
 
      add(r3, r3, Operand(Code::kHeaderSize - kHeapObjectTag));
939
 
    }
940
 
 
941
 
    Handle<Code> adaptor =
942
 
        isolate()->builtins()->ArgumentsAdaptorTrampoline();
943
 
    if (flag == CALL_FUNCTION) {
944
 
      call_wrapper.BeforeCall(CallSize(adaptor));
945
 
      SetCallKind(r5, call_kind);
946
 
      Call(adaptor);
947
 
      call_wrapper.AfterCall();
948
 
      b(done);
949
 
    } else {
950
 
      SetCallKind(r5, call_kind);
951
 
      Jump(adaptor, RelocInfo::CODE_TARGET);
952
 
    }
953
 
    bind(&regular_invoke);
954
 
  }
955
 
}
956
 
 
957
 
 
958
 
void MacroAssembler::InvokeCode(Register code,
959
 
                                const ParameterCount& expected,
960
 
                                const ParameterCount& actual,
961
 
                                InvokeFlag flag,
962
 
                                const CallWrapper& call_wrapper,
963
 
                                CallKind call_kind) {
964
 
  Label done;
965
 
 
966
 
  InvokePrologue(expected, actual, Handle<Code>::null(), code, &done, flag,
967
 
                 call_wrapper, call_kind);
968
 
  if (flag == CALL_FUNCTION) {
969
 
    call_wrapper.BeforeCall(CallSize(code));
970
 
    SetCallKind(r5, call_kind);
971
 
    Call(code);
972
 
    call_wrapper.AfterCall();
973
 
  } else {
974
 
    ASSERT(flag == JUMP_FUNCTION);
975
 
    SetCallKind(r5, call_kind);
976
 
    Jump(code);
977
 
  }
978
 
 
979
 
  // Continue here if InvokePrologue does handle the invocation due to
980
 
  // mismatched parameter counts.
981
 
  bind(&done);
982
 
}
983
 
 
984
 
 
985
 
void MacroAssembler::InvokeCode(Handle<Code> code,
986
 
                                const ParameterCount& expected,
987
 
                                const ParameterCount& actual,
988
 
                                RelocInfo::Mode rmode,
989
 
                                InvokeFlag flag,
990
 
                                CallKind call_kind) {
991
 
  Label done;
992
 
 
993
 
  InvokePrologue(expected, actual, code, no_reg, &done, flag,
994
 
                 NullCallWrapper(), call_kind);
995
 
  if (flag == CALL_FUNCTION) {
996
 
    SetCallKind(r5, call_kind);
997
 
    Call(code, rmode);
998
 
  } else {
999
 
    SetCallKind(r5, call_kind);
1000
 
    Jump(code, rmode);
1001
 
  }
1002
 
 
1003
 
  // Continue here if InvokePrologue does handle the invocation due to
1004
 
  // mismatched parameter counts.
1005
 
  bind(&done);
1006
 
}
1007
 
 
1008
 
 
1009
 
void MacroAssembler::InvokeFunction(Register fun,
1010
 
                                    const ParameterCount& actual,
1011
 
                                    InvokeFlag flag,
1012
 
                                    const CallWrapper& call_wrapper,
1013
 
                                    CallKind call_kind) {
1014
 
  // Contract with called JS functions requires that function is passed in r1.
1015
 
  ASSERT(fun.is(r1));
1016
 
 
1017
 
  Register expected_reg = r2;
1018
 
  Register code_reg = r3;
1019
 
 
1020
 
  ldr(code_reg, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset));
1021
 
  ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset));
1022
 
  ldr(expected_reg,
1023
 
      FieldMemOperand(code_reg,
1024
 
                      SharedFunctionInfo::kFormalParameterCountOffset));
1025
 
  mov(expected_reg, Operand(expected_reg, ASR, kSmiTagSize));
1026
 
  ldr(code_reg,
1027
 
      FieldMemOperand(r1, JSFunction::kCodeEntryOffset));
1028
 
 
1029
 
  ParameterCount expected(expected_reg);
1030
 
  InvokeCode(code_reg, expected, actual, flag, call_wrapper, call_kind);
1031
 
}
1032
 
 
1033
 
 
1034
 
void MacroAssembler::InvokeFunction(JSFunction* function,
1035
 
                                    const ParameterCount& actual,
1036
 
                                    InvokeFlag flag,
1037
 
                                    CallKind call_kind) {
1038
 
  ASSERT(function->is_compiled());
1039
 
 
1040
 
  // Get the function and setup the context.
1041
 
  mov(r1, Operand(Handle<JSFunction>(function)));
1042
 
  ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset));
1043
 
 
1044
 
  // Invoke the cached code.
1045
 
  Handle<Code> code(function->code());
1046
 
  ParameterCount expected(function->shared()->formal_parameter_count());
1047
 
  if (V8::UseCrankshaft()) {
1048
 
    // TODO(kasperl): For now, we always call indirectly through the
1049
 
    // code field in the function to allow recompilation to take effect
1050
 
    // without changing any of the call sites.
1051
 
    ldr(r3, FieldMemOperand(r1, JSFunction::kCodeEntryOffset));
1052
 
    InvokeCode(r3, expected, actual, flag, NullCallWrapper(), call_kind);
1053
 
  } else {
1054
 
    InvokeCode(code, expected, actual, RelocInfo::CODE_TARGET, flag, call_kind);
1055
 
  }
1056
 
}
1057
 
 
1058
 
 
1059
 
void MacroAssembler::IsObjectJSObjectType(Register heap_object,
1060
 
                                          Register map,
1061
 
                                          Register scratch,
1062
 
                                          Label* fail) {
1063
 
  ldr(map, FieldMemOperand(heap_object, HeapObject::kMapOffset));
1064
 
  IsInstanceJSObjectType(map, scratch, fail);
1065
 
}
1066
 
 
1067
 
 
1068
 
void MacroAssembler::IsInstanceJSObjectType(Register map,
1069
 
                                            Register scratch,
1070
 
                                            Label* fail) {
1071
 
  ldrb(scratch, FieldMemOperand(map, Map::kInstanceTypeOffset));
1072
 
  cmp(scratch, Operand(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE));
1073
 
  b(lt, fail);
1074
 
  cmp(scratch, Operand(LAST_NONCALLABLE_SPEC_OBJECT_TYPE));
1075
 
  b(gt, fail);
1076
 
}
1077
 
 
1078
 
 
1079
 
void MacroAssembler::IsObjectJSStringType(Register object,
1080
 
                                          Register scratch,
1081
 
                                          Label* fail) {
1082
 
  ASSERT(kNotStringTag != 0);
1083
 
 
1084
 
  ldr(scratch, FieldMemOperand(object, HeapObject::kMapOffset));
1085
 
  ldrb(scratch, FieldMemOperand(scratch, Map::kInstanceTypeOffset));
1086
 
  tst(scratch, Operand(kIsNotStringMask));
1087
 
  b(ne, fail);
1088
 
}
1089
 
 
1090
 
 
1091
 
#ifdef ENABLE_DEBUGGER_SUPPORT
1092
 
void MacroAssembler::DebugBreak() {
1093
 
  ASSERT(allow_stub_calls());
1094
 
  mov(r0, Operand(0, RelocInfo::NONE));
1095
 
  mov(r1, Operand(ExternalReference(Runtime::kDebugBreak, isolate())));
1096
 
  CEntryStub ces(1);
1097
 
  Call(ces.GetCode(), RelocInfo::DEBUG_BREAK);
1098
 
}
1099
 
#endif
1100
 
 
1101
 
 
1102
 
void MacroAssembler::PushTryHandler(CodeLocation try_location,
1103
 
                                    HandlerType type) {
1104
 
  // Adjust this code if not the case.
1105
 
  STATIC_ASSERT(StackHandlerConstants::kSize == 5 * kPointerSize);
1106
 
  STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0 * kPointerSize);
1107
 
  STATIC_ASSERT(StackHandlerConstants::kStateOffset == 1 * kPointerSize);
1108
 
  STATIC_ASSERT(StackHandlerConstants::kContextOffset == 2 * kPointerSize);
1109
 
  STATIC_ASSERT(StackHandlerConstants::kFPOffset == 3 * kPointerSize);
1110
 
  STATIC_ASSERT(StackHandlerConstants::kPCOffset == 4 * kPointerSize);
1111
 
 
1112
 
  // The pc (return address) is passed in register lr.
1113
 
  if (try_location == IN_JAVASCRIPT) {
1114
 
    if (type == TRY_CATCH_HANDLER) {
1115
 
      mov(r3, Operand(StackHandler::TRY_CATCH));
1116
 
    } else {
1117
 
      mov(r3, Operand(StackHandler::TRY_FINALLY));
1118
 
    }
1119
 
    stm(db_w, sp, r3.bit() | cp.bit() | fp.bit() | lr.bit());
1120
 
    // Save the current handler as the next handler.
1121
 
    mov(r3, Operand(ExternalReference(Isolate::kHandlerAddress, isolate())));
1122
 
    ldr(r1, MemOperand(r3));
1123
 
    push(r1);
1124
 
    // Link this handler as the new current one.
1125
 
    str(sp, MemOperand(r3));
1126
 
  } else {
1127
 
    // Must preserve r0-r4, r5-r7 are available.
1128
 
    ASSERT(try_location == IN_JS_ENTRY);
1129
 
    // The frame pointer does not point to a JS frame so we save NULL
1130
 
    // for fp. We expect the code throwing an exception to check fp
1131
 
    // before dereferencing it to restore the context.
1132
 
    mov(r5, Operand(StackHandler::ENTRY));  // State.
1133
 
    mov(r6, Operand(Smi::FromInt(0)));  // Indicates no context.
1134
 
    mov(r7, Operand(0, RelocInfo::NONE));  // NULL frame pointer.
1135
 
    stm(db_w, sp, r5.bit() | r6.bit() | r7.bit() | lr.bit());
1136
 
    // Save the current handler as the next handler.
1137
 
    mov(r7, Operand(ExternalReference(Isolate::kHandlerAddress, isolate())));
1138
 
    ldr(r6, MemOperand(r7));
1139
 
    push(r6);
1140
 
    // Link this handler as the new current one.
1141
 
    str(sp, MemOperand(r7));
1142
 
  }
1143
 
}
1144
 
 
1145
 
 
1146
 
void MacroAssembler::PopTryHandler() {
1147
 
  STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0);
1148
 
  pop(r1);
1149
 
  mov(ip, Operand(ExternalReference(Isolate::kHandlerAddress, isolate())));
1150
 
  add(sp, sp, Operand(StackHandlerConstants::kSize - kPointerSize));
1151
 
  str(r1, MemOperand(ip));
1152
 
}
1153
 
 
1154
 
 
1155
 
void MacroAssembler::Throw(Register value) {
1156
 
  // Adjust this code if not the case.
1157
 
  STATIC_ASSERT(StackHandlerConstants::kSize == 5 * kPointerSize);
1158
 
  STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0 * kPointerSize);
1159
 
  STATIC_ASSERT(StackHandlerConstants::kStateOffset == 1 * kPointerSize);
1160
 
  STATIC_ASSERT(StackHandlerConstants::kContextOffset == 2 * kPointerSize);
1161
 
  STATIC_ASSERT(StackHandlerConstants::kFPOffset == 3 * kPointerSize);
1162
 
  STATIC_ASSERT(StackHandlerConstants::kPCOffset == 4 * kPointerSize);
1163
 
  // r0 is expected to hold the exception.
1164
 
  if (!value.is(r0)) {
1165
 
    mov(r0, value);
1166
 
  }
1167
 
 
1168
 
  // Drop the sp to the top of the handler.
1169
 
  mov(r3, Operand(ExternalReference(Isolate::kHandlerAddress, isolate())));
1170
 
  ldr(sp, MemOperand(r3));
1171
 
 
1172
 
  // Restore the next handler.
1173
 
  pop(r2);
1174
 
  str(r2, MemOperand(r3));
1175
 
 
1176
 
  // Restore context and frame pointer, discard state (r3).
1177
 
  ldm(ia_w, sp, r3.bit() | cp.bit() | fp.bit());
1178
 
 
1179
 
  // If the handler is a JS frame, restore the context to the frame.
1180
 
  // (r3 == ENTRY) == (fp == 0) == (cp == 0), so we could test any
1181
 
  // of them.
1182
 
  cmp(r3, Operand(StackHandler::ENTRY));
1183
 
  str(cp, MemOperand(fp, StandardFrameConstants::kContextOffset), ne);
1184
 
 
1185
 
#ifdef DEBUG
1186
 
  if (emit_debug_code()) {
1187
 
    mov(lr, Operand(pc));
1188
 
  }
1189
 
#endif
1190
 
  pop(pc);
1191
 
}
1192
 
 
1193
 
 
1194
 
void MacroAssembler::ThrowUncatchable(UncatchableExceptionType type,
1195
 
                                      Register value) {
1196
 
  // Adjust this code if not the case.
1197
 
  STATIC_ASSERT(StackHandlerConstants::kSize == 5 * kPointerSize);
1198
 
  STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0 * kPointerSize);
1199
 
  STATIC_ASSERT(StackHandlerConstants::kStateOffset == 1 * kPointerSize);
1200
 
  STATIC_ASSERT(StackHandlerConstants::kContextOffset == 2 * kPointerSize);
1201
 
  STATIC_ASSERT(StackHandlerConstants::kFPOffset == 3 * kPointerSize);
1202
 
  STATIC_ASSERT(StackHandlerConstants::kPCOffset == 4 * kPointerSize);
1203
 
  // r0 is expected to hold the exception.
1204
 
  if (!value.is(r0)) {
1205
 
    mov(r0, value);
1206
 
  }
1207
 
 
1208
 
  // Drop sp to the top stack handler.
1209
 
  mov(r3, Operand(ExternalReference(Isolate::kHandlerAddress, isolate())));
1210
 
  ldr(sp, MemOperand(r3));
1211
 
 
1212
 
  // Unwind the handlers until the ENTRY handler is found.
1213
 
  Label loop, done;
1214
 
  bind(&loop);
1215
 
  // Load the type of the current stack handler.
1216
 
  const int kStateOffset = StackHandlerConstants::kStateOffset;
1217
 
  ldr(r2, MemOperand(sp, kStateOffset));
1218
 
  cmp(r2, Operand(StackHandler::ENTRY));
1219
 
  b(eq, &done);
1220
 
  // Fetch the next handler in the list.
1221
 
  const int kNextOffset = StackHandlerConstants::kNextOffset;
1222
 
  ldr(sp, MemOperand(sp, kNextOffset));
1223
 
  jmp(&loop);
1224
 
  bind(&done);
1225
 
 
1226
 
  // Set the top handler address to next handler past the current ENTRY handler.
1227
 
  pop(r2);
1228
 
  str(r2, MemOperand(r3));
1229
 
 
1230
 
  if (type == OUT_OF_MEMORY) {
1231
 
    // Set external caught exception to false.
1232
 
    ExternalReference external_caught(
1233
 
        Isolate::kExternalCaughtExceptionAddress, isolate());
1234
 
    mov(r0, Operand(false, RelocInfo::NONE));
1235
 
    mov(r2, Operand(external_caught));
1236
 
    str(r0, MemOperand(r2));
1237
 
 
1238
 
    // Set pending exception and r0 to out of memory exception.
1239
 
    Failure* out_of_memory = Failure::OutOfMemoryException();
1240
 
    mov(r0, Operand(reinterpret_cast<int32_t>(out_of_memory)));
1241
 
    mov(r2, Operand(ExternalReference(Isolate::kPendingExceptionAddress,
1242
 
                                      isolate())));
1243
 
    str(r0, MemOperand(r2));
1244
 
  }
1245
 
 
1246
 
  // Stack layout at this point. See also StackHandlerConstants.
1247
 
  // sp ->   state (ENTRY)
1248
 
  //         cp
1249
 
  //         fp
1250
 
  //         lr
1251
 
 
1252
 
  // Restore context and frame pointer, discard state (r2).
1253
 
  ldm(ia_w, sp, r2.bit() | cp.bit() | fp.bit());
1254
 
#ifdef DEBUG
1255
 
  if (emit_debug_code()) {
1256
 
    mov(lr, Operand(pc));
1257
 
  }
1258
 
#endif
1259
 
  pop(pc);
1260
 
}
1261
 
 
1262
 
 
1263
 
void MacroAssembler::CheckAccessGlobalProxy(Register holder_reg,
1264
 
                                            Register scratch,
1265
 
                                            Label* miss) {
1266
 
  Label same_contexts;
1267
 
 
1268
 
  ASSERT(!holder_reg.is(scratch));
1269
 
  ASSERT(!holder_reg.is(ip));
1270
 
  ASSERT(!scratch.is(ip));
1271
 
 
1272
 
  // Load current lexical context from the stack frame.
1273
 
  ldr(scratch, MemOperand(fp, StandardFrameConstants::kContextOffset));
1274
 
  // In debug mode, make sure the lexical context is set.
1275
 
#ifdef DEBUG
1276
 
  cmp(scratch, Operand(0, RelocInfo::NONE));
1277
 
  Check(ne, "we should not have an empty lexical context");
1278
 
#endif
1279
 
 
1280
 
  // Load the global context of the current context.
1281
 
  int offset = Context::kHeaderSize + Context::GLOBAL_INDEX * kPointerSize;
1282
 
  ldr(scratch, FieldMemOperand(scratch, offset));
1283
 
  ldr(scratch, FieldMemOperand(scratch, GlobalObject::kGlobalContextOffset));
1284
 
 
1285
 
  // Check the context is a global context.
1286
 
  if (emit_debug_code()) {
1287
 
    // TODO(119): avoid push(holder_reg)/pop(holder_reg)
1288
 
    // Cannot use ip as a temporary in this verification code. Due to the fact
1289
 
    // that ip is clobbered as part of cmp with an object Operand.
1290
 
    push(holder_reg);  // Temporarily save holder on the stack.
1291
 
    // Read the first word and compare to the global_context_map.
1292
 
    ldr(holder_reg, FieldMemOperand(scratch, HeapObject::kMapOffset));
1293
 
    LoadRoot(ip, Heap::kGlobalContextMapRootIndex);
1294
 
    cmp(holder_reg, ip);
1295
 
    Check(eq, "JSGlobalObject::global_context should be a global context.");
1296
 
    pop(holder_reg);  // Restore holder.
1297
 
  }
1298
 
 
1299
 
  // Check if both contexts are the same.
1300
 
  ldr(ip, FieldMemOperand(holder_reg, JSGlobalProxy::kContextOffset));
1301
 
  cmp(scratch, Operand(ip));
1302
 
  b(eq, &same_contexts);
1303
 
 
1304
 
  // Check the context is a global context.
1305
 
  if (emit_debug_code()) {
1306
 
    // TODO(119): avoid push(holder_reg)/pop(holder_reg)
1307
 
    // Cannot use ip as a temporary in this verification code. Due to the fact
1308
 
    // that ip is clobbered as part of cmp with an object Operand.
1309
 
    push(holder_reg);  // Temporarily save holder on the stack.
1310
 
    mov(holder_reg, ip);  // Move ip to its holding place.
1311
 
    LoadRoot(ip, Heap::kNullValueRootIndex);
1312
 
    cmp(holder_reg, ip);
1313
 
    Check(ne, "JSGlobalProxy::context() should not be null.");
1314
 
 
1315
 
    ldr(holder_reg, FieldMemOperand(holder_reg, HeapObject::kMapOffset));
1316
 
    LoadRoot(ip, Heap::kGlobalContextMapRootIndex);
1317
 
    cmp(holder_reg, ip);
1318
 
    Check(eq, "JSGlobalObject::global_context should be a global context.");
1319
 
    // Restore ip is not needed. ip is reloaded below.
1320
 
    pop(holder_reg);  // Restore holder.
1321
 
    // Restore ip to holder's context.
1322
 
    ldr(ip, FieldMemOperand(holder_reg, JSGlobalProxy::kContextOffset));
1323
 
  }
1324
 
 
1325
 
  // Check that the security token in the calling global object is
1326
 
  // compatible with the security token in the receiving global
1327
 
  // object.
1328
 
  int token_offset = Context::kHeaderSize +
1329
 
                     Context::SECURITY_TOKEN_INDEX * kPointerSize;
1330
 
 
1331
 
  ldr(scratch, FieldMemOperand(scratch, token_offset));
1332
 
  ldr(ip, FieldMemOperand(ip, token_offset));
1333
 
  cmp(scratch, Operand(ip));
1334
 
  b(ne, miss);
1335
 
 
1336
 
  bind(&same_contexts);
1337
 
}
1338
 
 
1339
 
 
1340
 
void MacroAssembler::LoadFromNumberDictionary(Label* miss,
1341
 
                                              Register elements,
1342
 
                                              Register key,
1343
 
                                              Register result,
1344
 
                                              Register t0,
1345
 
                                              Register t1,
1346
 
                                              Register t2) {
1347
 
  // Register use:
1348
 
  //
1349
 
  // elements - holds the slow-case elements of the receiver on entry.
1350
 
  //            Unchanged unless 'result' is the same register.
1351
 
  //
1352
 
  // key      - holds the smi key on entry.
1353
 
  //            Unchanged unless 'result' is the same register.
1354
 
  //
1355
 
  // result   - holds the result on exit if the load succeeded.
1356
 
  //            Allowed to be the same as 'key' or 'result'.
1357
 
  //            Unchanged on bailout so 'key' or 'result' can be used
1358
 
  //            in further computation.
1359
 
  //
1360
 
  // Scratch registers:
1361
 
  //
1362
 
  // t0 - holds the untagged key on entry and holds the hash once computed.
1363
 
  //
1364
 
  // t1 - used to hold the capacity mask of the dictionary
1365
 
  //
1366
 
  // t2 - used for the index into the dictionary.
1367
 
  Label done;
1368
 
 
1369
 
  // Compute the hash code from the untagged key.  This must be kept in sync
1370
 
  // with ComputeIntegerHash in utils.h.
1371
 
  //
1372
 
  // hash = ~hash + (hash << 15);
1373
 
  mvn(t1, Operand(t0));
1374
 
  add(t0, t1, Operand(t0, LSL, 15));
1375
 
  // hash = hash ^ (hash >> 12);
1376
 
  eor(t0, t0, Operand(t0, LSR, 12));
1377
 
  // hash = hash + (hash << 2);
1378
 
  add(t0, t0, Operand(t0, LSL, 2));
1379
 
  // hash = hash ^ (hash >> 4);
1380
 
  eor(t0, t0, Operand(t0, LSR, 4));
1381
 
  // hash = hash * 2057;
1382
 
  mov(t1, Operand(2057));
1383
 
  mul(t0, t0, t1);
1384
 
  // hash = hash ^ (hash >> 16);
1385
 
  eor(t0, t0, Operand(t0, LSR, 16));
1386
 
 
1387
 
  // Compute the capacity mask.
1388
 
  ldr(t1, FieldMemOperand(elements, NumberDictionary::kCapacityOffset));
1389
 
  mov(t1, Operand(t1, ASR, kSmiTagSize));  // convert smi to int
1390
 
  sub(t1, t1, Operand(1));
1391
 
 
1392
 
  // Generate an unrolled loop that performs a few probes before giving up.
1393
 
  static const int kProbes = 4;
1394
 
  for (int i = 0; i < kProbes; i++) {
1395
 
    // Use t2 for index calculations and keep the hash intact in t0.
1396
 
    mov(t2, t0);
1397
 
    // Compute the masked index: (hash + i + i * i) & mask.
1398
 
    if (i > 0) {
1399
 
      add(t2, t2, Operand(NumberDictionary::GetProbeOffset(i)));
1400
 
    }
1401
 
    and_(t2, t2, Operand(t1));
1402
 
 
1403
 
    // Scale the index by multiplying by the element size.
1404
 
    ASSERT(NumberDictionary::kEntrySize == 3);
1405
 
    add(t2, t2, Operand(t2, LSL, 1));  // t2 = t2 * 3
1406
 
 
1407
 
    // Check if the key is identical to the name.
1408
 
    add(t2, elements, Operand(t2, LSL, kPointerSizeLog2));
1409
 
    ldr(ip, FieldMemOperand(t2, NumberDictionary::kElementsStartOffset));
1410
 
    cmp(key, Operand(ip));
1411
 
    if (i != kProbes - 1) {
1412
 
      b(eq, &done);
1413
 
    } else {
1414
 
      b(ne, miss);
1415
 
    }
1416
 
  }
1417
 
 
1418
 
  bind(&done);
1419
 
  // Check that the value is a normal property.
1420
 
  // t2: elements + (index * kPointerSize)
1421
 
  const int kDetailsOffset =
1422
 
      NumberDictionary::kElementsStartOffset + 2 * kPointerSize;
1423
 
  ldr(t1, FieldMemOperand(t2, kDetailsOffset));
1424
 
  tst(t1, Operand(Smi::FromInt(PropertyDetails::TypeField::kMask)));
1425
 
  b(ne, miss);
1426
 
 
1427
 
  // Get the value at the masked, scaled index and return.
1428
 
  const int kValueOffset =
1429
 
      NumberDictionary::kElementsStartOffset + kPointerSize;
1430
 
  ldr(result, FieldMemOperand(t2, kValueOffset));
1431
 
}
1432
 
 
1433
 
 
1434
 
void MacroAssembler::AllocateInNewSpace(int object_size,
1435
 
                                        Register result,
1436
 
                                        Register scratch1,
1437
 
                                        Register scratch2,
1438
 
                                        Label* gc_required,
1439
 
                                        AllocationFlags flags) {
1440
 
  if (!FLAG_inline_new) {
1441
 
    if (emit_debug_code()) {
1442
 
      // Trash the registers to simulate an allocation failure.
1443
 
      mov(result, Operand(0x7091));
1444
 
      mov(scratch1, Operand(0x7191));
1445
 
      mov(scratch2, Operand(0x7291));
1446
 
    }
1447
 
    jmp(gc_required);
1448
 
    return;
1449
 
  }
1450
 
 
1451
 
  ASSERT(!result.is(scratch1));
1452
 
  ASSERT(!result.is(scratch2));
1453
 
  ASSERT(!scratch1.is(scratch2));
1454
 
  ASSERT(!scratch1.is(ip));
1455
 
  ASSERT(!scratch2.is(ip));
1456
 
 
1457
 
  // Make object size into bytes.
1458
 
  if ((flags & SIZE_IN_WORDS) != 0) {
1459
 
    object_size *= kPointerSize;
1460
 
  }
1461
 
  ASSERT_EQ(0, object_size & kObjectAlignmentMask);
1462
 
 
1463
 
  // Check relative positions of allocation top and limit addresses.
1464
 
  // The values must be adjacent in memory to allow the use of LDM.
1465
 
  // Also, assert that the registers are numbered such that the values
1466
 
  // are loaded in the correct order.
1467
 
  ExternalReference new_space_allocation_top =
1468
 
      ExternalReference::new_space_allocation_top_address(isolate());
1469
 
  ExternalReference new_space_allocation_limit =
1470
 
      ExternalReference::new_space_allocation_limit_address(isolate());
1471
 
  intptr_t top   =
1472
 
      reinterpret_cast<intptr_t>(new_space_allocation_top.address());
1473
 
  intptr_t limit =
1474
 
      reinterpret_cast<intptr_t>(new_space_allocation_limit.address());
1475
 
  ASSERT((limit - top) == kPointerSize);
1476
 
  ASSERT(result.code() < ip.code());
1477
 
 
1478
 
  // Set up allocation top address and object size registers.
1479
 
  Register topaddr = scratch1;
1480
 
  Register obj_size_reg = scratch2;
1481
 
  mov(topaddr, Operand(new_space_allocation_top));
1482
 
  mov(obj_size_reg, Operand(object_size));
1483
 
 
1484
 
  // This code stores a temporary value in ip. This is OK, as the code below
1485
 
  // does not need ip for implicit literal generation.
1486
 
  if ((flags & RESULT_CONTAINS_TOP) == 0) {
1487
 
    // Load allocation top into result and allocation limit into ip.
1488
 
    ldm(ia, topaddr, result.bit() | ip.bit());
1489
 
  } else {
1490
 
    if (emit_debug_code()) {
1491
 
      // Assert that result actually contains top on entry. ip is used
1492
 
      // immediately below so this use of ip does not cause difference with
1493
 
      // respect to register content between debug and release mode.
1494
 
      ldr(ip, MemOperand(topaddr));
1495
 
      cmp(result, ip);
1496
 
      Check(eq, "Unexpected allocation top");
1497
 
    }
1498
 
    // Load allocation limit into ip. Result already contains allocation top.
1499
 
    ldr(ip, MemOperand(topaddr, limit - top));
1500
 
  }
1501
 
 
1502
 
  // Calculate new top and bail out if new space is exhausted. Use result
1503
 
  // to calculate the new top.
1504
 
  add(scratch2, result, Operand(obj_size_reg), SetCC);
1505
 
  b(cs, gc_required);
1506
 
  cmp(scratch2, Operand(ip));
1507
 
  b(hi, gc_required);
1508
 
  str(scratch2, MemOperand(topaddr));
1509
 
 
1510
 
  // Tag object if requested.
1511
 
  if ((flags & TAG_OBJECT) != 0) {
1512
 
    add(result, result, Operand(kHeapObjectTag));
1513
 
  }
1514
 
}
1515
 
 
1516
 
 
1517
 
void MacroAssembler::AllocateInNewSpace(Register object_size,
1518
 
                                        Register result,
1519
 
                                        Register scratch1,
1520
 
                                        Register scratch2,
1521
 
                                        Label* gc_required,
1522
 
                                        AllocationFlags flags) {
1523
 
  if (!FLAG_inline_new) {
1524
 
    if (emit_debug_code()) {
1525
 
      // Trash the registers to simulate an allocation failure.
1526
 
      mov(result, Operand(0x7091));
1527
 
      mov(scratch1, Operand(0x7191));
1528
 
      mov(scratch2, Operand(0x7291));
1529
 
    }
1530
 
    jmp(gc_required);
1531
 
    return;
1532
 
  }
1533
 
 
1534
 
  // Assert that the register arguments are different and that none of
1535
 
  // them are ip. ip is used explicitly in the code generated below.
1536
 
  ASSERT(!result.is(scratch1));
1537
 
  ASSERT(!result.is(scratch2));
1538
 
  ASSERT(!scratch1.is(scratch2));
1539
 
  ASSERT(!result.is(ip));
1540
 
  ASSERT(!scratch1.is(ip));
1541
 
  ASSERT(!scratch2.is(ip));
1542
 
 
1543
 
  // Check relative positions of allocation top and limit addresses.
1544
 
  // The values must be adjacent in memory to allow the use of LDM.
1545
 
  // Also, assert that the registers are numbered such that the values
1546
 
  // are loaded in the correct order.
1547
 
  ExternalReference new_space_allocation_top =
1548
 
      ExternalReference::new_space_allocation_top_address(isolate());
1549
 
  ExternalReference new_space_allocation_limit =
1550
 
      ExternalReference::new_space_allocation_limit_address(isolate());
1551
 
  intptr_t top =
1552
 
      reinterpret_cast<intptr_t>(new_space_allocation_top.address());
1553
 
  intptr_t limit =
1554
 
      reinterpret_cast<intptr_t>(new_space_allocation_limit.address());
1555
 
  ASSERT((limit - top) == kPointerSize);
1556
 
  ASSERT(result.code() < ip.code());
1557
 
 
1558
 
  // Set up allocation top address.
1559
 
  Register topaddr = scratch1;
1560
 
  mov(topaddr, Operand(new_space_allocation_top));
1561
 
 
1562
 
  // This code stores a temporary value in ip. This is OK, as the code below
1563
 
  // does not need ip for implicit literal generation.
1564
 
  if ((flags & RESULT_CONTAINS_TOP) == 0) {
1565
 
    // Load allocation top into result and allocation limit into ip.
1566
 
    ldm(ia, topaddr, result.bit() | ip.bit());
1567
 
  } else {
1568
 
    if (emit_debug_code()) {
1569
 
      // Assert that result actually contains top on entry. ip is used
1570
 
      // immediately below so this use of ip does not cause difference with
1571
 
      // respect to register content between debug and release mode.
1572
 
      ldr(ip, MemOperand(topaddr));
1573
 
      cmp(result, ip);
1574
 
      Check(eq, "Unexpected allocation top");
1575
 
    }
1576
 
    // Load allocation limit into ip. Result already contains allocation top.
1577
 
    ldr(ip, MemOperand(topaddr, limit - top));
1578
 
  }
1579
 
 
1580
 
  // Calculate new top and bail out if new space is exhausted. Use result
1581
 
  // to calculate the new top. Object size may be in words so a shift is
1582
 
  // required to get the number of bytes.
1583
 
  if ((flags & SIZE_IN_WORDS) != 0) {
1584
 
    add(scratch2, result, Operand(object_size, LSL, kPointerSizeLog2), SetCC);
1585
 
  } else {
1586
 
    add(scratch2, result, Operand(object_size), SetCC);
1587
 
  }
1588
 
  b(cs, gc_required);
1589
 
  cmp(scratch2, Operand(ip));
1590
 
  b(hi, gc_required);
1591
 
 
1592
 
  // Update allocation top. result temporarily holds the new top.
1593
 
  if (emit_debug_code()) {
1594
 
    tst(scratch2, Operand(kObjectAlignmentMask));
1595
 
    Check(eq, "Unaligned allocation in new space");
1596
 
  }
1597
 
  str(scratch2, MemOperand(topaddr));
1598
 
 
1599
 
  // Tag object if requested.
1600
 
  if ((flags & TAG_OBJECT) != 0) {
1601
 
    add(result, result, Operand(kHeapObjectTag));
1602
 
  }
1603
 
}
1604
 
 
1605
 
 
1606
 
void MacroAssembler::UndoAllocationInNewSpace(Register object,
1607
 
                                              Register scratch) {
1608
 
  ExternalReference new_space_allocation_top =
1609
 
      ExternalReference::new_space_allocation_top_address(isolate());
1610
 
 
1611
 
  // Make sure the object has no tag before resetting top.
1612
 
  and_(object, object, Operand(~kHeapObjectTagMask));
1613
 
#ifdef DEBUG
1614
 
  // Check that the object un-allocated is below the current top.
1615
 
  mov(scratch, Operand(new_space_allocation_top));
1616
 
  ldr(scratch, MemOperand(scratch));
1617
 
  cmp(object, scratch);
1618
 
  Check(lt, "Undo allocation of non allocated memory");
1619
 
#endif
1620
 
  // Write the address of the object to un-allocate as the current top.
1621
 
  mov(scratch, Operand(new_space_allocation_top));
1622
 
  str(object, MemOperand(scratch));
1623
 
}
1624
 
 
1625
 
 
1626
 
void MacroAssembler::AllocateTwoByteString(Register result,
1627
 
                                           Register length,
1628
 
                                           Register scratch1,
1629
 
                                           Register scratch2,
1630
 
                                           Register scratch3,
1631
 
                                           Label* gc_required) {
1632
 
  // Calculate the number of bytes needed for the characters in the string while
1633
 
  // observing object alignment.
1634
 
  ASSERT((SeqTwoByteString::kHeaderSize & kObjectAlignmentMask) == 0);
1635
 
  mov(scratch1, Operand(length, LSL, 1));  // Length in bytes, not chars.
1636
 
  add(scratch1, scratch1,
1637
 
      Operand(kObjectAlignmentMask + SeqTwoByteString::kHeaderSize));
1638
 
  and_(scratch1, scratch1, Operand(~kObjectAlignmentMask));
1639
 
 
1640
 
  // Allocate two-byte string in new space.
1641
 
  AllocateInNewSpace(scratch1,
1642
 
                     result,
1643
 
                     scratch2,
1644
 
                     scratch3,
1645
 
                     gc_required,
1646
 
                     TAG_OBJECT);
1647
 
 
1648
 
  // Set the map, length and hash field.
1649
 
  InitializeNewString(result,
1650
 
                      length,
1651
 
                      Heap::kStringMapRootIndex,
1652
 
                      scratch1,
1653
 
                      scratch2);
1654
 
}
1655
 
 
1656
 
 
1657
 
void MacroAssembler::AllocateAsciiString(Register result,
1658
 
                                         Register length,
1659
 
                                         Register scratch1,
1660
 
                                         Register scratch2,
1661
 
                                         Register scratch3,
1662
 
                                         Label* gc_required) {
1663
 
  // Calculate the number of bytes needed for the characters in the string while
1664
 
  // observing object alignment.
1665
 
  ASSERT((SeqAsciiString::kHeaderSize & kObjectAlignmentMask) == 0);
1666
 
  ASSERT(kCharSize == 1);
1667
 
  add(scratch1, length,
1668
 
      Operand(kObjectAlignmentMask + SeqAsciiString::kHeaderSize));
1669
 
  and_(scratch1, scratch1, Operand(~kObjectAlignmentMask));
1670
 
 
1671
 
  // Allocate ASCII string in new space.
1672
 
  AllocateInNewSpace(scratch1,
1673
 
                     result,
1674
 
                     scratch2,
1675
 
                     scratch3,
1676
 
                     gc_required,
1677
 
                     TAG_OBJECT);
1678
 
 
1679
 
  // Set the map, length and hash field.
1680
 
  InitializeNewString(result,
1681
 
                      length,
1682
 
                      Heap::kAsciiStringMapRootIndex,
1683
 
                      scratch1,
1684
 
                      scratch2);
1685
 
}
1686
 
 
1687
 
 
1688
 
void MacroAssembler::AllocateTwoByteConsString(Register result,
1689
 
                                               Register length,
1690
 
                                               Register scratch1,
1691
 
                                               Register scratch2,
1692
 
                                               Label* gc_required) {
1693
 
  AllocateInNewSpace(ConsString::kSize,
1694
 
                     result,
1695
 
                     scratch1,
1696
 
                     scratch2,
1697
 
                     gc_required,
1698
 
                     TAG_OBJECT);
1699
 
 
1700
 
  InitializeNewString(result,
1701
 
                      length,
1702
 
                      Heap::kConsStringMapRootIndex,
1703
 
                      scratch1,
1704
 
                      scratch2);
1705
 
}
1706
 
 
1707
 
 
1708
 
void MacroAssembler::AllocateAsciiConsString(Register result,
1709
 
                                             Register length,
1710
 
                                             Register scratch1,
1711
 
                                             Register scratch2,
1712
 
                                             Label* gc_required) {
1713
 
  AllocateInNewSpace(ConsString::kSize,
1714
 
                     result,
1715
 
                     scratch1,
1716
 
                     scratch2,
1717
 
                     gc_required,
1718
 
                     TAG_OBJECT);
1719
 
 
1720
 
  InitializeNewString(result,
1721
 
                      length,
1722
 
                      Heap::kConsAsciiStringMapRootIndex,
1723
 
                      scratch1,
1724
 
                      scratch2);
1725
 
}
1726
 
 
1727
 
 
1728
 
void MacroAssembler::AllocateTwoByteSlicedString(Register result,
1729
 
                                                 Register length,
1730
 
                                                 Register scratch1,
1731
 
                                                 Register scratch2,
1732
 
                                                 Label* gc_required) {
1733
 
  AllocateInNewSpace(SlicedString::kSize,
1734
 
                     result,
1735
 
                     scratch1,
1736
 
                     scratch2,
1737
 
                     gc_required,
1738
 
                     TAG_OBJECT);
1739
 
 
1740
 
  InitializeNewString(result,
1741
 
                      length,
1742
 
                      Heap::kSlicedStringMapRootIndex,
1743
 
                      scratch1,
1744
 
                      scratch2);
1745
 
}
1746
 
 
1747
 
 
1748
 
void MacroAssembler::AllocateAsciiSlicedString(Register result,
1749
 
                                               Register length,
1750
 
                                               Register scratch1,
1751
 
                                               Register scratch2,
1752
 
                                               Label* gc_required) {
1753
 
  AllocateInNewSpace(SlicedString::kSize,
1754
 
                     result,
1755
 
                     scratch1,
1756
 
                     scratch2,
1757
 
                     gc_required,
1758
 
                     TAG_OBJECT);
1759
 
 
1760
 
  InitializeNewString(result,
1761
 
                      length,
1762
 
                      Heap::kSlicedAsciiStringMapRootIndex,
1763
 
                      scratch1,
1764
 
                      scratch2);
1765
 
}
1766
 
 
1767
 
 
1768
 
void MacroAssembler::CompareObjectType(Register object,
1769
 
                                       Register map,
1770
 
                                       Register type_reg,
1771
 
                                       InstanceType type) {
1772
 
  ldr(map, FieldMemOperand(object, HeapObject::kMapOffset));
1773
 
  CompareInstanceType(map, type_reg, type);
1774
 
}
1775
 
 
1776
 
 
1777
 
void MacroAssembler::CompareInstanceType(Register map,
1778
 
                                         Register type_reg,
1779
 
                                         InstanceType type) {
1780
 
  ldrb(type_reg, FieldMemOperand(map, Map::kInstanceTypeOffset));
1781
 
  cmp(type_reg, Operand(type));
1782
 
}
1783
 
 
1784
 
 
1785
 
void MacroAssembler::CompareRoot(Register obj,
1786
 
                                 Heap::RootListIndex index) {
1787
 
  ASSERT(!obj.is(ip));
1788
 
  LoadRoot(ip, index);
1789
 
  cmp(obj, ip);
1790
 
}
1791
 
 
1792
 
 
1793
 
void MacroAssembler::CheckFastElements(Register map,
1794
 
                                       Register scratch,
1795
 
                                       Label* fail) {
1796
 
  STATIC_ASSERT(FAST_ELEMENTS == 0);
1797
 
  ldrb(scratch, FieldMemOperand(map, Map::kBitField2Offset));
1798
 
  cmp(scratch, Operand(Map::kMaximumBitField2FastElementValue));
1799
 
  b(hi, fail);
1800
 
}
1801
 
 
1802
 
 
1803
 
void MacroAssembler::CheckMap(Register obj,
1804
 
                              Register scratch,
1805
 
                              Handle<Map> map,
1806
 
                              Label* fail,
1807
 
                              SmiCheckType smi_check_type) {
1808
 
  if (smi_check_type == DO_SMI_CHECK) {
1809
 
    JumpIfSmi(obj, fail);
1810
 
  }
1811
 
  ldr(scratch, FieldMemOperand(obj, HeapObject::kMapOffset));
1812
 
  mov(ip, Operand(map));
1813
 
  cmp(scratch, ip);
1814
 
  b(ne, fail);
1815
 
}
1816
 
 
1817
 
 
1818
 
void MacroAssembler::CheckMap(Register obj,
1819
 
                              Register scratch,
1820
 
                              Heap::RootListIndex index,
1821
 
                              Label* fail,
1822
 
                              SmiCheckType smi_check_type) {
1823
 
  if (smi_check_type == DO_SMI_CHECK) {
1824
 
    JumpIfSmi(obj, fail);
1825
 
  }
1826
 
  ldr(scratch, FieldMemOperand(obj, HeapObject::kMapOffset));
1827
 
  LoadRoot(ip, index);
1828
 
  cmp(scratch, ip);
1829
 
  b(ne, fail);
1830
 
}
1831
 
 
1832
 
 
1833
 
void MacroAssembler::DispatchMap(Register obj,
1834
 
                                 Register scratch,
1835
 
                                 Handle<Map> map,
1836
 
                                 Handle<Code> success,
1837
 
                                 SmiCheckType smi_check_type) {
1838
 
  Label fail;
1839
 
  if (smi_check_type == DO_SMI_CHECK) {
1840
 
    JumpIfSmi(obj, &fail);
1841
 
  }
1842
 
  ldr(scratch, FieldMemOperand(obj, HeapObject::kMapOffset));
1843
 
  mov(ip, Operand(map));
1844
 
  cmp(scratch, ip);
1845
 
  Jump(success, RelocInfo::CODE_TARGET, eq);
1846
 
  bind(&fail);
1847
 
}
1848
 
 
1849
 
 
1850
 
void MacroAssembler::TryGetFunctionPrototype(Register function,
1851
 
                                             Register result,
1852
 
                                             Register scratch,
1853
 
                                             Label* miss) {
1854
 
  // Check that the receiver isn't a smi.
1855
 
  JumpIfSmi(function, miss);
1856
 
 
1857
 
  // Check that the function really is a function.  Load map into result reg.
1858
 
  CompareObjectType(function, result, scratch, JS_FUNCTION_TYPE);
1859
 
  b(ne, miss);
1860
 
 
1861
 
  // Make sure that the function has an instance prototype.
1862
 
  Label non_instance;
1863
 
  ldrb(scratch, FieldMemOperand(result, Map::kBitFieldOffset));
1864
 
  tst(scratch, Operand(1 << Map::kHasNonInstancePrototype));
1865
 
  b(ne, &non_instance);
1866
 
 
1867
 
  // Get the prototype or initial map from the function.
1868
 
  ldr(result,
1869
 
      FieldMemOperand(function, JSFunction::kPrototypeOrInitialMapOffset));
1870
 
 
1871
 
  // If the prototype or initial map is the hole, don't return it and
1872
 
  // simply miss the cache instead. This will allow us to allocate a
1873
 
  // prototype object on-demand in the runtime system.
1874
 
  LoadRoot(ip, Heap::kTheHoleValueRootIndex);
1875
 
  cmp(result, ip);
1876
 
  b(eq, miss);
1877
 
 
1878
 
  // If the function does not have an initial map, we're done.
1879
 
  Label done;
1880
 
  CompareObjectType(result, scratch, scratch, MAP_TYPE);
1881
 
  b(ne, &done);
1882
 
 
1883
 
  // Get the prototype from the initial map.
1884
 
  ldr(result, FieldMemOperand(result, Map::kPrototypeOffset));
1885
 
  jmp(&done);
1886
 
 
1887
 
  // Non-instance prototype: Fetch prototype from constructor field
1888
 
  // in initial map.
1889
 
  bind(&non_instance);
1890
 
  ldr(result, FieldMemOperand(result, Map::kConstructorOffset));
1891
 
 
1892
 
  // All done.
1893
 
  bind(&done);
1894
 
}
1895
 
 
1896
 
 
1897
 
void MacroAssembler::CallStub(CodeStub* stub, Condition cond) {
1898
 
  ASSERT(allow_stub_calls());  // Stub calls are not allowed in some stubs.
1899
 
  Call(stub->GetCode(), RelocInfo::CODE_TARGET, kNoASTId, cond);
1900
 
}
1901
 
 
1902
 
 
1903
 
MaybeObject* MacroAssembler::TryCallStub(CodeStub* stub, Condition cond) {
1904
 
  ASSERT(allow_stub_calls());  // Stub calls are not allowed in some stubs.
1905
 
  Object* result;
1906
 
  { MaybeObject* maybe_result = stub->TryGetCode();
1907
 
    if (!maybe_result->ToObject(&result)) return maybe_result;
1908
 
  }
1909
 
  Handle<Code> code(Code::cast(result));
1910
 
  Call(code, RelocInfo::CODE_TARGET, kNoASTId, cond);
1911
 
  return result;
1912
 
}
1913
 
 
1914
 
 
1915
 
void MacroAssembler::TailCallStub(CodeStub* stub, Condition cond) {
1916
 
  ASSERT(allow_stub_calls());  // Stub calls are not allowed in some stubs.
1917
 
  Jump(stub->GetCode(), RelocInfo::CODE_TARGET, cond);
1918
 
}
1919
 
 
1920
 
 
1921
 
MaybeObject* MacroAssembler::TryTailCallStub(CodeStub* stub, Condition cond) {
1922
 
  ASSERT(allow_stub_calls());  // Stub calls are not allowed in some stubs.
1923
 
  Object* result;
1924
 
  { MaybeObject* maybe_result = stub->TryGetCode();
1925
 
    if (!maybe_result->ToObject(&result)) return maybe_result;
1926
 
  }
1927
 
  Jump(Handle<Code>(Code::cast(result)), RelocInfo::CODE_TARGET, cond);
1928
 
  return result;
1929
 
}
1930
 
 
1931
 
 
1932
 
static int AddressOffset(ExternalReference ref0, ExternalReference ref1) {
1933
 
  return ref0.address() - ref1.address();
1934
 
}
1935
 
 
1936
 
 
1937
 
MaybeObject* MacroAssembler::TryCallApiFunctionAndReturn(
1938
 
    ExternalReference function, int stack_space) {
1939
 
  ExternalReference next_address =
1940
 
      ExternalReference::handle_scope_next_address();
1941
 
  const int kNextOffset = 0;
1942
 
  const int kLimitOffset = AddressOffset(
1943
 
      ExternalReference::handle_scope_limit_address(),
1944
 
      next_address);
1945
 
  const int kLevelOffset = AddressOffset(
1946
 
      ExternalReference::handle_scope_level_address(),
1947
 
      next_address);
1948
 
 
1949
 
  // Allocate HandleScope in callee-save registers.
1950
 
  mov(r7, Operand(next_address));
1951
 
  ldr(r4, MemOperand(r7, kNextOffset));
1952
 
  ldr(r5, MemOperand(r7, kLimitOffset));
1953
 
  ldr(r6, MemOperand(r7, kLevelOffset));
1954
 
  add(r6, r6, Operand(1));
1955
 
  str(r6, MemOperand(r7, kLevelOffset));
1956
 
 
1957
 
  // Native call returns to the DirectCEntry stub which redirects to the
1958
 
  // return address pushed on stack (could have moved after GC).
1959
 
  // DirectCEntry stub itself is generated early and never moves.
1960
 
  DirectCEntryStub stub;
1961
 
  stub.GenerateCall(this, function);
1962
 
 
1963
 
  Label promote_scheduled_exception;
1964
 
  Label delete_allocated_handles;
1965
 
  Label leave_exit_frame;
1966
 
 
1967
 
  // If result is non-zero, dereference to get the result value
1968
 
  // otherwise set it to undefined.
1969
 
  cmp(r0, Operand(0));
1970
 
  LoadRoot(r0, Heap::kUndefinedValueRootIndex, eq);
1971
 
  ldr(r0, MemOperand(r0), ne);
1972
 
 
1973
 
  // No more valid handles (the result handle was the last one). Restore
1974
 
  // previous handle scope.
1975
 
  str(r4, MemOperand(r7, kNextOffset));
1976
 
  if (emit_debug_code()) {
1977
 
    ldr(r1, MemOperand(r7, kLevelOffset));
1978
 
    cmp(r1, r6);
1979
 
    Check(eq, "Unexpected level after return from api call");
1980
 
  }
1981
 
  sub(r6, r6, Operand(1));
1982
 
  str(r6, MemOperand(r7, kLevelOffset));
1983
 
  ldr(ip, MemOperand(r7, kLimitOffset));
1984
 
  cmp(r5, ip);
1985
 
  b(ne, &delete_allocated_handles);
1986
 
 
1987
 
  // Check if the function scheduled an exception.
1988
 
  bind(&leave_exit_frame);
1989
 
  LoadRoot(r4, Heap::kTheHoleValueRootIndex);
1990
 
  mov(ip, Operand(ExternalReference::scheduled_exception_address(isolate())));
1991
 
  ldr(r5, MemOperand(ip));
1992
 
  cmp(r4, r5);
1993
 
  b(ne, &promote_scheduled_exception);
1994
 
 
1995
 
  // LeaveExitFrame expects unwind space to be in a register.
1996
 
  mov(r4, Operand(stack_space));
1997
 
  LeaveExitFrame(false, r4);
1998
 
  mov(pc, lr);
1999
 
 
2000
 
  bind(&promote_scheduled_exception);
2001
 
  MaybeObject* result
2002
 
      = TryTailCallExternalReference(
2003
 
          ExternalReference(Runtime::kPromoteScheduledException, isolate()),
2004
 
          0,
2005
 
          1);
2006
 
  if (result->IsFailure()) {
2007
 
    return result;
2008
 
  }
2009
 
 
2010
 
  // HandleScope limit has changed. Delete allocated extensions.
2011
 
  bind(&delete_allocated_handles);
2012
 
  str(r5, MemOperand(r7, kLimitOffset));
2013
 
  mov(r4, r0);
2014
 
  PrepareCallCFunction(1, r5);
2015
 
  mov(r0, Operand(ExternalReference::isolate_address()));
2016
 
  CallCFunction(
2017
 
      ExternalReference::delete_handle_scope_extensions(isolate()), 1);
2018
 
  mov(r0, r4);
2019
 
  jmp(&leave_exit_frame);
2020
 
 
2021
 
  return result;
2022
 
}
2023
 
 
2024
 
 
2025
 
void MacroAssembler::IllegalOperation(int num_arguments) {
2026
 
  if (num_arguments > 0) {
2027
 
    add(sp, sp, Operand(num_arguments * kPointerSize));
2028
 
  }
2029
 
  LoadRoot(r0, Heap::kUndefinedValueRootIndex);
2030
 
}
2031
 
 
2032
 
 
2033
 
void MacroAssembler::IndexFromHash(Register hash, Register index) {
2034
 
  // If the hash field contains an array index pick it out. The assert checks
2035
 
  // that the constants for the maximum number of digits for an array index
2036
 
  // cached in the hash field and the number of bits reserved for it does not
2037
 
  // conflict.
2038
 
  ASSERT(TenToThe(String::kMaxCachedArrayIndexLength) <
2039
 
         (1 << String::kArrayIndexValueBits));
2040
 
  // We want the smi-tagged index in key.  kArrayIndexValueMask has zeros in
2041
 
  // the low kHashShift bits.
2042
 
  STATIC_ASSERT(kSmiTag == 0);
2043
 
  Ubfx(hash, hash, String::kHashShift, String::kArrayIndexValueBits);
2044
 
  mov(index, Operand(hash, LSL, kSmiTagSize));
2045
 
}
2046
 
 
2047
 
 
2048
 
void MacroAssembler::IntegerToDoubleConversionWithVFP3(Register inReg,
2049
 
                                                       Register outHighReg,
2050
 
                                                       Register outLowReg) {
2051
 
  // ARMv7 VFP3 instructions to implement integer to double conversion.
2052
 
  mov(r7, Operand(inReg, ASR, kSmiTagSize));
2053
 
  vmov(s15, r7);
2054
 
  vcvt_f64_s32(d7, s15);
2055
 
  vmov(outLowReg, outHighReg, d7);
2056
 
}
2057
 
 
2058
 
 
2059
 
void MacroAssembler::ObjectToDoubleVFPRegister(Register object,
2060
 
                                               DwVfpRegister result,
2061
 
                                               Register scratch1,
2062
 
                                               Register scratch2,
2063
 
                                               Register heap_number_map,
2064
 
                                               SwVfpRegister scratch3,
2065
 
                                               Label* not_number,
2066
 
                                               ObjectToDoubleFlags flags) {
2067
 
  Label done;
2068
 
  if ((flags & OBJECT_NOT_SMI) == 0) {
2069
 
    Label not_smi;
2070
 
    JumpIfNotSmi(object, &not_smi);
2071
 
    // Remove smi tag and convert to double.
2072
 
    mov(scratch1, Operand(object, ASR, kSmiTagSize));
2073
 
    vmov(scratch3, scratch1);
2074
 
    vcvt_f64_s32(result, scratch3);
2075
 
    b(&done);
2076
 
    bind(&not_smi);
2077
 
  }
2078
 
  // Check for heap number and load double value from it.
2079
 
  ldr(scratch1, FieldMemOperand(object, HeapObject::kMapOffset));
2080
 
  sub(scratch2, object, Operand(kHeapObjectTag));
2081
 
  cmp(scratch1, heap_number_map);
2082
 
  b(ne, not_number);
2083
 
  if ((flags & AVOID_NANS_AND_INFINITIES) != 0) {
2084
 
    // If exponent is all ones the number is either a NaN or +/-Infinity.
2085
 
    ldr(scratch1, FieldMemOperand(object, HeapNumber::kExponentOffset));
2086
 
    Sbfx(scratch1,
2087
 
         scratch1,
2088
 
         HeapNumber::kExponentShift,
2089
 
         HeapNumber::kExponentBits);
2090
 
    // All-one value sign extend to -1.
2091
 
    cmp(scratch1, Operand(-1));
2092
 
    b(eq, not_number);
2093
 
  }
2094
 
  vldr(result, scratch2, HeapNumber::kValueOffset);
2095
 
  bind(&done);
2096
 
}
2097
 
 
2098
 
 
2099
 
void MacroAssembler::SmiToDoubleVFPRegister(Register smi,
2100
 
                                            DwVfpRegister value,
2101
 
                                            Register scratch1,
2102
 
                                            SwVfpRegister scratch2) {
2103
 
  mov(scratch1, Operand(smi, ASR, kSmiTagSize));
2104
 
  vmov(scratch2, scratch1);
2105
 
  vcvt_f64_s32(value, scratch2);
2106
 
}
2107
 
 
2108
 
 
2109
 
// Tries to get a signed int32 out of a double precision floating point heap
2110
 
// number. Rounds towards 0. Branch to 'not_int32' if the double is out of the
2111
 
// 32bits signed integer range.
2112
 
void MacroAssembler::ConvertToInt32(Register source,
2113
 
                                    Register dest,
2114
 
                                    Register scratch,
2115
 
                                    Register scratch2,
2116
 
                                    DwVfpRegister double_scratch,
2117
 
                                    Label *not_int32) {
2118
 
  if (CpuFeatures::IsSupported(VFP3)) {
2119
 
    CpuFeatures::Scope scope(VFP3);
2120
 
    sub(scratch, source, Operand(kHeapObjectTag));
2121
 
    vldr(double_scratch, scratch, HeapNumber::kValueOffset);
2122
 
    vcvt_s32_f64(double_scratch.low(), double_scratch);
2123
 
    vmov(dest, double_scratch.low());
2124
 
    // Signed vcvt instruction will saturate to the minimum (0x80000000) or
2125
 
    // maximun (0x7fffffff) signed 32bits integer when the double is out of
2126
 
    // range. When substracting one, the minimum signed integer becomes the
2127
 
    // maximun signed integer.
2128
 
    sub(scratch, dest, Operand(1));
2129
 
    cmp(scratch, Operand(LONG_MAX - 1));
2130
 
    // If equal then dest was LONG_MAX, if greater dest was LONG_MIN.
2131
 
    b(ge, not_int32);
2132
 
  } else {
2133
 
    // This code is faster for doubles that are in the ranges -0x7fffffff to
2134
 
    // -0x40000000 or 0x40000000 to 0x7fffffff. This corresponds almost to
2135
 
    // the range of signed int32 values that are not Smis.  Jumps to the label
2136
 
    // 'not_int32' if the double isn't in the range -0x80000000.0 to
2137
 
    // 0x80000000.0 (excluding the endpoints).
2138
 
    Label right_exponent, done;
2139
 
    // Get exponent word.
2140
 
    ldr(scratch, FieldMemOperand(source, HeapNumber::kExponentOffset));
2141
 
    // Get exponent alone in scratch2.
2142
 
    Ubfx(scratch2,
2143
 
         scratch,
2144
 
         HeapNumber::kExponentShift,
2145
 
         HeapNumber::kExponentBits);
2146
 
    // Load dest with zero.  We use this either for the final shift or
2147
 
    // for the answer.
2148
 
    mov(dest, Operand(0, RelocInfo::NONE));
2149
 
    // Check whether the exponent matches a 32 bit signed int that is not a Smi.
2150
 
    // A non-Smi integer is 1.xxx * 2^30 so the exponent is 30 (biased). This is
2151
 
    // the exponent that we are fastest at and also the highest exponent we can
2152
 
    // handle here.
2153
 
    const uint32_t non_smi_exponent = HeapNumber::kExponentBias + 30;
2154
 
    // The non_smi_exponent, 0x41d, is too big for ARM's immediate field so we
2155
 
    // split it up to avoid a constant pool entry.  You can't do that in general
2156
 
    // for cmp because of the overflow flag, but we know the exponent is in the
2157
 
    // range 0-2047 so there is no overflow.
2158
 
    int fudge_factor = 0x400;
2159
 
    sub(scratch2, scratch2, Operand(fudge_factor));
2160
 
    cmp(scratch2, Operand(non_smi_exponent - fudge_factor));
2161
 
    // If we have a match of the int32-but-not-Smi exponent then skip some
2162
 
    // logic.
2163
 
    b(eq, &right_exponent);
2164
 
    // If the exponent is higher than that then go to slow case.  This catches
2165
 
    // numbers that don't fit in a signed int32, infinities and NaNs.
2166
 
    b(gt, not_int32);
2167
 
 
2168
 
    // We know the exponent is smaller than 30 (biased).  If it is less than
2169
 
    // 0 (biased) then the number is smaller in magnitude than 1.0 * 2^0, ie
2170
 
    // it rounds to zero.
2171
 
    const uint32_t zero_exponent = HeapNumber::kExponentBias + 0;
2172
 
    sub(scratch2, scratch2, Operand(zero_exponent - fudge_factor), SetCC);
2173
 
    // Dest already has a Smi zero.
2174
 
    b(lt, &done);
2175
 
 
2176
 
    // We have an exponent between 0 and 30 in scratch2.  Subtract from 30 to
2177
 
    // get how much to shift down.
2178
 
    rsb(dest, scratch2, Operand(30));
2179
 
 
2180
 
    bind(&right_exponent);
2181
 
    // Get the top bits of the mantissa.
2182
 
    and_(scratch2, scratch, Operand(HeapNumber::kMantissaMask));
2183
 
    // Put back the implicit 1.
2184
 
    orr(scratch2, scratch2, Operand(1 << HeapNumber::kExponentShift));
2185
 
    // Shift up the mantissa bits to take up the space the exponent used to
2186
 
    // take. We just orred in the implicit bit so that took care of one and
2187
 
    // we want to leave the sign bit 0 so we subtract 2 bits from the shift
2188
 
    // distance.
2189
 
    const int shift_distance = HeapNumber::kNonMantissaBitsInTopWord - 2;
2190
 
    mov(scratch2, Operand(scratch2, LSL, shift_distance));
2191
 
    // Put sign in zero flag.
2192
 
    tst(scratch, Operand(HeapNumber::kSignMask));
2193
 
    // Get the second half of the double. For some exponents we don't
2194
 
    // actually need this because the bits get shifted out again, but
2195
 
    // it's probably slower to test than just to do it.
2196
 
    ldr(scratch, FieldMemOperand(source, HeapNumber::kMantissaOffset));
2197
 
    // Shift down 22 bits to get the last 10 bits.
2198
 
    orr(scratch, scratch2, Operand(scratch, LSR, 32 - shift_distance));
2199
 
    // Move down according to the exponent.
2200
 
    mov(dest, Operand(scratch, LSR, dest));
2201
 
    // Fix sign if sign bit was set.
2202
 
    rsb(dest, dest, Operand(0, RelocInfo::NONE), LeaveCC, ne);
2203
 
    bind(&done);
2204
 
  }
2205
 
}
2206
 
 
2207
 
 
2208
 
void MacroAssembler::EmitVFPTruncate(VFPRoundingMode rounding_mode,
2209
 
                                     SwVfpRegister result,
2210
 
                                     DwVfpRegister double_input,
2211
 
                                     Register scratch1,
2212
 
                                     Register scratch2,
2213
 
                                     CheckForInexactConversion check_inexact) {
2214
 
  ASSERT(CpuFeatures::IsSupported(VFP3));
2215
 
  CpuFeatures::Scope scope(VFP3);
2216
 
  Register prev_fpscr = scratch1;
2217
 
  Register scratch = scratch2;
2218
 
 
2219
 
  int32_t check_inexact_conversion =
2220
 
    (check_inexact == kCheckForInexactConversion) ? kVFPInexactExceptionBit : 0;
2221
 
 
2222
 
  // Set custom FPCSR:
2223
 
  //  - Set rounding mode.
2224
 
  //  - Clear vfp cumulative exception flags.
2225
 
  //  - Make sure Flush-to-zero mode control bit is unset.
2226
 
  vmrs(prev_fpscr);
2227
 
  bic(scratch,
2228
 
      prev_fpscr,
2229
 
      Operand(kVFPExceptionMask |
2230
 
              check_inexact_conversion |
2231
 
              kVFPRoundingModeMask |
2232
 
              kVFPFlushToZeroMask));
2233
 
  // 'Round To Nearest' is encoded by 0b00 so no bits need to be set.
2234
 
  if (rounding_mode != kRoundToNearest) {
2235
 
    orr(scratch, scratch, Operand(rounding_mode));
2236
 
  }
2237
 
  vmsr(scratch);
2238
 
 
2239
 
  // Convert the argument to an integer.
2240
 
  vcvt_s32_f64(result,
2241
 
               double_input,
2242
 
               (rounding_mode == kRoundToZero) ? kDefaultRoundToZero
2243
 
                                               : kFPSCRRounding);
2244
 
 
2245
 
  // Retrieve FPSCR.
2246
 
  vmrs(scratch);
2247
 
  // Restore FPSCR.
2248
 
  vmsr(prev_fpscr);
2249
 
  // Check for vfp exceptions.
2250
 
  tst(scratch, Operand(kVFPExceptionMask | check_inexact_conversion));
2251
 
}
2252
 
 
2253
 
 
2254
 
void MacroAssembler::EmitOutOfInt32RangeTruncate(Register result,
2255
 
                                                 Register input_high,
2256
 
                                                 Register input_low,
2257
 
                                                 Register scratch) {
2258
 
  Label done, normal_exponent, restore_sign;
2259
 
 
2260
 
  // Extract the biased exponent in result.
2261
 
  Ubfx(result,
2262
 
       input_high,
2263
 
       HeapNumber::kExponentShift,
2264
 
       HeapNumber::kExponentBits);
2265
 
 
2266
 
  // Check for Infinity and NaNs, which should return 0.
2267
 
  cmp(result, Operand(HeapNumber::kExponentMask));
2268
 
  mov(result, Operand(0), LeaveCC, eq);
2269
 
  b(eq, &done);
2270
 
 
2271
 
  // Express exponent as delta to (number of mantissa bits + 31).
2272
 
  sub(result,
2273
 
      result,
2274
 
      Operand(HeapNumber::kExponentBias + HeapNumber::kMantissaBits + 31),
2275
 
      SetCC);
2276
 
 
2277
 
  // If the delta is strictly positive, all bits would be shifted away,
2278
 
  // which means that we can return 0.
2279
 
  b(le, &normal_exponent);
2280
 
  mov(result, Operand(0));
2281
 
  b(&done);
2282
 
 
2283
 
  bind(&normal_exponent);
2284
 
  const int kShiftBase = HeapNumber::kNonMantissaBitsInTopWord - 1;
2285
 
  // Calculate shift.
2286
 
  add(scratch, result, Operand(kShiftBase + HeapNumber::kMantissaBits), SetCC);
2287
 
 
2288
 
  // Save the sign.
2289
 
  Register sign = result;
2290
 
  result = no_reg;
2291
 
  and_(sign, input_high, Operand(HeapNumber::kSignMask));
2292
 
 
2293
 
  // Set the implicit 1 before the mantissa part in input_high.
2294
 
  orr(input_high,
2295
 
      input_high,
2296
 
      Operand(1 << HeapNumber::kMantissaBitsInTopWord));
2297
 
  // Shift the mantissa bits to the correct position.
2298
 
  // We don't need to clear non-mantissa bits as they will be shifted away.
2299
 
  // If they weren't, it would mean that the answer is in the 32bit range.
2300
 
  mov(input_high, Operand(input_high, LSL, scratch));
2301
 
 
2302
 
  // Replace the shifted bits with bits from the lower mantissa word.
2303
 
  Label pos_shift, shift_done;
2304
 
  rsb(scratch, scratch, Operand(32), SetCC);
2305
 
  b(&pos_shift, ge);
2306
 
 
2307
 
  // Negate scratch.
2308
 
  rsb(scratch, scratch, Operand(0));
2309
 
  mov(input_low, Operand(input_low, LSL, scratch));
2310
 
  b(&shift_done);
2311
 
 
2312
 
  bind(&pos_shift);
2313
 
  mov(input_low, Operand(input_low, LSR, scratch));
2314
 
 
2315
 
  bind(&shift_done);
2316
 
  orr(input_high, input_high, Operand(input_low));
2317
 
  // Restore sign if necessary.
2318
 
  cmp(sign, Operand(0));
2319
 
  result = sign;
2320
 
  sign = no_reg;
2321
 
  rsb(result, input_high, Operand(0), LeaveCC, ne);
2322
 
  mov(result, input_high, LeaveCC, eq);
2323
 
  bind(&done);
2324
 
}
2325
 
 
2326
 
 
2327
 
void MacroAssembler::EmitECMATruncate(Register result,
2328
 
                                      DwVfpRegister double_input,
2329
 
                                      SwVfpRegister single_scratch,
2330
 
                                      Register scratch,
2331
 
                                      Register input_high,
2332
 
                                      Register input_low) {
2333
 
  CpuFeatures::Scope scope(VFP3);
2334
 
  ASSERT(!input_high.is(result));
2335
 
  ASSERT(!input_low.is(result));
2336
 
  ASSERT(!input_low.is(input_high));
2337
 
  ASSERT(!scratch.is(result) &&
2338
 
         !scratch.is(input_high) &&
2339
 
         !scratch.is(input_low));
2340
 
  ASSERT(!single_scratch.is(double_input.low()) &&
2341
 
         !single_scratch.is(double_input.high()));
2342
 
 
2343
 
  Label done;
2344
 
 
2345
 
  // Clear cumulative exception flags.
2346
 
  ClearFPSCRBits(kVFPExceptionMask, scratch);
2347
 
  // Try a conversion to a signed integer.
2348
 
  vcvt_s32_f64(single_scratch, double_input);
2349
 
  vmov(result, single_scratch);
2350
 
  // Retrieve he FPSCR.
2351
 
  vmrs(scratch);
2352
 
  // Check for overflow and NaNs.
2353
 
  tst(scratch, Operand(kVFPOverflowExceptionBit |
2354
 
                       kVFPUnderflowExceptionBit |
2355
 
                       kVFPInvalidOpExceptionBit));
2356
 
  // If we had no exceptions we are done.
2357
 
  b(eq, &done);
2358
 
 
2359
 
  // Load the double value and perform a manual truncation.
2360
 
  vmov(input_low, input_high, double_input);
2361
 
  EmitOutOfInt32RangeTruncate(result,
2362
 
                              input_high,
2363
 
                              input_low,
2364
 
                              scratch);
2365
 
  bind(&done);
2366
 
}
2367
 
 
2368
 
 
2369
 
void MacroAssembler::GetLeastBitsFromSmi(Register dst,
2370
 
                                         Register src,
2371
 
                                         int num_least_bits) {
2372
 
  if (CpuFeatures::IsSupported(ARMv7)) {
2373
 
    ubfx(dst, src, kSmiTagSize, num_least_bits);
2374
 
  } else {
2375
 
    mov(dst, Operand(src, ASR, kSmiTagSize));
2376
 
    and_(dst, dst, Operand((1 << num_least_bits) - 1));
2377
 
  }
2378
 
}
2379
 
 
2380
 
 
2381
 
void MacroAssembler::GetLeastBitsFromInt32(Register dst,
2382
 
                                           Register src,
2383
 
                                           int num_least_bits) {
2384
 
  and_(dst, src, Operand((1 << num_least_bits) - 1));
2385
 
}
2386
 
 
2387
 
 
2388
 
void MacroAssembler::CallRuntime(const Runtime::Function* f,
2389
 
                                 int num_arguments) {
2390
 
  // All parameters are on the stack.  r0 has the return value after call.
2391
 
 
2392
 
  // If the expected number of arguments of the runtime function is
2393
 
  // constant, we check that the actual number of arguments match the
2394
 
  // expectation.
2395
 
  if (f->nargs >= 0 && f->nargs != num_arguments) {
2396
 
    IllegalOperation(num_arguments);
2397
 
    return;
2398
 
  }
2399
 
 
2400
 
  // TODO(1236192): Most runtime routines don't need the number of
2401
 
  // arguments passed in because it is constant. At some point we
2402
 
  // should remove this need and make the runtime routine entry code
2403
 
  // smarter.
2404
 
  mov(r0, Operand(num_arguments));
2405
 
  mov(r1, Operand(ExternalReference(f, isolate())));
2406
 
  CEntryStub stub(1);
2407
 
  CallStub(&stub);
2408
 
}
2409
 
 
2410
 
 
2411
 
void MacroAssembler::CallRuntime(Runtime::FunctionId fid, int num_arguments) {
2412
 
  CallRuntime(Runtime::FunctionForId(fid), num_arguments);
2413
 
}
2414
 
 
2415
 
 
2416
 
void MacroAssembler::CallRuntimeSaveDoubles(Runtime::FunctionId id) {
2417
 
  const Runtime::Function* function = Runtime::FunctionForId(id);
2418
 
  mov(r0, Operand(function->nargs));
2419
 
  mov(r1, Operand(ExternalReference(function, isolate())));
2420
 
  CEntryStub stub(1);
2421
 
  stub.SaveDoubles();
2422
 
  CallStub(&stub);
2423
 
}
2424
 
 
2425
 
 
2426
 
void MacroAssembler::CallExternalReference(const ExternalReference& ext,
2427
 
                                           int num_arguments) {
2428
 
  mov(r0, Operand(num_arguments));
2429
 
  mov(r1, Operand(ext));
2430
 
 
2431
 
  CEntryStub stub(1);
2432
 
  CallStub(&stub);
2433
 
}
2434
 
 
2435
 
 
2436
 
void MacroAssembler::TailCallExternalReference(const ExternalReference& ext,
2437
 
                                               int num_arguments,
2438
 
                                               int result_size) {
2439
 
  // TODO(1236192): Most runtime routines don't need the number of
2440
 
  // arguments passed in because it is constant. At some point we
2441
 
  // should remove this need and make the runtime routine entry code
2442
 
  // smarter.
2443
 
  mov(r0, Operand(num_arguments));
2444
 
  JumpToExternalReference(ext);
2445
 
}
2446
 
 
2447
 
 
2448
 
MaybeObject* MacroAssembler::TryTailCallExternalReference(
2449
 
    const ExternalReference& ext, int num_arguments, int result_size) {
2450
 
  // TODO(1236192): Most runtime routines don't need the number of
2451
 
  // arguments passed in because it is constant. At some point we
2452
 
  // should remove this need and make the runtime routine entry code
2453
 
  // smarter.
2454
 
  mov(r0, Operand(num_arguments));
2455
 
  return TryJumpToExternalReference(ext);
2456
 
}
2457
 
 
2458
 
 
2459
 
void MacroAssembler::TailCallRuntime(Runtime::FunctionId fid,
2460
 
                                     int num_arguments,
2461
 
                                     int result_size) {
2462
 
  TailCallExternalReference(ExternalReference(fid, isolate()),
2463
 
                            num_arguments,
2464
 
                            result_size);
2465
 
}
2466
 
 
2467
 
 
2468
 
void MacroAssembler::JumpToExternalReference(const ExternalReference& builtin) {
2469
 
#if defined(__thumb__)
2470
 
  // Thumb mode builtin.
2471
 
  ASSERT((reinterpret_cast<intptr_t>(builtin.address()) & 1) == 1);
2472
 
#endif
2473
 
  mov(r1, Operand(builtin));
2474
 
  CEntryStub stub(1);
2475
 
  Jump(stub.GetCode(), RelocInfo::CODE_TARGET);
2476
 
}
2477
 
 
2478
 
 
2479
 
MaybeObject* MacroAssembler::TryJumpToExternalReference(
2480
 
    const ExternalReference& builtin) {
2481
 
#if defined(__thumb__)
2482
 
  // Thumb mode builtin.
2483
 
  ASSERT((reinterpret_cast<intptr_t>(builtin.address()) & 1) == 1);
2484
 
#endif
2485
 
  mov(r1, Operand(builtin));
2486
 
  CEntryStub stub(1);
2487
 
  return TryTailCallStub(&stub);
2488
 
}
2489
 
 
2490
 
 
2491
 
void MacroAssembler::InvokeBuiltin(Builtins::JavaScript id,
2492
 
                                   InvokeFlag flag,
2493
 
                                   const CallWrapper& call_wrapper) {
2494
 
  GetBuiltinEntry(r2, id);
2495
 
  if (flag == CALL_FUNCTION) {
2496
 
    call_wrapper.BeforeCall(CallSize(r2));
2497
 
    SetCallKind(r5, CALL_AS_METHOD);
2498
 
    Call(r2);
2499
 
    call_wrapper.AfterCall();
2500
 
  } else {
2501
 
    ASSERT(flag == JUMP_FUNCTION);
2502
 
    SetCallKind(r5, CALL_AS_METHOD);
2503
 
    Jump(r2);
2504
 
  }
2505
 
}
2506
 
 
2507
 
 
2508
 
void MacroAssembler::GetBuiltinFunction(Register target,
2509
 
                                        Builtins::JavaScript id) {
2510
 
  // Load the builtins object into target register.
2511
 
  ldr(target, MemOperand(cp, Context::SlotOffset(Context::GLOBAL_INDEX)));
2512
 
  ldr(target, FieldMemOperand(target, GlobalObject::kBuiltinsOffset));
2513
 
  // Load the JavaScript builtin function from the builtins object.
2514
 
  ldr(target, FieldMemOperand(target,
2515
 
                          JSBuiltinsObject::OffsetOfFunctionWithId(id)));
2516
 
}
2517
 
 
2518
 
 
2519
 
void MacroAssembler::GetBuiltinEntry(Register target, Builtins::JavaScript id) {
2520
 
  ASSERT(!target.is(r1));
2521
 
  GetBuiltinFunction(r1, id);
2522
 
  // Load the code entry point from the builtins object.
2523
 
  ldr(target, FieldMemOperand(r1, JSFunction::kCodeEntryOffset));
2524
 
}
2525
 
 
2526
 
 
2527
 
void MacroAssembler::SetCounter(StatsCounter* counter, int value,
2528
 
                                Register scratch1, Register scratch2) {
2529
 
  if (FLAG_native_code_counters && counter->Enabled()) {
2530
 
    mov(scratch1, Operand(value));
2531
 
    mov(scratch2, Operand(ExternalReference(counter)));
2532
 
    str(scratch1, MemOperand(scratch2));
2533
 
  }
2534
 
}
2535
 
 
2536
 
 
2537
 
void MacroAssembler::IncrementCounter(StatsCounter* counter, int value,
2538
 
                                      Register scratch1, Register scratch2) {
2539
 
  ASSERT(value > 0);
2540
 
  if (FLAG_native_code_counters && counter->Enabled()) {
2541
 
    mov(scratch2, Operand(ExternalReference(counter)));
2542
 
    ldr(scratch1, MemOperand(scratch2));
2543
 
    add(scratch1, scratch1, Operand(value));
2544
 
    str(scratch1, MemOperand(scratch2));
2545
 
  }
2546
 
}
2547
 
 
2548
 
 
2549
 
void MacroAssembler::DecrementCounter(StatsCounter* counter, int value,
2550
 
                                      Register scratch1, Register scratch2) {
2551
 
  ASSERT(value > 0);
2552
 
  if (FLAG_native_code_counters && counter->Enabled()) {
2553
 
    mov(scratch2, Operand(ExternalReference(counter)));
2554
 
    ldr(scratch1, MemOperand(scratch2));
2555
 
    sub(scratch1, scratch1, Operand(value));
2556
 
    str(scratch1, MemOperand(scratch2));
2557
 
  }
2558
 
}
2559
 
 
2560
 
 
2561
 
void MacroAssembler::Assert(Condition cond, const char* msg) {
2562
 
  if (emit_debug_code())
2563
 
    Check(cond, msg);
2564
 
}
2565
 
 
2566
 
 
2567
 
void MacroAssembler::AssertRegisterIsRoot(Register reg,
2568
 
                                          Heap::RootListIndex index) {
2569
 
  if (emit_debug_code()) {
2570
 
    LoadRoot(ip, index);
2571
 
    cmp(reg, ip);
2572
 
    Check(eq, "Register did not match expected root");
2573
 
  }
2574
 
}
2575
 
 
2576
 
 
2577
 
void MacroAssembler::AssertFastElements(Register elements) {
2578
 
  if (emit_debug_code()) {
2579
 
    ASSERT(!elements.is(ip));
2580
 
    Label ok;
2581
 
    push(elements);
2582
 
    ldr(elements, FieldMemOperand(elements, HeapObject::kMapOffset));
2583
 
    LoadRoot(ip, Heap::kFixedArrayMapRootIndex);
2584
 
    cmp(elements, ip);
2585
 
    b(eq, &ok);
2586
 
    LoadRoot(ip, Heap::kFixedDoubleArrayMapRootIndex);
2587
 
    cmp(elements, ip);
2588
 
    b(eq, &ok);
2589
 
    LoadRoot(ip, Heap::kFixedCOWArrayMapRootIndex);
2590
 
    cmp(elements, ip);
2591
 
    b(eq, &ok);
2592
 
    Abort("JSObject with fast elements map has slow elements");
2593
 
    bind(&ok);
2594
 
    pop(elements);
2595
 
  }
2596
 
}
2597
 
 
2598
 
 
2599
 
void MacroAssembler::Check(Condition cond, const char* msg) {
2600
 
  Label L;
2601
 
  b(cond, &L);
2602
 
  Abort(msg);
2603
 
  // will not return here
2604
 
  bind(&L);
2605
 
}
2606
 
 
2607
 
 
2608
 
void MacroAssembler::Abort(const char* msg) {
2609
 
  Label abort_start;
2610
 
  bind(&abort_start);
2611
 
  // We want to pass the msg string like a smi to avoid GC
2612
 
  // problems, however msg is not guaranteed to be aligned
2613
 
  // properly. Instead, we pass an aligned pointer that is
2614
 
  // a proper v8 smi, but also pass the alignment difference
2615
 
  // from the real pointer as a smi.
2616
 
  intptr_t p1 = reinterpret_cast<intptr_t>(msg);
2617
 
  intptr_t p0 = (p1 & ~kSmiTagMask) + kSmiTag;
2618
 
  ASSERT(reinterpret_cast<Object*>(p0)->IsSmi());
2619
 
#ifdef DEBUG
2620
 
  if (msg != NULL) {
2621
 
    RecordComment("Abort message: ");
2622
 
    RecordComment(msg);
2623
 
  }
2624
 
#endif
2625
 
  // Disable stub call restrictions to always allow calls to abort.
2626
 
  AllowStubCallsScope allow_scope(this, true);
2627
 
 
2628
 
  mov(r0, Operand(p0));
2629
 
  push(r0);
2630
 
  mov(r0, Operand(Smi::FromInt(p1 - p0)));
2631
 
  push(r0);
2632
 
  CallRuntime(Runtime::kAbort, 2);
2633
 
  // will not return here
2634
 
  if (is_const_pool_blocked()) {
2635
 
    // If the calling code cares about the exact number of
2636
 
    // instructions generated, we insert padding here to keep the size
2637
 
    // of the Abort macro constant.
2638
 
    static const int kExpectedAbortInstructions = 10;
2639
 
    int abort_instructions = InstructionsGeneratedSince(&abort_start);
2640
 
    ASSERT(abort_instructions <= kExpectedAbortInstructions);
2641
 
    while (abort_instructions++ < kExpectedAbortInstructions) {
2642
 
      nop();
2643
 
    }
2644
 
  }
2645
 
}
2646
 
 
2647
 
 
2648
 
void MacroAssembler::LoadContext(Register dst, int context_chain_length) {
2649
 
  if (context_chain_length > 0) {
2650
 
    // Move up the chain of contexts to the context containing the slot.
2651
 
    ldr(dst, MemOperand(cp, Context::SlotOffset(Context::PREVIOUS_INDEX)));
2652
 
    for (int i = 1; i < context_chain_length; i++) {
2653
 
      ldr(dst, MemOperand(dst, Context::SlotOffset(Context::PREVIOUS_INDEX)));
2654
 
    }
2655
 
  } else {
2656
 
    // Slot is in the current function context.  Move it into the
2657
 
    // destination register in case we store into it (the write barrier
2658
 
    // cannot be allowed to destroy the context in esi).
2659
 
    mov(dst, cp);
2660
 
  }
2661
 
}
2662
 
 
2663
 
 
2664
 
void MacroAssembler::LoadGlobalFunction(int index, Register function) {
2665
 
  // Load the global or builtins object from the current context.
2666
 
  ldr(function, MemOperand(cp, Context::SlotOffset(Context::GLOBAL_INDEX)));
2667
 
  // Load the global context from the global or builtins object.
2668
 
  ldr(function, FieldMemOperand(function,
2669
 
                                GlobalObject::kGlobalContextOffset));
2670
 
  // Load the function from the global context.
2671
 
  ldr(function, MemOperand(function, Context::SlotOffset(index)));
2672
 
}
2673
 
 
2674
 
 
2675
 
void MacroAssembler::LoadGlobalFunctionInitialMap(Register function,
2676
 
                                                  Register map,
2677
 
                                                  Register scratch) {
2678
 
  // Load the initial map. The global functions all have initial maps.
2679
 
  ldr(map, FieldMemOperand(function, JSFunction::kPrototypeOrInitialMapOffset));
2680
 
  if (emit_debug_code()) {
2681
 
    Label ok, fail;
2682
 
    CheckMap(map, scratch, Heap::kMetaMapRootIndex, &fail, DO_SMI_CHECK);
2683
 
    b(&ok);
2684
 
    bind(&fail);
2685
 
    Abort("Global functions must have initial map");
2686
 
    bind(&ok);
2687
 
  }
2688
 
}
2689
 
 
2690
 
 
2691
 
void MacroAssembler::JumpIfNotPowerOfTwoOrZero(
2692
 
    Register reg,
2693
 
    Register scratch,
2694
 
    Label* not_power_of_two_or_zero) {
2695
 
  sub(scratch, reg, Operand(1), SetCC);
2696
 
  b(mi, not_power_of_two_or_zero);
2697
 
  tst(scratch, reg);
2698
 
  b(ne, not_power_of_two_or_zero);
2699
 
}
2700
 
 
2701
 
 
2702
 
void MacroAssembler::JumpIfNotPowerOfTwoOrZeroAndNeg(
2703
 
    Register reg,
2704
 
    Register scratch,
2705
 
    Label* zero_and_neg,
2706
 
    Label* not_power_of_two) {
2707
 
  sub(scratch, reg, Operand(1), SetCC);
2708
 
  b(mi, zero_and_neg);
2709
 
  tst(scratch, reg);
2710
 
  b(ne, not_power_of_two);
2711
 
}
2712
 
 
2713
 
 
2714
 
void MacroAssembler::JumpIfNotBothSmi(Register reg1,
2715
 
                                      Register reg2,
2716
 
                                      Label* on_not_both_smi) {
2717
 
  STATIC_ASSERT(kSmiTag == 0);
2718
 
  tst(reg1, Operand(kSmiTagMask));
2719
 
  tst(reg2, Operand(kSmiTagMask), eq);
2720
 
  b(ne, on_not_both_smi);
2721
 
}
2722
 
 
2723
 
 
2724
 
void MacroAssembler::JumpIfEitherSmi(Register reg1,
2725
 
                                     Register reg2,
2726
 
                                     Label* on_either_smi) {
2727
 
  STATIC_ASSERT(kSmiTag == 0);
2728
 
  tst(reg1, Operand(kSmiTagMask));
2729
 
  tst(reg2, Operand(kSmiTagMask), ne);
2730
 
  b(eq, on_either_smi);
2731
 
}
2732
 
 
2733
 
 
2734
 
void MacroAssembler::AbortIfSmi(Register object) {
2735
 
  STATIC_ASSERT(kSmiTag == 0);
2736
 
  tst(object, Operand(kSmiTagMask));
2737
 
  Assert(ne, "Operand is a smi");
2738
 
}
2739
 
 
2740
 
 
2741
 
void MacroAssembler::AbortIfNotSmi(Register object) {
2742
 
  STATIC_ASSERT(kSmiTag == 0);
2743
 
  tst(object, Operand(kSmiTagMask));
2744
 
  Assert(eq, "Operand is not smi");
2745
 
}
2746
 
 
2747
 
 
2748
 
void MacroAssembler::AbortIfNotString(Register object) {
2749
 
  STATIC_ASSERT(kSmiTag == 0);
2750
 
  tst(object, Operand(kSmiTagMask));
2751
 
  Assert(ne, "Operand is not a string");
2752
 
  push(object);
2753
 
  ldr(object, FieldMemOperand(object, HeapObject::kMapOffset));
2754
 
  CompareInstanceType(object, object, FIRST_NONSTRING_TYPE);
2755
 
  pop(object);
2756
 
  Assert(lo, "Operand is not a string");
2757
 
}
2758
 
 
2759
 
 
2760
 
 
2761
 
void MacroAssembler::AbortIfNotRootValue(Register src,
2762
 
                                         Heap::RootListIndex root_value_index,
2763
 
                                         const char* message) {
2764
 
  CompareRoot(src, root_value_index);
2765
 
  Assert(eq, message);
2766
 
}
2767
 
 
2768
 
 
2769
 
void MacroAssembler::JumpIfNotHeapNumber(Register object,
2770
 
                                         Register heap_number_map,
2771
 
                                         Register scratch,
2772
 
                                         Label* on_not_heap_number) {
2773
 
  ldr(scratch, FieldMemOperand(object, HeapObject::kMapOffset));
2774
 
  AssertRegisterIsRoot(heap_number_map, Heap::kHeapNumberMapRootIndex);
2775
 
  cmp(scratch, heap_number_map);
2776
 
  b(ne, on_not_heap_number);
2777
 
}
2778
 
 
2779
 
 
2780
 
void MacroAssembler::JumpIfNonSmisNotBothSequentialAsciiStrings(
2781
 
    Register first,
2782
 
    Register second,
2783
 
    Register scratch1,
2784
 
    Register scratch2,
2785
 
    Label* failure) {
2786
 
  // Test that both first and second are sequential ASCII strings.
2787
 
  // Assume that they are non-smis.
2788
 
  ldr(scratch1, FieldMemOperand(first, HeapObject::kMapOffset));
2789
 
  ldr(scratch2, FieldMemOperand(second, HeapObject::kMapOffset));
2790
 
  ldrb(scratch1, FieldMemOperand(scratch1, Map::kInstanceTypeOffset));
2791
 
  ldrb(scratch2, FieldMemOperand(scratch2, Map::kInstanceTypeOffset));
2792
 
 
2793
 
  JumpIfBothInstanceTypesAreNotSequentialAscii(scratch1,
2794
 
                                               scratch2,
2795
 
                                               scratch1,
2796
 
                                               scratch2,
2797
 
                                               failure);
2798
 
}
2799
 
 
2800
 
void MacroAssembler::JumpIfNotBothSequentialAsciiStrings(Register first,
2801
 
                                                         Register second,
2802
 
                                                         Register scratch1,
2803
 
                                                         Register scratch2,
2804
 
                                                         Label* failure) {
2805
 
  // Check that neither is a smi.
2806
 
  STATIC_ASSERT(kSmiTag == 0);
2807
 
  and_(scratch1, first, Operand(second));
2808
 
  JumpIfSmi(scratch1, failure);
2809
 
  JumpIfNonSmisNotBothSequentialAsciiStrings(first,
2810
 
                                             second,
2811
 
                                             scratch1,
2812
 
                                             scratch2,
2813
 
                                             failure);
2814
 
}
2815
 
 
2816
 
 
2817
 
// Allocates a heap number or jumps to the need_gc label if the young space
2818
 
// is full and a scavenge is needed.
2819
 
void MacroAssembler::AllocateHeapNumber(Register result,
2820
 
                                        Register scratch1,
2821
 
                                        Register scratch2,
2822
 
                                        Register heap_number_map,
2823
 
                                        Label* gc_required) {
2824
 
  // Allocate an object in the heap for the heap number and tag it as a heap
2825
 
  // object.
2826
 
  AllocateInNewSpace(HeapNumber::kSize,
2827
 
                     result,
2828
 
                     scratch1,
2829
 
                     scratch2,
2830
 
                     gc_required,
2831
 
                     TAG_OBJECT);
2832
 
 
2833
 
  // Store heap number map in the allocated object.
2834
 
  AssertRegisterIsRoot(heap_number_map, Heap::kHeapNumberMapRootIndex);
2835
 
  str(heap_number_map, FieldMemOperand(result, HeapObject::kMapOffset));
2836
 
}
2837
 
 
2838
 
 
2839
 
void MacroAssembler::AllocateHeapNumberWithValue(Register result,
2840
 
                                                 DwVfpRegister value,
2841
 
                                                 Register scratch1,
2842
 
                                                 Register scratch2,
2843
 
                                                 Register heap_number_map,
2844
 
                                                 Label* gc_required) {
2845
 
  AllocateHeapNumber(result, scratch1, scratch2, heap_number_map, gc_required);
2846
 
  sub(scratch1, result, Operand(kHeapObjectTag));
2847
 
  vstr(value, scratch1, HeapNumber::kValueOffset);
2848
 
}
2849
 
 
2850
 
 
2851
 
// Copies a fixed number of fields of heap objects from src to dst.
2852
 
void MacroAssembler::CopyFields(Register dst,
2853
 
                                Register src,
2854
 
                                RegList temps,
2855
 
                                int field_count) {
2856
 
  // At least one bit set in the first 15 registers.
2857
 
  ASSERT((temps & ((1 << 15) - 1)) != 0);
2858
 
  ASSERT((temps & dst.bit()) == 0);
2859
 
  ASSERT((temps & src.bit()) == 0);
2860
 
  // Primitive implementation using only one temporary register.
2861
 
 
2862
 
  Register tmp = no_reg;
2863
 
  // Find a temp register in temps list.
2864
 
  for (int i = 0; i < 15; i++) {
2865
 
    if ((temps & (1 << i)) != 0) {
2866
 
      tmp.set_code(i);
2867
 
      break;
2868
 
    }
2869
 
  }
2870
 
  ASSERT(!tmp.is(no_reg));
2871
 
 
2872
 
  for (int i = 0; i < field_count; i++) {
2873
 
    ldr(tmp, FieldMemOperand(src, i * kPointerSize));
2874
 
    str(tmp, FieldMemOperand(dst, i * kPointerSize));
2875
 
  }
2876
 
}
2877
 
 
2878
 
 
2879
 
void MacroAssembler::CopyBytes(Register src,
2880
 
                               Register dst,
2881
 
                               Register length,
2882
 
                               Register scratch) {
2883
 
  Label align_loop, align_loop_1, word_loop, byte_loop, byte_loop_1, done;
2884
 
 
2885
 
  // Align src before copying in word size chunks.
2886
 
  bind(&align_loop);
2887
 
  cmp(length, Operand(0));
2888
 
  b(eq, &done);
2889
 
  bind(&align_loop_1);
2890
 
  tst(src, Operand(kPointerSize - 1));
2891
 
  b(eq, &word_loop);
2892
 
  ldrb(scratch, MemOperand(src, 1, PostIndex));
2893
 
  strb(scratch, MemOperand(dst, 1, PostIndex));
2894
 
  sub(length, length, Operand(1), SetCC);
2895
 
  b(ne, &byte_loop_1);
2896
 
 
2897
 
  // Copy bytes in word size chunks.
2898
 
  bind(&word_loop);
2899
 
  if (emit_debug_code()) {
2900
 
    tst(src, Operand(kPointerSize - 1));
2901
 
    Assert(eq, "Expecting alignment for CopyBytes");
2902
 
  }
2903
 
  cmp(length, Operand(kPointerSize));
2904
 
  b(lt, &byte_loop);
2905
 
  ldr(scratch, MemOperand(src, kPointerSize, PostIndex));
2906
 
#if CAN_USE_UNALIGNED_ACCESSES
2907
 
  str(scratch, MemOperand(dst, kPointerSize, PostIndex));
2908
 
#else
2909
 
  strb(scratch, MemOperand(dst, 1, PostIndex));
2910
 
  mov(scratch, Operand(scratch, LSR, 8));
2911
 
  strb(scratch, MemOperand(dst, 1, PostIndex));
2912
 
  mov(scratch, Operand(scratch, LSR, 8));
2913
 
  strb(scratch, MemOperand(dst, 1, PostIndex));
2914
 
  mov(scratch, Operand(scratch, LSR, 8));
2915
 
  strb(scratch, MemOperand(dst, 1, PostIndex));
2916
 
#endif
2917
 
  sub(length, length, Operand(kPointerSize));
2918
 
  b(&word_loop);
2919
 
 
2920
 
  // Copy the last bytes if any left.
2921
 
  bind(&byte_loop);
2922
 
  cmp(length, Operand(0));
2923
 
  b(eq, &done);
2924
 
  bind(&byte_loop_1);
2925
 
  ldrb(scratch, MemOperand(src, 1, PostIndex));
2926
 
  strb(scratch, MemOperand(dst, 1, PostIndex));
2927
 
  sub(length, length, Operand(1), SetCC);
2928
 
  b(ne, &byte_loop_1);
2929
 
  bind(&done);
2930
 
}
2931
 
 
2932
 
 
2933
 
void MacroAssembler::CountLeadingZeros(Register zeros,   // Answer.
2934
 
                                       Register source,  // Input.
2935
 
                                       Register scratch) {
2936
 
  ASSERT(!zeros.is(source) || !source.is(scratch));
2937
 
  ASSERT(!zeros.is(scratch));
2938
 
  ASSERT(!scratch.is(ip));
2939
 
  ASSERT(!source.is(ip));
2940
 
  ASSERT(!zeros.is(ip));
2941
 
#ifdef CAN_USE_ARMV5_INSTRUCTIONS
2942
 
  clz(zeros, source);  // This instruction is only supported after ARM5.
2943
 
#else
2944
 
  Move(scratch, source);
2945
 
  mov(zeros, Operand(0, RelocInfo::NONE));
2946
 
  // Top 16.
2947
 
  tst(scratch, Operand(0xffff0000));
2948
 
  add(zeros, zeros, Operand(16), LeaveCC, eq);
2949
 
  mov(scratch, Operand(scratch, LSL, 16), LeaveCC, eq);
2950
 
  // Top 8.
2951
 
  tst(scratch, Operand(0xff000000));
2952
 
  add(zeros, zeros, Operand(8), LeaveCC, eq);
2953
 
  mov(scratch, Operand(scratch, LSL, 8), LeaveCC, eq);
2954
 
  // Top 4.
2955
 
  tst(scratch, Operand(0xf0000000));
2956
 
  add(zeros, zeros, Operand(4), LeaveCC, eq);
2957
 
  mov(scratch, Operand(scratch, LSL, 4), LeaveCC, eq);
2958
 
  // Top 2.
2959
 
  tst(scratch, Operand(0xc0000000));
2960
 
  add(zeros, zeros, Operand(2), LeaveCC, eq);
2961
 
  mov(scratch, Operand(scratch, LSL, 2), LeaveCC, eq);
2962
 
  // Top bit.
2963
 
  tst(scratch, Operand(0x80000000u));
2964
 
  add(zeros, zeros, Operand(1), LeaveCC, eq);
2965
 
#endif
2966
 
}
2967
 
 
2968
 
 
2969
 
void MacroAssembler::JumpIfBothInstanceTypesAreNotSequentialAscii(
2970
 
    Register first,
2971
 
    Register second,
2972
 
    Register scratch1,
2973
 
    Register scratch2,
2974
 
    Label* failure) {
2975
 
  int kFlatAsciiStringMask =
2976
 
      kIsNotStringMask | kStringEncodingMask | kStringRepresentationMask;
2977
 
  int kFlatAsciiStringTag = ASCII_STRING_TYPE;
2978
 
  and_(scratch1, first, Operand(kFlatAsciiStringMask));
2979
 
  and_(scratch2, second, Operand(kFlatAsciiStringMask));
2980
 
  cmp(scratch1, Operand(kFlatAsciiStringTag));
2981
 
  // Ignore second test if first test failed.
2982
 
  cmp(scratch2, Operand(kFlatAsciiStringTag), eq);
2983
 
  b(ne, failure);
2984
 
}
2985
 
 
2986
 
 
2987
 
void MacroAssembler::JumpIfInstanceTypeIsNotSequentialAscii(Register type,
2988
 
                                                            Register scratch,
2989
 
                                                            Label* failure) {
2990
 
  int kFlatAsciiStringMask =
2991
 
      kIsNotStringMask | kStringEncodingMask | kStringRepresentationMask;
2992
 
  int kFlatAsciiStringTag = ASCII_STRING_TYPE;
2993
 
  and_(scratch, type, Operand(kFlatAsciiStringMask));
2994
 
  cmp(scratch, Operand(kFlatAsciiStringTag));
2995
 
  b(ne, failure);
2996
 
}
2997
 
 
2998
 
static const int kRegisterPassedArguments = 4;
2999
 
 
3000
 
 
3001
 
int MacroAssembler::CalculateStackPassedWords(int num_reg_arguments,
3002
 
                                              int num_double_arguments) {
3003
 
  int stack_passed_words = 0;
3004
 
  if (use_eabi_hardfloat()) {
3005
 
    // In the hard floating point calling convention, we can use
3006
 
    // all double registers to pass doubles.
3007
 
    if (num_double_arguments > DoubleRegister::kNumRegisters) {
3008
 
      stack_passed_words +=
3009
 
          2 * (num_double_arguments - DoubleRegister::kNumRegisters);
3010
 
    }
3011
 
  } else {
3012
 
    // In the soft floating point calling convention, every double
3013
 
    // argument is passed using two registers.
3014
 
    num_reg_arguments += 2 * num_double_arguments;
3015
 
  }
3016
 
  // Up to four simple arguments are passed in registers r0..r3.
3017
 
  if (num_reg_arguments > kRegisterPassedArguments) {
3018
 
    stack_passed_words += num_reg_arguments - kRegisterPassedArguments;
3019
 
  }
3020
 
  return stack_passed_words;
3021
 
}
3022
 
 
3023
 
 
3024
 
void MacroAssembler::PrepareCallCFunction(int num_reg_arguments,
3025
 
                                          int num_double_arguments,
3026
 
                                          Register scratch) {
3027
 
  int frame_alignment = ActivationFrameAlignment();
3028
 
  int stack_passed_arguments = CalculateStackPassedWords(
3029
 
      num_reg_arguments, num_double_arguments);
3030
 
  if (frame_alignment > kPointerSize) {
3031
 
    // Make stack end at alignment and make room for num_arguments - 4 words
3032
 
    // and the original value of sp.
3033
 
    mov(scratch, sp);
3034
 
    sub(sp, sp, Operand((stack_passed_arguments + 1) * kPointerSize));
3035
 
    ASSERT(IsPowerOf2(frame_alignment));
3036
 
    and_(sp, sp, Operand(-frame_alignment));
3037
 
    str(scratch, MemOperand(sp, stack_passed_arguments * kPointerSize));
3038
 
  } else {
3039
 
    sub(sp, sp, Operand(stack_passed_arguments * kPointerSize));
3040
 
  }
3041
 
}
3042
 
 
3043
 
 
3044
 
void MacroAssembler::PrepareCallCFunction(int num_reg_arguments,
3045
 
                                          Register scratch) {
3046
 
  PrepareCallCFunction(num_reg_arguments, 0, scratch);
3047
 
}
3048
 
 
3049
 
 
3050
 
void MacroAssembler::SetCallCDoubleArguments(DoubleRegister dreg) {
3051
 
  if (use_eabi_hardfloat()) {
3052
 
    Move(d0, dreg);
3053
 
  } else {
3054
 
    vmov(r0, r1, dreg);
3055
 
  }
3056
 
}
3057
 
 
3058
 
 
3059
 
void MacroAssembler::SetCallCDoubleArguments(DoubleRegister dreg1,
3060
 
                                             DoubleRegister dreg2) {
3061
 
  if (use_eabi_hardfloat()) {
3062
 
    if (dreg2.is(d0)) {
3063
 
      ASSERT(!dreg1.is(d1));
3064
 
      Move(d1, dreg2);
3065
 
      Move(d0, dreg1);
3066
 
    } else {
3067
 
      Move(d0, dreg1);
3068
 
      Move(d1, dreg2);
3069
 
    }
3070
 
  } else {
3071
 
    vmov(r0, r1, dreg1);
3072
 
    vmov(r2, r3, dreg2);
3073
 
  }
3074
 
}
3075
 
 
3076
 
 
3077
 
void MacroAssembler::SetCallCDoubleArguments(DoubleRegister dreg,
3078
 
                                             Register reg) {
3079
 
  if (use_eabi_hardfloat()) {
3080
 
    Move(d0, dreg);
3081
 
    Move(r0, reg);
3082
 
  } else {
3083
 
    Move(r2, reg);
3084
 
    vmov(r0, r1, dreg);
3085
 
  }
3086
 
}
3087
 
 
3088
 
 
3089
 
void MacroAssembler::CallCFunction(ExternalReference function,
3090
 
                                   int num_reg_arguments,
3091
 
                                   int num_double_arguments) {
3092
 
  CallCFunctionHelper(no_reg,
3093
 
                      function,
3094
 
                      ip,
3095
 
                      num_reg_arguments,
3096
 
                      num_double_arguments);
3097
 
}
3098
 
 
3099
 
 
3100
 
void MacroAssembler::CallCFunction(Register function,
3101
 
                                     Register scratch,
3102
 
                                     int num_reg_arguments,
3103
 
                                     int num_double_arguments) {
3104
 
  CallCFunctionHelper(function,
3105
 
                      ExternalReference::the_hole_value_location(isolate()),
3106
 
                      scratch,
3107
 
                      num_reg_arguments,
3108
 
                      num_double_arguments);
3109
 
}
3110
 
 
3111
 
 
3112
 
void MacroAssembler::CallCFunction(ExternalReference function,
3113
 
                                   int num_arguments) {
3114
 
  CallCFunction(function, num_arguments, 0);
3115
 
}
3116
 
 
3117
 
 
3118
 
void MacroAssembler::CallCFunction(Register function,
3119
 
                                   Register scratch,
3120
 
                                   int num_arguments) {
3121
 
  CallCFunction(function, scratch, num_arguments, 0);
3122
 
}
3123
 
 
3124
 
 
3125
 
void MacroAssembler::CallCFunctionHelper(Register function,
3126
 
                                         ExternalReference function_reference,
3127
 
                                         Register scratch,
3128
 
                                         int num_reg_arguments,
3129
 
                                         int num_double_arguments) {
3130
 
  // Make sure that the stack is aligned before calling a C function unless
3131
 
  // running in the simulator. The simulator has its own alignment check which
3132
 
  // provides more information.
3133
 
#if defined(V8_HOST_ARCH_ARM)
3134
 
  if (emit_debug_code()) {
3135
 
    int frame_alignment = OS::ActivationFrameAlignment();
3136
 
    int frame_alignment_mask = frame_alignment - 1;
3137
 
    if (frame_alignment > kPointerSize) {
3138
 
      ASSERT(IsPowerOf2(frame_alignment));
3139
 
      Label alignment_as_expected;
3140
 
      tst(sp, Operand(frame_alignment_mask));
3141
 
      b(eq, &alignment_as_expected);
3142
 
      // Don't use Check here, as it will call Runtime_Abort possibly
3143
 
      // re-entering here.
3144
 
      stop("Unexpected alignment");
3145
 
      bind(&alignment_as_expected);
3146
 
    }
3147
 
  }
3148
 
#endif
3149
 
 
3150
 
  // Just call directly. The function called cannot cause a GC, or
3151
 
  // allow preemption, so the return address in the link register
3152
 
  // stays correct.
3153
 
  if (function.is(no_reg)) {
3154
 
    mov(scratch, Operand(function_reference));
3155
 
    function = scratch;
3156
 
  }
3157
 
  Call(function);
3158
 
  int stack_passed_arguments = CalculateStackPassedWords(
3159
 
      num_reg_arguments, num_double_arguments);
3160
 
  if (ActivationFrameAlignment() > kPointerSize) {
3161
 
    ldr(sp, MemOperand(sp, stack_passed_arguments * kPointerSize));
3162
 
  } else {
3163
 
    add(sp, sp, Operand(stack_passed_arguments * sizeof(kPointerSize)));
3164
 
  }
3165
 
}
3166
 
 
3167
 
 
3168
 
void MacroAssembler::GetRelocatedValueLocation(Register ldr_location,
3169
 
                               Register result) {
3170
 
  const uint32_t kLdrOffsetMask = (1 << 12) - 1;
3171
 
  const int32_t kPCRegOffset = 2 * kPointerSize;
3172
 
  ldr(result, MemOperand(ldr_location));
3173
 
  if (emit_debug_code()) {
3174
 
    // Check that the instruction is a ldr reg, [pc + offset] .
3175
 
    and_(result, result, Operand(kLdrPCPattern));
3176
 
    cmp(result, Operand(kLdrPCPattern));
3177
 
    Check(eq, "The instruction to patch should be a load from pc.");
3178
 
    // Result was clobbered. Restore it.
3179
 
    ldr(result, MemOperand(ldr_location));
3180
 
  }
3181
 
  // Get the address of the constant.
3182
 
  and_(result, result, Operand(kLdrOffsetMask));
3183
 
  add(result, ldr_location, Operand(result));
3184
 
  add(result, result, Operand(kPCRegOffset));
3185
 
}
3186
 
 
3187
 
 
3188
 
void MacroAssembler::ClampUint8(Register output_reg, Register input_reg) {
3189
 
  Usat(output_reg, 8, Operand(input_reg));
3190
 
}
3191
 
 
3192
 
 
3193
 
void MacroAssembler::ClampDoubleToUint8(Register result_reg,
3194
 
                                        DoubleRegister input_reg,
3195
 
                                        DoubleRegister temp_double_reg) {
3196
 
  Label above_zero;
3197
 
  Label done;
3198
 
  Label in_bounds;
3199
 
 
3200
 
  Vmov(temp_double_reg, 0.0);
3201
 
  VFPCompareAndSetFlags(input_reg, temp_double_reg);
3202
 
  b(gt, &above_zero);
3203
 
 
3204
 
  // Double value is less than zero, NaN or Inf, return 0.
3205
 
  mov(result_reg, Operand(0));
3206
 
  b(al, &done);
3207
 
 
3208
 
  // Double value is >= 255, return 255.
3209
 
  bind(&above_zero);
3210
 
  Vmov(temp_double_reg, 255.0);
3211
 
  VFPCompareAndSetFlags(input_reg, temp_double_reg);
3212
 
  b(le, &in_bounds);
3213
 
  mov(result_reg, Operand(255));
3214
 
  b(al, &done);
3215
 
 
3216
 
  // In 0-255 range, round and truncate.
3217
 
  bind(&in_bounds);
3218
 
  Vmov(temp_double_reg, 0.5);
3219
 
  vadd(temp_double_reg, input_reg, temp_double_reg);
3220
 
  vcvt_u32_f64(s0, temp_double_reg);
3221
 
  vmov(result_reg, s0);
3222
 
  bind(&done);
3223
 
}
3224
 
 
3225
 
 
3226
 
void MacroAssembler::LoadInstanceDescriptors(Register map,
3227
 
                                             Register descriptors) {
3228
 
  ldr(descriptors,
3229
 
      FieldMemOperand(map, Map::kInstanceDescriptorsOrBitField3Offset));
3230
 
  Label not_smi;
3231
 
  JumpIfNotSmi(descriptors, &not_smi);
3232
 
  mov(descriptors, Operand(FACTORY->empty_descriptor_array()));
3233
 
  bind(&not_smi);
3234
 
}
3235
 
 
3236
 
 
3237
 
CodePatcher::CodePatcher(byte* address, int instructions)
3238
 
    : address_(address),
3239
 
      instructions_(instructions),
3240
 
      size_(instructions * Assembler::kInstrSize),
3241
 
      masm_(Isolate::Current(), address, size_ + Assembler::kGap) {
3242
 
  // Create a new macro assembler pointing to the address of the code to patch.
3243
 
  // The size is adjusted with kGap on order for the assembler to generate size
3244
 
  // bytes of instructions without failing with buffer size constraints.
3245
 
  ASSERT(masm_.reloc_info_writer.pos() == address_ + size_ + Assembler::kGap);
3246
 
}
3247
 
 
3248
 
 
3249
 
CodePatcher::~CodePatcher() {
3250
 
  // Indicate that code has changed.
3251
 
  CPU::FlushICache(address_, size_);
3252
 
 
3253
 
  // Check that the code was patched as expected.
3254
 
  ASSERT(masm_.pc_ == address_ + size_);
3255
 
  ASSERT(masm_.reloc_info_writer.pos() == address_ + size_ + Assembler::kGap);
3256
 
}
3257
 
 
3258
 
 
3259
 
void CodePatcher::Emit(Instr instr) {
3260
 
  masm()->emit(instr);
3261
 
}
3262
 
 
3263
 
 
3264
 
void CodePatcher::Emit(Address addr) {
3265
 
  masm()->emit(reinterpret_cast<Instr>(addr));
3266
 
}
3267
 
 
3268
 
 
3269
 
void CodePatcher::EmitCondition(Condition cond) {
3270
 
  Instr instr = Assembler::instr_at(masm_.pc_);
3271
 
  instr = (instr & ~kCondMask) | cond;
3272
 
  masm_.emit(instr);
3273
 
}
3274
 
 
3275
 
 
3276
 
} }  // namespace v8::internal
3277
 
 
3278
 
#endif  // V8_TARGET_ARCH_ARM