macro-assembler-ia32.cc revision 4515c472dc3e5ed2448a564600976759e569a0a8
1a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// Copyright 2006-2009 the V8 project authors. All rights reserved.
2a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// Redistribution and use in source and binary forms, with or without
3a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// modification, are permitted provided that the following conditions are
4a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// met:
5a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block//
6a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block//     * Redistributions of source code must retain the above copyright
7a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block//       notice, this list of conditions and the following disclaimer.
8a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block//     * Redistributions in binary form must reproduce the above
9a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block//       copyright notice, this list of conditions and the following
10a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block//       disclaimer in the documentation and/or other materials provided
11a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block//       with the distribution.
12a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block//     * Neither the name of Google Inc. nor the names of its
13a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block//       contributors may be used to endorse or promote products derived
14a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block//       from this software without specific prior written permission.
15a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block//
16a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
28a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#include "v8.h"
29a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
30a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#include "bootstrapper.h"
31a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#include "codegen-inl.h"
32a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#include "debug.h"
33a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#include "runtime.h"
34a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#include "serialize.h"
35a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
36a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blocknamespace v8 {
37a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blocknamespace internal {
38a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
39a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// -------------------------------------------------------------------------
40a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// MacroAssembler implementation.
41a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
42a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockMacroAssembler::MacroAssembler(void* buffer, int size)
43a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    : Assembler(buffer, size),
44a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      unresolved_(0),
45a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      generating_stub_(false),
46a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      allow_stub_calls_(true),
47a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      code_object_(Heap::undefined_value()) {
48a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
49a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
50a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
51a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockstatic void RecordWriteHelper(MacroAssembler* masm,
52a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                              Register object,
53a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                              Register addr,
54a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                              Register scratch) {
55a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Label fast;
56a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
57a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Compute the page start address from the heap object pointer, and reuse
58a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // the 'object' register for it.
59a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  masm->and_(object, ~Page::kPageAlignmentMask);
60a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Register page_start = object;
61a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
62a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Compute the bit addr in the remembered set/index of the pointer in the
63a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // page. Reuse 'addr' as pointer_offset.
64a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  masm->sub(addr, Operand(page_start));
65a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  masm->shr(addr, kObjectAlignmentBits);
66a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Register pointer_offset = addr;
67a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
68a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // If the bit offset lies beyond the normal remembered set range, it is in
69a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // the extra remembered set area of a large object.
70a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  masm->cmp(pointer_offset, Page::kPageSize / kPointerSize);
71a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  masm->j(less, &fast);
72a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
73a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Adjust 'page_start' so that addressing using 'pointer_offset' hits the
74a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // extra remembered set after the large object.
75a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
76a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Find the length of the large object (FixedArray).
77a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  masm->mov(scratch, Operand(page_start, Page::kObjectStartOffset
78a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                         + FixedArray::kLengthOffset));
79a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Register array_length = scratch;
80a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
81a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Extra remembered set starts right after the large object (a FixedArray), at
82a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //   page_start + kObjectStartOffset + objectSize
83a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // where objectSize is FixedArray::kHeaderSize + kPointerSize * array_length.
84a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Add the delta between the end of the normal RSet and the start of the
85a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // extra RSet to 'page_start', so that addressing the bit using
86a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // 'pointer_offset' hits the extra RSet words.
87a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  masm->lea(page_start,
88a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block            Operand(page_start, array_length, times_pointer_size,
89a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                    Page::kObjectStartOffset + FixedArray::kHeaderSize
90a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                        - Page::kRSetEndOffset));
91a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
92a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // NOTE: For now, we use the bit-test-and-set (bts) x86 instruction
93a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // to limit code size. We should probably evaluate this decision by
94a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // measuring the performance of an equivalent implementation using
95a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // "simpler" instructions
96a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  masm->bind(&fast);
97a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  masm->bts(Operand(page_start, Page::kRSetOffset), pointer_offset);
98a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
99a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
100a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
101a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockclass RecordWriteStub : public CodeStub {
102a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block public:
103a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  RecordWriteStub(Register object, Register addr, Register scratch)
104a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      : object_(object), addr_(addr), scratch_(scratch) { }
105a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
106a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  void Generate(MacroAssembler* masm);
107a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
108a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block private:
109a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Register object_;
110a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Register addr_;
111a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Register scratch_;
112a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
113a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#ifdef DEBUG
114a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  void Print() {
115a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    PrintF("RecordWriteStub (object reg %d), (addr reg %d), (scratch reg %d)\n",
116a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block           object_.code(), addr_.code(), scratch_.code());
117a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
118a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#endif
119a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
120a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Minor key encoding in 12 bits of three registers (object, address and
121a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // scratch) OOOOAAAASSSS.
122a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  class ScratchBits: public BitField<uint32_t, 0, 4> {};
123a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  class AddressBits: public BitField<uint32_t, 4, 4> {};
124a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  class ObjectBits: public BitField<uint32_t, 8, 4> {};
125a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
126a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Major MajorKey() { return RecordWrite; }
127a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
128a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  int MinorKey() {
129a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Encode the registers.
130a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    return ObjectBits::encode(object_.code()) |
131a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block           AddressBits::encode(addr_.code()) |
132a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block           ScratchBits::encode(scratch_.code());
133a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
134a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block};
135a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
136a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
137a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid RecordWriteStub::Generate(MacroAssembler* masm) {
138a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  RecordWriteHelper(masm, object_, addr_, scratch_);
139a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  masm->ret(0);
140a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
141a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
142a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
143a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// Set the remembered set bit for [object+offset].
144a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// object is the object being stored into, value is the object being stored.
145a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// If offset is zero, then the scratch register contains the array index into
146a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// the elements array represented as a Smi.
147a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// All registers are clobbered by the operation.
148a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid MacroAssembler::RecordWrite(Register object, int offset,
149a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                 Register value, Register scratch) {
1504515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  // The compiled code assumes that record write doesn't change the
1514515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  // context register, so we check that none of the clobbered
1524515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  // registers are esi.
1534515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  ASSERT(!object.is(esi) && !value.is(esi) && !scratch.is(esi));
1544515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke
155a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // First, check if a remembered set write is even needed. The tests below
156a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // catch stores of Smis and stores into young gen (which does not have space
157a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // for the remembered set bits.
158a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Label done;
159a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
160a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Skip barrier if writing a smi.
161a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT_EQ(0, kSmiTag);
162a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  test(value, Immediate(kSmiTagMask));
163a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  j(zero, &done);
164a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
165a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (Serializer::enabled()) {
166a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Can't do arithmetic on external references if it might get serialized.
167a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    mov(value, Operand(object));
168a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    and_(value, Heap::NewSpaceMask());
169a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    cmp(Operand(value), Immediate(ExternalReference::new_space_start()));
170a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    j(equal, &done);
171a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  } else {
172a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    int32_t new_space_start = reinterpret_cast<int32_t>(
173a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        ExternalReference::new_space_start().address());
174a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    lea(value, Operand(object, -new_space_start));
175a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    and_(value, Heap::NewSpaceMask());
176a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    j(equal, &done);
177a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
178a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
179a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if ((offset > 0) && (offset < Page::kMaxHeapObjectSize)) {
180a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Compute the bit offset in the remembered set, leave it in 'value'.
181a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    lea(value, Operand(object, offset));
182a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    and_(value, Page::kPageAlignmentMask);
183a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    shr(value, kPointerSizeLog2);
184a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
185a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Compute the page address from the heap object pointer, leave it in
186a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // 'object'.
187a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    and_(object, ~Page::kPageAlignmentMask);
188a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
189a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // NOTE: For now, we use the bit-test-and-set (bts) x86 instruction
190a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // to limit code size. We should probably evaluate this decision by
191a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // measuring the performance of an equivalent implementation using
192a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // "simpler" instructions
193a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    bts(Operand(object, Page::kRSetOffset), value);
194a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  } else {
195a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    Register dst = scratch;
196a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (offset != 0) {
197a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      lea(dst, Operand(object, offset));
198a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    } else {
199a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // array access: calculate the destination address in the same manner as
200a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // KeyedStoreIC::GenerateGeneric.  Multiply a smi by 2 to get an offset
201a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // into an array of words.
202a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      ASSERT_EQ(1, kSmiTagSize);
203a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      ASSERT_EQ(0, kSmiTag);
204a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      lea(dst, Operand(object, dst, times_half_pointer_size,
205a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                       FixedArray::kHeaderSize - kHeapObjectTag));
206a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
207a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // If we are already generating a shared stub, not inlining the
208a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // record write code isn't going to save us any memory.
209a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (generating_stub()) {
210a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      RecordWriteHelper(this, object, dst, value);
211a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    } else {
212a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      RecordWriteStub stub(object, dst, value);
213a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      CallStub(&stub);
214a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
215a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
216a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
217a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  bind(&done);
2184515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke
2194515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  // Clobber all input registers when running with the debug-code flag
2204515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  // turned on to provoke errors.
2214515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  if (FLAG_debug_code) {
2224515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke    mov(object, Immediate(bit_cast<int32_t>(kZapValue)));
2234515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke    mov(value, Immediate(bit_cast<int32_t>(kZapValue)));
2244515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke    mov(scratch, Immediate(bit_cast<int32_t>(kZapValue)));
2254515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  }
226a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
227a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
228a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
229d0582a6c46733687d045e4188a1bcd0123c758a1Steve Blockvoid MacroAssembler::StackLimitCheck(Label* on_stack_overflow) {
230d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  cmp(esp,
231d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block      Operand::StaticVariable(ExternalReference::address_of_stack_limit()));
232d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  j(below, on_stack_overflow);
233d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block}
234d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
235d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
236a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#ifdef ENABLE_DEBUGGER_SUPPORT
237a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid MacroAssembler::SaveRegistersToMemory(RegList regs) {
238a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT((regs & ~kJSCallerSaved) == 0);
239a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Copy the content of registers to memory location.
240a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  for (int i = 0; i < kNumJSCallerSaved; i++) {
241a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    int r = JSCallerSavedCode(i);
242a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if ((regs & (1 << r)) != 0) {
243a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      Register reg = { r };
244a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      ExternalReference reg_addr =
245a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block          ExternalReference(Debug_Address::Register(i));
246a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      mov(Operand::StaticVariable(reg_addr), reg);
247a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
248a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
249a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
250a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
251a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
252a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid MacroAssembler::RestoreRegistersFromMemory(RegList regs) {
253a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT((regs & ~kJSCallerSaved) == 0);
254a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Copy the content of memory location to registers.
255a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  for (int i = kNumJSCallerSaved; --i >= 0;) {
256a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    int r = JSCallerSavedCode(i);
257a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if ((regs & (1 << r)) != 0) {
258a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      Register reg = { r };
259a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      ExternalReference reg_addr =
260a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block          ExternalReference(Debug_Address::Register(i));
261a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      mov(reg, Operand::StaticVariable(reg_addr));
262a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
263a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
264a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
265a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
266a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
267a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid MacroAssembler::PushRegistersFromMemory(RegList regs) {
268a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT((regs & ~kJSCallerSaved) == 0);
269a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Push the content of the memory location to the stack.
270a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  for (int i = 0; i < kNumJSCallerSaved; i++) {
271a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    int r = JSCallerSavedCode(i);
272a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if ((regs & (1 << r)) != 0) {
273a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      ExternalReference reg_addr =
274a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block          ExternalReference(Debug_Address::Register(i));
275a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      push(Operand::StaticVariable(reg_addr));
276a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
277a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
278a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
279a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
280a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
281a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid MacroAssembler::PopRegistersToMemory(RegList regs) {
282a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT((regs & ~kJSCallerSaved) == 0);
283a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Pop the content from the stack to the memory location.
284a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  for (int i = kNumJSCallerSaved; --i >= 0;) {
285a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    int r = JSCallerSavedCode(i);
286a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if ((regs & (1 << r)) != 0) {
287a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      ExternalReference reg_addr =
288a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block          ExternalReference(Debug_Address::Register(i));
289a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      pop(Operand::StaticVariable(reg_addr));
290a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
291a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
292a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
293a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
294a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
295a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid MacroAssembler::CopyRegistersFromStackToMemory(Register base,
296a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                                    Register scratch,
297a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                                    RegList regs) {
298a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT((regs & ~kJSCallerSaved) == 0);
299a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Copy the content of the stack to the memory location and adjust base.
300a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  for (int i = kNumJSCallerSaved; --i >= 0;) {
301a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    int r = JSCallerSavedCode(i);
302a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if ((regs & (1 << r)) != 0) {
303a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      mov(scratch, Operand(base, 0));
304a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      ExternalReference reg_addr =
305a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block          ExternalReference(Debug_Address::Register(i));
306a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      mov(Operand::StaticVariable(reg_addr), scratch);
307a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      lea(base, Operand(base, kPointerSize));
308a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
309a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
310a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
311a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#endif
312a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
313a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid MacroAssembler::Set(Register dst, const Immediate& x) {
314a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (x.is_zero()) {
315a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    xor_(dst, Operand(dst));  // shorter than mov
316a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  } else {
317a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    mov(dst, x);
318a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
319a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
320a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
321a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
322a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid MacroAssembler::Set(const Operand& dst, const Immediate& x) {
323a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  mov(dst, x);
324a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
325a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
326a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
327a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid MacroAssembler::CmpObjectType(Register heap_object,
328a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                   InstanceType type,
329a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                   Register map) {
330a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  mov(map, FieldOperand(heap_object, HeapObject::kMapOffset));
331a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CmpInstanceType(map, type);
332a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
333a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
334a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
335a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid MacroAssembler::CmpInstanceType(Register map, InstanceType type) {
336a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  cmpb(FieldOperand(map, Map::kInstanceTypeOffset),
337a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block       static_cast<int8_t>(type));
338a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
339a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
340a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
341e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon ClarkeCondition MacroAssembler::IsObjectStringType(Register heap_object,
342e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke                                             Register map,
343e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke                                             Register instance_type) {
344e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  mov(map, FieldOperand(heap_object, HeapObject::kMapOffset));
345e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  movzx_b(instance_type, FieldOperand(map, Map::kInstanceTypeOffset));
346e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  ASSERT(kNotStringTag != 0);
347e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  test(instance_type, Immediate(kIsNotStringMask));
348e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  return zero;
349e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke}
350e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
351e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
352a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid MacroAssembler::FCmp() {
353d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  if (CpuFeatures::IsSupported(CMOV)) {
3543ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    fucomip();
3553ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    ffree(0);
3563ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    fincstp();
3573ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  } else {
3583ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    fucompp();
3593ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    push(eax);
3603ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    fnstsw_ax();
3613ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    sahf();
3623ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    pop(eax);
3633ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  }
364a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
365a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
366a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
367a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid MacroAssembler::EnterFrame(StackFrame::Type type) {
368a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  push(ebp);
369a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  mov(ebp, Operand(esp));
370a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  push(esi);
371a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  push(Immediate(Smi::FromInt(type)));
372a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  push(Immediate(CodeObject()));
373a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (FLAG_debug_code) {
374a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    cmp(Operand(esp, 0), Immediate(Factory::undefined_value()));
375a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    Check(not_equal, "code object not properly patched");
376a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
377a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
378a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
379a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
380a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid MacroAssembler::LeaveFrame(StackFrame::Type type) {
381a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (FLAG_debug_code) {
382a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    cmp(Operand(ebp, StandardFrameConstants::kMarkerOffset),
383a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        Immediate(Smi::FromInt(type)));
384a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    Check(equal, "stack frame types must match");
385a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
386a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  leave();
387a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
388a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
389d0582a6c46733687d045e4188a1bcd0123c758a1Steve Blockvoid MacroAssembler::EnterExitFramePrologue(ExitFrame::Mode mode) {
390a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Setup the frame structure on the stack.
391a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(ExitFrameConstants::kCallerSPDisplacement == +2 * kPointerSize);
392a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(ExitFrameConstants::kCallerPCOffset == +1 * kPointerSize);
393a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(ExitFrameConstants::kCallerFPOffset ==  0 * kPointerSize);
394a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  push(ebp);
395a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  mov(ebp, Operand(esp));
396a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
397a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Reserve room for entry stack pointer and push the debug marker.
398a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(ExitFrameConstants::kSPOffset  == -1 * kPointerSize);
399a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  push(Immediate(0));  // saved entry sp, patched before call
400d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  if (mode == ExitFrame::MODE_DEBUG) {
401d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    push(Immediate(0));
402d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  } else {
403d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    push(Immediate(CodeObject()));
404d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  }
405a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
406a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Save the frame pointer and the context in top.
407a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ExternalReference c_entry_fp_address(Top::k_c_entry_fp_address);
408a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ExternalReference context_address(Top::k_context_address);
409a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  mov(Operand::StaticVariable(c_entry_fp_address), ebp);
410a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  mov(Operand::StaticVariable(context_address), esi);
411d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block}
412a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
413d0582a6c46733687d045e4188a1bcd0123c758a1Steve Blockvoid MacroAssembler::EnterExitFrameEpilogue(ExitFrame::Mode mode, int argc) {
414a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#ifdef ENABLE_DEBUGGER_SUPPORT
415a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Save the state of all registers to the stack from the memory
416a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // location. This is needed to allow nested break points.
417d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  if (mode == ExitFrame::MODE_DEBUG) {
418a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // TODO(1243899): This should be symmetric to
419a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // CopyRegistersFromStackToMemory() but it isn't! esp is assumed
420a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // correct here, but computed for the other call. Very error
421a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // prone! FIX THIS.  Actually there are deeper problems with
422a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // register saving than this asymmetry (see the bug report
423a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // associated with this issue).
424a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    PushRegistersFromMemory(kJSCallerSaved);
425a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
426a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#endif
427a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
428d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  // Reserve space for arguments.
429d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  sub(Operand(esp), Immediate(argc * kPointerSize));
430a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
431a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Get the required frame alignment for the OS.
432a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  static const int kFrameAlignment = OS::ActivationFrameAlignment();
433a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (kFrameAlignment > 0) {
434a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    ASSERT(IsPowerOf2(kFrameAlignment));
435a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    and_(esp, -kFrameAlignment);
436a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
437a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
438a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Patch the saved entry sp.
439a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  mov(Operand(ebp, ExitFrameConstants::kSPOffset), esp);
440a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
441a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
442a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
443d0582a6c46733687d045e4188a1bcd0123c758a1Steve Blockvoid MacroAssembler::EnterExitFrame(ExitFrame::Mode mode) {
444d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  EnterExitFramePrologue(mode);
445d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
446d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  // Setup argc and argv in callee-saved registers.
447d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  int offset = StandardFrameConstants::kCallerSPOffset - kPointerSize;
448d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  mov(edi, Operand(eax));
449d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  lea(esi, Operand(ebp, eax, times_4, offset));
450d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
451d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  EnterExitFrameEpilogue(mode, 2);
452d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block}
453d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
454d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
455d0582a6c46733687d045e4188a1bcd0123c758a1Steve Blockvoid MacroAssembler::EnterApiExitFrame(ExitFrame::Mode mode,
456d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block                                       int stack_space,
457d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block                                       int argc) {
458d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  EnterExitFramePrologue(mode);
459d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
460d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  int offset = StandardFrameConstants::kCallerSPOffset - kPointerSize;
461d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  lea(esi, Operand(ebp, (stack_space * kPointerSize) + offset));
462d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
463d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  EnterExitFrameEpilogue(mode, argc);
464d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block}
465d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
466d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
467d0582a6c46733687d045e4188a1bcd0123c758a1Steve Blockvoid MacroAssembler::LeaveExitFrame(ExitFrame::Mode mode) {
468a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#ifdef ENABLE_DEBUGGER_SUPPORT
469a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Restore the memory copy of the registers by digging them out from
470a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // the stack. This is needed to allow nested break points.
471d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  if (mode == ExitFrame::MODE_DEBUG) {
472a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // It's okay to clobber register ebx below because we don't need
473a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // the function pointer after this.
474a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    const int kCallerSavedSize = kNumJSCallerSaved * kPointerSize;
475d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    int kOffset = ExitFrameConstants::kCodeOffset - kCallerSavedSize;
476a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    lea(ebx, Operand(ebp, kOffset));
477a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    CopyRegistersFromStackToMemory(ebx, ecx, kJSCallerSaved);
478a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
479a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#endif
480a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
481a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Get the return address from the stack and restore the frame pointer.
482a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  mov(ecx, Operand(ebp, 1 * kPointerSize));
483a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  mov(ebp, Operand(ebp, 0 * kPointerSize));
484a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
485a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Pop the arguments and the receiver from the caller stack.
486a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  lea(esp, Operand(esi, 1 * kPointerSize));
487a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
488a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Restore current context from top and clear it in debug mode.
489a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ExternalReference context_address(Top::k_context_address);
490a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  mov(esi, Operand::StaticVariable(context_address));
491a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#ifdef DEBUG
492a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  mov(Operand::StaticVariable(context_address), Immediate(0));
493a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#endif
494a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
495a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Push the return address to get ready to return.
496a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  push(ecx);
497a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
498a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Clear the top frame.
499a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ExternalReference c_entry_fp_address(Top::k_c_entry_fp_address);
500a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  mov(Operand::StaticVariable(c_entry_fp_address), Immediate(0));
501a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
502a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
503a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
504a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid MacroAssembler::PushTryHandler(CodeLocation try_location,
505a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                    HandlerType type) {
506a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Adjust this code if not the case.
507a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(StackHandlerConstants::kSize == 4 * kPointerSize);
508a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // The pc (return address) is already on TOS.
509a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (try_location == IN_JAVASCRIPT) {
510a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (type == TRY_CATCH_HANDLER) {
511a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      push(Immediate(StackHandler::TRY_CATCH));
512a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    } else {
513a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      push(Immediate(StackHandler::TRY_FINALLY));
514a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
515a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    push(ebp);
516a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  } else {
517a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    ASSERT(try_location == IN_JS_ENTRY);
518a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // The frame pointer does not point to a JS frame so we save NULL
519a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // for ebp. We expect the code throwing an exception to check ebp
520a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // before dereferencing it to restore the context.
521a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    push(Immediate(StackHandler::ENTRY));
522a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    push(Immediate(0));  // NULL frame pointer.
523a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
524a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Save the current handler as the next handler.
525a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  push(Operand::StaticVariable(ExternalReference(Top::k_handler_address)));
526a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Link this handler as the new current one.
527a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  mov(Operand::StaticVariable(ExternalReference(Top::k_handler_address)), esp);
528a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
529a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
530a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
531e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarkevoid MacroAssembler::PopTryHandler() {
532e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  ASSERT_EQ(0, StackHandlerConstants::kNextOffset);
533e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  pop(Operand::StaticVariable(ExternalReference(Top::k_handler_address)));
534e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  add(Operand(esp), Immediate(StackHandlerConstants::kSize - kPointerSize));
535e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke}
536e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
537e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
538a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockRegister MacroAssembler::CheckMaps(JSObject* object, Register object_reg,
539a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                   JSObject* holder, Register holder_reg,
540a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                   Register scratch,
541a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                   Label* miss) {
542a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Make sure there's no overlap between scratch and the other
543a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // registers.
544a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(!scratch.is(object_reg) && !scratch.is(holder_reg));
545a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
546a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Keep track of the current object in register reg.
547a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Register reg = object_reg;
548a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  int depth = 1;
549a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
550a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check the maps in the prototype chain.
551a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Traverse the prototype chain from the object and do map checks.
552a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  while (object != holder) {
553a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    depth++;
554a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
555a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Only global objects and objects that do not require access
556a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // checks are allowed in stubs.
557a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
558a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
559a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    JSObject* prototype = JSObject::cast(object->GetPrototype());
560a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (Heap::InNewSpace(prototype)) {
561a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // Get the map of the current object.
562a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      mov(scratch, FieldOperand(reg, HeapObject::kMapOffset));
563a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      cmp(Operand(scratch), Immediate(Handle<Map>(object->map())));
564a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // Branch on the result of the map check.
565a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      j(not_equal, miss, not_taken);
566a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // Check access rights to the global object.  This has to happen
567a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // after the map check so that we know that the object is
568a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // actually a global object.
569a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      if (object->IsJSGlobalProxy()) {
570a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        CheckAccessGlobalProxy(reg, scratch, miss);
571a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
572a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        // Restore scratch register to be the map of the object.
573a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        // We load the prototype from the map in the scratch register.
574a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        mov(scratch, FieldOperand(reg, HeapObject::kMapOffset));
575a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      }
576a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // The prototype is in new space; we cannot store a reference
577a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // to it in the code. Load it from the map.
578a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      reg = holder_reg;  // from now the object is in holder_reg
579a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      mov(reg, FieldOperand(scratch, Map::kPrototypeOffset));
580a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
581a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    } else {
582a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // Check the map of the current object.
583a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      cmp(FieldOperand(reg, HeapObject::kMapOffset),
584a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block          Immediate(Handle<Map>(object->map())));
585a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // Branch on the result of the map check.
586a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      j(not_equal, miss, not_taken);
587a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // Check access rights to the global object.  This has to happen
588a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // after the map check so that we know that the object is
589a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // actually a global object.
590a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      if (object->IsJSGlobalProxy()) {
591a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        CheckAccessGlobalProxy(reg, scratch, miss);
592a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      }
593a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // The prototype is in old space; load it directly.
594a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      reg = holder_reg;  // from now the object is in holder_reg
595a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      mov(reg, Handle<JSObject>(prototype));
596a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
597a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
598a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Go to the next object in the prototype chain.
599a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    object = prototype;
600a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
601a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
602a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check the holder map.
603a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  cmp(FieldOperand(reg, HeapObject::kMapOffset),
604a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      Immediate(Handle<Map>(holder->map())));
605a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  j(not_equal, miss, not_taken);
606a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
607a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Log the check depth.
608a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  LOG(IntEvent("check-maps-depth", depth));
609a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
610a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Perform security check for access to the global object and return
611a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // the holder register.
612a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(object == holder);
613a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
614a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (object->IsJSGlobalProxy()) {
615a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    CheckAccessGlobalProxy(reg, scratch, miss);
616a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
617a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  return reg;
618a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
619a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
620a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
621a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid MacroAssembler::CheckAccessGlobalProxy(Register holder_reg,
622a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                            Register scratch,
623a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                            Label* miss) {
624a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Label same_contexts;
625a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
626a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(!holder_reg.is(scratch));
627a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
628a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Load current lexical context from the stack frame.
629a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  mov(scratch, Operand(ebp, StandardFrameConstants::kContextOffset));
630a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
631a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // When generating debug code, make sure the lexical context is set.
632a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (FLAG_debug_code) {
633a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    cmp(Operand(scratch), Immediate(0));
634a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    Check(not_equal, "we should not have an empty lexical context");
635a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
636a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Load the global context of the current context.
637a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  int offset = Context::kHeaderSize + Context::GLOBAL_INDEX * kPointerSize;
638a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  mov(scratch, FieldOperand(scratch, offset));
639a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  mov(scratch, FieldOperand(scratch, GlobalObject::kGlobalContextOffset));
640a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
641a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check the context is a global context.
642a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (FLAG_debug_code) {
643a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    push(scratch);
644a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Read the first word and compare to global_context_map.
645a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    mov(scratch, FieldOperand(scratch, HeapObject::kMapOffset));
646a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    cmp(scratch, Factory::global_context_map());
647a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    Check(equal, "JSGlobalObject::global_context should be a global context.");
648a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    pop(scratch);
649a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
650a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
651a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check if both contexts are the same.
652a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  cmp(scratch, FieldOperand(holder_reg, JSGlobalProxy::kContextOffset));
653a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  j(equal, &same_contexts, taken);
654a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
655a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Compare security tokens, save holder_reg on the stack so we can use it
656a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // as a temporary register.
657a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //
658a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // TODO(119): avoid push(holder_reg)/pop(holder_reg)
659a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  push(holder_reg);
660a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check that the security token in the calling global object is
661a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // compatible with the security token in the receiving global
662a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // object.
663a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  mov(holder_reg, FieldOperand(holder_reg, JSGlobalProxy::kContextOffset));
664a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
665a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check the context is a global context.
666a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (FLAG_debug_code) {
667a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    cmp(holder_reg, Factory::null_value());
668a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    Check(not_equal, "JSGlobalProxy::context() should not be null.");
669a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
670a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    push(holder_reg);
671a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Read the first word and compare to global_context_map(),
672a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    mov(holder_reg, FieldOperand(holder_reg, HeapObject::kMapOffset));
673a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    cmp(holder_reg, Factory::global_context_map());
674a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    Check(equal, "JSGlobalObject::global_context should be a global context.");
675a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    pop(holder_reg);
676a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
677a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
678a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  int token_offset = Context::kHeaderSize +
679a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                     Context::SECURITY_TOKEN_INDEX * kPointerSize;
680a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  mov(scratch, FieldOperand(scratch, token_offset));
681a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  cmp(scratch, FieldOperand(holder_reg, token_offset));
682a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  pop(holder_reg);
683a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  j(not_equal, miss, not_taken);
684a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
685a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  bind(&same_contexts);
686a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
687a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
688a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
689a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid MacroAssembler::LoadAllocationTopHelper(Register result,
690a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                             Register result_end,
691a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                             Register scratch,
692a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                             AllocationFlags flags) {
693a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ExternalReference new_space_allocation_top =
694a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      ExternalReference::new_space_allocation_top_address();
695a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
696a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Just return if allocation top is already known.
697a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if ((flags & RESULT_CONTAINS_TOP) != 0) {
698a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // No use of scratch if allocation top is provided.
699a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    ASSERT(scratch.is(no_reg));
700a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#ifdef DEBUG
701a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Assert that result actually contains top on entry.
702a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    cmp(result, Operand::StaticVariable(new_space_allocation_top));
703a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    Check(equal, "Unexpected allocation top");
704a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#endif
705a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    return;
706a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
707a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
708a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Move address of new object to result. Use scratch register if available.
709a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (scratch.is(no_reg)) {
710a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    mov(result, Operand::StaticVariable(new_space_allocation_top));
711a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  } else {
712a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    ASSERT(!scratch.is(result_end));
713a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    mov(Operand(scratch), Immediate(new_space_allocation_top));
714a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    mov(result, Operand(scratch, 0));
715a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
716a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
717a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
718a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
719a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid MacroAssembler::UpdateAllocationTopHelper(Register result_end,
720a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                               Register scratch) {
721d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  if (FLAG_debug_code) {
722d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    test(result_end, Immediate(kObjectAlignmentMask));
723d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    Check(zero, "Unaligned allocation in new space");
724d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  }
725d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
726a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ExternalReference new_space_allocation_top =
727a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      ExternalReference::new_space_allocation_top_address();
728a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
729a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Update new top. Use scratch if available.
730a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (scratch.is(no_reg)) {
731a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    mov(Operand::StaticVariable(new_space_allocation_top), result_end);
732a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  } else {
733a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    mov(Operand(scratch, 0), result_end);
734a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
735a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
736a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
737a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
738a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid MacroAssembler::AllocateInNewSpace(int object_size,
739a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                        Register result,
740a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                        Register result_end,
741a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                        Register scratch,
742a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                        Label* gc_required,
743a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                        AllocationFlags flags) {
744a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(!result.is(result_end));
745a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
746a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Load address of new object into result.
747a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  LoadAllocationTopHelper(result, result_end, scratch, flags);
748a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
749a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Calculate new top and bail out if new space is exhausted.
750a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ExternalReference new_space_allocation_limit =
751a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      ExternalReference::new_space_allocation_limit_address();
752a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  lea(result_end, Operand(result, object_size));
753a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  cmp(result_end, Operand::StaticVariable(new_space_allocation_limit));
754a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  j(above, gc_required, not_taken);
755a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
756a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Tag result if requested.
757a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if ((flags & TAG_OBJECT) != 0) {
758e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke    lea(result, Operand(result, kHeapObjectTag));
759a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
760e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
761e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // Update allocation top.
762e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  UpdateAllocationTopHelper(result_end, scratch);
763a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
764a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
765a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
766a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid MacroAssembler::AllocateInNewSpace(int header_size,
767a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                        ScaleFactor element_size,
768a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                        Register element_count,
769a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                        Register result,
770a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                        Register result_end,
771a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                        Register scratch,
772a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                        Label* gc_required,
773a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                        AllocationFlags flags) {
774a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(!result.is(result_end));
775a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
776a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Load address of new object into result.
777a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  LoadAllocationTopHelper(result, result_end, scratch, flags);
778a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
779a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Calculate new top and bail out if new space is exhausted.
780a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ExternalReference new_space_allocation_limit =
781a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      ExternalReference::new_space_allocation_limit_address();
782a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  lea(result_end, Operand(result, element_count, element_size, header_size));
783a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  cmp(result_end, Operand::StaticVariable(new_space_allocation_limit));
784a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  j(above, gc_required);
785a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
786a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Tag result if requested.
787a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if ((flags & TAG_OBJECT) != 0) {
788e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke    lea(result, Operand(result, kHeapObjectTag));
789a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
790e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
791e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // Update allocation top.
792e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  UpdateAllocationTopHelper(result_end, scratch);
793a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
794a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
795a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
796a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid MacroAssembler::AllocateInNewSpace(Register object_size,
797a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                        Register result,
798a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                        Register result_end,
799a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                        Register scratch,
800a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                        Label* gc_required,
801a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                        AllocationFlags flags) {
802a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(!result.is(result_end));
803a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
804a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Load address of new object into result.
805a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  LoadAllocationTopHelper(result, result_end, scratch, flags);
806a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
807a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Calculate new top and bail out if new space is exhausted.
808a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ExternalReference new_space_allocation_limit =
809a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      ExternalReference::new_space_allocation_limit_address();
810a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (!object_size.is(result_end)) {
811a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    mov(result_end, object_size);
812a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
813a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  add(result_end, Operand(result));
814a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  cmp(result_end, Operand::StaticVariable(new_space_allocation_limit));
815a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  j(above, gc_required, not_taken);
816a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
817a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Tag result if requested.
818a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if ((flags & TAG_OBJECT) != 0) {
819e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke    lea(result, Operand(result, kHeapObjectTag));
820a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
821e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
822e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // Update allocation top.
823e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  UpdateAllocationTopHelper(result_end, scratch);
824a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
825a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
826a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
827a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid MacroAssembler::UndoAllocationInNewSpace(Register object) {
828a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ExternalReference new_space_allocation_top =
829a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      ExternalReference::new_space_allocation_top_address();
830a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
831a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Make sure the object has no tag before resetting top.
832a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  and_(Operand(object), Immediate(~kHeapObjectTagMask));
833a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#ifdef DEBUG
834a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  cmp(object, Operand::StaticVariable(new_space_allocation_top));
835a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Check(below, "Undo allocation of non allocated memory");
836a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#endif
837a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  mov(Operand::StaticVariable(new_space_allocation_top), object);
838a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
839a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
840a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
8413ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Blockvoid MacroAssembler::AllocateHeapNumber(Register result,
8423ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block                                        Register scratch1,
8433ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block                                        Register scratch2,
8443ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block                                        Label* gc_required) {
8453ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // Allocate heap number in new space.
8463ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  AllocateInNewSpace(HeapNumber::kSize,
8473ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block                     result,
8483ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block                     scratch1,
8493ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block                     scratch2,
8503ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block                     gc_required,
8513ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block                     TAG_OBJECT);
8523ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block
8533ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // Set the map.
8543ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  mov(FieldOperand(result, HeapObject::kMapOffset),
8553ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      Immediate(Factory::heap_number_map()));
8563ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block}
8573ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block
8583ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block
859d0582a6c46733687d045e4188a1bcd0123c758a1Steve Blockvoid MacroAssembler::AllocateTwoByteString(Register result,
860d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block                                           Register length,
861d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block                                           Register scratch1,
862d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block                                           Register scratch2,
863d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block                                           Register scratch3,
864d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block                                           Label* gc_required) {
865d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  // Calculate the number of bytes needed for the characters in the string while
866d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  // observing object alignment.
867d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  ASSERT((SeqTwoByteString::kHeaderSize & kObjectAlignmentMask) == 0);
868d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  ASSERT(kShortSize == 2);
869e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // scratch1 = length * 2 + kObjectAlignmentMask.
870e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  lea(scratch1, Operand(length, length, times_1, kObjectAlignmentMask));
871d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  and_(Operand(scratch1), Immediate(~kObjectAlignmentMask));
872d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
873d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  // Allocate two byte string in new space.
874d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  AllocateInNewSpace(SeqTwoByteString::kHeaderSize,
875d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block                     times_1,
876d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block                     scratch1,
877d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block                     result,
878d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block                     scratch2,
879d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block                     scratch3,
880d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block                     gc_required,
881d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block                     TAG_OBJECT);
882d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
883d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  // Set the map, length and hash field.
884d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  mov(FieldOperand(result, HeapObject::kMapOffset),
885d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block      Immediate(Factory::string_map()));
886d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  mov(FieldOperand(result, String::kLengthOffset), length);
887d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  mov(FieldOperand(result, String::kHashFieldOffset),
888d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block      Immediate(String::kEmptyHashField));
889d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block}
890d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
891d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
892d0582a6c46733687d045e4188a1bcd0123c758a1Steve Blockvoid MacroAssembler::AllocateAsciiString(Register result,
893d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block                                         Register length,
894d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block                                         Register scratch1,
895d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block                                         Register scratch2,
896d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block                                         Register scratch3,
897d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block                                         Label* gc_required) {
898d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  // Calculate the number of bytes needed for the characters in the string while
899d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  // observing object alignment.
900d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  ASSERT((SeqAsciiString::kHeaderSize & kObjectAlignmentMask) == 0);
901d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  mov(scratch1, length);
902d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  ASSERT(kCharSize == 1);
903d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  add(Operand(scratch1), Immediate(kObjectAlignmentMask));
904d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  and_(Operand(scratch1), Immediate(~kObjectAlignmentMask));
905d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
906d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  // Allocate ascii string in new space.
907d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  AllocateInNewSpace(SeqAsciiString::kHeaderSize,
908d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block                     times_1,
909d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block                     scratch1,
910d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block                     result,
911d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block                     scratch2,
912d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block                     scratch3,
913d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block                     gc_required,
914d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block                     TAG_OBJECT);
915d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
916d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  // Set the map, length and hash field.
917d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  mov(FieldOperand(result, HeapObject::kMapOffset),
918d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block      Immediate(Factory::ascii_string_map()));
919d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  mov(FieldOperand(result, String::kLengthOffset), length);
920d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  mov(FieldOperand(result, String::kHashFieldOffset),
921d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block      Immediate(String::kEmptyHashField));
922d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block}
923d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
924d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
925d0582a6c46733687d045e4188a1bcd0123c758a1Steve Blockvoid MacroAssembler::AllocateConsString(Register result,
926d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block                                        Register scratch1,
927d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block                                        Register scratch2,
928d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block                                        Label* gc_required) {
929d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  // Allocate heap number in new space.
930d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  AllocateInNewSpace(ConsString::kSize,
931d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block                     result,
932d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block                     scratch1,
933d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block                     scratch2,
934d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block                     gc_required,
935d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block                     TAG_OBJECT);
936d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
937d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  // Set the map. The other fields are left uninitialized.
938d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  mov(FieldOperand(result, HeapObject::kMapOffset),
939d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block      Immediate(Factory::cons_string_map()));
940d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block}
941d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
942d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
943d0582a6c46733687d045e4188a1bcd0123c758a1Steve Blockvoid MacroAssembler::AllocateAsciiConsString(Register result,
944d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block                                             Register scratch1,
945d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block                                             Register scratch2,
946d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block                                             Label* gc_required) {
947d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  // Allocate heap number in new space.
948d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  AllocateInNewSpace(ConsString::kSize,
949d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block                     result,
950d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block                     scratch1,
951d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block                     scratch2,
952d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block                     gc_required,
953d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block                     TAG_OBJECT);
954d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
955d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  // Set the map. The other fields are left uninitialized.
956d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  mov(FieldOperand(result, HeapObject::kMapOffset),
957d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block      Immediate(Factory::cons_ascii_string_map()));
958d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block}
959d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
960d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
961a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid MacroAssembler::NegativeZeroTest(CodeGenerator* cgen,
962a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                      Register result,
963a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                      Register op,
964a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                      JumpTarget* then_target) {
965a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  JumpTarget ok;
966a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  test(result, Operand(result));
967a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ok.Branch(not_zero, taken);
968a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  test(op, Operand(op));
969a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  then_target->Branch(sign, not_taken);
970a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ok.Bind();
971a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
972a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
973a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
974a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid MacroAssembler::NegativeZeroTest(Register result,
975a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                      Register op,
976a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                      Label* then_label) {
977a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Label ok;
978a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  test(result, Operand(result));
979a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  j(not_zero, &ok, taken);
980a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  test(op, Operand(op));
981a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  j(sign, then_label, not_taken);
982a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  bind(&ok);
983a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
984a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
985a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
986a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid MacroAssembler::NegativeZeroTest(Register result,
987a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                      Register op1,
988a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                      Register op2,
989a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                      Register scratch,
990a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                      Label* then_label) {
991a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Label ok;
992a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  test(result, Operand(result));
993a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  j(not_zero, &ok, taken);
994a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  mov(scratch, Operand(op1));
995a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  or_(scratch, Operand(op2));
996a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  j(sign, then_label, not_taken);
997a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  bind(&ok);
998a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
999a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1000a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1001a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid MacroAssembler::TryGetFunctionPrototype(Register function,
1002a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                             Register result,
1003a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                             Register scratch,
1004a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                             Label* miss) {
1005a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check that the receiver isn't a smi.
1006a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  test(function, Immediate(kSmiTagMask));
1007a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  j(zero, miss, not_taken);
1008a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1009a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check that the function really is a function.
1010a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CmpObjectType(function, JS_FUNCTION_TYPE, result);
1011a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  j(not_equal, miss, not_taken);
1012a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1013a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Make sure that the function has an instance prototype.
1014a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Label non_instance;
1015a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  movzx_b(scratch, FieldOperand(result, Map::kBitFieldOffset));
1016a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  test(scratch, Immediate(1 << Map::kHasNonInstancePrototype));
1017a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  j(not_zero, &non_instance, not_taken);
1018a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1019a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Get the prototype or initial map from the function.
1020a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  mov(result,
1021a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      FieldOperand(function, JSFunction::kPrototypeOrInitialMapOffset));
1022a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1023a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // If the prototype or initial map is the hole, don't return it and
1024a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // simply miss the cache instead. This will allow us to allocate a
1025a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // prototype object on-demand in the runtime system.
1026a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  cmp(Operand(result), Immediate(Factory::the_hole_value()));
1027a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  j(equal, miss, not_taken);
1028a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1029a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // If the function does not have an initial map, we're done.
1030a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Label done;
1031a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CmpObjectType(result, MAP_TYPE, scratch);
1032a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  j(not_equal, &done);
1033a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1034a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Get the prototype from the initial map.
1035a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  mov(result, FieldOperand(result, Map::kPrototypeOffset));
1036a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  jmp(&done);
1037a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1038a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Non-instance prototype: Fetch prototype from constructor field
1039a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // in initial map.
1040a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  bind(&non_instance);
1041a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  mov(result, FieldOperand(result, Map::kConstructorOffset));
1042a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1043a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // All done.
1044a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  bind(&done);
1045a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
1046a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1047a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1048a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid MacroAssembler::CallStub(CodeStub* stub) {
1049e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  ASSERT(allow_stub_calls());  // Calls are not allowed in some stubs.
1050a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  call(stub->GetCode(), RelocInfo::CODE_TARGET);
1051a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
1052a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1053a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1054e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon ClarkeObject* MacroAssembler::TryCallStub(CodeStub* stub) {
1055e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  ASSERT(allow_stub_calls());  // Calls are not allowed in some stubs.
1056e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  Object* result = stub->TryGetCode();
1057e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  if (!result->IsFailure()) {
1058e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke    call(Handle<Code>(Code::cast(result)), RelocInfo::CODE_TARGET);
1059e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  }
1060e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  return result;
1061e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke}
1062e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
1063e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
1064d0582a6c46733687d045e4188a1bcd0123c758a1Steve Blockvoid MacroAssembler::TailCallStub(CodeStub* stub) {
1065e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  ASSERT(allow_stub_calls());  // Calls are not allowed in some stubs.
1066d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  jmp(stub->GetCode(), RelocInfo::CODE_TARGET);
1067d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block}
1068d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
1069d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
1070e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon ClarkeObject* MacroAssembler::TryTailCallStub(CodeStub* stub) {
1071e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  ASSERT(allow_stub_calls());  // Calls are not allowed in some stubs.
1072e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  Object* result = stub->TryGetCode();
1073e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  if (!result->IsFailure()) {
1074e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke    jmp(Handle<Code>(Code::cast(result)), RelocInfo::CODE_TARGET);
1075e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  }
1076e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  return result;
1077e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke}
1078e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
1079e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
1080a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid MacroAssembler::StubReturn(int argc) {
1081a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(argc >= 1 && generating_stub());
1082a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ret((argc - 1) * kPointerSize);
1083a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
1084a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1085a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1086a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid MacroAssembler::IllegalOperation(int num_arguments) {
1087a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (num_arguments > 0) {
1088a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    add(Operand(esp), Immediate(num_arguments * kPointerSize));
1089a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
1090a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  mov(eax, Immediate(Factory::undefined_value()));
1091a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
1092a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1093a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1094a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid MacroAssembler::CallRuntime(Runtime::FunctionId id, int num_arguments) {
1095a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CallRuntime(Runtime::FunctionForId(id), num_arguments);
1096a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
1097a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1098a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1099e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon ClarkeObject* MacroAssembler::TryCallRuntime(Runtime::FunctionId id,
1100e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke                                       int num_arguments) {
1101e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  return TryCallRuntime(Runtime::FunctionForId(id), num_arguments);
1102e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke}
1103e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
1104e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
1105a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid MacroAssembler::CallRuntime(Runtime::Function* f, int num_arguments) {
1106a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // If the expected number of arguments of the runtime function is
1107a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // constant, we check that the actual number of arguments match the
1108a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // expectation.
1109a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (f->nargs >= 0 && f->nargs != num_arguments) {
1110a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    IllegalOperation(num_arguments);
1111a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    return;
1112a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
1113a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
11144515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  // TODO(1236192): Most runtime routines don't need the number of
11154515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  // arguments passed in because it is constant. At some point we
11164515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  // should remove this need and make the runtime routine entry code
11174515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  // smarter.
11184515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  Set(eax, Immediate(num_arguments));
11194515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  mov(ebx, Immediate(ExternalReference(f)));
11204515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  CEntryStub ces(1);
11214515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  CallStub(&ces);
1122a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
1123a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1124a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1125e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon ClarkeObject* MacroAssembler::TryCallRuntime(Runtime::Function* f,
1126e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke                                       int num_arguments) {
1127e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  if (f->nargs >= 0 && f->nargs != num_arguments) {
1128e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke    IllegalOperation(num_arguments);
1129e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke    // Since we did not call the stub, there was no allocation failure.
1130e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke    // Return some non-failure object.
1131e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke    return Heap::undefined_value();
1132e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  }
1133e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
11344515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  // TODO(1236192): Most runtime routines don't need the number of
11354515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  // arguments passed in because it is constant. At some point we
11364515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  // should remove this need and make the runtime routine entry code
11374515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  // smarter.
11384515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  Set(eax, Immediate(num_arguments));
11394515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  mov(ebx, Immediate(ExternalReference(f)));
11404515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  CEntryStub ces(1);
11414515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  return TryCallStub(&ces);
1142e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke}
1143e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
1144e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
1145a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid MacroAssembler::TailCallRuntime(const ExternalReference& ext,
1146a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                     int num_arguments,
1147a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                     int result_size) {
1148a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // TODO(1236192): Most runtime routines don't need the number of
1149a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // arguments passed in because it is constant. At some point we
1150a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // should remove this need and make the runtime routine entry code
1151a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // smarter.
1152a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Set(eax, Immediate(num_arguments));
1153a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  JumpToRuntime(ext);
1154a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
1155a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1156a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1157d0582a6c46733687d045e4188a1bcd0123c758a1Steve Blockvoid MacroAssembler::PushHandleScope(Register scratch) {
1158d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  // Push the number of extensions, smi-tagged so the gc will ignore it.
1159d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  ExternalReference extensions_address =
1160d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block      ExternalReference::handle_scope_extensions_address();
1161d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  mov(scratch, Operand::StaticVariable(extensions_address));
1162d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  ASSERT_EQ(0, kSmiTag);
1163d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  shl(scratch, kSmiTagSize);
1164d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  push(scratch);
1165d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  mov(Operand::StaticVariable(extensions_address), Immediate(0));
1166d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  // Push next and limit pointers which will be wordsize aligned and
1167d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  // hence automatically smi tagged.
1168d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  ExternalReference next_address =
1169d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block      ExternalReference::handle_scope_next_address();
1170d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  push(Operand::StaticVariable(next_address));
1171d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  ExternalReference limit_address =
1172d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block      ExternalReference::handle_scope_limit_address();
1173d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  push(Operand::StaticVariable(limit_address));
1174d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block}
1175d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
1176d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
1177e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon ClarkeObject* MacroAssembler::PopHandleScopeHelper(Register saved,
1178e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke                                             Register scratch,
1179e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke                                             bool gc_allowed) {
1180e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  Object* result = NULL;
1181d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  ExternalReference extensions_address =
1182d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block        ExternalReference::handle_scope_extensions_address();
1183d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  Label write_back;
1184d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  mov(scratch, Operand::StaticVariable(extensions_address));
1185d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  cmp(Operand(scratch), Immediate(0));
1186d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  j(equal, &write_back);
1187d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  // Calling a runtime function messes with registers so we save and
1188d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  // restore any one we're asked not to change
1189d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  if (saved.is_valid()) push(saved);
1190e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  if (gc_allowed) {
1191e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke    CallRuntime(Runtime::kDeleteHandleScopeExtensions, 0);
1192e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  } else {
1193e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke    result = TryCallRuntime(Runtime::kDeleteHandleScopeExtensions, 0);
1194e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke    if (result->IsFailure()) return result;
1195e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  }
1196d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  if (saved.is_valid()) pop(saved);
1197d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
1198d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  bind(&write_back);
1199d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  ExternalReference limit_address =
1200d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block        ExternalReference::handle_scope_limit_address();
1201d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  pop(Operand::StaticVariable(limit_address));
1202d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  ExternalReference next_address =
1203d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block        ExternalReference::handle_scope_next_address();
1204d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  pop(Operand::StaticVariable(next_address));
1205d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  pop(scratch);
1206d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  shr(scratch, kSmiTagSize);
1207d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  mov(Operand::StaticVariable(extensions_address), scratch);
1208e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
1209e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  return result;
1210e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke}
1211e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
1212e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
1213e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarkevoid MacroAssembler::PopHandleScope(Register saved, Register scratch) {
1214e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  PopHandleScopeHelper(saved, scratch, true);
1215e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke}
1216e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
1217e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
1218e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon ClarkeObject* MacroAssembler::TryPopHandleScope(Register saved, Register scratch) {
1219e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  return PopHandleScopeHelper(saved, scratch, false);
1220d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block}
1221d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
1222d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
1223a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid MacroAssembler::JumpToRuntime(const ExternalReference& ext) {
1224a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Set the entry point and jump to the C entry runtime stub.
1225a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  mov(ebx, Immediate(ext));
1226a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CEntryStub ces(1);
1227a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  jmp(ces.GetCode(), RelocInfo::CODE_TARGET);
1228a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
1229a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1230a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1231a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid MacroAssembler::InvokePrologue(const ParameterCount& expected,
1232a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                    const ParameterCount& actual,
1233a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                    Handle<Code> code_constant,
1234a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                    const Operand& code_operand,
1235a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                    Label* done,
1236a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                    InvokeFlag flag) {
1237a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  bool definitely_matches = false;
1238a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Label invoke;
1239a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (expected.is_immediate()) {
1240a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    ASSERT(actual.is_immediate());
1241a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (expected.immediate() == actual.immediate()) {
1242a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      definitely_matches = true;
1243a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    } else {
1244a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      mov(eax, actual.immediate());
1245a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      const int sentinel = SharedFunctionInfo::kDontAdaptArgumentsSentinel;
1246a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      if (expected.immediate() == sentinel) {
1247a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        // Don't worry about adapting arguments for builtins that
1248a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        // don't want that done. Skip adaption code by making it look
1249a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        // like we have a match between expected and actual number of
1250a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        // arguments.
1251a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        definitely_matches = true;
1252a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      } else {
1253a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        mov(ebx, expected.immediate());
1254a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      }
1255a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
1256a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  } else {
1257a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (actual.is_immediate()) {
1258a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // Expected is in register, actual is immediate. This is the
1259a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // case when we invoke function values without going through the
1260a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // IC mechanism.
1261a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      cmp(expected.reg(), actual.immediate());
1262a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      j(equal, &invoke);
1263a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      ASSERT(expected.reg().is(ebx));
1264a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      mov(eax, actual.immediate());
1265a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    } else if (!expected.reg().is(actual.reg())) {
1266a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // Both expected and actual are in (different) registers. This
1267a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // is the case when we invoke functions using call and apply.
1268a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      cmp(expected.reg(), Operand(actual.reg()));
1269a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      j(equal, &invoke);
1270a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      ASSERT(actual.reg().is(eax));
1271a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      ASSERT(expected.reg().is(ebx));
1272a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
1273a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
1274a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1275a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (!definitely_matches) {
1276a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    Handle<Code> adaptor =
1277a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        Handle<Code>(Builtins::builtin(Builtins::ArgumentsAdaptorTrampoline));
1278a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (!code_constant.is_null()) {
1279a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      mov(edx, Immediate(code_constant));
1280a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      add(Operand(edx), Immediate(Code::kHeaderSize - kHeapObjectTag));
1281a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    } else if (!code_operand.is_reg(edx)) {
1282a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      mov(edx, code_operand);
1283a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
1284a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1285a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (flag == CALL_FUNCTION) {
1286a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      call(adaptor, RelocInfo::CODE_TARGET);
1287a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      jmp(done);
1288a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    } else {
1289a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      jmp(adaptor, RelocInfo::CODE_TARGET);
1290a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
1291a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    bind(&invoke);
1292a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
1293a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
1294a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1295a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1296a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid MacroAssembler::InvokeCode(const Operand& code,
1297a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                const ParameterCount& expected,
1298a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                const ParameterCount& actual,
1299a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                InvokeFlag flag) {
1300a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Label done;
1301a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  InvokePrologue(expected, actual, Handle<Code>::null(), code, &done, flag);
1302a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (flag == CALL_FUNCTION) {
1303a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    call(code);
1304a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  } else {
1305a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    ASSERT(flag == JUMP_FUNCTION);
1306a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    jmp(code);
1307a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
1308a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  bind(&done);
1309a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
1310a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1311a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1312a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid MacroAssembler::InvokeCode(Handle<Code> code,
1313a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                const ParameterCount& expected,
1314a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                const ParameterCount& actual,
1315a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                RelocInfo::Mode rmode,
1316a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                InvokeFlag flag) {
1317a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Label done;
1318a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Operand dummy(eax);
1319a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  InvokePrologue(expected, actual, code, dummy, &done, flag);
1320a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (flag == CALL_FUNCTION) {
1321a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    call(code, rmode);
1322a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  } else {
1323a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    ASSERT(flag == JUMP_FUNCTION);
1324a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    jmp(code, rmode);
1325a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
1326a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  bind(&done);
1327a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
1328a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1329a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1330a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid MacroAssembler::InvokeFunction(Register fun,
1331a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                    const ParameterCount& actual,
1332a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                    InvokeFlag flag) {
1333a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(fun.is(edi));
1334a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  mov(edx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
1335a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
1336a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  mov(ebx, FieldOperand(edx, SharedFunctionInfo::kFormalParameterCountOffset));
1337a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  mov(edx, FieldOperand(edx, SharedFunctionInfo::kCodeOffset));
1338a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  lea(edx, FieldOperand(edx, Code::kHeaderSize));
1339a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1340a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ParameterCount expected(ebx);
1341a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  InvokeCode(Operand(edx), expected, actual, flag);
1342a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
1343a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1344a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1345a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid MacroAssembler::InvokeBuiltin(Builtins::JavaScript id, InvokeFlag flag) {
1346a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  bool resolved;
1347a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Handle<Code> code = ResolveBuiltin(id, &resolved);
1348a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1349a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Calls are not allowed in some stubs.
1350a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(flag == JUMP_FUNCTION || allow_stub_calls());
1351a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1352a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Rely on the assertion to check that the number of provided
1353a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // arguments match the expected number of arguments. Fake a
1354a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // parameter count to avoid emitting code to do the check.
1355a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ParameterCount expected(0);
1356a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  InvokeCode(Handle<Code>(code), expected, expected,
1357a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block             RelocInfo::CODE_TARGET, flag);
1358a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1359a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  const char* name = Builtins::GetName(id);
1360a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  int argc = Builtins::GetArgumentsCount(id);
1361a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1362a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (!resolved) {
1363a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    uint32_t flags =
1364a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        Bootstrapper::FixupFlagsArgumentsCount::encode(argc) |
1365a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        Bootstrapper::FixupFlagsUseCodeObject::encode(false);
1366a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    Unresolved entry = { pc_offset() - sizeof(int32_t), flags, name };
1367a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    unresolved_.Add(entry);
1368a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
1369a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
1370a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1371a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1372a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid MacroAssembler::GetBuiltinEntry(Register target, Builtins::JavaScript id) {
1373a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  bool resolved;
1374a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Handle<Code> code = ResolveBuiltin(id, &resolved);
1375a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1376a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  const char* name = Builtins::GetName(id);
1377a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  int argc = Builtins::GetArgumentsCount(id);
1378a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1379a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  mov(Operand(target), Immediate(code));
1380a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (!resolved) {
1381a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    uint32_t flags =
1382a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        Bootstrapper::FixupFlagsArgumentsCount::encode(argc) |
1383a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        Bootstrapper::FixupFlagsUseCodeObject::encode(true);
1384a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    Unresolved entry = { pc_offset() - sizeof(int32_t), flags, name };
1385a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    unresolved_.Add(entry);
1386a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
1387a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  add(Operand(target), Immediate(Code::kHeaderSize - kHeapObjectTag));
1388a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
1389a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1390a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1391a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockHandle<Code> MacroAssembler::ResolveBuiltin(Builtins::JavaScript id,
1392a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                            bool* resolved) {
1393a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Move the builtin function into the temporary function slot by
1394a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // reading it from the builtins object. NOTE: We should be able to
1395a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // reduce this to two instructions by putting the function table in
1396a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // the global object instead of the "builtins" object and by using a
1397a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // real register for the function.
1398a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  mov(edx, Operand(esi, Context::SlotOffset(Context::GLOBAL_INDEX)));
1399a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  mov(edx, FieldOperand(edx, GlobalObject::kBuiltinsOffset));
1400a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  int builtins_offset =
1401a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      JSBuiltinsObject::kJSBuiltinsOffset + (id * kPointerSize);
1402a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  mov(edi, FieldOperand(edx, builtins_offset));
1403a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1404a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  return Builtins::GetCode(id, resolved);
1405a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
1406a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1407a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1408d0582a6c46733687d045e4188a1bcd0123c758a1Steve Blockvoid MacroAssembler::LoadContext(Register dst, int context_chain_length) {
1409d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  if (context_chain_length > 0) {
1410d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    // Move up the chain of contexts to the context containing the slot.
1411d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    mov(dst, Operand(esi, Context::SlotOffset(Context::CLOSURE_INDEX)));
1412d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    // Load the function context (which is the incoming, outer context).
1413d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    mov(dst, FieldOperand(dst, JSFunction::kContextOffset));
1414d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    for (int i = 1; i < context_chain_length; i++) {
1415d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block      mov(dst, Operand(dst, Context::SlotOffset(Context::CLOSURE_INDEX)));
1416d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block      mov(dst, FieldOperand(dst, JSFunction::kContextOffset));
1417d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    }
1418d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    // The context may be an intermediate context, not a function context.
1419d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    mov(dst, Operand(dst, Context::SlotOffset(Context::FCONTEXT_INDEX)));
1420d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  } else {  // Slot is in the current function context.
1421d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    // The context may be an intermediate context, not a function context.
1422d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    mov(dst, Operand(esi, Context::SlotOffset(Context::FCONTEXT_INDEX)));
1423d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  }
1424d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block}
1425d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
1426d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
1427d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
1428a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid MacroAssembler::Ret() {
1429a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ret(0);
1430a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
1431a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1432a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1433e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarkevoid MacroAssembler::Drop(int stack_elements) {
1434e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  if (stack_elements > 0) {
1435e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke    add(Operand(esp), Immediate(stack_elements * kPointerSize));
1436e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  }
1437e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke}
1438e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
1439e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
1440e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarkevoid MacroAssembler::Move(Register dst, Handle<Object> value) {
1441e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  mov(dst, value);
1442e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke}
1443e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
1444e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
1445a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid MacroAssembler::SetCounter(StatsCounter* counter, int value) {
1446a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (FLAG_native_code_counters && counter->Enabled()) {
1447a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    mov(Operand::StaticVariable(ExternalReference(counter)), Immediate(value));
1448a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
1449a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
1450a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1451a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1452a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid MacroAssembler::IncrementCounter(StatsCounter* counter, int value) {
1453a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(value > 0);
1454a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (FLAG_native_code_counters && counter->Enabled()) {
1455a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    Operand operand = Operand::StaticVariable(ExternalReference(counter));
1456a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (value == 1) {
1457a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      inc(operand);
1458a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    } else {
1459a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      add(operand, Immediate(value));
1460a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
1461a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
1462a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
1463a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1464a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1465a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid MacroAssembler::DecrementCounter(StatsCounter* counter, int value) {
1466a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(value > 0);
1467a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (FLAG_native_code_counters && counter->Enabled()) {
1468a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    Operand operand = Operand::StaticVariable(ExternalReference(counter));
1469a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (value == 1) {
1470a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      dec(operand);
1471a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    } else {
1472a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      sub(operand, Immediate(value));
1473a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
1474a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
1475a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
1476a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1477a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1478d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarkevoid MacroAssembler::IncrementCounter(Condition cc,
1479d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke                                      StatsCounter* counter,
1480d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke                                      int value) {
1481d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  ASSERT(value > 0);
1482d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  if (FLAG_native_code_counters && counter->Enabled()) {
1483d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    Label skip;
1484d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    j(NegateCondition(cc), &skip);
1485d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    pushfd();
1486d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    IncrementCounter(counter, value);
1487d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    popfd();
1488d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    bind(&skip);
1489d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  }
1490d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke}
1491d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke
1492d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke
1493d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarkevoid MacroAssembler::DecrementCounter(Condition cc,
1494d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke                                      StatsCounter* counter,
1495d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke                                      int value) {
1496d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  ASSERT(value > 0);
1497d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  if (FLAG_native_code_counters && counter->Enabled()) {
1498d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    Label skip;
1499d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    j(NegateCondition(cc), &skip);
1500d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    pushfd();
1501d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    DecrementCounter(counter, value);
1502d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    popfd();
1503d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    bind(&skip);
1504d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  }
1505d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke}
1506d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke
1507d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke
1508a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid MacroAssembler::Assert(Condition cc, const char* msg) {
1509a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (FLAG_debug_code) Check(cc, msg);
1510a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
1511a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1512a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1513a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid MacroAssembler::Check(Condition cc, const char* msg) {
1514a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Label L;
1515a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  j(cc, &L, taken);
1516a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Abort(msg);
1517a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // will not return here
1518a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  bind(&L);
1519a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
1520a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1521a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1522a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid MacroAssembler::Abort(const char* msg) {
1523a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // We want to pass the msg string like a smi to avoid GC
1524a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // problems, however msg is not guaranteed to be aligned
1525a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // properly. Instead, we pass an aligned pointer that is
1526a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // a proper v8 smi, but also pass the alignment difference
1527a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // from the real pointer as a smi.
1528a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  intptr_t p1 = reinterpret_cast<intptr_t>(msg);
1529a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  intptr_t p0 = (p1 & ~kSmiTagMask) + kSmiTag;
1530a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(reinterpret_cast<Object*>(p0)->IsSmi());
1531a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#ifdef DEBUG
1532a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (msg != NULL) {
1533a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    RecordComment("Abort message: ");
1534a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    RecordComment(msg);
1535a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
1536a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#endif
1537d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  // Disable stub call restrictions to always allow calls to abort.
1538d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  set_allow_stub_calls(true);
1539d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
1540a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  push(eax);
1541a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  push(Immediate(p0));
1542a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  push(Immediate(reinterpret_cast<intptr_t>(Smi::FromInt(p1 - p0))));
1543a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CallRuntime(Runtime::kAbort, 2);
1544a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // will not return here
1545d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  int3();
1546a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
1547a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1548a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1549d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarkevoid MacroAssembler::JumpIfNotBothSequentialAsciiStrings(Register object1,
1550d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke                                                         Register object2,
1551d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke                                                         Register scratch1,
1552d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke                                                         Register scratch2,
1553d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke                                                         Label* failure) {
1554d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  // Check that both objects are not smis.
1555d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  ASSERT_EQ(0, kSmiTag);
1556d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  mov(scratch1, Operand(object1));
1557d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  and_(scratch1, Operand(object2));
1558d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  test(scratch1, Immediate(kSmiTagMask));
1559d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  j(zero, failure);
1560d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke
1561d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  // Load instance type for both strings.
1562d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  mov(scratch1, FieldOperand(object1, HeapObject::kMapOffset));
1563d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  mov(scratch2, FieldOperand(object2, HeapObject::kMapOffset));
1564d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  movzx_b(scratch1, FieldOperand(scratch1, Map::kInstanceTypeOffset));
1565d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  movzx_b(scratch2, FieldOperand(scratch2, Map::kInstanceTypeOffset));
1566d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke
1567d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  // Check that both are flat ascii strings.
1568d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  const int kFlatAsciiStringMask =
1569d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      kIsNotStringMask | kStringRepresentationMask | kStringEncodingMask;
1570d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  const int kFlatAsciiStringTag = ASCII_STRING_TYPE;
1571d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  // Interleave bits from both instance types and compare them in one check.
1572d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  ASSERT_EQ(0, kFlatAsciiStringMask & (kFlatAsciiStringMask << 3));
1573d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  and_(scratch1, kFlatAsciiStringMask);
1574d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  and_(scratch2, kFlatAsciiStringMask);
1575d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  lea(scratch1, Operand(scratch1, scratch2, times_8, 0));
1576d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  cmp(scratch1, kFlatAsciiStringTag | (kFlatAsciiStringTag << 3));
1577d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  j(not_equal, failure);
1578d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke}
1579d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke
1580d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke
1581a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockCodePatcher::CodePatcher(byte* address, int size)
1582a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    : address_(address), size_(size), masm_(address, size + Assembler::kGap) {
1583a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Create a new macro assembler pointing to the address of the code to patch.
1584a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // The size is adjusted with kGap on order for the assembler to generate size
1585a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // bytes of instructions without failing with buffer size constraints.
1586a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(masm_.reloc_info_writer.pos() == address_ + size_ + Assembler::kGap);
1587a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
1588a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1589a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1590a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockCodePatcher::~CodePatcher() {
1591a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Indicate that code has changed.
1592a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CPU::FlushICache(address_, size_);
1593a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1594a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check that the code was patched as expected.
1595a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(masm_.pc_ == address_ + size_);
1596a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(masm_.reloc_info_writer.pos() == address_ + size_ + Assembler::kGap);
1597a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
1598a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1599a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1600a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} }  // namespace v8::internal
1601