1d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke// Copyright 2010 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"
32d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block#include "compiler.h"
33a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#include "debug.h"
34a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#include "ic-inl.h"
35a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#include "parser.h"
364515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke#include "regexp-macro-assembler.h"
37a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#include "register-allocator-inl.h"
38a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#include "scopes.h"
39a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
40a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blocknamespace v8 {
41a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blocknamespace internal {
42a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
43a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#define __ ACCESS_MASM(masm_)
44a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
45a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// -------------------------------------------------------------------------
46a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// Platform-specific DeferredCode functions.
47a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
48a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid DeferredCode::SaveRegisters() {
49a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  for (int i = 0; i < RegisterAllocator::kNumRegisters; i++) {
50a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    int action = registers_[i];
51a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (action == kPush) {
52a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      __ push(RegisterAllocator::ToRegister(i));
53a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    } else if (action != kIgnore && (action & kSyncedFlag) == 0) {
54a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      __ movq(Operand(rbp, action), RegisterAllocator::ToRegister(i));
55a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
56a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
57a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
58a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
593ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block
60a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid DeferredCode::RestoreRegisters() {
61a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Restore registers in reverse order due to the stack.
62a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  for (int i = RegisterAllocator::kNumRegisters - 1; i >= 0; i--) {
63a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    int action = registers_[i];
64a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (action == kPush) {
65a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      __ pop(RegisterAllocator::ToRegister(i));
66a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    } else if (action != kIgnore) {
67a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      action &= ~kSyncedFlag;
68a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      __ movq(RegisterAllocator::ToRegister(i), Operand(rbp, action));
69a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
70a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
71a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
72a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
73a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
74a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// -------------------------------------------------------------------------
75a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// CodeGenState implementation.
76a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
77a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockCodeGenState::CodeGenState(CodeGenerator* owner)
78a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    : owner_(owner),
79a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      destination_(NULL),
80a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      previous_(NULL) {
81a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  owner_->set_state(this);
82a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
83a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
84a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
85a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockCodeGenState::CodeGenState(CodeGenerator* owner,
86a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                           ControlDestination* destination)
87a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    : owner_(owner),
88a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      destination_(destination),
89a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      previous_(owner->state()) {
90a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  owner_->set_state(this);
91a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
92a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
93a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
94a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockCodeGenState::~CodeGenState() {
95a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(owner_->state() == this);
96a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  owner_->set_state(previous_);
97a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
98a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
99a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
100a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// -------------------------------------------------------------------------
101a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// Deferred code objects
102a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block//
103a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// These subclasses of DeferredCode add pieces of code to the end of generated
104a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// code.  They are branched to from the generated code, and
105a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// keep some slower code out of the main body of the generated code.
106a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// Many of them call a code stub or a runtime function.
107a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
108a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockclass DeferredInlineSmiAdd: public DeferredCode {
109a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block public:
110a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  DeferredInlineSmiAdd(Register dst,
111a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                       Smi* value,
112a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                       OverwriteMode overwrite_mode)
113a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      : dst_(dst), value_(value), overwrite_mode_(overwrite_mode) {
114a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    set_comment("[ DeferredInlineSmiAdd");
115a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
116a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
117a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  virtual void Generate();
118a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
119a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block private:
120a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Register dst_;
121a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Smi* value_;
122a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  OverwriteMode overwrite_mode_;
123a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block};
124a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
125a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
126a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// The result of value + src is in dst.  It either overflowed or was not
127a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// smi tagged.  Undo the speculative addition and call the appropriate
128a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// specialized stub for add.  The result is left in dst.
129a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockclass DeferredInlineSmiAddReversed: public DeferredCode {
130a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block public:
131a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  DeferredInlineSmiAddReversed(Register dst,
132a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                               Smi* value,
133a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                               OverwriteMode overwrite_mode)
134a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      : dst_(dst), value_(value), overwrite_mode_(overwrite_mode) {
135a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    set_comment("[ DeferredInlineSmiAddReversed");
136a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
137a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
138a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  virtual void Generate();
139a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
140a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block private:
141a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Register dst_;
142a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Smi* value_;
143a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  OverwriteMode overwrite_mode_;
144a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block};
145a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
146a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
147a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockclass DeferredInlineSmiSub: public DeferredCode {
148a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block public:
149a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  DeferredInlineSmiSub(Register dst,
150a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                       Smi* value,
151a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                       OverwriteMode overwrite_mode)
152a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      : dst_(dst), value_(value), overwrite_mode_(overwrite_mode) {
153a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    set_comment("[ DeferredInlineSmiSub");
154a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
155a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
156a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  virtual void Generate();
157a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
158a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block private:
159a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Register dst_;
160a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Smi* value_;
161a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  OverwriteMode overwrite_mode_;
162a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block};
163a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
164a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
165a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// Call the appropriate binary operation stub to compute src op value
166a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// and leave the result in dst.
167a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockclass DeferredInlineSmiOperation: public DeferredCode {
168a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block public:
169a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  DeferredInlineSmiOperation(Token::Value op,
170a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                             Register dst,
171a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                             Register src,
172a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                             Smi* value,
173a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                             OverwriteMode overwrite_mode)
174a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      : op_(op),
175a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        dst_(dst),
176a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        src_(src),
177a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        value_(value),
178a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        overwrite_mode_(overwrite_mode) {
179a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    set_comment("[ DeferredInlineSmiOperation");
180a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
181a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
182a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  virtual void Generate();
183a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
184a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block private:
185a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Token::Value op_;
186a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Register dst_;
187a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Register src_;
188a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Smi* value_;
189a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  OverwriteMode overwrite_mode_;
190a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block};
191a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
192a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
193a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockclass FloatingPointHelper : public AllStatic {
194a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block public:
195a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Code pattern for loading a floating point value. Input value must
196a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // be either a smi or a heap number object (fp value). Requirements:
197a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // operand on TOS+1. Returns operand as floating point number on FPU
198a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // stack.
199a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  static void LoadFloatOperand(MacroAssembler* masm, Register scratch);
200a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
201a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Code pattern for loading a floating point value. Input value must
202a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // be either a smi or a heap number object (fp value). Requirements:
203a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // operand in src register. Returns operand as floating point number
204a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // in XMM register
205a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  static void LoadFloatOperand(MacroAssembler* masm,
206a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                               Register src,
207a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                               XMMRegister dst);
208a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
209a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Code pattern for loading floating point values. Input values must
210a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // be either smi or heap number objects (fp values). Requirements:
2114515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  // operand_1 in rdx, operand_2 in rax; Returns operands as
212a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // floating point numbers in XMM registers.
213a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  static void LoadFloatOperands(MacroAssembler* masm,
214a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                XMMRegister dst1,
215a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                XMMRegister dst2);
216a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2174515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  // Similar to LoadFloatOperands, assumes that the operands are smis.
2184515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  static void LoadFloatOperandsFromSmis(MacroAssembler* masm,
2194515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke                                        XMMRegister dst1,
2204515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke                                        XMMRegister dst2);
2214515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke
222a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Code pattern for loading floating point values onto the fp stack.
223a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Input values must be either smi or heap number objects (fp values).
224a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Requirements:
225a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Register version: operands in registers lhs and rhs.
226a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Stack version: operands on TOS+1 and TOS+2.
227a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Returns operands as floating point numbers on fp stack.
228a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  static void LoadFloatOperands(MacroAssembler* masm,
229a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                Register lhs,
230a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                Register rhs);
231a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
232a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Test if operands are smi or number objects (fp). Requirements:
233a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // operand_1 in rax, operand_2 in rdx; falls through on float or smi
234a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // operands, jumps to the non_float label otherwise.
2353ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  static void CheckNumberOperands(MacroAssembler* masm,
2363ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block                                  Label* non_float);
237d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke
238d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  // Takes the operands in rdx and rax and loads them as integers in rax
239d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  // and rcx.
240d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  static void LoadAsIntegers(MacroAssembler* masm,
241d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke                             bool use_sse3,
242d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke                             Label* operand_conversion_failure);
243a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block};
244a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
245a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
246a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// -----------------------------------------------------------------------------
247a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// CodeGenerator implementation.
248a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2493100271588b61cbc1dc472a3f2f105d2eed8497fAndrei PopescuCodeGenerator::CodeGenerator(MacroAssembler* masm)
2503100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    : deferred_(8),
2514515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke      masm_(masm),
2523100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu      info_(NULL),
253a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      frame_(NULL),
254a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      allocator_(NULL),
255a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      state_(NULL),
256a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      loop_nesting_(0),
257a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      function_return_is_shadowed_(false),
258a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      in_spilled_code_(false) {
259a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
260a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
261a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2623100271588b61cbc1dc472a3f2f105d2eed8497fAndrei PopescuScope* CodeGenerator::scope() { return info_->function()->scope(); }
2633100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
2643100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu
265a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) {
266a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Call the runtime to declare the globals.  The inevitable call
267a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // will sync frame elements to memory anyway, so we do it eagerly to
268a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // allow us to push the arguments directly into place.
269a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  frame_->SyncRange(0, frame_->element_count() - 1);
270a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
271a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ movq(kScratchRegister, pairs, RelocInfo::EMBEDDED_OBJECT);
2723ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  frame_->EmitPush(rsi);  // The context is the first argument.
273a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  frame_->EmitPush(kScratchRegister);
2743ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  frame_->EmitPush(Smi::FromInt(is_eval() ? 1 : 0));
275a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Result ignored = frame_->CallRuntime(Runtime::kDeclareGlobals, 3);
276a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Return value is ignored.
277a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
278a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
279a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
280402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescuvoid CodeGenerator::Generate(CompilationInfo* info) {
281a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Record the position for debugging purposes.
2823100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  CodeForFunctionPosition(info->function());
283a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
284a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Initialize state.
2853100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  info_ = info;
286a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(allocator_ == NULL);
287a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  RegisterAllocator register_allocator(this);
288a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  allocator_ = &register_allocator;
289a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(frame_ == NULL);
290a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  frame_ = new VirtualFrame();
291a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  set_in_spilled_code(false);
292a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
293a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Adjust for function-level loop nesting.
2944515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  loop_nesting_ += info->loop_nesting();
295a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
296a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  JumpTarget::set_compiling_deferred_code(false);
297a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
298a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#ifdef DEBUG
299a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (strlen(FLAG_stop_at) > 0 &&
3003100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu      info->function()->name()->IsEqualTo(CStrVector(FLAG_stop_at))) {
301a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    frame_->SpillAll();
302a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ int3();
303a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
304a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#endif
305a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
306a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // New scope to get automatic timing calculation.
307a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  {  // NOLINT
308a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    HistogramTimerScope codegen_timer(&Counters::code_generation);
309a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    CodeGenState state(this);
310a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
311a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Entry:
312a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Stack: receiver, arguments, return address.
313a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // rbp: caller's frame pointer
314a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // rsp: stack pointer
315a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // rdi: called JS function
316a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // rsi: callee's context
317a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    allocator_->Initialize();
318a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
319402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    if (info->mode() == CompilationInfo::PRIMARY) {
3204515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke      frame_->Enter();
3214515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke
3224515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke      // Allocate space for locals and initialize them.
3234515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke      frame_->AllocateStackSlots();
3244515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke
3254515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke      // Allocate the local context if needed.
3263100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu      int heap_slots = scope()->num_heap_slots();
3274515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke      if (heap_slots > 0) {
3284515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke        Comment cmnt(masm_, "[ allocate local context");
3294515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke        // Allocate local context.
3304515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke        // Get outer context and create a new context based on it.
3314515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke        frame_->PushFunction();
3324515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke        Result context;
3334515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke        if (heap_slots <= FastNewContextStub::kMaximumSlots) {
3344515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke          FastNewContextStub stub(heap_slots);
3354515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke          context = frame_->CallStub(&stub, 1);
3364515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke        } else {
3374515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke          context = frame_->CallRuntime(Runtime::kNewContext, 1);
3384515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke        }
339a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3404515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke        // Update context local.
3414515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke        frame_->SaveContextRegister();
342a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3434515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke        // Verify that the runtime call result and rsi agree.
3444515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke        if (FLAG_debug_code) {
3454515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke          __ cmpq(context.reg(), rsi);
3464515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke          __ Assert(equal, "Runtime::NewContext should end up in rsi");
3474515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke        }
348a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      }
349a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3504515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke      // TODO(1241774): Improve this code:
3514515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke      // 1) only needed if we have a context
3524515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke      // 2) no need to recompute context ptr every single time
3534515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke      // 3) don't copy parameter operand code from SlotOperand!
3544515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke      {
3554515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke        Comment cmnt2(masm_, "[ copy context parameters into .context");
3564515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke        // Note that iteration order is relevant here! If we have the same
3574515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke        // parameter twice (e.g., function (x, y, x)), and that parameter
3584515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke        // needs to be copied into the context, it must be the last argument
3594515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke        // passed to the parameter that needs to be copied. This is a rare
3604515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke        // case so we don't check for it, instead we rely on the copying
3614515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke        // order: such a parameter is copied repeatedly into the same
3624515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke        // context location and thus the last value is what is seen inside
3634515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke        // the function.
3643100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu        for (int i = 0; i < scope()->num_parameters(); i++) {
3653100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu          Variable* par = scope()->parameter(i);
3664515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke          Slot* slot = par->slot();
3674515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke          if (slot != NULL && slot->type() == Slot::CONTEXT) {
3684515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke            // The use of SlotOperand below is safe in unspilled code
3694515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke            // because the slot is guaranteed to be a context slot.
3704515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke            //
3714515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke            // There are no parameters in the global scope.
3723100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu            ASSERT(!scope()->is_global_scope());
3734515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke            frame_->PushParameterAt(i);
3744515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke            Result value = frame_->Pop();
3754515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke            value.ToRegister();
3764515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke
3774515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke            // SlotOperand loads context.reg() with the context object
3784515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke            // stored to, used below in RecordWrite.
3794515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke            Result context = allocator_->Allocate();
3804515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke            ASSERT(context.is_valid());
3814515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke            __ movq(SlotOperand(slot, context.reg()), value.reg());
3824515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke            int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize;
3834515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke            Result scratch = allocator_->Allocate();
3844515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke            ASSERT(scratch.is_valid());
3854515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke            frame_->Spill(context.reg());
3864515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke            frame_->Spill(value.reg());
3874515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke            __ RecordWrite(context.reg(), offset, value.reg(), scratch.reg());
3884515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke          }
389a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        }
390a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      }
391a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3924515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke      // Store the arguments object.  This must happen after context
3934515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke      // initialization because the arguments object may be stored in
3944515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke      // the context.
3954515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke      if (ArgumentsMode() != NO_ARGUMENTS_ALLOCATION) {
3964515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke        StoreArgumentsObject(true);
3974515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke      }
398a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3994515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke      // Initialize ThisFunction reference if present.
4003100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu      if (scope()->is_function_scope() && scope()->function() != NULL) {
4014515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke        frame_->Push(Factory::the_hole_value());
4023100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu        StoreToSlot(scope()->function()->slot(), NOT_CONST_INIT);
4034515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke      }
4044515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke    } else {
4054515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke      // When used as the secondary compiler for splitting, rbp, rsi,
4064515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke      // and rdi have been pushed on the stack.  Adjust the virtual
4074515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke      // frame to match this state.
4084515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke      frame_->Adjust(3);
4094515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke      allocator_->Unuse(rdi);
410402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu
411402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu      // Bind all the bailout labels to the beginning of the function.
412402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu      List<CompilationInfo::Bailout*>* bailouts = info->bailouts();
413402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu      for (int i = 0; i < bailouts->length(); i++) {
414402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu        __ bind(bailouts->at(i)->label());
415402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu      }
416e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke    }
417e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
4184515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke    // Initialize the function return target after the locals are set
4194515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke    // up, because it needs the expected frame height from the frame.
4204515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke    function_return_.set_direction(JumpTarget::BIDIRECTIONAL);
4214515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke    function_return_is_shadowed_ = false;
4224515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke
423a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Generate code to 'execute' declarations and initialize functions
424a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // (source elements). In case of an illegal redeclaration we need to
425a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // handle that instead of processing the declarations.
4263100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    if (scope()->HasIllegalRedeclaration()) {
427a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      Comment cmnt(masm_, "[ illegal redeclarations");
4283100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu      scope()->VisitIllegalRedeclaration(this);
429a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    } else {
430a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      Comment cmnt(masm_, "[ declarations");
4313100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu      ProcessDeclarations(scope()->declarations());
432a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // Bail out if a stack-overflow exception occurred when processing
433a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // declarations.
434a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      if (HasStackOverflow()) return;
435a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
436a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
437a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (FLAG_trace) {
438a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      frame_->CallRuntime(Runtime::kTraceEnter, 0);
439a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // Ignore the return value.
440a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
441a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    CheckStack();
442a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
443a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Compile the body of the function in a vanilla state. Don't
444a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // bother compiling all the code if the scope has an illegal
445a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // redeclaration.
4463100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    if (!scope()->HasIllegalRedeclaration()) {
447a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      Comment cmnt(masm_, "[ function body");
448a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#ifdef DEBUG
449a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      bool is_builtin = Bootstrapper::IsActive();
450a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      bool should_trace =
451a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block          is_builtin ? FLAG_trace_builtin_calls : FLAG_trace_calls;
452a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      if (should_trace) {
453a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        frame_->CallRuntime(Runtime::kDebugTrace, 0);
454a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        // Ignore the return value.
455a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      }
456a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#endif
4573100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu      VisitStatements(info->function()->body());
458a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
459a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // Handle the return from the function.
460a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      if (has_valid_frame()) {
461a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        // If there is a valid frame, control flow can fall off the end of
462a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        // the body.  In that case there is an implicit return statement.
463a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        ASSERT(!function_return_is_shadowed_);
4643100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu        CodeForReturnPosition(info->function());
465a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        frame_->PrepareForReturn();
466a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        Result undefined(Factory::undefined_value());
467a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        if (function_return_.is_bound()) {
468a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block          function_return_.Jump(&undefined);
469a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        } else {
470a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block          function_return_.Bind(&undefined);
471a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block          GenerateReturnSequence(&undefined);
472a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        }
473a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      } else if (function_return_.is_linked()) {
474a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        // If the return target has dangling jumps to it, then we have not
475a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        // yet generated the return sequence.  This can happen when (a)
476a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        // control does not flow off the end of the body so we did not
477a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        // compile an artificial return statement just above, and (b) there
478a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        // are return statements in the body but (c) they are all shadowed.
479a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        Result return_value;
480a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        function_return_.Bind(&return_value);
481a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        GenerateReturnSequence(&return_value);
482a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      }
483a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
484a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
485a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
486a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Adjust for function-level loop nesting.
4874515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  loop_nesting_ -= info->loop_nesting();
488a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
489a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Code generation state must be reset.
490a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(state_ == NULL);
491a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(loop_nesting() == 0);
492a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(!function_return_is_shadowed_);
493a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  function_return_.Unuse();
494a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  DeleteFrame();
495a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
496a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Process any deferred code using the register allocator.
497a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (!HasStackOverflow()) {
498a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    HistogramTimerScope deferred_timer(&Counters::deferred_code_generation);
499a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    JumpTarget::set_compiling_deferred_code(true);
500a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    ProcessDeferred();
501a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    JumpTarget::set_compiling_deferred_code(false);
502a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
503a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
504a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // There is no need to delete the register allocator, it is a
505a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // stack-allocated local.
506a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  allocator_ = NULL;
507a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
508a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
509a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CodeGenerator::GenerateReturnSequence(Result* return_value) {
510a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // The return value is a live (but not currently reference counted)
511a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // reference to rax.  This is safe because the current frame does not
512a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // contain a reference to rax (it is prepared for the return by spilling
513a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // all registers).
514a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (FLAG_trace) {
515a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    frame_->Push(return_value);
516a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    *return_value = frame_->CallRuntime(Runtime::kTraceExit, 1);
517a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
518a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  return_value->ToRegister(rax);
519a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
520a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Add a label for checking the size of the code used for returning.
521a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#ifdef DEBUG
522a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Label check_exit_codesize;
523a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  masm_->bind(&check_exit_codesize);
524a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#endif
525a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
526a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Leave the frame and return popping the arguments and the
527a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // receiver.
528a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  frame_->Exit();
5293100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  masm_->ret((scope()->num_parameters() + 1) * kPointerSize);
530a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#ifdef ENABLE_DEBUGGER_SUPPORT
531a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Add padding that will be overwritten by a debugger breakpoint.
532a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // frame_->Exit() generates "movq rsp, rbp; pop rbp; ret k"
533a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // with length 7 (3 + 1 + 3).
534d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  const int kPadding = Assembler::kJSReturnSequenceLength - 7;
535a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  for (int i = 0; i < kPadding; ++i) {
536a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    masm_->int3();
537a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
538a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check that the size of the code used for returning matches what is
539a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // expected by the debugger.
540d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  ASSERT_EQ(Assembler::kJSReturnSequenceLength,
541a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block            masm_->SizeOfCodeGeneratedSince(&check_exit_codesize));
542a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#endif
543a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  DeleteFrame();
544a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
545a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
546a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
547a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#ifdef DEBUG
548a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockbool CodeGenerator::HasValidEntryRegisters() {
549a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  return (allocator()->count(rax) == (frame()->is_used(rax) ? 1 : 0))
550a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      && (allocator()->count(rbx) == (frame()->is_used(rbx) ? 1 : 0))
551a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      && (allocator()->count(rcx) == (frame()->is_used(rcx) ? 1 : 0))
552a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      && (allocator()->count(rdx) == (frame()->is_used(rdx) ? 1 : 0))
553a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      && (allocator()->count(rdi) == (frame()->is_used(rdi) ? 1 : 0))
554a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      && (allocator()->count(r8) == (frame()->is_used(r8) ? 1 : 0))
555a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      && (allocator()->count(r9) == (frame()->is_used(r9) ? 1 : 0))
556a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      && (allocator()->count(r11) == (frame()->is_used(r11) ? 1 : 0))
557a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      && (allocator()->count(r14) == (frame()->is_used(r14) ? 1 : 0))
558a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      && (allocator()->count(r15) == (frame()->is_used(r15) ? 1 : 0))
559a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      && (allocator()->count(r12) == (frame()->is_used(r12) ? 1 : 0));
560a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
561a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#endif
562a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
563a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
564a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockclass DeferredReferenceGetKeyedValue: public DeferredCode {
565a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block public:
566a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  explicit DeferredReferenceGetKeyedValue(Register dst,
567a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                          Register receiver,
568a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                          Register key,
569a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                          bool is_global)
570a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      : dst_(dst), receiver_(receiver), key_(key), is_global_(is_global) {
571a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    set_comment("[ DeferredReferenceGetKeyedValue");
572a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
573a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
574a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  virtual void Generate();
575a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
576a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Label* patch_site() { return &patch_site_; }
577a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
578a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block private:
579a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Label patch_site_;
580a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Register dst_;
581a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Register receiver_;
582a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Register key_;
583a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  bool is_global_;
584a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block};
585a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
586a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
587a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid DeferredReferenceGetKeyedValue::Generate() {
588a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ push(receiver_);  // First IC argument.
589a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ push(key_);       // Second IC argument.
590a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
591a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Calculate the delta from the IC call instruction to the map check
592a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // movq instruction in the inlined version.  This delta is stored in
593a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // a test(rax, delta) instruction after the call so that we can find
594a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // it in the IC initialization code and patch the movq instruction.
595a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // This means that we cannot allow test instructions after calls to
596a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // KeyedLoadIC stubs in other places.
597a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
598a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  RelocInfo::Mode mode = is_global_
599a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                         ? RelocInfo::CODE_TARGET_CONTEXT
600a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                         : RelocInfo::CODE_TARGET;
601a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ Call(ic, mode);
602a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // The delta from the start of the map-compare instruction to the
603a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // test instruction.  We use masm_-> directly here instead of the __
604a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // macro because the macro sometimes uses macro expansion to turn
605a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // into something that can't return a value.  This is encountered
606a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // when doing generated code coverage tests.
607a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  int delta_to_patch_site = masm_->SizeOfCodeGeneratedSince(patch_site());
608a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Here we use masm_-> instead of the __ macro because this is the
609a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // instruction that gets patched and coverage code gets in the way.
610a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // TODO(X64): Consider whether it's worth switching the test to a
611a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // 7-byte NOP with non-zero immediate (0f 1f 80 xxxxxxxx) which won't
612a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // be generated normally.
613a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  masm_->testl(rax, Immediate(-delta_to_patch_site));
614a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ IncrementCounter(&Counters::keyed_load_inline_miss, 1);
615a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
616a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (!dst_.is(rax)) __ movq(dst_, rax);
617a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ pop(key_);
618a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ pop(receiver_);
619a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
620a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
621a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
622a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockclass DeferredReferenceSetKeyedValue: public DeferredCode {
623a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block public:
624a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  DeferredReferenceSetKeyedValue(Register value,
625a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                 Register key,
626a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                 Register receiver)
627a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      : value_(value), key_(key), receiver_(receiver) {
628a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    set_comment("[ DeferredReferenceSetKeyedValue");
629a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
630a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
631a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  virtual void Generate();
632a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
633a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Label* patch_site() { return &patch_site_; }
634a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
635a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block private:
636a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Register value_;
637a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Register key_;
638a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Register receiver_;
639a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Label patch_site_;
640a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block};
641a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
642a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
643a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid DeferredReferenceSetKeyedValue::Generate() {
644a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ IncrementCounter(&Counters::keyed_store_inline_miss, 1);
645a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Push receiver and key arguments on the stack.
646a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ push(receiver_);
647a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ push(key_);
648a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Move value argument to eax as expected by the IC stub.
649a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (!value_.is(rax)) __ movq(rax, value_);
650a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Call the IC stub.
651a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize));
652a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ Call(ic, RelocInfo::CODE_TARGET);
653a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // The delta from the start of the map-compare instructions (initial movq)
654a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // to the test instruction.  We use masm_-> directly here instead of the
655a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // __ macro because the macro sometimes uses macro expansion to turn
656a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // into something that can't return a value.  This is encountered
657a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // when doing generated code coverage tests.
658a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  int delta_to_patch_site = masm_->SizeOfCodeGeneratedSince(patch_site());
659a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Here we use masm_-> instead of the __ macro because this is the
660a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // instruction that gets patched and coverage code gets in the way.
661a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  masm_->testl(rax, Immediate(-delta_to_patch_site));
662a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Restore value (returned from store IC), key and receiver
663a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // registers.
664a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (!value_.is(rax)) __ movq(value_, rax);
665a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ pop(key_);
666a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ pop(receiver_);
667a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
668a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
669a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
670d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarkevoid CodeGenerator::CallApplyLazy(Expression* applicand,
671a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                  Expression* receiver,
672a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                  VariableProxy* arguments,
673a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                  int position) {
674d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  // An optimized implementation of expressions of the form
675d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  // x.apply(y, arguments).
676d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  // If the arguments object of the scope has not been allocated,
677d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  // and x.apply is Function.prototype.apply, this optimization
678d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  // just copies y and the arguments of the current function on the
679d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  // stack, as receiver and arguments, and calls x.
680d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  // In the implementation comments, we call x the applicand
681d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  // and y the receiver.
682a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(ArgumentsMode() == LAZY_ARGUMENTS_ALLOCATION);
683a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(arguments->IsArguments());
684a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
685d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  // Load applicand.apply onto the stack. This will usually
686a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // give us a megamorphic load site. Not super, but it works.
687d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  Load(applicand);
688d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  Handle<String> name = Factory::LookupAsciiSymbol("apply");
689d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  frame()->Push(name);
690d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  Result answer = frame()->CallLoadIC(RelocInfo::CODE_TARGET);
691d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  __ nop();
692d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  frame()->Push(&answer);
693a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
694a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Load the receiver and the existing arguments object onto the
695a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // expression stack. Avoid allocating the arguments object here.
696a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Load(receiver);
6973100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  LoadFromSlot(scope()->arguments()->var()->slot(), NOT_INSIDE_TYPEOF);
698a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
699a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Emit the source position information after having loaded the
700a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // receiver and the arguments.
701a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CodeForSourcePosition(position);
702d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  // Contents of frame at this point:
703d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  // Frame[0]: arguments object of the current function or the hole.
704d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  // Frame[1]: receiver
705d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  // Frame[2]: applicand.apply
706d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  // Frame[3]: applicand.
707a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
708a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check if the arguments object has been lazily allocated
709a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // already. If so, just use that instead of copying the arguments
710a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // from the stack. This also deals with cases where a local variable
711a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // named 'arguments' has been introduced.
712a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  frame_->Dup();
713a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Result probe = frame_->Pop();
714d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  { VirtualFrame::SpilledScope spilled_scope;
715d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    Label slow, done;
716d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    bool try_lazy = true;
717d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    if (probe.is_constant()) {
718d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      try_lazy = probe.handle()->IsTheHole();
719d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    } else {
720d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      __ CompareRoot(probe.reg(), Heap::kTheHoleValueRootIndex);
721d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      probe.Unuse();
722d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      __ j(not_equal, &slow);
723d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    }
724a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
725d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    if (try_lazy) {
726d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      Label build_args;
727d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      // Get rid of the arguments object probe.
728d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      frame_->Drop();  // Can be called on a spilled frame.
729d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      // Stack now has 3 elements on it.
730d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      // Contents of stack at this point:
731d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      // rsp[0]: receiver
732d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      // rsp[1]: applicand.apply
733d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      // rsp[2]: applicand.
734d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke
735d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      // Check that the receiver really is a JavaScript object.
736d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      __ movq(rax, Operand(rsp, 0));
737d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      Condition is_smi = masm_->CheckSmi(rax);
738d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      __ j(is_smi, &build_args);
739a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // We allow all JSObjects including JSFunctions.  As long as
740a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // JS_FUNCTION_TYPE is the last instance type and it is right
741a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // after LAST_JS_OBJECT_TYPE, we do not have to check the upper
742a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // bound.
743a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      ASSERT(LAST_TYPE == JS_FUNCTION_TYPE);
744a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      ASSERT(JS_FUNCTION_TYPE == LAST_JS_OBJECT_TYPE + 1);
745d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      __ CmpObjectType(rax, FIRST_JS_OBJECT_TYPE, rcx);
746d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      __ j(below, &build_args);
747d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke
748d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      // Check that applicand.apply is Function.prototype.apply.
749d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      __ movq(rax, Operand(rsp, kPointerSize));
750d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      is_smi = masm_->CheckSmi(rax);
751d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      __ j(is_smi, &build_args);
752d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      __ CmpObjectType(rax, JS_FUNCTION_TYPE, rcx);
753d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      __ j(not_equal, &build_args);
754d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      __ movq(rax, FieldOperand(rax, JSFunction::kSharedFunctionInfoOffset));
755a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      Handle<Code> apply_code(Builtins::builtin(Builtins::FunctionApply));
756d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      __ Cmp(FieldOperand(rax, SharedFunctionInfo::kCodeOffset), apply_code);
757d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      __ j(not_equal, &build_args);
758d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke
759d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      // Check that applicand is a function.
760d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      __ movq(rdi, Operand(rsp, 2 * kPointerSize));
761d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      is_smi = masm_->CheckSmi(rdi);
762d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      __ j(is_smi, &build_args);
763d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      __ CmpObjectType(rdi, JS_FUNCTION_TYPE, rcx);
764d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      __ j(not_equal, &build_args);
765d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke
766d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      // Copy the arguments to this function possibly from the
767d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      // adaptor frame below it.
768d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      Label invoke, adapted;
769d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      __ movq(rdx, Operand(rbp, StandardFrameConstants::kCallerFPOffset));
770d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      __ SmiCompare(Operand(rdx, StandardFrameConstants::kContextOffset),
771d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke                    Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR));
772d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      __ j(equal, &adapted);
773d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke
774d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      // No arguments adaptor frame. Copy fixed number of arguments.
7753100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu      __ movq(rax, Immediate(scope()->num_parameters()));
7763100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu      for (int i = 0; i < scope()->num_parameters(); i++) {
777d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke        __ push(frame_->ParameterAt(i));
778d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      }
779d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      __ jmp(&invoke);
780d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke
781d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      // Arguments adaptor frame present. Copy arguments from there, but
782d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      // avoid copying too many arguments to avoid stack overflows.
783d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      __ bind(&adapted);
784d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      static const uint32_t kArgumentsLimit = 1 * KB;
785d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      __ movq(rax, Operand(rdx, ArgumentsAdaptorFrameConstants::kLengthOffset));
786d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      __ SmiToInteger32(rax, rax);
787d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      __ movq(rcx, rax);
788d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      __ cmpq(rax, Immediate(kArgumentsLimit));
789d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      __ j(above, &build_args);
790d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke
791d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      // Loop through the arguments pushing them onto the execution
792d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      // stack. We don't inform the virtual frame of the push, so we don't
793d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      // have to worry about getting rid of the elements from the virtual
794d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      // frame.
795d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      Label loop;
796d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      // rcx is a small non-negative integer, due to the test above.
797d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      __ testl(rcx, rcx);
798d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      __ j(zero, &invoke);
799d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      __ bind(&loop);
800d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      __ push(Operand(rdx, rcx, times_pointer_size, 1 * kPointerSize));
801d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      __ decl(rcx);
802d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      __ j(not_zero, &loop);
803d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke
804d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      // Invoke the function.
805d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      __ bind(&invoke);
806d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      ParameterCount actual(rax);
807d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      __ InvokeFunction(rdi, actual, CALL_FUNCTION);
808d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      // Drop applicand.apply and applicand from the stack, and push
809d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      // the result of the function call, but leave the spilled frame
810d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      // unchanged, with 3 elements, so it is correct when we compile the
811d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      // slow-case code.
812d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      __ addq(rsp, Immediate(2 * kPointerSize));
813d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      __ push(rax);
814d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      // Stack now has 1 element:
815d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      //   rsp[0]: result
816d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      __ jmp(&done);
817d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke
818d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      // Slow-case: Allocate the arguments object since we know it isn't
819d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      // there, and fall-through to the slow-case where we call
820d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      // applicand.apply.
821d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      __ bind(&build_args);
822d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      // Stack now has 3 elements, because we have jumped from where:
823d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      // rsp[0]: receiver
824d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      // rsp[1]: applicand.apply
825d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      // rsp[2]: applicand.
826d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke
827d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      // StoreArgumentsObject requires a correct frame, and may modify it.
828d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      Result arguments_object = StoreArgumentsObject(false);
829d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      frame_->SpillAll();
830d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      arguments_object.ToRegister();
831d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      frame_->EmitPush(arguments_object.reg());
832d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      arguments_object.Unuse();
833d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      // Stack and frame now have 4 elements.
834d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      __ bind(&slow);
835a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
836a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
837d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    // Generic computation of x.apply(y, args) with no special optimization.
838d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    // Flip applicand.apply and applicand on the stack, so
839d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    // applicand looks like the receiver of the applicand.apply call.
840d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    // Then process it as a normal function call.
841d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    __ movq(rax, Operand(rsp, 3 * kPointerSize));
842d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    __ movq(rbx, Operand(rsp, 2 * kPointerSize));
843d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    __ movq(Operand(rsp, 2 * kPointerSize), rax);
844d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    __ movq(Operand(rsp, 3 * kPointerSize), rbx);
845d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke
846d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    CallFunctionStub call_function(2, NOT_IN_LOOP, NO_CALL_FUNCTION_FLAGS);
847d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    Result res = frame_->CallStub(&call_function, 3);
848d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    // The function and its two arguments have been dropped.
849d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    frame_->Drop(1);  // Drop the receiver as well.
850d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    res.ToRegister();
851d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    frame_->EmitPush(res.reg());
852d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    // Stack now has 1 element:
853d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    //   rsp[0]: result
854d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    if (try_lazy) __ bind(&done);
855d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  }  // End of spilled scope.
856d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  // Restore the context register after a call.
857a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  frame_->RestoreContextRegister();
858a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
859a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
860a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
861a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockclass DeferredStackCheck: public DeferredCode {
862a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block public:
863a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  DeferredStackCheck() {
864a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    set_comment("[ DeferredStackCheck");
865a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
866a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
867a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  virtual void Generate();
868a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block};
869a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
870a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
871a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid DeferredStackCheck::Generate() {
872a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  StackCheckStub stub;
873a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ CallStub(&stub);
874a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
875a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
876a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
877a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CodeGenerator::CheckStack() {
878d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  DeferredStackCheck* deferred = new DeferredStackCheck;
879d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  __ CompareRoot(rsp, Heap::kStackLimitRootIndex);
880d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  deferred->Branch(below);
881d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  deferred->BindExit();
882a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
883a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
884a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
885a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CodeGenerator::VisitAndSpill(Statement* statement) {
886a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // TODO(X64): No architecture specific code. Move to shared location.
887a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(in_spilled_code());
888a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  set_in_spilled_code(false);
889a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Visit(statement);
890a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (frame_ != NULL) {
891a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    frame_->SpillAll();
892a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
893a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  set_in_spilled_code(true);
894a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
895a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
896a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
897a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CodeGenerator::VisitStatementsAndSpill(ZoneList<Statement*>* statements) {
898a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(in_spilled_code());
899a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  set_in_spilled_code(false);
900a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  VisitStatements(statements);
901a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (frame_ != NULL) {
902a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    frame_->SpillAll();
903a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
904a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  set_in_spilled_code(true);
905a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
906a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
907a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
908a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CodeGenerator::VisitStatements(ZoneList<Statement*>* statements) {
909a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(!in_spilled_code());
910a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  for (int i = 0; has_valid_frame() && i < statements->length(); i++) {
911a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    Visit(statements->at(i));
912a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
913a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
914a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
915a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
916a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CodeGenerator::VisitBlock(Block* node) {
917a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(!in_spilled_code());
918a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Comment cmnt(masm_, "[ Block");
919a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CodeForStatementPosition(node);
920a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  node->break_target()->set_direction(JumpTarget::FORWARD_ONLY);
921a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  VisitStatements(node->statements());
922a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (node->break_target()->is_linked()) {
923a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    node->break_target()->Bind();
924a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
925a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  node->break_target()->Unuse();
926a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
927a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
928a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
929a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CodeGenerator::VisitDeclaration(Declaration* node) {
930a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Comment cmnt(masm_, "[ Declaration");
931a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Variable* var = node->proxy()->var();
932a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(var != NULL);  // must have been resolved
933a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Slot* slot = var->slot();
934a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
935a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // If it was not possible to allocate the variable at compile time,
936a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // we need to "declare" it at runtime to make sure it actually
937a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // exists in the local context.
938a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (slot != NULL && slot->type() == Slot::LOOKUP) {
939a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Variables with a "LOOKUP" slot were introduced as non-locals
940a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // during variable resolution and must have mode DYNAMIC.
941a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    ASSERT(var->is_dynamic());
942a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // For now, just do a runtime call.  Sync the virtual frame eagerly
943a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // so we can simply push the arguments into place.
944a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    frame_->SyncRange(0, frame_->element_count() - 1);
945a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    frame_->EmitPush(rsi);
946a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ movq(kScratchRegister, var->name(), RelocInfo::EMBEDDED_OBJECT);
947a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    frame_->EmitPush(kScratchRegister);
948a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Declaration nodes are always introduced in one of two modes.
949a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    ASSERT(node->mode() == Variable::VAR || node->mode() == Variable::CONST);
950a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    PropertyAttributes attr = node->mode() == Variable::VAR ? NONE : READ_ONLY;
9513ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    frame_->EmitPush(Smi::FromInt(attr));
952a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Push initial value, if any.
953a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Note: For variables we must not push an initial value (such as
954a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // 'undefined') because we may have a (legal) redeclaration and we
955a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // must not destroy the current value.
956a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (node->mode() == Variable::CONST) {
957a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      frame_->EmitPush(Heap::kTheHoleValueRootIndex);
958a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    } else if (node->fun() != NULL) {
959a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      Load(node->fun());
960a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    } else {
9613ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      frame_->EmitPush(Smi::FromInt(0));  // no initial value!
962a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
963a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    Result ignored = frame_->CallRuntime(Runtime::kDeclareContextSlot, 4);
964a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Ignore the return value (declarations are statements).
965a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    return;
966a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
967a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
968a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(!var->is_global());
969a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
970a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // If we have a function or a constant, we need to initialize the variable.
971a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Expression* val = NULL;
972a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (node->mode() == Variable::CONST) {
973a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    val = new Literal(Factory::the_hole_value());
974a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  } else {
975a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    val = node->fun();  // NULL if we don't have a function
976a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
977a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
978a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (val != NULL) {
979a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    {
980a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // Set the initial value.
981a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      Reference target(this, node->proxy());
982a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      Load(val);
983a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      target.SetValue(NOT_CONST_INIT);
984a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // The reference is removed from the stack (preserving TOS) when
985a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // it goes out of scope.
986a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
987a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Get rid of the assigned value (declarations are statements).
988a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    frame_->Drop();
989a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
990a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
991a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
992a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
993a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CodeGenerator::VisitExpressionStatement(ExpressionStatement* node) {
994a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(!in_spilled_code());
995a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Comment cmnt(masm_, "[ ExpressionStatement");
996a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CodeForStatementPosition(node);
997a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Expression* expression = node->expression();
998a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  expression->MarkAsStatement();
999a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Load(expression);
1000a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Remove the lingering expression result from the top of stack.
1001a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  frame_->Drop();
1002a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
1003a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1004a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1005a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CodeGenerator::VisitEmptyStatement(EmptyStatement* node) {
1006a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(!in_spilled_code());
1007a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Comment cmnt(masm_, "// EmptyStatement");
1008a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CodeForStatementPosition(node);
1009a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // nothing to do
1010a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
1011a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1012a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1013a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CodeGenerator::VisitIfStatement(IfStatement* node) {
1014a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(!in_spilled_code());
1015a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Comment cmnt(masm_, "[ IfStatement");
1016a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Generate different code depending on which parts of the if statement
1017a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // are present or not.
1018a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  bool has_then_stm = node->HasThenStatement();
1019a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  bool has_else_stm = node->HasElseStatement();
1020a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1021a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CodeForStatementPosition(node);
1022a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  JumpTarget exit;
1023a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (has_then_stm && has_else_stm) {
1024a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    JumpTarget then;
1025a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    JumpTarget else_;
1026a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    ControlDestination dest(&then, &else_, true);
1027d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    LoadCondition(node->condition(), &dest, true);
1028a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1029a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (dest.false_was_fall_through()) {
1030a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // The else target was bound, so we compile the else part first.
1031a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      Visit(node->else_statement());
1032a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1033a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // We may have dangling jumps to the then part.
1034a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      if (then.is_linked()) {
1035a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        if (has_valid_frame()) exit.Jump();
1036a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        then.Bind();
1037a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        Visit(node->then_statement());
1038a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      }
1039a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    } else {
1040a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // The then target was bound, so we compile the then part first.
1041a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      Visit(node->then_statement());
1042a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1043a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      if (else_.is_linked()) {
1044a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        if (has_valid_frame()) exit.Jump();
1045a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        else_.Bind();
1046a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        Visit(node->else_statement());
1047a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      }
1048a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
1049a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1050a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  } else if (has_then_stm) {
1051a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    ASSERT(!has_else_stm);
1052a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    JumpTarget then;
1053a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    ControlDestination dest(&then, &exit, true);
1054d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    LoadCondition(node->condition(), &dest, true);
1055a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1056a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (dest.false_was_fall_through()) {
1057a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // The exit label was bound.  We may have dangling jumps to the
1058a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // then part.
1059a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      if (then.is_linked()) {
1060a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        exit.Unuse();
1061a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        exit.Jump();
1062a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        then.Bind();
1063a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        Visit(node->then_statement());
1064a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      }
1065a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    } else {
1066a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // The then label was bound.
1067a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      Visit(node->then_statement());
1068a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
1069a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1070a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  } else if (has_else_stm) {
1071a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    ASSERT(!has_then_stm);
1072a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    JumpTarget else_;
1073a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    ControlDestination dest(&exit, &else_, false);
1074d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    LoadCondition(node->condition(), &dest, true);
1075a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1076a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (dest.true_was_fall_through()) {
1077a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // The exit label was bound.  We may have dangling jumps to the
1078a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // else part.
1079a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      if (else_.is_linked()) {
1080a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        exit.Unuse();
1081a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        exit.Jump();
1082a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        else_.Bind();
1083a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        Visit(node->else_statement());
1084a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      }
1085a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    } else {
1086a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // The else label was bound.
1087a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      Visit(node->else_statement());
1088a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
1089a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1090a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  } else {
1091a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    ASSERT(!has_then_stm && !has_else_stm);
1092a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // We only care about the condition's side effects (not its value
1093a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // or control flow effect).  LoadCondition is called without
1094a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // forcing control flow.
1095a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    ControlDestination dest(&exit, &exit, true);
1096d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    LoadCondition(node->condition(), &dest, false);
1097a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (!dest.is_used()) {
1098a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // We got a value on the frame rather than (or in addition to)
1099a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // control flow.
1100a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      frame_->Drop();
1101a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
1102a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
1103a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1104a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (exit.is_linked()) {
1105a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    exit.Bind();
1106a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
1107a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
1108a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1109a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1110a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CodeGenerator::VisitContinueStatement(ContinueStatement* node) {
1111a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(!in_spilled_code());
1112a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Comment cmnt(masm_, "[ ContinueStatement");
1113a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CodeForStatementPosition(node);
1114a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  node->target()->continue_target()->Jump();
1115a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
1116a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1117a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1118a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CodeGenerator::VisitBreakStatement(BreakStatement* node) {
1119a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(!in_spilled_code());
1120a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Comment cmnt(masm_, "[ BreakStatement");
1121a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CodeForStatementPosition(node);
1122a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  node->target()->break_target()->Jump();
1123a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
1124a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1125a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1126a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CodeGenerator::VisitReturnStatement(ReturnStatement* node) {
1127a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(!in_spilled_code());
1128a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Comment cmnt(masm_, "[ ReturnStatement");
1129a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1130a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CodeForStatementPosition(node);
1131a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Load(node->expression());
1132a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Result return_value = frame_->Pop();
1133a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (function_return_is_shadowed_) {
1134a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    function_return_.Jump(&return_value);
1135a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  } else {
1136a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    frame_->PrepareForReturn();
1137a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (function_return_.is_bound()) {
1138a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // If the function return label is already bound we reuse the
1139a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // code by jumping to the return site.
1140a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      function_return_.Jump(&return_value);
1141a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    } else {
1142a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      function_return_.Bind(&return_value);
1143a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      GenerateReturnSequence(&return_value);
1144a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
1145a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
1146a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
1147a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1148a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1149a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CodeGenerator::VisitWithEnterStatement(WithEnterStatement* node) {
1150a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(!in_spilled_code());
1151a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Comment cmnt(masm_, "[ WithEnterStatement");
1152a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CodeForStatementPosition(node);
1153a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Load(node->expression());
1154a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Result context;
1155a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (node->is_catch_block()) {
1156a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    context = frame_->CallRuntime(Runtime::kPushCatchContext, 1);
1157a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  } else {
1158a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    context = frame_->CallRuntime(Runtime::kPushContext, 1);
1159a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
1160a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1161a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Update context local.
1162a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  frame_->SaveContextRegister();
1163a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1164a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Verify that the runtime call result and rsi agree.
1165a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (FLAG_debug_code) {
1166a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ cmpq(context.reg(), rsi);
1167a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ Assert(equal, "Runtime::NewContext should end up in rsi");
1168a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
1169a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
1170a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1171a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1172a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CodeGenerator::VisitWithExitStatement(WithExitStatement* node) {
1173a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(!in_spilled_code());
1174a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Comment cmnt(masm_, "[ WithExitStatement");
1175a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CodeForStatementPosition(node);
1176a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Pop context.
1177a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ movq(rsi, ContextOperand(rsi, Context::PREVIOUS_INDEX));
1178a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Update context local.
1179a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  frame_->SaveContextRegister();
1180a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
1181a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1182a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1183a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CodeGenerator::VisitSwitchStatement(SwitchStatement* node) {
1184a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // TODO(X64): This code is completely generic and should be moved somewhere
1185a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // where it can be shared between architectures.
1186a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(!in_spilled_code());
1187a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Comment cmnt(masm_, "[ SwitchStatement");
1188a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CodeForStatementPosition(node);
1189a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  node->break_target()->set_direction(JumpTarget::FORWARD_ONLY);
1190a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1191a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Compile the switch value.
1192a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Load(node->tag());
1193a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1194a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ZoneList<CaseClause*>* cases = node->cases();
1195a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  int length = cases->length();
1196a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CaseClause* default_clause = NULL;
1197a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1198a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  JumpTarget next_test;
1199a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Compile the case label expressions and comparisons.  Exit early
1200a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // if a comparison is unconditionally true.  The target next_test is
1201a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // bound before the loop in order to indicate control flow to the
1202a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // first comparison.
1203a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  next_test.Bind();
1204a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  for (int i = 0; i < length && !next_test.is_unused(); i++) {
1205a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    CaseClause* clause = cases->at(i);
1206a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // The default is not a test, but remember it for later.
1207a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (clause->is_default()) {
1208a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      default_clause = clause;
1209a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      continue;
1210a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
1211a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1212a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    Comment cmnt(masm_, "[ Case comparison");
1213a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // We recycle the same target next_test for each test.  Bind it if
1214a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // the previous test has not done so and then unuse it for the
1215a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // loop.
1216a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (next_test.is_linked()) {
1217a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      next_test.Bind();
1218a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
1219a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    next_test.Unuse();
1220a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1221a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Duplicate the switch value.
1222a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    frame_->Dup();
1223a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1224a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Compile the label expression.
1225a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    Load(clause->label());
1226a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1227a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Compare and branch to the body if true or the next test if
1228a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // false.  Prefer the next test as a fall through.
1229a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    ControlDestination dest(clause->body_target(), &next_test, false);
1230402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    Comparison(node, equal, true, &dest);
1231a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1232a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // If the comparison fell through to the true target, jump to the
1233a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // actual body.
1234a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (dest.true_was_fall_through()) {
1235a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      clause->body_target()->Unuse();
1236a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      clause->body_target()->Jump();
1237a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
1238a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
1239a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1240a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // If there was control flow to a next test from the last one
1241a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // compiled, compile a jump to the default or break target.
1242a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (!next_test.is_unused()) {
1243a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (next_test.is_linked()) {
1244a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      next_test.Bind();
1245a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
1246a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Drop the switch value.
1247a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    frame_->Drop();
1248a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (default_clause != NULL) {
1249a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      default_clause->body_target()->Jump();
1250a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    } else {
1251a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      node->break_target()->Jump();
1252a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
1253a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
1254a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1255a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // The last instruction emitted was a jump, either to the default
1256a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // clause or the break target, or else to a case body from the loop
1257a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // that compiles the tests.
1258a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(!has_valid_frame());
1259a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Compile case bodies as needed.
1260a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  for (int i = 0; i < length; i++) {
1261a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    CaseClause* clause = cases->at(i);
1262a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1263a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // There are two ways to reach the body: from the corresponding
1264a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // test or as the fall through of the previous body.
1265a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (clause->body_target()->is_linked() || has_valid_frame()) {
1266a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      if (clause->body_target()->is_linked()) {
1267a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        if (has_valid_frame()) {
1268a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block          // If we have both a jump to the test and a fall through, put
1269a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block          // a jump on the fall through path to avoid the dropping of
1270a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block          // the switch value on the test path.  The exception is the
1271a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block          // default which has already had the switch value dropped.
1272a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block          if (clause->is_default()) {
1273a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block            clause->body_target()->Bind();
1274a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block          } else {
1275a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block            JumpTarget body;
1276a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block            body.Jump();
1277a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block            clause->body_target()->Bind();
1278a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block            frame_->Drop();
1279a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block            body.Bind();
1280a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block          }
1281a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        } else {
1282a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block          // No fall through to worry about.
1283a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block          clause->body_target()->Bind();
1284a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block          if (!clause->is_default()) {
1285a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block            frame_->Drop();
1286a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block          }
1287a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        }
1288a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      } else {
1289a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        // Otherwise, we have only fall through.
1290a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        ASSERT(has_valid_frame());
1291a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      }
1292a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1293a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // We are now prepared to compile the body.
1294a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      Comment cmnt(masm_, "[ Case body");
1295a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      VisitStatements(clause->statements());
1296a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
1297a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    clause->body_target()->Unuse();
1298a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
1299a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1300a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // We may not have a valid frame here so bind the break target only
1301a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // if needed.
1302a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (node->break_target()->is_linked()) {
1303a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    node->break_target()->Bind();
1304a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
1305a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  node->break_target()->Unuse();
1306a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
1307a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1308a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
13093ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Blockvoid CodeGenerator::VisitDoWhileStatement(DoWhileStatement* node) {
1310a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(!in_spilled_code());
13113ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  Comment cmnt(masm_, "[ DoWhileStatement");
1312a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CodeForStatementPosition(node);
1313a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  node->break_target()->set_direction(JumpTarget::FORWARD_ONLY);
13143ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  JumpTarget body(JumpTarget::BIDIRECTIONAL);
13153ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  IncrementLoopNesting();
13163ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block
13173ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  ConditionAnalysis info = AnalyzeCondition(node->cond());
13183ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // Label the top of the loop for the backward jump if necessary.
13193ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  switch (info) {
13203ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    case ALWAYS_TRUE:
13213ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      // Use the continue target.
13223ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      node->continue_target()->set_direction(JumpTarget::BIDIRECTIONAL);
13233ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      node->continue_target()->Bind();
13243ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      break;
13253ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    case ALWAYS_FALSE:
13263ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      // No need to label it.
13273ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      node->continue_target()->set_direction(JumpTarget::FORWARD_ONLY);
13283ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      break;
13293ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    case DONT_KNOW:
13303ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      // Continue is the test, so use the backward body target.
13313ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      node->continue_target()->set_direction(JumpTarget::FORWARD_ONLY);
13323ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      body.Bind();
13333ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      break;
13343ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  }
1335a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
13363ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  CheckStack();  // TODO(1222600): ignore if body contains calls.
13373ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  Visit(node->body());
13383ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block
13393ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // Compile the test.
13403ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  switch (info) {
13413ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    case ALWAYS_TRUE:
13423ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      // If control flow can fall off the end of the body, jump back
13433ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      // to the top and bind the break target at the exit.
13443ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      if (has_valid_frame()) {
13453ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block        node->continue_target()->Jump();
1346a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      }
13473ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      if (node->break_target()->is_linked()) {
13483ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block        node->break_target()->Bind();
13493ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      }
13503ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      break;
13513ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    case ALWAYS_FALSE:
13523ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      // We may have had continues or breaks in the body.
13533ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      if (node->continue_target()->is_linked()) {
13543ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block        node->continue_target()->Bind();
13553ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      }
13563ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      if (node->break_target()->is_linked()) {
13573ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block        node->break_target()->Bind();
13583ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      }
13593ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      break;
13603ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    case DONT_KNOW:
13613ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      // We have to compile the test expression if it can be reached by
13623ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      // control flow falling out of the body or via continue.
13633ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      if (node->continue_target()->is_linked()) {
13643ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block        node->continue_target()->Bind();
13653ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      }
13663ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      if (has_valid_frame()) {
1367d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block        Comment cmnt(masm_, "[ DoWhileCondition");
1368d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block        CodeForDoWhileConditionPosition(node);
13693ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block        ControlDestination dest(&body, node->break_target(), false);
1370d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block        LoadCondition(node->cond(), &dest, true);
13713ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      }
13723ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      if (node->break_target()->is_linked()) {
13733ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block        node->break_target()->Bind();
13743ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      }
13753ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      break;
1376a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
1377a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
13783ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  DecrementLoopNesting();
13793ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  node->continue_target()->Unuse();
13803ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  node->break_target()->Unuse();
13813ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block}
1382a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
13833ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block
13843ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Blockvoid CodeGenerator::VisitWhileStatement(WhileStatement* node) {
13853ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  ASSERT(!in_spilled_code());
13863ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  Comment cmnt(masm_, "[ WhileStatement");
13873ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  CodeForStatementPosition(node);
13883ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block
13893ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // If the condition is always false and has no side effects, we do not
13903ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // need to compile anything.
13913ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  ConditionAnalysis info = AnalyzeCondition(node->cond());
13923ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  if (info == ALWAYS_FALSE) return;
13933ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block
13943ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // Do not duplicate conditions that may have function literal
13953ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // subexpressions.  This can cause us to compile the function literal
13963ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // twice.
13973ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  bool test_at_bottom = !node->may_have_function_literal();
13983ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  node->break_target()->set_direction(JumpTarget::FORWARD_ONLY);
13993ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  IncrementLoopNesting();
14003ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  JumpTarget body;
14013ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  if (test_at_bottom) {
14023ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    body.set_direction(JumpTarget::BIDIRECTIONAL);
14033ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  }
14043ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block
14053ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // Based on the condition analysis, compile the test as necessary.
14063ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  switch (info) {
14073ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    case ALWAYS_TRUE:
14083ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      // We will not compile the test expression.  Label the top of the
14093ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      // loop with the continue target.
14103ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      node->continue_target()->set_direction(JumpTarget::BIDIRECTIONAL);
14113ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      node->continue_target()->Bind();
14123ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      break;
14133ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    case DONT_KNOW: {
14143ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      if (test_at_bottom) {
14153ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block        // Continue is the test at the bottom, no need to label the test
14163ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block        // at the top.  The body is a backward target.
1417a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        node->continue_target()->set_direction(JumpTarget::FORWARD_ONLY);
1418a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      } else {
14193ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block        // Label the test at the top as the continue target.  The body
14203ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block        // is a forward-only target.
14213ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block        node->continue_target()->set_direction(JumpTarget::BIDIRECTIONAL);
14223ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block        node->continue_target()->Bind();
1423a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      }
14243ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      // Compile the test with the body as the true target and preferred
14253ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      // fall-through and with the break target as the false target.
14263ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      ControlDestination dest(&body, node->break_target(), true);
1427d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block      LoadCondition(node->cond(), &dest, true);
14283ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block
14293ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      if (dest.false_was_fall_through()) {
14303ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block        // If we got the break target as fall-through, the test may have
14313ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block        // been unconditionally false (if there are no jumps to the
14323ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block        // body).
14333ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block        if (!body.is_linked()) {
14343ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block          DecrementLoopNesting();
14353ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block          return;
1436a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        }
1437a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
14383ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block        // Otherwise, jump around the body on the fall through and then
14393ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block        // bind the body target.
14403ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block        node->break_target()->Unuse();
14413ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block        node->break_target()->Jump();
14423ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block        body.Bind();
14433ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      }
14443ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      break;
14453ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    }
14463ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    case ALWAYS_FALSE:
14473ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      UNREACHABLE();
14483ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      break;
14493ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  }
1450a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
14513ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  CheckStack();  // TODO(1222600): ignore if body contains calls.
14523ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  Visit(node->body());
14533ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block
14543ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // Based on the condition analysis, compile the backward jump as
14553ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // necessary.
14563ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  switch (info) {
14573ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    case ALWAYS_TRUE:
14583ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      // The loop body has been labeled with the continue target.
14593ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      if (has_valid_frame()) {
14603ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block        node->continue_target()->Jump();
14613ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      }
14623ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      break;
14633ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    case DONT_KNOW:
14643ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      if (test_at_bottom) {
14653ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block        // If we have chosen to recompile the test at the bottom,
14663ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block        // then it is the continue target.
1467a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        if (node->continue_target()->is_linked()) {
1468a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block          node->continue_target()->Bind();
1469a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        }
1470a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        if (has_valid_frame()) {
14713ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block          // The break target is the fall-through (body is a backward
14723ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block          // jump from here and thus an invalid fall-through).
1473a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block          ControlDestination dest(&body, node->break_target(), false);
1474d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block          LoadCondition(node->cond(), &dest, true);
1475a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        }
14763ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      } else {
14773ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block        // If we have chosen not to recompile the test at the
14783ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block        // bottom, jump back to the one at the top.
14793ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block        if (has_valid_frame()) {
14803ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block          node->continue_target()->Jump();
1481a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        }
1482a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      }
1483a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      break;
14843ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    case ALWAYS_FALSE:
14853ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      UNREACHABLE();
14863ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      break;
14873ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  }
14883ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block
14893ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // The break target may be already bound (by the condition), or there
14903ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // may not be a valid frame.  Bind it only if needed.
14913ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  if (node->break_target()->is_linked()) {
14923ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    node->break_target()->Bind();
14933ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  }
14943ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  DecrementLoopNesting();
14953ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block}
1496a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1497a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
14983ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Blockvoid CodeGenerator::VisitForStatement(ForStatement* node) {
14993ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  ASSERT(!in_spilled_code());
15003ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  Comment cmnt(masm_, "[ ForStatement");
15013ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  CodeForStatementPosition(node);
1502a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
15033ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // Compile the init expression if present.
15043ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  if (node->init() != NULL) {
15053ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    Visit(node->init());
15063ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  }
1507a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
15083ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // If the condition is always false and has no side effects, we do not
15093ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // need to compile anything else.
15103ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  ConditionAnalysis info = AnalyzeCondition(node->cond());
15113ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  if (info == ALWAYS_FALSE) return;
1512a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
15133ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // Do not duplicate conditions that may have function literal
15143ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // subexpressions.  This can cause us to compile the function literal
15153ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // twice.
15163ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  bool test_at_bottom = !node->may_have_function_literal();
15173ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  node->break_target()->set_direction(JumpTarget::FORWARD_ONLY);
15183ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  IncrementLoopNesting();
15193ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block
15203ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // Target for backward edge if no test at the bottom, otherwise
15213ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // unused.
15223ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  JumpTarget loop(JumpTarget::BIDIRECTIONAL);
15233ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block
15243ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // Target for backward edge if there is a test at the bottom,
15253ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // otherwise used as target for test at the top.
15263ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  JumpTarget body;
15273ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  if (test_at_bottom) {
15283ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    body.set_direction(JumpTarget::BIDIRECTIONAL);
15293ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  }
15303ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block
15313ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // Based on the condition analysis, compile the test as necessary.
15323ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  switch (info) {
15333ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    case ALWAYS_TRUE:
15343ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      // We will not compile the test expression.  Label the top of the
15353ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      // loop.
15363ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      if (node->next() == NULL) {
15373ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block        // Use the continue target if there is no update expression.
1538a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        node->continue_target()->set_direction(JumpTarget::BIDIRECTIONAL);
1539a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        node->continue_target()->Bind();
1540a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      } else {
15413ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block        // Otherwise use the backward loop target.
15423ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block        node->continue_target()->set_direction(JumpTarget::FORWARD_ONLY);
15433ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block        loop.Bind();
1544a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      }
15453ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      break;
15463ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    case DONT_KNOW: {
15473ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      if (test_at_bottom) {
15483ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block        // Continue is either the update expression or the test at the
15493ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block        // bottom, no need to label the test at the top.
15503ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block        node->continue_target()->set_direction(JumpTarget::FORWARD_ONLY);
15513ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      } else if (node->next() == NULL) {
15523ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block        // We are not recompiling the test at the bottom and there is no
15533ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block        // update expression.
15543ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block        node->continue_target()->set_direction(JumpTarget::BIDIRECTIONAL);
15553ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block        node->continue_target()->Bind();
1556a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      } else {
15573ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block        // We are not recompiling the test at the bottom and there is an
15583ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block        // update expression.
15593ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block        node->continue_target()->set_direction(JumpTarget::FORWARD_ONLY);
15603ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block        loop.Bind();
1561a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      }
1562a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
15633ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      // Compile the test with the body as the true target and preferred
15643ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      // fall-through and with the break target as the false target.
15653ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      ControlDestination dest(&body, node->break_target(), true);
1566d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block      LoadCondition(node->cond(), &dest, true);
15673ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block
15683ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      if (dest.false_was_fall_through()) {
15693ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block        // If we got the break target as fall-through, the test may have
15703ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block        // been unconditionally false (if there are no jumps to the
15713ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block        // body).
15723ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block        if (!body.is_linked()) {
15733ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block          DecrementLoopNesting();
15743ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block          return;
15753ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block        }
15763ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block
15773ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block        // Otherwise, jump around the body on the fall through and then
15783ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block        // bind the body target.
15793ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block        node->break_target()->Unuse();
15803ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block        node->break_target()->Jump();
15813ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block        body.Bind();
1582a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      }
1583a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      break;
1584a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
15853ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    case ALWAYS_FALSE:
15863ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      UNREACHABLE();
15873ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      break;
15883ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  }
1589a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
15903ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  CheckStack();  // TODO(1222600): ignore if body contains calls.
15913ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  Visit(node->body());
1592a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
15933ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // If there is an update expression, compile it if necessary.
15943ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  if (node->next() != NULL) {
15953ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    if (node->continue_target()->is_linked()) {
15963ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      node->continue_target()->Bind();
15973ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    }
1598a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
15993ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    // Control can reach the update by falling out of the body or by a
16003ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    // continue.
16013ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    if (has_valid_frame()) {
16023ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      // Record the source position of the statement as this code which
16033ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      // is after the code for the body actually belongs to the loop
16043ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      // statement and not the body.
16053ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      CodeForStatementPosition(node);
16063ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      Visit(node->next());
16073ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    }
16083ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  }
1609a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
16103ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // Based on the condition analysis, compile the backward jump as
16113ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // necessary.
16123ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  switch (info) {
16133ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    case ALWAYS_TRUE:
16143ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      if (has_valid_frame()) {
1615a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        if (node->next() == NULL) {
16163ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block          node->continue_target()->Jump();
1617a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        } else {
16183ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block          loop.Jump();
1619a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        }
1620a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      }
16213ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      break;
16223ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    case DONT_KNOW:
16233ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      if (test_at_bottom) {
1624a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        if (node->continue_target()->is_linked()) {
16253ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block          // We can have dangling jumps to the continue target if there
16263ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block          // was no update expression.
1627a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block          node->continue_target()->Bind();
1628a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        }
16293ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block        // Control can reach the test at the bottom by falling out of
16303ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block        // the body, by a continue in the body, or from the update
16313ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block        // expression.
1632a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        if (has_valid_frame()) {
16333ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block          // The break target is the fall-through (body is a backward
16343ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block          // jump from here).
16353ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block          ControlDestination dest(&body, node->break_target(), false);
1636d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block          LoadCondition(node->cond(), &dest, true);
1637a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        }
16383ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      } else {
16393ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block        // Otherwise, jump back to the test at the top.
1640a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        if (has_valid_frame()) {
1641a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block          if (node->next() == NULL) {
1642a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block            node->continue_target()->Jump();
1643a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block          } else {
1644a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block            loop.Jump();
1645a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block          }
1646a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        }
1647a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      }
1648a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      break;
16493ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    case ALWAYS_FALSE:
16503ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      UNREACHABLE();
16513ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      break;
1652a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
1653a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
16543ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // The break target may be already bound (by the condition), or there
16553ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // may not be a valid frame.  Bind it only if needed.
16563ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  if (node->break_target()->is_linked()) {
16573ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    node->break_target()->Bind();
16583ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  }
1659a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  DecrementLoopNesting();
1660a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
1661a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1662a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1663a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CodeGenerator::VisitForInStatement(ForInStatement* node) {
1664a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(!in_spilled_code());
1665a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  VirtualFrame::SpilledScope spilled_scope;
1666a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Comment cmnt(masm_, "[ ForInStatement");
1667a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CodeForStatementPosition(node);
1668a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1669a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  JumpTarget primitive;
1670a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  JumpTarget jsobject;
1671a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  JumpTarget fixed_array;
1672a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  JumpTarget entry(JumpTarget::BIDIRECTIONAL);
1673a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  JumpTarget end_del_check;
1674a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  JumpTarget exit;
1675a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1676a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Get the object to enumerate over (converted to JSObject).
1677a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  LoadAndSpill(node->enumerable());
1678a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1679a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Both SpiderMonkey and kjs ignore null and undefined in contrast
1680a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // to the specification.  12.6.4 mandates a call to ToObject.
1681a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  frame_->EmitPop(rax);
1682a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1683a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // rax: value to be iterated over
1684a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ CompareRoot(rax, Heap::kUndefinedValueRootIndex);
1685a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  exit.Branch(equal);
1686a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ CompareRoot(rax, Heap::kNullValueRootIndex);
1687a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  exit.Branch(equal);
1688a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1689a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Stack layout in body:
1690a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // [iteration counter (smi)] <- slot 0
1691a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // [length of array]         <- slot 1
1692a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // [FixedArray]              <- slot 2
1693a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // [Map or 0]                <- slot 3
1694a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // [Object]                  <- slot 4
1695a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1696a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check if enumerable is already a JSObject
1697a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // rax: value to be iterated over
1698a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Condition is_smi = masm_->CheckSmi(rax);
1699a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  primitive.Branch(is_smi);
1700a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ CmpObjectType(rax, FIRST_JS_OBJECT_TYPE, rcx);
1701a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  jsobject.Branch(above_equal);
1702a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1703a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  primitive.Bind();
1704a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  frame_->EmitPush(rax);
1705a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  frame_->InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION, 1);
1706a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // function call returns the value in rax, which is where we want it below
1707a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1708a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  jsobject.Bind();
1709a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Get the set of properties (as a FixedArray or Map).
1710a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // rax: value to be iterated over
1711d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  frame_->EmitPush(rax);  // Push the object being iterated over.
1712d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
1713a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1714d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  // Check cache validity in generated code. This is a fast case for
1715d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  // the JSObject::IsSimpleEnum cache validity checks. If we cannot
1716d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  // guarantee cache validity, call the runtime system to check cache
1717d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  // validity or get the property names in a fixed array.
1718d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  JumpTarget call_runtime;
1719d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  JumpTarget loop(JumpTarget::BIDIRECTIONAL);
1720d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  JumpTarget check_prototype;
1721d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  JumpTarget use_cache;
1722d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  __ movq(rcx, rax);
1723d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  loop.Bind();
1724d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  // Check that there are no elements.
1725d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  __ movq(rdx, FieldOperand(rcx, JSObject::kElementsOffset));
1726d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  __ CompareRoot(rdx, Heap::kEmptyFixedArrayRootIndex);
1727d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  call_runtime.Branch(not_equal);
1728d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  // Check that instance descriptors are not empty so that we can
1729d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  // check for an enum cache.  Leave the map in ebx for the subsequent
1730d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  // prototype load.
1731d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  __ movq(rbx, FieldOperand(rcx, HeapObject::kMapOffset));
1732d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  __ movq(rdx, FieldOperand(rbx, Map::kInstanceDescriptorsOffset));
1733d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  __ CompareRoot(rdx, Heap::kEmptyDescriptorArrayRootIndex);
1734d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  call_runtime.Branch(equal);
1735d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  // Check that there in an enum cache in the non-empty instance
1736d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  // descriptors.  This is the case if the next enumeration index
1737d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  // field does not contain a smi.
1738d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  __ movq(rdx, FieldOperand(rdx, DescriptorArray::kEnumerationIndexOffset));
1739d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  is_smi = masm_->CheckSmi(rdx);
1740d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  call_runtime.Branch(is_smi);
1741d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  // For all objects but the receiver, check that the cache is empty.
1742d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  __ cmpq(rcx, rax);
1743d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  check_prototype.Branch(equal);
1744d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  __ movq(rdx, FieldOperand(rdx, DescriptorArray::kEnumCacheBridgeCacheOffset));
1745d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  __ CompareRoot(rdx, Heap::kEmptyFixedArrayRootIndex);
1746d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  call_runtime.Branch(not_equal);
1747d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  check_prototype.Bind();
1748d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  // Load the prototype from the map and loop if non-null.
1749d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  __ movq(rcx, FieldOperand(rbx, Map::kPrototypeOffset));
1750d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  __ CompareRoot(rcx, Heap::kNullValueRootIndex);
1751d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  loop.Branch(not_equal);
1752d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  // The enum cache is valid.  Load the map of the object being
1753d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  // iterated over and use the cache for the iteration.
1754d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  __ movq(rax, FieldOperand(rax, HeapObject::kMapOffset));
1755d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  use_cache.Jump();
1756d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
1757d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  call_runtime.Bind();
1758d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  // Call the runtime to get the property names for the object.
1759a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  frame_->EmitPush(rax);  // push the Object (slot 4) for the runtime call
1760a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  frame_->CallRuntime(Runtime::kGetPropertyNamesFast, 1);
1761a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1762a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // If we got a Map, we can do a fast modification check.
1763a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Otherwise, we got a FixedArray, and we have to do a slow check.
1764a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // rax: map or fixed array (result from call to
1765a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Runtime::kGetPropertyNamesFast)
1766a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ movq(rdx, rax);
1767a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ movq(rcx, FieldOperand(rdx, HeapObject::kMapOffset));
1768a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ CompareRoot(rcx, Heap::kMetaMapRootIndex);
1769a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  fixed_array.Branch(not_equal);
1770a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1771d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  use_cache.Bind();
1772a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Get enum cache
1773d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  // rax: map (either the result from a call to
1774d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  // Runtime::kGetPropertyNamesFast or has been fetched directly from
1775d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  // the object)
1776a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ movq(rcx, rax);
1777a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ movq(rcx, FieldOperand(rcx, Map::kInstanceDescriptorsOffset));
1778a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Get the bridge array held in the enumeration index field.
1779a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ movq(rcx, FieldOperand(rcx, DescriptorArray::kEnumerationIndexOffset));
1780a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Get the cache from the bridge array.
1781a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ movq(rdx, FieldOperand(rcx, DescriptorArray::kEnumCacheBridgeCacheOffset));
1782a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1783a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  frame_->EmitPush(rax);  // <- slot 3
1784a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  frame_->EmitPush(rdx);  // <- slot 2
1785a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ movl(rax, FieldOperand(rdx, FixedArray::kLengthOffset));
1786a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ Integer32ToSmi(rax, rax);
1787a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  frame_->EmitPush(rax);  // <- slot 1
17883ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  frame_->EmitPush(Smi::FromInt(0));  // <- slot 0
1789a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  entry.Jump();
1790a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1791a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  fixed_array.Bind();
1792a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // rax: fixed array (result from call to Runtime::kGetPropertyNamesFast)
17933ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  frame_->EmitPush(Smi::FromInt(0));  // <- slot 3
1794a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  frame_->EmitPush(rax);  // <- slot 2
1795a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1796a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Push the length of the array and the initial index onto the stack.
1797a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ movl(rax, FieldOperand(rax, FixedArray::kLengthOffset));
1798a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ Integer32ToSmi(rax, rax);
1799a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  frame_->EmitPush(rax);  // <- slot 1
18003ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  frame_->EmitPush(Smi::FromInt(0));  // <- slot 0
1801a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1802a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Condition.
1803a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  entry.Bind();
1804a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Grab the current frame's height for the break and continue
1805a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // targets only after all the state is pushed on the frame.
1806a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  node->break_target()->set_direction(JumpTarget::FORWARD_ONLY);
1807a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  node->continue_target()->set_direction(JumpTarget::FORWARD_ONLY);
1808a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1809a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ movq(rax, frame_->ElementAt(0));  // load the current count
18103ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  __ SmiCompare(frame_->ElementAt(1), rax);  // compare to the array length
18113ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  node->break_target()->Branch(below_equal);
1812a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1813a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Get the i'th entry of the array.
1814a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ movq(rdx, frame_->ElementAt(2));
1815a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  SmiIndex index = masm_->SmiToIndex(rbx, rax, kPointerSizeLog2);
1816a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ movq(rbx,
1817a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block          FieldOperand(rdx, index.reg, index.scale, FixedArray::kHeaderSize));
1818a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1819a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Get the expected map from the stack or a zero map in the
1820a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // permanent slow case rax: current iteration count rbx: i'th entry
1821a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // of the enum cache
1822a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ movq(rdx, frame_->ElementAt(3));
1823a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check if the expected map still matches that of the enumerable.
1824a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // If not, we have to filter the key.
1825a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // rax: current iteration count
1826a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // rbx: i'th entry of the enum cache
1827a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // rdx: expected map value
1828a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ movq(rcx, frame_->ElementAt(4));
1829a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ movq(rcx, FieldOperand(rcx, HeapObject::kMapOffset));
1830a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ cmpq(rcx, rdx);
1831a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  end_del_check.Branch(equal);
1832a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1833a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Convert the entry to a string (or null if it isn't a property anymore).
1834a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  frame_->EmitPush(frame_->ElementAt(4));  // push enumerable
1835a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  frame_->EmitPush(rbx);  // push entry
1836a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  frame_->InvokeBuiltin(Builtins::FILTER_KEY, CALL_FUNCTION, 2);
1837a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ movq(rbx, rax);
1838a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1839a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // If the property has been removed while iterating, we just skip it.
1840a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ CompareRoot(rbx, Heap::kNullValueRootIndex);
1841a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  node->continue_target()->Branch(equal);
1842a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1843a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  end_del_check.Bind();
1844a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Store the entry in the 'each' expression and take another spin in the
1845a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // loop.  rdx: i'th entry of the enum cache (or string there of)
1846a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  frame_->EmitPush(rbx);
1847a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  { Reference each(this, node->each());
1848a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Loading a reference may leave the frame in an unspilled state.
1849a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    frame_->SpillAll();
1850a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (!each.is_illegal()) {
1851a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      if (each.size() > 0) {
1852a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        frame_->EmitPush(frame_->ElementAt(each.size()));
1853d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke        each.SetValue(NOT_CONST_INIT);
1854d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke        frame_->Drop(2);  // Drop the original and the copy of the element.
1855d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      } else {
1856d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke        // If the reference has size zero then we can use the value below
1857d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke        // the reference as if it were above the reference, instead of pushing
1858d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke        // a new copy of it above the reference.
1859d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke        each.SetValue(NOT_CONST_INIT);
1860d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke        frame_->Drop();  // Drop the original of the element.
1861a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      }
1862a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
1863a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
1864a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Unloading a reference may leave the frame in an unspilled state.
1865a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  frame_->SpillAll();
1866a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1867a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Body.
1868a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CheckStack();  // TODO(1222600): ignore if body contains calls.
1869a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  VisitAndSpill(node->body());
1870a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1871a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Next.  Reestablish a spilled frame in case we are coming here via
1872a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // a continue in the body.
1873a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  node->continue_target()->Bind();
1874a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  frame_->SpillAll();
1875a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  frame_->EmitPop(rax);
18763ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  __ SmiAddConstant(rax, rax, Smi::FromInt(1));
1877a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  frame_->EmitPush(rax);
1878a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  entry.Jump();
1879a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1880a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Cleanup.  No need to spill because VirtualFrame::Drop is safe for
1881a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // any frame.
1882a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  node->break_target()->Bind();
1883a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  frame_->Drop(5);
1884a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1885a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Exit.
1886a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  exit.Bind();
1887a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1888a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  node->continue_target()->Unuse();
1889a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  node->break_target()->Unuse();
1890a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
1891a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
18923ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Blockvoid CodeGenerator::VisitTryCatchStatement(TryCatchStatement* node) {
1893a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(!in_spilled_code());
1894a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  VirtualFrame::SpilledScope spilled_scope;
18953ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  Comment cmnt(masm_, "[ TryCatchStatement");
1896a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CodeForStatementPosition(node);
1897a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1898a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  JumpTarget try_block;
1899a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  JumpTarget exit;
1900a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1901a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  try_block.Call();
1902a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // --- Catch block ---
1903a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  frame_->EmitPush(rax);
1904a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1905a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Store the caught exception in the catch variable.
1906e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  Variable* catch_var = node->catch_var()->var();
1907e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  ASSERT(catch_var != NULL && catch_var->slot() != NULL);
1908e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  StoreToSlot(catch_var->slot(), NOT_CONST_INIT);
1909a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1910a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Remove the exception from the stack.
1911a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  frame_->Drop();
1912a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1913a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  VisitStatementsAndSpill(node->catch_block()->statements());
1914a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (has_valid_frame()) {
1915a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    exit.Jump();
1916a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
1917a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1918a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1919a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // --- Try block ---
1920a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  try_block.Bind();
1921a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1922a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  frame_->PushTryHandler(TRY_CATCH_HANDLER);
1923a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  int handler_height = frame_->height();
1924a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1925a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Shadow the jump targets for all escapes from the try block, including
1926a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // returns.  During shadowing, the original target is hidden as the
1927a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // ShadowTarget and operations on the original actually affect the
1928a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // shadowing target.
1929a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //
1930a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // We should probably try to unify the escaping targets and the return
1931a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // target.
1932a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  int nof_escapes = node->escaping_targets()->length();
1933a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  List<ShadowTarget*> shadows(1 + nof_escapes);
1934a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1935a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Add the shadow target for the function return.
1936a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  static const int kReturnShadowIndex = 0;
1937a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  shadows.Add(new ShadowTarget(&function_return_));
1938a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  bool function_return_was_shadowed = function_return_is_shadowed_;
1939a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  function_return_is_shadowed_ = true;
1940a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(shadows[kReturnShadowIndex]->other_target() == &function_return_);
1941a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1942a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Add the remaining shadow targets.
1943a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  for (int i = 0; i < nof_escapes; i++) {
1944a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    shadows.Add(new ShadowTarget(node->escaping_targets()->at(i)));
1945a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
1946a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1947a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Generate code for the statements in the try block.
1948a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  VisitStatementsAndSpill(node->try_block()->statements());
1949a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1950a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Stop the introduced shadowing and count the number of required unlinks.
1951a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // After shadowing stops, the original targets are unshadowed and the
1952a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // ShadowTargets represent the formerly shadowing targets.
1953a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  bool has_unlinks = false;
1954a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  for (int i = 0; i < shadows.length(); i++) {
1955a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    shadows[i]->StopShadowing();
1956a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    has_unlinks = has_unlinks || shadows[i]->is_linked();
1957a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
1958a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  function_return_is_shadowed_ = function_return_was_shadowed;
1959a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1960a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Get an external reference to the handler address.
1961a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ExternalReference handler_address(Top::k_handler_address);
1962a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1963a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Make sure that there's nothing left on the stack above the
1964a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // handler structure.
1965a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (FLAG_debug_code) {
1966a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ movq(kScratchRegister, handler_address);
1967a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ cmpq(rsp, Operand(kScratchRegister, 0));
1968a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ Assert(equal, "stack pointer should point to top handler");
1969a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
1970a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1971a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // If we can fall off the end of the try block, unlink from try chain.
1972a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (has_valid_frame()) {
1973a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // The next handler address is on top of the frame.  Unlink from
1974a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // the handler list and drop the rest of this handler from the
1975a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // frame.
1976a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    ASSERT(StackHandlerConstants::kNextOffset == 0);
1977a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ movq(kScratchRegister, handler_address);
1978a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    frame_->EmitPop(Operand(kScratchRegister, 0));
1979a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    frame_->Drop(StackHandlerConstants::kSize / kPointerSize - 1);
1980a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (has_unlinks) {
1981a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      exit.Jump();
1982a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
1983a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
1984a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1985a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Generate unlink code for the (formerly) shadowing targets that
1986a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // have been jumped to.  Deallocate each shadow target.
1987a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Result return_value;
1988a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  for (int i = 0; i < shadows.length(); i++) {
1989a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (shadows[i]->is_linked()) {
1990a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // Unlink from try chain; be careful not to destroy the TOS if
1991a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // there is one.
1992a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      if (i == kReturnShadowIndex) {
1993a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        shadows[i]->Bind(&return_value);
1994a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        return_value.ToRegister(rax);
1995a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      } else {
1996a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        shadows[i]->Bind();
1997a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      }
1998a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // Because we can be jumping here (to spilled code) from
1999a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // unspilled code, we need to reestablish a spilled frame at
2000a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // this block.
2001a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      frame_->SpillAll();
2002a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2003a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // Reload sp from the top handler, because some statements that we
2004a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // break from (eg, for...in) may have left stuff on the stack.
2005a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      __ movq(kScratchRegister, handler_address);
2006a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      __ movq(rsp, Operand(kScratchRegister, 0));
2007a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      frame_->Forget(frame_->height() - handler_height);
2008a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2009a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      ASSERT(StackHandlerConstants::kNextOffset == 0);
2010a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      __ movq(kScratchRegister, handler_address);
2011a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      frame_->EmitPop(Operand(kScratchRegister, 0));
2012a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      frame_->Drop(StackHandlerConstants::kSize / kPointerSize - 1);
2013a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2014a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      if (i == kReturnShadowIndex) {
2015a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        if (!function_return_is_shadowed_) frame_->PrepareForReturn();
2016a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        shadows[i]->other_target()->Jump(&return_value);
2017a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      } else {
2018a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        shadows[i]->other_target()->Jump();
2019a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      }
2020a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
2021a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
2022a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2023a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  exit.Bind();
2024a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
2025a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2026a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
20273ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Blockvoid CodeGenerator::VisitTryFinallyStatement(TryFinallyStatement* node) {
2028a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(!in_spilled_code());
2029a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  VirtualFrame::SpilledScope spilled_scope;
20303ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  Comment cmnt(masm_, "[ TryFinallyStatement");
2031a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CodeForStatementPosition(node);
2032a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2033a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // State: Used to keep track of reason for entering the finally
2034a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // block. Should probably be extended to hold information for
2035a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // break/continue from within the try block.
2036a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  enum { FALLING, THROWING, JUMPING };
2037a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2038a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  JumpTarget try_block;
2039a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  JumpTarget finally_block;
2040a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2041a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  try_block.Call();
2042a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2043a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  frame_->EmitPush(rax);
2044a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // In case of thrown exceptions, this is where we continue.
20453ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  __ Move(rcx, Smi::FromInt(THROWING));
2046a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  finally_block.Jump();
2047a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2048a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // --- Try block ---
2049a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  try_block.Bind();
2050a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2051a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  frame_->PushTryHandler(TRY_FINALLY_HANDLER);
2052a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  int handler_height = frame_->height();
2053a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2054a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Shadow the jump targets for all escapes from the try block, including
2055a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // returns.  During shadowing, the original target is hidden as the
2056a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // ShadowTarget and operations on the original actually affect the
2057a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // shadowing target.
2058a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //
2059a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // We should probably try to unify the escaping targets and the return
2060a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // target.
2061a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  int nof_escapes = node->escaping_targets()->length();
2062a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  List<ShadowTarget*> shadows(1 + nof_escapes);
2063a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2064a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Add the shadow target for the function return.
2065a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  static const int kReturnShadowIndex = 0;
2066a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  shadows.Add(new ShadowTarget(&function_return_));
2067a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  bool function_return_was_shadowed = function_return_is_shadowed_;
2068a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  function_return_is_shadowed_ = true;
2069a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(shadows[kReturnShadowIndex]->other_target() == &function_return_);
2070a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2071a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Add the remaining shadow targets.
2072a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  for (int i = 0; i < nof_escapes; i++) {
2073a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    shadows.Add(new ShadowTarget(node->escaping_targets()->at(i)));
2074a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
2075a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2076a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Generate code for the statements in the try block.
2077a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  VisitStatementsAndSpill(node->try_block()->statements());
2078a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2079a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Stop the introduced shadowing and count the number of required unlinks.
2080a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // After shadowing stops, the original targets are unshadowed and the
2081a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // ShadowTargets represent the formerly shadowing targets.
2082a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  int nof_unlinks = 0;
2083a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  for (int i = 0; i < shadows.length(); i++) {
2084a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    shadows[i]->StopShadowing();
2085a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (shadows[i]->is_linked()) nof_unlinks++;
2086a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
2087a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  function_return_is_shadowed_ = function_return_was_shadowed;
2088a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2089a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Get an external reference to the handler address.
2090a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ExternalReference handler_address(Top::k_handler_address);
2091a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2092a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // If we can fall off the end of the try block, unlink from the try
2093a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // chain and set the state on the frame to FALLING.
2094a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (has_valid_frame()) {
2095a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // The next handler address is on top of the frame.
2096a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    ASSERT(StackHandlerConstants::kNextOffset == 0);
2097a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ movq(kScratchRegister, handler_address);
2098a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    frame_->EmitPop(Operand(kScratchRegister, 0));
2099a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    frame_->Drop(StackHandlerConstants::kSize / kPointerSize - 1);
2100a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2101a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Fake a top of stack value (unneeded when FALLING) and set the
2102a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // state in ecx, then jump around the unlink blocks if any.
2103a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    frame_->EmitPush(Heap::kUndefinedValueRootIndex);
21043ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    __ Move(rcx, Smi::FromInt(FALLING));
2105a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (nof_unlinks > 0) {
2106a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      finally_block.Jump();
2107a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
2108a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
2109a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2110a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Generate code to unlink and set the state for the (formerly)
2111a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // shadowing targets that have been jumped to.
2112a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  for (int i = 0; i < shadows.length(); i++) {
2113a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (shadows[i]->is_linked()) {
2114a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // If we have come from the shadowed return, the return value is
2115a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // on the virtual frame.  We must preserve it until it is
2116a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // pushed.
2117a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      if (i == kReturnShadowIndex) {
2118a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        Result return_value;
2119a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        shadows[i]->Bind(&return_value);
2120a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        return_value.ToRegister(rax);
2121a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      } else {
2122a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        shadows[i]->Bind();
2123a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      }
2124a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // Because we can be jumping here (to spilled code) from
2125a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // unspilled code, we need to reestablish a spilled frame at
2126a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // this block.
2127a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      frame_->SpillAll();
2128a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2129a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // Reload sp from the top handler, because some statements that
2130a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // we break from (eg, for...in) may have left stuff on the
2131a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // stack.
2132a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      __ movq(kScratchRegister, handler_address);
2133a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      __ movq(rsp, Operand(kScratchRegister, 0));
2134a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      frame_->Forget(frame_->height() - handler_height);
2135a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2136a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // Unlink this handler and drop it from the frame.
2137a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      ASSERT(StackHandlerConstants::kNextOffset == 0);
2138a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      __ movq(kScratchRegister, handler_address);
2139a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      frame_->EmitPop(Operand(kScratchRegister, 0));
2140a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      frame_->Drop(StackHandlerConstants::kSize / kPointerSize - 1);
2141a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2142a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      if (i == kReturnShadowIndex) {
2143a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        // If this target shadowed the function return, materialize
2144a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        // the return value on the stack.
2145a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        frame_->EmitPush(rax);
2146a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      } else {
2147a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        // Fake TOS for targets that shadowed breaks and continues.
2148a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        frame_->EmitPush(Heap::kUndefinedValueRootIndex);
2149a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      }
21503ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      __ Move(rcx, Smi::FromInt(JUMPING + i));
2151a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      if (--nof_unlinks > 0) {
2152a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        // If this is not the last unlink block, jump around the next.
2153a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        finally_block.Jump();
2154a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      }
2155a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
2156a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
2157a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2158a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // --- Finally block ---
2159a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  finally_block.Bind();
2160a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2161a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Push the state on the stack.
2162a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  frame_->EmitPush(rcx);
2163a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2164a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // We keep two elements on the stack - the (possibly faked) result
2165a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // and the state - while evaluating the finally block.
2166a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //
2167a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Generate code for the statements in the finally block.
2168a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  VisitStatementsAndSpill(node->finally_block()->statements());
2169a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2170a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (has_valid_frame()) {
2171a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Restore state and return value or faked TOS.
2172a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    frame_->EmitPop(rcx);
2173a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    frame_->EmitPop(rax);
2174a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
2175a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2176a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Generate code to jump to the right destination for all used
2177a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // formerly shadowing targets.  Deallocate each shadow target.
2178a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  for (int i = 0; i < shadows.length(); i++) {
2179a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (has_valid_frame() && shadows[i]->is_bound()) {
2180a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      BreakTarget* original = shadows[i]->other_target();
21813ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      __ SmiCompare(rcx, Smi::FromInt(JUMPING + i));
2182a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      if (i == kReturnShadowIndex) {
2183a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        // The return value is (already) in rax.
2184a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        Result return_value = allocator_->Allocate(rax);
2185a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        ASSERT(return_value.is_valid());
2186a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        if (function_return_is_shadowed_) {
2187a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block          original->Branch(equal, &return_value);
2188a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        } else {
2189a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block          // Branch around the preparation for return which may emit
2190a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block          // code.
2191a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block          JumpTarget skip;
2192a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block          skip.Branch(not_equal);
2193a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block          frame_->PrepareForReturn();
2194a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block          original->Jump(&return_value);
2195a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block          skip.Bind();
2196a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        }
2197a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      } else {
2198a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        original->Branch(equal);
2199a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      }
2200a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
2201a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
2202a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2203a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (has_valid_frame()) {
2204a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Check if we need to rethrow the exception.
2205a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    JumpTarget exit;
22063ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    __ SmiCompare(rcx, Smi::FromInt(THROWING));
2207a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    exit.Branch(not_equal);
2208a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2209a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Rethrow exception.
2210a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    frame_->EmitPush(rax);  // undo pop from above
2211a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    frame_->CallRuntime(Runtime::kReThrow, 1);
2212a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2213a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Done.
2214a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    exit.Bind();
2215a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
2216a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
2217a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2218a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2219a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CodeGenerator::VisitDebuggerStatement(DebuggerStatement* node) {
2220a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(!in_spilled_code());
2221a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Comment cmnt(masm_, "[ DebuggerStatement");
2222a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CodeForStatementPosition(node);
2223a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#ifdef ENABLE_DEBUGGER_SUPPORT
2224a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Spill everything, even constants, to the frame.
2225a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  frame_->SpillAll();
22264515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke
2227402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  frame_->DebugBreak();
2228a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Ignore the return value.
2229a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#endif
2230a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
2231a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2232a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2233a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CodeGenerator::InstantiateBoilerplate(Handle<JSFunction> boilerplate) {
2234e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  ASSERT(boilerplate->IsBoilerplate());
2235e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
2236a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // The inevitable call will sync frame elements to memory anyway, so
2237a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // we do it eagerly to allow us to push the arguments directly into
2238a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // place.
2239a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  frame_->SyncRange(0, frame_->element_count() - 1);
2240a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2241e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // Use the fast case closure allocation code that allocates in new
2242e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // space for nested functions that don't need literals cloning.
2243e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  if (scope()->is_function_scope() && boilerplate->NumberOfLiterals() == 0) {
2244e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke    FastNewClosureStub stub;
2245e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke    frame_->Push(boilerplate);
2246e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke    Result answer = frame_->CallStub(&stub, 1);
2247e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke    frame_->Push(&answer);
2248e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  } else {
2249e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke    // Call the runtime to instantiate the function boilerplate
2250e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke    // object.
2251e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke    frame_->EmitPush(rsi);
2252e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke    frame_->EmitPush(boilerplate);
2253e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke    Result result = frame_->CallRuntime(Runtime::kNewClosure, 2);
2254e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke    frame_->Push(&result);
2255e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  }
2256a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
2257a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2258a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2259a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CodeGenerator::VisitFunctionLiteral(FunctionLiteral* node) {
2260a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Comment cmnt(masm_, "[ FunctionLiteral");
2261a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2262a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Build the function boilerplate and instantiate it.
2263d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  Handle<JSFunction> boilerplate =
22643100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu      Compiler::BuildBoilerplate(node, script(), this);
2265a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check for stack-overflow exception.
2266a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (HasStackOverflow()) return;
2267a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  InstantiateBoilerplate(boilerplate);
2268a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
2269a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2270a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2271a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CodeGenerator::VisitFunctionBoilerplateLiteral(
2272a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    FunctionBoilerplateLiteral* node) {
2273a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Comment cmnt(masm_, "[ FunctionBoilerplateLiteral");
2274a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  InstantiateBoilerplate(node->boilerplate());
2275a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
2276a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2277a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2278a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CodeGenerator::VisitConditional(Conditional* node) {
2279a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Comment cmnt(masm_, "[ Conditional");
2280a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  JumpTarget then;
2281a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  JumpTarget else_;
2282a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  JumpTarget exit;
2283a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ControlDestination dest(&then, &else_, true);
2284d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  LoadCondition(node->condition(), &dest, true);
2285a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2286a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (dest.false_was_fall_through()) {
2287a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // The else target was bound, so we compile the else part first.
2288d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    Load(node->else_expression());
2289a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2290a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (then.is_linked()) {
2291a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      exit.Jump();
2292a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      then.Bind();
2293d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block      Load(node->then_expression());
2294a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
2295a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  } else {
2296a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // The then target was bound, so we compile the then part first.
2297d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    Load(node->then_expression());
2298a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2299a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (else_.is_linked()) {
2300a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      exit.Jump();
2301a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      else_.Bind();
2302d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block      Load(node->else_expression());
2303a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
2304a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
2305a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2306a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  exit.Bind();
2307a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
2308a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2309a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2310a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CodeGenerator::VisitSlot(Slot* node) {
2311a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Comment cmnt(masm_, "[ Slot");
2312d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  LoadFromSlotCheckForArguments(node, NOT_INSIDE_TYPEOF);
2313a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
2314a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2315a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2316a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CodeGenerator::VisitVariableProxy(VariableProxy* node) {
2317a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Comment cmnt(masm_, "[ VariableProxy");
2318a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Variable* var = node->var();
2319a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Expression* expr = var->rewrite();
2320a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (expr != NULL) {
2321a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    Visit(expr);
2322a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  } else {
2323a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    ASSERT(var->is_global());
2324a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    Reference ref(this, node);
2325d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    ref.GetValue();
2326a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
2327a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
2328a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2329a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2330a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CodeGenerator::VisitLiteral(Literal* node) {
2331a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Comment cmnt(masm_, "[ Literal");
2332a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  frame_->Push(node->handle());
2333a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
2334a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2335a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2336a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// Materialize the regexp literal 'node' in the literals array
2337a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// 'literals' of the function.  Leave the regexp boilerplate in
2338a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// 'boilerplate'.
2339a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockclass DeferredRegExpLiteral: public DeferredCode {
2340a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block public:
2341a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  DeferredRegExpLiteral(Register boilerplate,
2342a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                        Register literals,
2343a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                        RegExpLiteral* node)
2344a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      : boilerplate_(boilerplate), literals_(literals), node_(node) {
2345a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    set_comment("[ DeferredRegExpLiteral");
2346a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
2347a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2348a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  void Generate();
2349a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2350a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block private:
2351a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Register boilerplate_;
2352a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Register literals_;
2353a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  RegExpLiteral* node_;
2354a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block};
2355a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2356a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2357a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid DeferredRegExpLiteral::Generate() {
2358a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Since the entry is undefined we call the runtime system to
2359a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // compute the literal.
2360a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Literal array (0).
2361a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ push(literals_);
2362a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Literal index (1).
23633ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  __ Push(Smi::FromInt(node_->literal_index()));
2364a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // RegExp pattern (2).
2365a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ Push(node_->pattern());
2366a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // RegExp flags (3).
2367a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ Push(node_->flags());
2368a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ CallRuntime(Runtime::kMaterializeRegExpLiteral, 4);
2369a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (!boilerplate_.is(rax)) __ movq(boilerplate_, rax);
2370a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
2371a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2372a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2373a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CodeGenerator::VisitRegExpLiteral(RegExpLiteral* node) {
2374a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Comment cmnt(masm_, "[ RegExp Literal");
2375a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2376a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Retrieve the literals array and check the allocated entry.  Begin
2377a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // with a writable copy of the function of this activation in a
2378a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // register.
2379a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  frame_->PushFunction();
2380a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Result literals = frame_->Pop();
2381a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  literals.ToRegister();
2382a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  frame_->Spill(literals.reg());
2383a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2384a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Load the literals array of the function.
2385a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ movq(literals.reg(),
2386a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block          FieldOperand(literals.reg(), JSFunction::kLiteralsOffset));
2387a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2388a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Load the literal at the ast saved index.
2389a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Result boilerplate = allocator_->Allocate();
2390a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(boilerplate.is_valid());
2391a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  int literal_offset =
2392a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      FixedArray::kHeaderSize + node->literal_index() * kPointerSize;
2393a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ movq(boilerplate.reg(), FieldOperand(literals.reg(), literal_offset));
2394a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2395a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check whether we need to materialize the RegExp object.  If so,
2396a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // jump to the deferred code passing the literals array.
2397a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  DeferredRegExpLiteral* deferred =
2398a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      new DeferredRegExpLiteral(boilerplate.reg(), literals.reg(), node);
2399a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ CompareRoot(boilerplate.reg(), Heap::kUndefinedValueRootIndex);
2400a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  deferred->Branch(equal);
2401a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  deferred->BindExit();
2402a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  literals.Unuse();
2403a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2404a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Push the boilerplate object.
2405a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  frame_->Push(&boilerplate);
2406a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
2407a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2408a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2409a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CodeGenerator::VisitObjectLiteral(ObjectLiteral* node) {
2410a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Comment cmnt(masm_, "[ ObjectLiteral");
2411a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2412e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // Load a writable copy of the function of this activation in a
2413a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // register.
2414a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  frame_->PushFunction();
2415a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Result literals = frame_->Pop();
2416a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  literals.ToRegister();
2417a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  frame_->Spill(literals.reg());
2418a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2419a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Load the literals array of the function.
2420a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ movq(literals.reg(),
2421a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block          FieldOperand(literals.reg(), JSFunction::kLiteralsOffset));
2422e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // Literal array.
2423e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  frame_->Push(&literals);
2424e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // Literal index.
2425e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  frame_->Push(Smi::FromInt(node->literal_index()));
2426e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // Constant properties.
2427e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  frame_->Push(node->constant_properties());
2428e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  Result clone;
2429e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  if (node->depth() > 1) {
2430e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke    clone = frame_->CallRuntime(Runtime::kCreateObjectLiteral, 3);
2431e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  } else {
2432e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke    clone = frame_->CallRuntime(Runtime::kCreateObjectLiteralShallow, 3);
2433a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
2434a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  frame_->Push(&clone);
2435a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2436a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  for (int i = 0; i < node->properties()->length(); i++) {
2437a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    ObjectLiteral::Property* property = node->properties()->at(i);
2438a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    switch (property->kind()) {
2439a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      case ObjectLiteral::Property::CONSTANT:
2440a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        break;
2441a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      case ObjectLiteral::Property::MATERIALIZED_LITERAL:
2442a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        if (CompileTimeValue::IsCompileTimeValue(property->value())) break;
2443a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        // else fall through.
2444a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      case ObjectLiteral::Property::COMPUTED: {
2445a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        Handle<Object> key(property->key()->handle());
2446a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        if (key->IsSymbol()) {
2447a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block          // Duplicate the object as the IC receiver.
2448a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block          frame_->Dup();
2449a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block          Load(property->value());
2450a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block          frame_->Push(key);
2451a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block          Result ignored = frame_->CallStoreIC();
2452a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block          break;
2453a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        }
2454a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        // Fall through
2455a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      }
2456a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      case ObjectLiteral::Property::PROTOTYPE: {
2457a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        // Duplicate the object as an argument to the runtime call.
2458a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        frame_->Dup();
2459a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        Load(property->key());
2460a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        Load(property->value());
2461a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        Result ignored = frame_->CallRuntime(Runtime::kSetProperty, 3);
2462a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        // Ignore the result.
2463a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        break;
2464a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      }
2465a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      case ObjectLiteral::Property::SETTER: {
2466a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        // Duplicate the object as an argument to the runtime call.
2467a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        frame_->Dup();
2468a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        Load(property->key());
2469a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        frame_->Push(Smi::FromInt(1));
2470a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        Load(property->value());
2471a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        Result ignored = frame_->CallRuntime(Runtime::kDefineAccessor, 4);
2472a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        // Ignore the result.
2473a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        break;
2474a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      }
2475a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      case ObjectLiteral::Property::GETTER: {
2476a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        // Duplicate the object as an argument to the runtime call.
2477a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        frame_->Dup();
2478a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        Load(property->key());
2479a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        frame_->Push(Smi::FromInt(0));
2480a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        Load(property->value());
2481a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        Result ignored = frame_->CallRuntime(Runtime::kDefineAccessor, 4);
2482a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        // Ignore the result.
2483a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        break;
2484a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      }
2485a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      default: UNREACHABLE();
2486a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
2487a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
2488a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
2489a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2490a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2491a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CodeGenerator::VisitArrayLiteral(ArrayLiteral* node) {
2492a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Comment cmnt(masm_, "[ ArrayLiteral");
2493a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2494e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // Load a writable copy of the function of this activation in a
2495a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // register.
2496a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  frame_->PushFunction();
2497a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Result literals = frame_->Pop();
2498a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  literals.ToRegister();
2499a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  frame_->Spill(literals.reg());
2500a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2501a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Load the literals array of the function.
2502a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ movq(literals.reg(),
2503a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block          FieldOperand(literals.reg(), JSFunction::kLiteralsOffset));
2504402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu
2505e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  frame_->Push(&literals);
2506e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  frame_->Push(Smi::FromInt(node->literal_index()));
2507e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  frame_->Push(node->constant_elements());
2508402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  int length = node->values()->length();
2509e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  Result clone;
2510e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  if (node->depth() > 1) {
2511e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke    clone = frame_->CallRuntime(Runtime::kCreateArrayLiteral, 3);
2512402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  } else if (length > FastCloneShallowArrayStub::kMaximumLength) {
2513e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke    clone = frame_->CallRuntime(Runtime::kCreateArrayLiteralShallow, 3);
2514402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  } else {
2515402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    FastCloneShallowArrayStub stub(length);
2516402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    clone = frame_->CallStub(&stub, 3);
2517a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
2518a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  frame_->Push(&clone);
2519a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2520a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Generate code to set the elements in the array that are not
2521a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // literals.
2522a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  for (int i = 0; i < node->values()->length(); i++) {
2523a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    Expression* value = node->values()->at(i);
2524a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2525a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // If value is a literal the property value is already set in the
2526a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // boilerplate object.
2527a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (value->AsLiteral() != NULL) continue;
2528a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // If value is a materialized literal the property value is already set
2529a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // in the boilerplate object if it is simple.
2530a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (CompileTimeValue::IsCompileTimeValue(value)) continue;
2531a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2532a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // The property must be set by generated code.
2533a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    Load(value);
2534a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2535a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Get the property value off the stack.
2536a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    Result prop_value = frame_->Pop();
2537a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    prop_value.ToRegister();
2538a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2539a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Fetch the array literal while leaving a copy on the stack and
2540a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // use it to get the elements array.
2541a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    frame_->Dup();
2542a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    Result elements = frame_->Pop();
2543a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    elements.ToRegister();
2544a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    frame_->Spill(elements.reg());
2545a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Get the elements FixedArray.
2546a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ movq(elements.reg(),
2547a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block            FieldOperand(elements.reg(), JSObject::kElementsOffset));
2548a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2549a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Write to the indexed properties array.
2550a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    int offset = i * kPointerSize + FixedArray::kHeaderSize;
2551a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ movq(FieldOperand(elements.reg(), offset), prop_value.reg());
2552a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2553a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Update the write barrier for the array address.
2554a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    frame_->Spill(prop_value.reg());  // Overwritten by the write barrier.
2555a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    Result scratch = allocator_->Allocate();
2556a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    ASSERT(scratch.is_valid());
2557a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ RecordWrite(elements.reg(), offset, prop_value.reg(), scratch.reg());
2558a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
2559a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
2560a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2561a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2562a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CodeGenerator::VisitCatchExtensionObject(CatchExtensionObject* node) {
2563a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(!in_spilled_code());
2564a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Call runtime routine to allocate the catch extension object and
2565a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // assign the exception value to the catch variable.
2566a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Comment cmnt(masm_, "[ CatchExtensionObject");
2567a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Load(node->key());
2568a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Load(node->value());
2569a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Result result =
2570a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      frame_->CallRuntime(Runtime::kCreateCatchExtensionObject, 2);
2571a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  frame_->Push(&result);
2572a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
2573a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2574a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2575a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CodeGenerator::VisitAssignment(Assignment* node) {
2576a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Comment cmnt(masm_, "[ Assignment");
2577a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2578d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  { Reference target(this, node->target(), node->is_compound());
2579a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (target.is_illegal()) {
2580a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // Fool the virtual frame into thinking that we left the assignment's
2581a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // value on the frame.
2582a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      frame_->Push(Smi::FromInt(0));
2583a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      return;
2584a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
2585a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    Variable* var = node->target()->AsVariableProxy()->AsVariable();
2586a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2587a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (node->starts_initialization_block()) {
2588a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      ASSERT(target.type() == Reference::NAMED ||
2589a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block             target.type() == Reference::KEYED);
2590a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // Change to slow case in the beginning of an initialization
2591a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // block to avoid the quadratic behavior of repeatedly adding
2592a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // fast properties.
2593a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2594a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // The receiver is the argument to the runtime call.  It is the
2595a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // first value pushed when the reference was loaded to the
2596a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // frame.
2597a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      frame_->PushElementAt(target.size() - 1);
2598a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      Result ignored = frame_->CallRuntime(Runtime::kToSlowProperties, 1);
2599a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
2600d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    if (node->ends_initialization_block()) {
2601d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      // Add an extra copy of the receiver to the frame, so that it can be
2602d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      // converted back to fast case after the assignment.
2603d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      ASSERT(target.type() == Reference::NAMED ||
2604d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke             target.type() == Reference::KEYED);
2605d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      if (target.type() == Reference::NAMED) {
2606d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke        frame_->Dup();
2607d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke        // Dup target receiver on stack.
2608d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      } else {
2609d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke        ASSERT(target.type() == Reference::KEYED);
2610d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke        Result temp = frame_->Pop();
2611d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke        frame_->Dup();
2612d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke        frame_->Push(&temp);
2613d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      }
2614d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    }
2615a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (node->op() == Token::ASSIGN ||
2616a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        node->op() == Token::INIT_VAR ||
2617a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        node->op() == Token::INIT_CONST) {
2618a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      Load(node->value());
2619a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2620d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    } else {  // Assignment is a compound assignment.
2621a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      Literal* literal = node->value()->AsLiteral();
2622a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      bool overwrite_value =
2623a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block          (node->value()->AsBinaryOperation() != NULL &&
2624a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block           node->value()->AsBinaryOperation()->ResultOverwriteAllowed());
2625a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      Variable* right_var = node->value()->AsVariableProxy()->AsVariable();
2626a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // There are two cases where the target is not read in the right hand
2627a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // side, that are easy to test for: the right hand side is a literal,
2628a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // or the right hand side is a different variable.  TakeValue invalidates
2629a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // the target, with an implicit promise that it will be written to again
2630a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // before it is read.
2631a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      if (literal != NULL || (right_var != NULL && right_var != var)) {
2632d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block        target.TakeValue();
2633a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      } else {
2634d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block        target.GetValue();
2635a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      }
2636a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      Load(node->value());
2637a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      GenericBinaryOperation(node->binary_op(),
2638a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                             node->type(),
2639a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                             overwrite_value ? OVERWRITE_RIGHT : NO_OVERWRITE);
2640a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
2641a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2642a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (var != NULL &&
2643a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        var->mode() == Variable::CONST &&
2644a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        node->op() != Token::INIT_VAR && node->op() != Token::INIT_CONST) {
2645a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // Assignment ignored - leave the value on the stack.
2646d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      UnloadReference(&target);
2647a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    } else {
2648a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      CodeForSourcePosition(node->position());
2649a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      if (node->op() == Token::INIT_CONST) {
2650a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        // Dynamic constant initializations must use the function context
2651a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        // and initialize the actual constant declared. Dynamic variable
2652a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        // initializations are simply assignments and use SetValue.
2653a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        target.SetValue(CONST_INIT);
2654a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      } else {
2655a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        target.SetValue(NOT_CONST_INIT);
2656a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      }
2657a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      if (node->ends_initialization_block()) {
2658d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke        ASSERT(target.type() == Reference::UNLOADED);
2659a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        // End of initialization block. Revert to fast case.  The
2660d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke        // argument to the runtime call is the extra copy of the receiver,
2661d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke        // which is below the value of the assignment.
2662d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke        // Swap the receiver and the value of the assignment expression.
2663d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke        Result lhs = frame_->Pop();
2664d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke        Result receiver = frame_->Pop();
2665d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke        frame_->Push(&lhs);
2666d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke        frame_->Push(&receiver);
2667a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        Result ignored = frame_->CallRuntime(Runtime::kToFastProperties, 1);
2668a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      }
2669a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
2670a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
2671a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
2672a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2673a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2674a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CodeGenerator::VisitThrow(Throw* node) {
2675a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Comment cmnt(masm_, "[ Throw");
2676a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Load(node->exception());
2677a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Result result = frame_->CallRuntime(Runtime::kThrow, 1);
2678a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  frame_->Push(&result);
2679a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
2680a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2681a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2682a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CodeGenerator::VisitProperty(Property* node) {
2683a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Comment cmnt(masm_, "[ Property");
2684a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Reference property(this, node);
2685d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  property.GetValue();
2686a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
2687a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2688a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2689a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CodeGenerator::VisitCall(Call* node) {
2690a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Comment cmnt(masm_, "[ Call");
2691a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2692a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ZoneList<Expression*>* args = node->arguments();
2693a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2694a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check if the function is a variable or a property.
2695a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Expression* function = node->expression();
2696a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Variable* var = function->AsVariableProxy()->AsVariable();
2697a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Property* property = function->AsProperty();
2698a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2699a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // ------------------------------------------------------------------------
2700a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Fast-case: Use inline caching.
2701a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // ---
2702a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // According to ECMA-262, section 11.2.3, page 44, the function to call
2703a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // must be resolved after the arguments have been evaluated. The IC code
2704a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // automatically handles this by loading the arguments before the function
2705a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // is resolved in cache misses (this also holds for megamorphic calls).
2706a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // ------------------------------------------------------------------------
2707a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2708a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (var != NULL && var->is_possibly_eval()) {
2709a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // ----------------------------------
2710a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // JavaScript example: 'eval(arg)'  // eval is not known to be shadowed
2711a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // ----------------------------------
2712a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2713a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // In a call to eval, we first call %ResolvePossiblyDirectEval to
2714a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // resolve the function we need to call and the receiver of the
2715a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // call.  Then we call the resolved function using the given
2716a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // arguments.
2717a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2718a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Prepare the stack for the call to the resolved function.
2719a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    Load(function);
2720a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2721a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Allocate a frame slot for the receiver.
2722a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    frame_->Push(Factory::undefined_value());
2723a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    int arg_count = args->length();
2724a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    for (int i = 0; i < arg_count; i++) {
2725a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      Load(args->at(i));
2726a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
2727a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2728a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Prepare the stack for the call to ResolvePossiblyDirectEval.
2729a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    frame_->PushElementAt(arg_count + 1);
2730a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (arg_count > 0) {
2731a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      frame_->PushElementAt(arg_count);
2732a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    } else {
2733a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      frame_->Push(Factory::undefined_value());
2734a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
2735a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2736e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke    // Push the receiver.
2737e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke    frame_->PushParameterAt(-1);
2738e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
2739a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Resolve the call.
2740a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    Result result =
2741e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke        frame_->CallRuntime(Runtime::kResolvePossiblyDirectEval, 3);
2742a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2743e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke    // The runtime call returns a pair of values in rax (function) and
2744e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke    // rdx (receiver). Touch up the stack with the right values.
2745e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke    Result receiver = allocator_->Allocate(rdx);
2746e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke    frame_->SetElementAt(arg_count + 1, &result);
2747e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke    frame_->SetElementAt(arg_count, &receiver);
2748e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke    receiver.Unuse();
2749a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2750a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Call the function.
2751a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    CodeForSourcePosition(node->position());
2752a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    InLoopFlag in_loop = loop_nesting() > 0 ? IN_LOOP : NOT_IN_LOOP;
2753e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke    CallFunctionStub call_function(arg_count, in_loop, RECEIVER_MIGHT_BE_VALUE);
2754a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    result = frame_->CallStub(&call_function, arg_count + 1);
2755a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2756a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Restore the context and overwrite the function on the stack with
2757a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // the result.
2758a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    frame_->RestoreContextRegister();
2759a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    frame_->SetElementAt(0, &result);
2760a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2761a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  } else if (var != NULL && !var->is_this() && var->is_global()) {
2762a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // ----------------------------------
2763a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // JavaScript example: 'foo(1, 2, 3)'  // foo is global
2764a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // ----------------------------------
2765a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2766a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Pass the global object as the receiver and let the IC stub
2767a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // patch the stack to use the global proxy as 'this' in the
2768a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // invoked function.
2769a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    LoadGlobal();
2770a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2771a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Load the arguments.
2772a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    int arg_count = args->length();
2773a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    for (int i = 0; i < arg_count; i++) {
2774a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      Load(args->at(i));
2775a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
2776a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2777402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    // Push the name of the function on the frame.
2778402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    frame_->Push(var->name());
2779402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu
2780a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Call the IC initialization code.
2781a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    CodeForSourcePosition(node->position());
2782a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    Result result = frame_->CallCallIC(RelocInfo::CODE_TARGET_CONTEXT,
2783a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                       arg_count,
2784a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                       loop_nesting());
2785a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    frame_->RestoreContextRegister();
2786a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Replace the function on the stack with the result.
2787402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    frame_->Push(&result);
2788a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2789a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  } else if (var != NULL && var->slot() != NULL &&
2790a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block             var->slot()->type() == Slot::LOOKUP) {
2791a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // ----------------------------------
2792a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // JavaScript example: 'with (obj) foo(1, 2, 3)'  // foo is in obj
2793a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // ----------------------------------
2794a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2795a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Load the function from the context.  Sync the frame so we can
2796a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // push the arguments directly into place.
2797a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    frame_->SyncRange(0, frame_->element_count() - 1);
2798a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    frame_->EmitPush(rsi);
2799a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    frame_->EmitPush(var->name());
2800a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    frame_->CallRuntime(Runtime::kLoadContextSlot, 2);
2801a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // The runtime call returns a pair of values in rax and rdx.  The
2802a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // looked-up function is in rax and the receiver is in rdx.  These
2803a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // register references are not ref counted here.  We spill them
2804a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // eagerly since they are arguments to an inevitable call (and are
2805a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // not sharable by the arguments).
2806a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    ASSERT(!allocator()->is_used(rax));
2807a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    frame_->EmitPush(rax);
2808a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2809a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Load the receiver.
2810a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    ASSERT(!allocator()->is_used(rdx));
2811a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    frame_->EmitPush(rdx);
2812a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2813a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Call the function.
2814e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke    CallWithArguments(args, NO_CALL_FUNCTION_FLAGS, node->position());
2815a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2816a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  } else if (property != NULL) {
2817a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Check if the key is a literal string.
2818a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    Literal* literal = property->key()->AsLiteral();
2819a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2820a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (literal != NULL && literal->handle()->IsSymbol()) {
2821a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // ------------------------------------------------------------------
2822a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // JavaScript example: 'object.foo(1, 2, 3)' or 'map["key"](1, 2, 3)'
2823a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // ------------------------------------------------------------------
2824a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2825a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      Handle<String> name = Handle<String>::cast(literal->handle());
2826a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2827a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      if (ArgumentsMode() == LAZY_ARGUMENTS_ALLOCATION &&
2828a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block          name->IsEqualTo(CStrVector("apply")) &&
2829a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block          args->length() == 2 &&
2830a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block          args->at(1)->AsVariableProxy() != NULL &&
2831a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block          args->at(1)->AsVariableProxy()->IsArguments()) {
2832a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        // Use the optimized Function.prototype.apply that avoids
2833a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        // allocating lazily allocated arguments objects.
2834d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke        CallApplyLazy(property->obj(),
2835a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                      args->at(0),
2836a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                      args->at(1)->AsVariableProxy(),
2837a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                      node->position());
2838a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2839a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      } else {
2840402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu        // Push the receiver onto the frame.
2841a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        Load(property->obj());
2842a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2843a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        // Load the arguments.
2844a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        int arg_count = args->length();
2845a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        for (int i = 0; i < arg_count; i++) {
2846a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block          Load(args->at(i));
2847a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        }
2848a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2849402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu        // Push the name of the function onto the frame.
2850402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu        frame_->Push(name);
2851402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu
2852a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        // Call the IC initialization code.
2853a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        CodeForSourcePosition(node->position());
2854a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        Result result = frame_->CallCallIC(RelocInfo::CODE_TARGET,
2855a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                           arg_count,
2856a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                           loop_nesting());
2857a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        frame_->RestoreContextRegister();
2858402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu        frame_->Push(&result);
2859a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      }
2860a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2861a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    } else {
2862a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // -------------------------------------------
2863a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // JavaScript example: 'array[index](1, 2, 3)'
2864a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // -------------------------------------------
2865a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2866a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // Load the function to call from the property through a reference.
2867a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      if (property->is_synthetic()) {
2868d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke        Reference ref(this, property, false);
2869d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke        ref.GetValue();
2870a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        // Use global object as receiver.
2871a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        LoadGlobalReceiver();
2872a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      } else {
2873d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke        Reference ref(this, property, false);
2874d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke        ASSERT(ref.size() == 2);
2875d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke        Result key = frame_->Pop();
2876d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke        frame_->Dup();  // Duplicate the receiver.
2877d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke        frame_->Push(&key);
2878d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke        ref.GetValue();
2879d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke        // Top of frame contains function to call, with duplicate copy of
2880d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke        // receiver below it.  Swap them.
2881d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke        Result function = frame_->Pop();
2882d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke        Result receiver = frame_->Pop();
2883d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke        frame_->Push(&function);
2884d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke        frame_->Push(&receiver);
2885a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      }
2886a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2887a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // Call the function.
2888e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke      CallWithArguments(args, RECEIVER_MIGHT_BE_VALUE, node->position());
2889a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
2890a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2891a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  } else {
2892a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // ----------------------------------
2893a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // JavaScript example: 'foo(1, 2, 3)'  // foo is not global
2894a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // ----------------------------------
2895a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2896a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Load the function.
2897a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    Load(function);
2898a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2899a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Pass the global proxy as the receiver.
2900a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    LoadGlobalReceiver();
2901a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2902a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Call the function.
2903e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke    CallWithArguments(args, NO_CALL_FUNCTION_FLAGS, node->position());
2904a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
2905a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
2906a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2907a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2908a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CodeGenerator::VisitCallNew(CallNew* node) {
2909a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Comment cmnt(masm_, "[ CallNew");
2910a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2911a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // According to ECMA-262, section 11.2.2, page 44, the function
2912a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // expression in new calls must be evaluated before the
2913a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // arguments. This is different from ordinary calls, where the
2914a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // actual function to call is resolved after the arguments have been
2915a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // evaluated.
2916a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2917a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Compute function to call and use the global object as the
2918a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // receiver. There is no need to use the global proxy here because
2919a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // it will always be replaced with a newly allocated object.
2920a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Load(node->expression());
2921a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  LoadGlobal();
2922a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2923a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Push the arguments ("left-to-right") on the stack.
2924a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ZoneList<Expression*>* args = node->arguments();
2925a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  int arg_count = args->length();
2926a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  for (int i = 0; i < arg_count; i++) {
2927a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    Load(args->at(i));
2928a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
2929a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2930a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Call the construct call builtin that handles allocation and
2931a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // constructor invocation.
2932a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CodeForSourcePosition(node->position());
2933a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Result result = frame_->CallConstructor(arg_count);
2934a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Replace the function on the stack with the result.
2935a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  frame_->SetElementAt(0, &result);
2936a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
2937a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2938a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2939a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CodeGenerator::VisitCallRuntime(CallRuntime* node) {
2940a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (CheckForInlineRuntimeCall(node)) {
2941a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    return;
2942a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
2943a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2944a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ZoneList<Expression*>* args = node->arguments();
2945a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Comment cmnt(masm_, "[ CallRuntime");
2946a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Runtime::Function* function = node->function();
2947a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2948a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (function == NULL) {
2949a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Push the builtins object found in the current global object.
2950a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    Result temp = allocator()->Allocate();
2951a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    ASSERT(temp.is_valid());
2952a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ movq(temp.reg(), GlobalObject());
2953a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ movq(temp.reg(),
2954a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block            FieldOperand(temp.reg(), GlobalObject::kBuiltinsOffset));
2955a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    frame_->Push(&temp);
2956a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
2957a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2958a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Push the arguments ("left-to-right").
2959a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  int arg_count = args->length();
2960a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  for (int i = 0; i < arg_count; i++) {
2961a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    Load(args->at(i));
2962a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
2963a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2964a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (function == NULL) {
2965a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Call the JS runtime function.
2966402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    frame_->Push(node->name());
2967a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    Result answer = frame_->CallCallIC(RelocInfo::CODE_TARGET,
2968a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                       arg_count,
2969a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                       loop_nesting_);
2970a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    frame_->RestoreContextRegister();
2971402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    frame_->Push(&answer);
2972a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  } else {
2973a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Call the C runtime function.
2974a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    Result answer = frame_->CallRuntime(function, arg_count);
2975a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    frame_->Push(&answer);
2976a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
2977a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
2978a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2979a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2980a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CodeGenerator::VisitUnaryOperation(UnaryOperation* node) {
2981a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Comment cmnt(masm_, "[ UnaryOperation");
2982a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2983a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Token::Value op = node->op();
2984a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2985a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (op == Token::NOT) {
2986a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Swap the true and false targets but keep the same actual label
2987a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // as the fall through.
2988a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    destination()->Invert();
2989d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    LoadCondition(node->expression(), destination(), true);
2990a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Swap the labels back.
2991a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    destination()->Invert();
2992a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2993a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  } else if (op == Token::DELETE) {
2994a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    Property* property = node->expression()->AsProperty();
2995a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (property != NULL) {
2996a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      Load(property->obj());
2997a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      Load(property->key());
2998a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      Result answer = frame_->InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION, 2);
2999a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      frame_->Push(&answer);
3000a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      return;
3001a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
3002a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3003a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    Variable* variable = node->expression()->AsVariableProxy()->AsVariable();
3004a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (variable != NULL) {
3005a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      Slot* slot = variable->slot();
3006a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      if (variable->is_global()) {
3007a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        LoadGlobal();
3008a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        frame_->Push(variable->name());
3009a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        Result answer = frame_->InvokeBuiltin(Builtins::DELETE,
3010a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                              CALL_FUNCTION, 2);
3011a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        frame_->Push(&answer);
3012a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        return;
3013a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3014a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      } else if (slot != NULL && slot->type() == Slot::LOOKUP) {
3015a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        // Call the runtime to look up the context holding the named
3016a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        // variable.  Sync the virtual frame eagerly so we can push the
3017a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        // arguments directly into place.
3018a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        frame_->SyncRange(0, frame_->element_count() - 1);
3019a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        frame_->EmitPush(rsi);
3020a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        frame_->EmitPush(variable->name());
3021a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        Result context = frame_->CallRuntime(Runtime::kLookupContext, 2);
3022a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        ASSERT(context.is_register());
3023a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        frame_->EmitPush(context.reg());
3024a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        context.Unuse();
3025a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        frame_->EmitPush(variable->name());
3026a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        Result answer = frame_->InvokeBuiltin(Builtins::DELETE,
3027a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                              CALL_FUNCTION, 2);
3028a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        frame_->Push(&answer);
3029a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        return;
3030a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      }
3031a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3032a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // Default: Result of deleting non-global, not dynamically
3033a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // introduced variables is false.
3034a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      frame_->Push(Factory::false_value());
3035a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3036a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    } else {
3037a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // Default: Result of deleting expressions is true.
3038a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      Load(node->expression());  // may have side-effects
3039a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      frame_->SetElementAt(0, Factory::true_value());
3040a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
3041a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3042a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  } else if (op == Token::TYPEOF) {
3043a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Special case for loading the typeof expression; see comment on
3044a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // LoadTypeofExpression().
3045a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    LoadTypeofExpression(node->expression());
3046a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    Result answer = frame_->CallRuntime(Runtime::kTypeof, 1);
3047a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    frame_->Push(&answer);
3048a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3049a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  } else if (op == Token::VOID) {
3050a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    Expression* expression = node->expression();
3051a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (expression && expression->AsLiteral() && (
3052a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        expression->AsLiteral()->IsTrue() ||
3053a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        expression->AsLiteral()->IsFalse() ||
3054a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        expression->AsLiteral()->handle()->IsNumber() ||
3055a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        expression->AsLiteral()->handle()->IsString() ||
3056a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        expression->AsLiteral()->handle()->IsJSRegExp() ||
3057a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        expression->AsLiteral()->IsNull())) {
3058a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // Omit evaluating the value of the primitive literal.
3059a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // It will be discarded anyway, and can have no side effect.
3060a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      frame_->Push(Factory::undefined_value());
3061a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    } else {
3062a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      Load(node->expression());
3063a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      frame_->SetElementAt(0, Factory::undefined_value());
3064a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
3065a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3066a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  } else {
3067d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    bool overwrite =
3068d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      (node->expression()->AsBinaryOperation() != NULL &&
3069d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke       node->expression()->AsBinaryOperation()->ResultOverwriteAllowed());
3070a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    Load(node->expression());
3071a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    switch (op) {
3072a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      case Token::NOT:
3073a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      case Token::DELETE:
3074a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      case Token::TYPEOF:
3075a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        UNREACHABLE();  // handled above
3076a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        break;
3077a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3078a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      case Token::SUB: {
3079e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke        GenericUnaryOpStub stub(Token::SUB, overwrite);
3080a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        Result operand = frame_->Pop();
3081a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        Result answer = frame_->CallStub(&stub, &operand);
3082a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        frame_->Push(&answer);
3083a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        break;
3084a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      }
3085a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3086a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      case Token::BIT_NOT: {
3087a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        // Smi check.
3088a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        JumpTarget smi_label;
3089a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        JumpTarget continue_label;
3090a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        Result operand = frame_->Pop();
3091a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        operand.ToRegister();
3092a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3093a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        Condition is_smi = masm_->CheckSmi(operand.reg());
3094a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        smi_label.Branch(is_smi, &operand);
3095a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3096d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke        GenericUnaryOpStub stub(Token::BIT_NOT, overwrite);
3097d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke        Result answer = frame_->CallStub(&stub, &operand);
3098a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        continue_label.Jump(&answer);
3099d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke
3100a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        smi_label.Bind(&answer);
3101a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        answer.ToRegister();
3102a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        frame_->Spill(answer.reg());
3103a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        __ SmiNot(answer.reg(), answer.reg());
3104a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        continue_label.Bind(&answer);
3105a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        frame_->Push(&answer);
3106a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        break;
3107a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      }
3108a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3109a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      case Token::ADD: {
3110a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        // Smi check.
3111a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        JumpTarget continue_label;
3112a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        Result operand = frame_->Pop();
3113a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        operand.ToRegister();
3114a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        Condition is_smi = masm_->CheckSmi(operand.reg());
3115a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        continue_label.Branch(is_smi, &operand);
3116a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        frame_->Push(&operand);
3117a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        Result answer = frame_->InvokeBuiltin(Builtins::TO_NUMBER,
3118a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                              CALL_FUNCTION, 1);
3119a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3120a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        continue_label.Bind(&answer);
3121a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        frame_->Push(&answer);
3122a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        break;
3123a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      }
3124a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3125a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      default:
3126a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        UNREACHABLE();
3127a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
3128a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
3129a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
3130a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3131a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3132a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// The value in dst was optimistically incremented or decremented.  The
3133a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// result overflowed or was not smi tagged.  Undo the operation, call
3134a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// into the runtime to convert the argument to a number, and call the
3135a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// specialized add or subtract stub.  The result is left in dst.
3136a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockclass DeferredPrefixCountOperation: public DeferredCode {
3137a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block public:
3138a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  DeferredPrefixCountOperation(Register dst, bool is_increment)
3139a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      : dst_(dst), is_increment_(is_increment) {
3140a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    set_comment("[ DeferredCountOperation");
3141a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
3142a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3143a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  virtual void Generate();
3144a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3145a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block private:
3146a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Register dst_;
3147a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  bool is_increment_;
3148a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block};
3149a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3150a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3151a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid DeferredPrefixCountOperation::Generate() {
3152a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ push(dst_);
3153a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ InvokeBuiltin(Builtins::TO_NUMBER, CALL_FUNCTION);
3154a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ push(rax);
31553ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  __ Push(Smi::FromInt(1));
3156a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (is_increment_) {
3157a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ CallRuntime(Runtime::kNumberAdd, 2);
3158a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  } else {
3159a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ CallRuntime(Runtime::kNumberSub, 2);
3160a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
3161a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (!dst_.is(rax)) __ movq(dst_, rax);
3162a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
3163a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3164a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3165a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// The value in dst was optimistically incremented or decremented.  The
3166a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// result overflowed or was not smi tagged.  Undo the operation and call
3167a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// into the runtime to convert the argument to a number.  Update the
3168a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// original value in old.  Call the specialized add or subtract stub.
3169a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// The result is left in dst.
3170a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockclass DeferredPostfixCountOperation: public DeferredCode {
3171a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block public:
3172a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  DeferredPostfixCountOperation(Register dst, Register old, bool is_increment)
3173a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      : dst_(dst), old_(old), is_increment_(is_increment) {
3174a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    set_comment("[ DeferredCountOperation");
3175a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
3176a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3177a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  virtual void Generate();
3178a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3179a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block private:
3180a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Register dst_;
3181a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Register old_;
3182a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  bool is_increment_;
3183a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block};
3184a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3185a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3186a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid DeferredPostfixCountOperation::Generate() {
3187a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ push(dst_);
3188a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ InvokeBuiltin(Builtins::TO_NUMBER, CALL_FUNCTION);
3189a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3190a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Save the result of ToNumber to use as the old value.
3191a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ push(rax);
3192a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3193a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Call the runtime for the addition or subtraction.
3194a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ push(rax);
31953ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  __ Push(Smi::FromInt(1));
3196a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (is_increment_) {
3197a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ CallRuntime(Runtime::kNumberAdd, 2);
3198a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  } else {
3199a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ CallRuntime(Runtime::kNumberSub, 2);
3200a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
3201a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (!dst_.is(rax)) __ movq(dst_, rax);
3202a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ pop(old_);
3203a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
3204a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3205a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3206a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CodeGenerator::VisitCountOperation(CountOperation* node) {
3207a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Comment cmnt(masm_, "[ CountOperation");
3208a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3209a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  bool is_postfix = node->is_postfix();
3210a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  bool is_increment = node->op() == Token::INC;
3211a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3212a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Variable* var = node->expression()->AsVariableProxy()->AsVariable();
3213a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  bool is_const = (var != NULL && var->mode() == Variable::CONST);
3214a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3215a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Postfix operations need a stack slot under the reference to hold
3216a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // the old value while the new value is being stored.  This is so that
3217a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // in the case that storing the new value requires a call, the old
3218a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // value will be in the frame to be spilled.
3219a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (is_postfix) frame_->Push(Smi::FromInt(0));
3220a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3221d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  // A constant reference is not saved to, so the reference is not a
3222d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  // compound assignment reference.
3223d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  { Reference target(this, node->expression(), !is_const);
3224a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (target.is_illegal()) {
3225a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // Spoof the virtual frame to have the expected height (one higher
3226a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // than on entry).
3227a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      if (!is_postfix) frame_->Push(Smi::FromInt(0));
3228a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      return;
3229a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
3230d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    target.TakeValue();
3231a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3232a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    Result new_value = frame_->Pop();
3233a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    new_value.ToRegister();
3234a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3235a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    Result old_value;  // Only allocated in the postfix case.
3236a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (is_postfix) {
3237a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // Allocate a temporary to preserve the old value.
3238a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      old_value = allocator_->Allocate();
3239a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      ASSERT(old_value.is_valid());
3240a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      __ movq(old_value.reg(), new_value.reg());
3241a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
3242a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Ensure the new value is writable.
3243a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    frame_->Spill(new_value.reg());
3244a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3245a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    DeferredCode* deferred = NULL;
3246a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (is_postfix) {
3247a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      deferred = new DeferredPostfixCountOperation(new_value.reg(),
3248a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                                   old_value.reg(),
3249a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                                   is_increment);
3250a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    } else {
3251a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      deferred = new DeferredPrefixCountOperation(new_value.reg(),
3252a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                                  is_increment);
3253a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
3254a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
32553ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    __ JumpIfNotSmi(new_value.reg(), deferred->entry_label());
3256a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (is_increment) {
32573ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      __ SmiAddConstant(kScratchRegister,
32583ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block                        new_value.reg(),
32593ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block                        Smi::FromInt(1),
32603ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block                        deferred->entry_label());
3261a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    } else {
32623ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      __ SmiSubConstant(kScratchRegister,
32633ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block                        new_value.reg(),
32643ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block                        Smi::FromInt(1),
32653ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block                        deferred->entry_label());
3266a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
3267a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ movq(new_value.reg(), kScratchRegister);
3268a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    deferred->BindExit();
3269a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3270a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Postfix: store the old value in the allocated slot under the
3271a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // reference.
3272a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (is_postfix) frame_->SetElementAt(target.size(), &old_value);
3273a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3274a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    frame_->Push(&new_value);
3275a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Non-constant: update the reference.
3276a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (!is_const) target.SetValue(NOT_CONST_INIT);
3277a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
3278a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3279a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Postfix: drop the new value and use the old.
3280a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (is_postfix) frame_->Drop();
3281a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
3282a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3283a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3284a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CodeGenerator::VisitBinaryOperation(BinaryOperation* node) {
3285a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // TODO(X64): This code was copied verbatim from codegen-ia32.
3286a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //     Either find a reason to change it or move it to a shared location.
3287a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3288a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Comment cmnt(masm_, "[ BinaryOperation");
3289a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Token::Value op = node->op();
3290a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3291a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // According to ECMA-262 section 11.11, page 58, the binary logical
3292a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // operators must yield the result of one of the two expressions
3293a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // before any ToBoolean() conversions. This means that the value
3294a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // produced by a && or || operator is not necessarily a boolean.
3295a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3296a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // NOTE: If the left hand side produces a materialized value (not
3297a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // control flow), we force the right hand side to do the same. This
3298a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // is necessary because we assume that if we get control flow on the
3299a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // last path out of an expression we got it on all paths.
3300a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (op == Token::AND) {
3301a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    JumpTarget is_true;
3302a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    ControlDestination dest(&is_true, destination()->false_target(), true);
3303d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    LoadCondition(node->left(), &dest, false);
3304a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3305a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (dest.false_was_fall_through()) {
3306a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // The current false target was used as the fall-through.  If
3307a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // there are no dangling jumps to is_true then the left
3308a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // subexpression was unconditionally false.  Otherwise we have
3309a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // paths where we do have to evaluate the right subexpression.
3310a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      if (is_true.is_linked()) {
3311a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        // We need to compile the right subexpression.  If the jump to
3312a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        // the current false target was a forward jump then we have a
3313a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        // valid frame, we have just bound the false target, and we
3314a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        // have to jump around the code for the right subexpression.
3315a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        if (has_valid_frame()) {
3316a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block          destination()->false_target()->Unuse();
3317a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block          destination()->false_target()->Jump();
3318a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        }
3319a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        is_true.Bind();
3320a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        // The left subexpression compiled to control flow, so the
3321a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        // right one is free to do so as well.
3322d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block        LoadCondition(node->right(), destination(), false);
3323a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      } else {
3324a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        // We have actually just jumped to or bound the current false
3325a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        // target but the current control destination is not marked as
3326a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        // used.
3327a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        destination()->Use(false);
3328a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      }
3329a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3330a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    } else if (dest.is_used()) {
3331a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // The left subexpression compiled to control flow (and is_true
3332a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // was just bound), so the right is free to do so as well.
3333d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block      LoadCondition(node->right(), destination(), false);
3334a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3335a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    } else {
3336a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // We have a materialized value on the frame, so we exit with
3337a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // one on all paths.  There are possibly also jumps to is_true
3338a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // from nested subexpressions.
3339a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      JumpTarget pop_and_continue;
3340a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      JumpTarget exit;
3341a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3342a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // Avoid popping the result if it converts to 'false' using the
3343a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // standard ToBoolean() conversion as described in ECMA-262,
3344a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // section 9.2, page 30.
3345a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      //
3346a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // Duplicate the TOS value. The duplicate will be popped by
3347a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // ToBoolean.
3348a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      frame_->Dup();
3349a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      ControlDestination dest(&pop_and_continue, &exit, true);
3350a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      ToBoolean(&dest);
3351a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3352a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // Pop the result of evaluating the first part.
3353a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      frame_->Drop();
3354a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3355a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // Compile right side expression.
3356a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      is_true.Bind();
3357a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      Load(node->right());
3358a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3359a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // Exit (always with a materialized value).
3360a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      exit.Bind();
3361a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
3362a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3363a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  } else if (op == Token::OR) {
3364a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    JumpTarget is_false;
3365a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    ControlDestination dest(destination()->true_target(), &is_false, false);
3366d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    LoadCondition(node->left(), &dest, false);
3367a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3368a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (dest.true_was_fall_through()) {
3369a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // The current true target was used as the fall-through.  If
3370a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // there are no dangling jumps to is_false then the left
3371a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // subexpression was unconditionally true.  Otherwise we have
3372a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // paths where we do have to evaluate the right subexpression.
3373a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      if (is_false.is_linked()) {
3374a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        // We need to compile the right subexpression.  If the jump to
3375a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        // the current true target was a forward jump then we have a
3376a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        // valid frame, we have just bound the true target, and we
3377a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        // have to jump around the code for the right subexpression.
3378a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        if (has_valid_frame()) {
3379a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block          destination()->true_target()->Unuse();
3380a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block          destination()->true_target()->Jump();
3381a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        }
3382a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        is_false.Bind();
3383a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        // The left subexpression compiled to control flow, so the
3384a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        // right one is free to do so as well.
3385d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block        LoadCondition(node->right(), destination(), false);
3386a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      } else {
3387a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        // We have just jumped to or bound the current true target but
3388a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        // the current control destination is not marked as used.
3389a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        destination()->Use(true);
3390a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      }
3391a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3392a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    } else if (dest.is_used()) {
3393a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // The left subexpression compiled to control flow (and is_false
3394a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // was just bound), so the right is free to do so as well.
3395d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block      LoadCondition(node->right(), destination(), false);
3396a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3397a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    } else {
3398a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // We have a materialized value on the frame, so we exit with
3399a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // one on all paths.  There are possibly also jumps to is_false
3400a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // from nested subexpressions.
3401a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      JumpTarget pop_and_continue;
3402a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      JumpTarget exit;
3403a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3404a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // Avoid popping the result if it converts to 'true' using the
3405a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // standard ToBoolean() conversion as described in ECMA-262,
3406a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // section 9.2, page 30.
3407a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      //
3408a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // Duplicate the TOS value. The duplicate will be popped by
3409a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // ToBoolean.
3410a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      frame_->Dup();
3411a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      ControlDestination dest(&exit, &pop_and_continue, false);
3412a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      ToBoolean(&dest);
3413a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3414a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // Pop the result of evaluating the first part.
3415a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      frame_->Drop();
3416a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3417a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // Compile right side expression.
3418a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      is_false.Bind();
3419a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      Load(node->right());
3420a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3421a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // Exit (always with a materialized value).
3422a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      exit.Bind();
3423a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
3424a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3425a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  } else {
3426a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // NOTE: The code below assumes that the slow cases (calls to runtime)
3427a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // never return a constant/immutable object.
3428a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    OverwriteMode overwrite_mode = NO_OVERWRITE;
3429a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (node->left()->AsBinaryOperation() != NULL &&
3430a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        node->left()->AsBinaryOperation()->ResultOverwriteAllowed()) {
3431a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      overwrite_mode = OVERWRITE_LEFT;
3432a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    } else if (node->right()->AsBinaryOperation() != NULL &&
3433a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block               node->right()->AsBinaryOperation()->ResultOverwriteAllowed()) {
3434a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      overwrite_mode = OVERWRITE_RIGHT;
3435a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
3436a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3437a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    Load(node->left());
3438a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    Load(node->right());
3439a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    GenericBinaryOperation(node->op(), node->type(), overwrite_mode);
3440a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
3441a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
3442a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3443a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3444a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3445a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CodeGenerator::VisitCompareOperation(CompareOperation* node) {
3446a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Comment cmnt(masm_, "[ CompareOperation");
3447a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3448a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Get the expressions from the node.
3449a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Expression* left = node->left();
3450a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Expression* right = node->right();
3451a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Token::Value op = node->op();
3452a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // To make typeof testing for natives implemented in JavaScript really
3453a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // efficient, we generate special code for expressions of the form:
3454a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // 'typeof <expression> == <string>'.
3455a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  UnaryOperation* operation = left->AsUnaryOperation();
3456a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if ((op == Token::EQ || op == Token::EQ_STRICT) &&
3457a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      (operation != NULL && operation->op() == Token::TYPEOF) &&
3458a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      (right->AsLiteral() != NULL &&
3459a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block       right->AsLiteral()->handle()->IsString())) {
3460a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    Handle<String> check(Handle<String>::cast(right->AsLiteral()->handle()));
3461a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3462a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Load the operand and move it to a register.
3463a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    LoadTypeofExpression(operation->expression());
3464a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    Result answer = frame_->Pop();
3465a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    answer.ToRegister();
3466a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3467a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (check->Equals(Heap::number_symbol())) {
3468a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      Condition is_smi = masm_->CheckSmi(answer.reg());
3469a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      destination()->true_target()->Branch(is_smi);
3470a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      frame_->Spill(answer.reg());
3471a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      __ movq(answer.reg(), FieldOperand(answer.reg(), HeapObject::kMapOffset));
3472a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      __ CompareRoot(answer.reg(), Heap::kHeapNumberMapRootIndex);
3473a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      answer.Unuse();
3474a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      destination()->Split(equal);
3475a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3476a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    } else if (check->Equals(Heap::string_symbol())) {
3477a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      Condition is_smi = masm_->CheckSmi(answer.reg());
3478a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      destination()->false_target()->Branch(is_smi);
3479a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3480a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // It can be an undetectable string object.
3481a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      __ movq(kScratchRegister,
3482a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block              FieldOperand(answer.reg(), HeapObject::kMapOffset));
3483a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      __ testb(FieldOperand(kScratchRegister, Map::kBitFieldOffset),
3484a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block               Immediate(1 << Map::kIsUndetectable));
3485a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      destination()->false_target()->Branch(not_zero);
3486a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      __ CmpInstanceType(kScratchRegister, FIRST_NONSTRING_TYPE);
3487a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      answer.Unuse();
3488a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      destination()->Split(below);  // Unsigned byte comparison needed.
3489a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3490a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    } else if (check->Equals(Heap::boolean_symbol())) {
3491a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      __ CompareRoot(answer.reg(), Heap::kTrueValueRootIndex);
3492a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      destination()->true_target()->Branch(equal);
3493a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      __ CompareRoot(answer.reg(), Heap::kFalseValueRootIndex);
3494a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      answer.Unuse();
3495a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      destination()->Split(equal);
3496a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3497a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    } else if (check->Equals(Heap::undefined_symbol())) {
3498a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      __ CompareRoot(answer.reg(), Heap::kUndefinedValueRootIndex);
3499a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      destination()->true_target()->Branch(equal);
3500a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3501a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      Condition is_smi = masm_->CheckSmi(answer.reg());
3502a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      destination()->false_target()->Branch(is_smi);
3503a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3504a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // It can be an undetectable object.
3505a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      __ movq(kScratchRegister,
3506a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block              FieldOperand(answer.reg(), HeapObject::kMapOffset));
3507a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      __ testb(FieldOperand(kScratchRegister, Map::kBitFieldOffset),
3508a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block               Immediate(1 << Map::kIsUndetectable));
3509a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      answer.Unuse();
3510a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      destination()->Split(not_zero);
3511a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3512a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    } else if (check->Equals(Heap::function_symbol())) {
3513a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      Condition is_smi = masm_->CheckSmi(answer.reg());
3514a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      destination()->false_target()->Branch(is_smi);
3515a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      frame_->Spill(answer.reg());
3516a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      __ CmpObjectType(answer.reg(), JS_FUNCTION_TYPE, answer.reg());
3517d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block      destination()->true_target()->Branch(equal);
3518d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block      // Regular expressions are callable so typeof == 'function'.
3519d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block      __ CmpInstanceType(answer.reg(), JS_REGEXP_TYPE);
3520a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      answer.Unuse();
3521a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      destination()->Split(equal);
3522a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3523a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    } else if (check->Equals(Heap::object_symbol())) {
3524a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      Condition is_smi = masm_->CheckSmi(answer.reg());
3525a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      destination()->false_target()->Branch(is_smi);
3526a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      __ CompareRoot(answer.reg(), Heap::kNullValueRootIndex);
3527a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      destination()->true_target()->Branch(equal);
3528a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3529d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block      // Regular expressions are typeof == 'function', not 'object'.
3530d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block      __ CmpObjectType(answer.reg(), JS_REGEXP_TYPE, kScratchRegister);
3531d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block      destination()->false_target()->Branch(equal);
3532d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
3533a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // It can be an undetectable object.
3534a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      __ testb(FieldOperand(kScratchRegister, Map::kBitFieldOffset),
3535a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block               Immediate(1 << Map::kIsUndetectable));
3536a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      destination()->false_target()->Branch(not_zero);
3537a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      __ CmpInstanceType(kScratchRegister, FIRST_JS_OBJECT_TYPE);
3538a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      destination()->false_target()->Branch(below);
3539a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      __ CmpInstanceType(kScratchRegister, LAST_JS_OBJECT_TYPE);
3540a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      answer.Unuse();
3541a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      destination()->Split(below_equal);
3542a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    } else {
3543a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // Uncommon case: typeof testing against a string literal that is
3544a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // never returned from the typeof operator.
3545a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      answer.Unuse();
3546a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      destination()->Goto(false);
3547a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
3548a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    return;
3549a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
3550a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3551a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Condition cc = no_condition;
3552a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  bool strict = false;
3553a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  switch (op) {
3554a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    case Token::EQ_STRICT:
3555a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      strict = true;
3556a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // Fall through
3557a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    case Token::EQ:
3558a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      cc = equal;
3559a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      break;
3560a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    case Token::LT:
3561a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      cc = less;
3562a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      break;
3563a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    case Token::GT:
3564a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      cc = greater;
3565a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      break;
3566a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    case Token::LTE:
3567a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      cc = less_equal;
3568a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      break;
3569a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    case Token::GTE:
3570a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      cc = greater_equal;
3571a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      break;
3572a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    case Token::IN: {
3573a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      Load(left);
3574a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      Load(right);
3575a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      Result answer = frame_->InvokeBuiltin(Builtins::IN, CALL_FUNCTION, 2);
3576a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      frame_->Push(&answer);  // push the result
3577a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      return;
3578a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
3579a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    case Token::INSTANCEOF: {
3580a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      Load(left);
3581a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      Load(right);
3582a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      InstanceofStub stub;
3583a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      Result answer = frame_->CallStub(&stub, 2);
3584a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      answer.ToRegister();
3585a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      __ testq(answer.reg(), answer.reg());
3586a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      answer.Unuse();
3587a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      destination()->Split(zero);
3588a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      return;
3589a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
3590a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    default:
3591a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      UNREACHABLE();
3592a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
3593a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Load(left);
3594a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Load(right);
3595402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  Comparison(node, cc, strict, destination());
3596a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
3597a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3598a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3599a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CodeGenerator::VisitThisFunction(ThisFunction* node) {
3600a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  frame_->PushFunction();
3601a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
3602a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3603a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3604a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CodeGenerator::GenerateArgumentsAccess(ZoneList<Expression*>* args) {
3605a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(args->length() == 1);
3606a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3607a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // ArgumentsAccessStub expects the key in rdx and the formal
3608a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // parameter count in rax.
3609a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Load(args->at(0));
3610a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Result key = frame_->Pop();
3611a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Explicitly create a constant result.
36123100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  Result count(Handle<Smi>(Smi::FromInt(scope()->num_parameters())));
3613a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Call the shared stub to get to arguments[key].
3614a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ArgumentsAccessStub stub(ArgumentsAccessStub::READ_ELEMENT);
3615a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Result result = frame_->CallStub(&stub, &key, &count);
3616a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  frame_->Push(&result);
3617a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
3618a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3619a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3620a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CodeGenerator::GenerateIsArray(ZoneList<Expression*>* args) {
3621a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(args->length() == 1);
3622a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Load(args->at(0));
3623a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Result value = frame_->Pop();
3624a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  value.ToRegister();
3625a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(value.is_valid());
3626a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Condition is_smi = masm_->CheckSmi(value.reg());
3627a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  destination()->false_target()->Branch(is_smi);
3628a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // It is a heap object - get map.
3629a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check if the object is a JS array or not.
3630a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ CmpObjectType(value.reg(), JS_ARRAY_TYPE, kScratchRegister);
3631a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  value.Unuse();
3632a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  destination()->Split(equal);
3633a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
3634a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3635a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3636402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescuvoid CodeGenerator::GenerateIsRegExp(ZoneList<Expression*>* args) {
3637402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  ASSERT(args->length() == 1);
3638402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  Load(args->at(0));
3639402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  Result value = frame_->Pop();
3640402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  value.ToRegister();
3641402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  ASSERT(value.is_valid());
3642402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  Condition is_smi = masm_->CheckSmi(value.reg());
3643402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  destination()->false_target()->Branch(is_smi);
3644402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // It is a heap object - get map.
3645402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // Check if the object is a regexp.
3646402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ CmpObjectType(value.reg(), JS_REGEXP_TYPE, kScratchRegister);
3647402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  value.Unuse();
3648402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  destination()->Split(equal);
3649402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu}
3650402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu
3651402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu
3652d0582a6c46733687d045e4188a1bcd0123c758a1Steve Blockvoid CodeGenerator::GenerateIsObject(ZoneList<Expression*>* args) {
3653d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  // This generates a fast version of:
3654d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  // (typeof(arg) === 'object' || %_ClassOf(arg) == 'RegExp')
3655d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  ASSERT(args->length() == 1);
3656d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  Load(args->at(0));
3657d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  Result obj = frame_->Pop();
3658d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  obj.ToRegister();
3659d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  Condition is_smi = masm_->CheckSmi(obj.reg());
3660d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  destination()->false_target()->Branch(is_smi);
3661d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
3662d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  __ Move(kScratchRegister, Factory::null_value());
3663d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  __ cmpq(obj.reg(), kScratchRegister);
3664d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  destination()->true_target()->Branch(equal);
3665d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
3666d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  __ movq(kScratchRegister, FieldOperand(obj.reg(), HeapObject::kMapOffset));
3667d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  // Undetectable objects behave like undefined when tested with typeof.
3668d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  __ testb(FieldOperand(kScratchRegister, Map::kBitFieldOffset),
3669d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block          Immediate(1 << Map::kIsUndetectable));
3670d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  destination()->false_target()->Branch(not_zero);
3671d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  __ CmpInstanceType(kScratchRegister, FIRST_JS_OBJECT_TYPE);
3672d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  destination()->false_target()->Branch(less);
3673d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  __ CmpInstanceType(kScratchRegister, LAST_JS_OBJECT_TYPE);
3674d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  obj.Unuse();
3675d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  destination()->Split(less_equal);
3676d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block}
3677d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
3678d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
3679d0582a6c46733687d045e4188a1bcd0123c758a1Steve Blockvoid CodeGenerator::GenerateIsFunction(ZoneList<Expression*>* args) {
3680d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  // This generates a fast version of:
3681d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  // (%_ClassOf(arg) === 'Function')
3682d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  ASSERT(args->length() == 1);
3683d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  Load(args->at(0));
3684d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  Result obj = frame_->Pop();
3685d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  obj.ToRegister();
3686d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  Condition is_smi = masm_->CheckSmi(obj.reg());
3687d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  destination()->false_target()->Branch(is_smi);
3688d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  __ CmpObjectType(obj.reg(), JS_FUNCTION_TYPE, kScratchRegister);
3689d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  obj.Unuse();
3690d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  destination()->Split(equal);
3691d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block}
3692d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
3693d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
3694d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarkevoid CodeGenerator::GenerateIsUndetectableObject(ZoneList<Expression*>* args) {
3695d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  ASSERT(args->length() == 1);
3696d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  Load(args->at(0));
3697d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  Result obj = frame_->Pop();
3698d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  obj.ToRegister();
3699d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  Condition is_smi = masm_->CheckSmi(obj.reg());
3700d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  destination()->false_target()->Branch(is_smi);
3701d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  __ movq(kScratchRegister, FieldOperand(obj.reg(), HeapObject::kMapOffset));
3702d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  __ movzxbl(kScratchRegister,
3703d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke             FieldOperand(kScratchRegister, Map::kBitFieldOffset));
3704d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  __ testl(kScratchRegister, Immediate(1 << Map::kIsUndetectable));
3705d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  obj.Unuse();
3706d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  destination()->Split(not_zero);
3707d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke}
3708d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke
3709d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke
3710a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CodeGenerator::GenerateIsConstructCall(ZoneList<Expression*>* args) {
3711a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(args->length() == 0);
3712a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3713a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Get the frame pointer for the calling frame.
3714a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Result fp = allocator()->Allocate();
3715a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ movq(fp.reg(), Operand(rbp, StandardFrameConstants::kCallerFPOffset));
3716a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3717a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Skip the arguments adaptor frame if it exists.
3718a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Label check_frame_marker;
37193ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  __ SmiCompare(Operand(fp.reg(), StandardFrameConstants::kContextOffset),
37203ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block                Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR));
3721a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(not_equal, &check_frame_marker);
3722a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ movq(fp.reg(), Operand(fp.reg(), StandardFrameConstants::kCallerFPOffset));
3723a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3724a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check the marker in the calling frame.
3725a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&check_frame_marker);
37263ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  __ SmiCompare(Operand(fp.reg(), StandardFrameConstants::kMarkerOffset),
37273ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block                Smi::FromInt(StackFrame::CONSTRUCT));
3728a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  fp.Unuse();
3729a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  destination()->Split(equal);
3730a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
3731a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3732a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3733a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CodeGenerator::GenerateArgumentsLength(ZoneList<Expression*>* args) {
3734a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(args->length() == 0);
3735a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // ArgumentsAccessStub takes the parameter count as an input argument
3736a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // in register eax.  Create a constant result for it.
37373100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  Result count(Handle<Smi>(Smi::FromInt(scope()->num_parameters())));
3738a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Call the shared stub to get to the arguments.length.
3739a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ArgumentsAccessStub stub(ArgumentsAccessStub::READ_LENGTH);
3740a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Result result = frame_->CallStub(&stub, &count);
3741a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  frame_->Push(&result);
3742a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
3743a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3744a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3745a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CodeGenerator::GenerateFastCharCodeAt(ZoneList<Expression*>* args) {
3746a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Comment(masm_, "[ GenerateFastCharCodeAt");
3747a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(args->length() == 2);
3748a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3749a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Label slow_case;
3750a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Label end;
3751a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Label not_a_flat_string;
3752a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Label try_again_with_new_string;
3753a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Label ascii_string;
3754a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Label got_char_code;
3755a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3756a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Load(args->at(0));
3757a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Load(args->at(1));
3758a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Result index = frame_->Pop();
3759a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Result object = frame_->Pop();
3760a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3761a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Get register rcx to use as shift amount later.
3762a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Result shift_amount;
3763a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (object.is_register() && object.reg().is(rcx)) {
3764a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    Result fresh = allocator_->Allocate();
3765a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    shift_amount = object;
3766a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    object = fresh;
3767a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ movq(object.reg(), rcx);
3768a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
3769a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (index.is_register() && index.reg().is(rcx)) {
3770a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    Result fresh = allocator_->Allocate();
3771a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    shift_amount = index;
3772a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    index = fresh;
3773a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ movq(index.reg(), rcx);
3774a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
3775a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // There could be references to ecx in the frame. Allocating will
3776a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // spill them, otherwise spill explicitly.
3777a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (shift_amount.is_valid()) {
3778a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    frame_->Spill(rcx);
3779a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  } else {
3780a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    shift_amount = allocator()->Allocate(rcx);
3781a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
3782a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(shift_amount.is_register());
3783a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(shift_amount.reg().is(rcx));
3784a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(allocator_->count(rcx) == 1);
3785a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3786a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // We will mutate the index register and possibly the object register.
3787a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // The case where they are somehow the same register is handled
3788a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // because we only mutate them in the case where the receiver is a
3789a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // heap object and the index is not.
3790a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  object.ToRegister();
3791a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  index.ToRegister();
3792a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  frame_->Spill(object.reg());
3793a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  frame_->Spill(index.reg());
3794a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3795a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // We need a single extra temporary register.
3796a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Result temp = allocator()->Allocate();
3797a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(temp.is_valid());
3798a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3799a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // There is no virtual frame effect from here up to the final result
3800a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // push.
3801a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3802a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // If the receiver is a smi trigger the slow case.
3803a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ JumpIfSmi(object.reg(), &slow_case);
3804a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3805a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // If the index is negative or non-smi trigger the slow case.
3806a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ JumpIfNotPositiveSmi(index.reg(), &slow_case);
3807a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3808a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Untag the index.
3809a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ SmiToInteger32(index.reg(), index.reg());
3810a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3811a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&try_again_with_new_string);
3812a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Fetch the instance type of the receiver into rcx.
3813a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ movq(rcx, FieldOperand(object.reg(), HeapObject::kMapOffset));
3814a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ movzxbl(rcx, FieldOperand(rcx, Map::kInstanceTypeOffset));
3815a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // If the receiver is not a string trigger the slow case.
3816a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ testb(rcx, Immediate(kIsNotStringMask));
3817a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(not_zero, &slow_case);
3818a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3819a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check for index out of range.
3820d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  __ cmpl(index.reg(), FieldOperand(object.reg(), String::kLengthOffset));
3821a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(greater_equal, &slow_case);
3822a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Reload the instance type (into the temp register this time)..
3823a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ movq(temp.reg(), FieldOperand(object.reg(), HeapObject::kMapOffset));
3824a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ movzxbl(temp.reg(), FieldOperand(temp.reg(), Map::kInstanceTypeOffset));
3825a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3826a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // We need special handling for non-flat strings.
3827d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  ASSERT_EQ(0, kSeqStringTag);
3828a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ testb(temp.reg(), Immediate(kStringRepresentationMask));
3829a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(not_zero, &not_a_flat_string);
3830a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check for 1-byte or 2-byte string.
3831d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  ASSERT_EQ(0, kTwoByteStringTag);
3832a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ testb(temp.reg(), Immediate(kStringEncodingMask));
3833a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(not_zero, &ascii_string);
3834a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3835a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // 2-byte string.
3836a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Load the 2-byte character code into the temp register.
3837a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ movzxwl(temp.reg(), FieldOperand(object.reg(),
3838a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                      index.reg(),
3839a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                      times_2,
3840a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                      SeqTwoByteString::kHeaderSize));
3841a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ jmp(&got_char_code);
3842a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3843a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // ASCII string.
3844a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&ascii_string);
3845a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Load the byte into the temp register.
3846a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ movzxbl(temp.reg(), FieldOperand(object.reg(),
3847a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                      index.reg(),
3848a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                      times_1,
3849a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                      SeqAsciiString::kHeaderSize));
3850a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&got_char_code);
3851a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ Integer32ToSmi(temp.reg(), temp.reg());
3852a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ jmp(&end);
3853a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3854a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Handle non-flat strings.
3855a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&not_a_flat_string);
3856a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ and_(temp.reg(), Immediate(kStringRepresentationMask));
3857a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ cmpb(temp.reg(), Immediate(kConsStringTag));
3858a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(not_equal, &slow_case);
3859a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3860a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // ConsString.
3861d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  // Check that the right hand side is the empty string (ie if this is really a
3862d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  // flat string in a cons string).  If that is not the case we would rather go
3863d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  // to the runtime system now, to flatten the string.
3864d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  __ movq(temp.reg(), FieldOperand(object.reg(), ConsString::kSecondOffset));
3865d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  __ CompareRoot(temp.reg(), Heap::kEmptyStringRootIndex);
3866d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  __ j(not_equal, &slow_case);
3867d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  // Get the first of the two strings.
3868a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ movq(object.reg(), FieldOperand(object.reg(), ConsString::kFirstOffset));
3869a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ jmp(&try_again_with_new_string);
3870a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3871a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&slow_case);
3872a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Move the undefined value into the result register, which will
3873a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // trigger the slow case.
3874a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ LoadRoot(temp.reg(), Heap::kUndefinedValueRootIndex);
3875a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3876a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&end);
3877a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  frame_->Push(&temp);
3878a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
3879a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3880a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3881a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CodeGenerator::GenerateIsNonNegativeSmi(ZoneList<Expression*>* args) {
3882a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(args->length() == 1);
3883a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Load(args->at(0));
3884a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Result value = frame_->Pop();
3885a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  value.ToRegister();
3886a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(value.is_valid());
3887a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Condition positive_smi = masm_->CheckPositiveSmi(value.reg());
3888a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  value.Unuse();
3889a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  destination()->Split(positive_smi);
3890a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
3891a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3892a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3893a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CodeGenerator::GenerateIsSmi(ZoneList<Expression*>* args) {
3894a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(args->length() == 1);
3895a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Load(args->at(0));
3896a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Result value = frame_->Pop();
3897a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  value.ToRegister();
3898a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(value.is_valid());
3899a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Condition is_smi = masm_->CheckSmi(value.reg());
3900a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  value.Unuse();
3901a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  destination()->Split(is_smi);
3902a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
3903a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3904a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3905a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CodeGenerator::GenerateLog(ZoneList<Expression*>* args) {
3906a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Conditionally generate a log call.
3907a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Args:
3908a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //   0 (literal string): The type of logging (corresponds to the flags).
3909a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //     This is used to determine whether or not to generate the log call.
3910a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //   1 (string): Format string.  Access the string at argument index 2
3911a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //     with '%2s' (see Logger::LogRuntime for all the formats).
3912a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //   2 (array): Arguments to the format string.
3913a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT_EQ(args->length(), 3);
3914a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#ifdef ENABLE_LOGGING_AND_PROFILING
3915a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (ShouldGenerateLog(args->at(0))) {
3916a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    Load(args->at(1));
3917a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    Load(args->at(2));
3918a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    frame_->CallRuntime(Runtime::kLog, 2);
3919a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
3920a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#endif
3921a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Finally, we're expected to leave a value on the top of the stack.
3922a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  frame_->Push(Factory::undefined_value());
3923a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
3924a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3925a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3926a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CodeGenerator::GenerateObjectEquals(ZoneList<Expression*>* args) {
3927a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(args->length() == 2);
3928a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3929a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Load the two objects into registers and perform the comparison.
3930a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Load(args->at(0));
3931a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Load(args->at(1));
3932a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Result right = frame_->Pop();
3933a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Result left = frame_->Pop();
3934a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  right.ToRegister();
3935a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  left.ToRegister();
3936a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ cmpq(right.reg(), left.reg());
3937a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  right.Unuse();
3938a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  left.Unuse();
3939a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  destination()->Split(equal);
3940a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
3941a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3942a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3943a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CodeGenerator::GenerateGetFramePointer(ZoneList<Expression*>* args) {
3944a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(args->length() == 0);
3945a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // RBP value is aligned, so it should be tagged as a smi (without necesarily
39463ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // being padded as a smi, so it should not be treated as a smi.).
3947a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(kSmiTag == 0 && kSmiTagSize == 1);
3948a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Result rbp_as_smi = allocator_->Allocate();
3949a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(rbp_as_smi.is_valid());
3950a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ movq(rbp_as_smi.reg(), rbp);
3951a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  frame_->Push(&rbp_as_smi);
3952a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
3953a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3954a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3955a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CodeGenerator::GenerateRandomPositiveSmi(ZoneList<Expression*>* args) {
3956a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(args->length() == 0);
3957a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  frame_->SpillAll();
3958a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ push(rsi);
3959a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3960a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Make sure the frame is aligned like the OS expects.
3961a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  static const int kFrameAlignment = OS::ActivationFrameAlignment();
3962a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (kFrameAlignment > 0) {
3963a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    ASSERT(IsPowerOf2(kFrameAlignment));
3964a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ movq(rbx, rsp);  // Save in AMD-64 abi callee-saved register.
3965a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ and_(rsp, Immediate(-kFrameAlignment));
3966a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
3967a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3968a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Call V8::RandomPositiveSmi().
3969a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ Call(FUNCTION_ADDR(V8::RandomPositiveSmi), RelocInfo::RUNTIME_ENTRY);
3970a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3971a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Restore stack pointer from callee-saved register.
3972a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (kFrameAlignment > 0) {
3973a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ movq(rsp, rbx);
3974a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
3975a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3976a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ pop(rsi);
3977a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Result result = allocator_->Allocate(rax);
3978a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  frame_->Push(&result);
3979a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
3980a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3981a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3982e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarkevoid CodeGenerator::GenerateRegExpExec(ZoneList<Expression*>* args) {
3983e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  ASSERT_EQ(args->length(), 4);
3984a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3985e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // Load the arguments on the stack and call the runtime system.
3986a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Load(args->at(0));
3987e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  Load(args->at(1));
3988e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  Load(args->at(2));
3989e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  Load(args->at(3));
39904515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  RegExpExecStub stub;
39914515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  Result result = frame_->CallStub(&stub, 4);
3992e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  frame_->Push(&result);
3993e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke}
3994a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3995a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3996402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescuvoid CodeGenerator::GenerateNumberToString(ZoneList<Expression*>* args) {
3997402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  ASSERT_EQ(args->length(), 1);
3998402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu
3999402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // Load the argument on the stack and jump to the runtime.
4000402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  Load(args->at(0));
4001402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu
4002402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  Result answer = frame_->CallRuntime(Runtime::kNumberToString, 1);
4003402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  frame_->Push(&answer);
4004402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu}
4005402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu
4006402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu
4007402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescuvoid CodeGenerator::GenerateMathSin(ZoneList<Expression*>* args) {
4008402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  ASSERT_EQ(args->length(), 1);
4009402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // Load the argument on the stack and jump to the runtime.
4010402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  Load(args->at(0));
4011402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  Result answer = frame_->CallRuntime(Runtime::kMath_sin, 1);
4012402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  frame_->Push(&answer);
4013402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu}
4014402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu
4015402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu
4016402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescuvoid CodeGenerator::GenerateMathCos(ZoneList<Expression*>* args) {
4017402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  ASSERT_EQ(args->length(), 1);
4018402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // Load the argument on the stack and jump to the runtime.
4019402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  Load(args->at(0));
4020402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  Result answer = frame_->CallRuntime(Runtime::kMath_cos, 1);
4021402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  frame_->Push(&answer);
4022402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu}
4023402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu
4024402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu
4025e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarkevoid CodeGenerator::GenerateStringAdd(ZoneList<Expression*>* args) {
4026e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  ASSERT_EQ(2, args->length());
4027a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
4028e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  Load(args->at(0));
4029e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  Load(args->at(1));
4030a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
4031e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  StringAddStub stub(NO_STRING_ADD_FLAGS);
4032e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  Result answer = frame_->CallStub(&stub, 2);
4033e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  frame_->Push(&answer);
4034e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke}
4035a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
4036e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
4037e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarkevoid CodeGenerator::GenerateSubString(ZoneList<Expression*>* args) {
4038e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  ASSERT_EQ(3, args->length());
4039e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
4040e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  Load(args->at(0));
4041e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  Load(args->at(1));
4042e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  Load(args->at(2));
4043e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
4044d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  SubStringStub stub;
4045d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  Result answer = frame_->CallStub(&stub, 3);
4046a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  frame_->Push(&answer);
4047a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
4048a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
4049a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
4050e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarkevoid CodeGenerator::GenerateStringCompare(ZoneList<Expression*>* args) {
4051d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  ASSERT_EQ(2, args->length());
4052d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
4053d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  Load(args->at(0));
4054d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  Load(args->at(1));
4055d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
4056e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  StringCompareStub stub;
4057e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  Result answer = frame_->CallStub(&stub, 2);
4058d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  frame_->Push(&answer);
4059d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block}
4060d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
4061d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
4062a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CodeGenerator::GenerateClassOf(ZoneList<Expression*>* args) {
4063a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(args->length() == 1);
4064a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  JumpTarget leave, null, function, non_function_constructor;
4065a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Load(args->at(0));  // Load the object.
4066a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Result obj = frame_->Pop();
4067a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  obj.ToRegister();
4068a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  frame_->Spill(obj.reg());
4069a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
4070a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // If the object is a smi, we return null.
4071a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Condition is_smi = masm_->CheckSmi(obj.reg());
4072a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  null.Branch(is_smi);
4073a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
4074a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check that the object is a JS object but take special care of JS
4075a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // functions to make sure they have 'Function' as their class.
4076a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
4077a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ CmpObjectType(obj.reg(), FIRST_JS_OBJECT_TYPE, obj.reg());
4078a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  null.Branch(below);
4079a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
4080a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // As long as JS_FUNCTION_TYPE is the last instance type and it is
4081a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // right after LAST_JS_OBJECT_TYPE, we can avoid checking for
4082a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // LAST_JS_OBJECT_TYPE.
4083a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(LAST_TYPE == JS_FUNCTION_TYPE);
4084a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(JS_FUNCTION_TYPE == LAST_JS_OBJECT_TYPE + 1);
4085a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ CmpInstanceType(obj.reg(), JS_FUNCTION_TYPE);
4086a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  function.Branch(equal);
4087a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
4088a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check if the constructor in the map is a function.
4089a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ movq(obj.reg(), FieldOperand(obj.reg(), Map::kConstructorOffset));
4090a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ CmpObjectType(obj.reg(), JS_FUNCTION_TYPE, kScratchRegister);
4091a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  non_function_constructor.Branch(not_equal);
4092a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
4093a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // The obj register now contains the constructor function. Grab the
4094a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // instance class name from there.
4095a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ movq(obj.reg(),
4096a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block          FieldOperand(obj.reg(), JSFunction::kSharedFunctionInfoOffset));
4097a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ movq(obj.reg(),
4098a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block          FieldOperand(obj.reg(),
4099a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                       SharedFunctionInfo::kInstanceClassNameOffset));
4100a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  frame_->Push(&obj);
4101a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  leave.Jump();
4102a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
4103a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Functions have class 'Function'.
4104a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  function.Bind();
4105a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  frame_->Push(Factory::function_class_symbol());
4106a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  leave.Jump();
4107a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
4108a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Objects with a non-function constructor have class 'Object'.
4109a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  non_function_constructor.Bind();
4110a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  frame_->Push(Factory::Object_symbol());
4111a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  leave.Jump();
4112a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
4113a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Non-JS objects have class null.
4114a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  null.Bind();
4115a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  frame_->Push(Factory::null_value());
4116a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
4117a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // All done.
4118a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  leave.Bind();
4119a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
4120a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
4121a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
4122a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CodeGenerator::GenerateSetValueOf(ZoneList<Expression*>* args) {
4123a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(args->length() == 2);
4124a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  JumpTarget leave;
4125a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Load(args->at(0));  // Load the object.
4126a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Load(args->at(1));  // Load the value.
4127a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Result value = frame_->Pop();
4128a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Result object = frame_->Pop();
4129a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  value.ToRegister();
4130a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  object.ToRegister();
4131a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
4132a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // if (object->IsSmi()) return value.
4133a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Condition is_smi = masm_->CheckSmi(object.reg());
4134a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  leave.Branch(is_smi, &value);
4135a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
4136a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // It is a heap object - get its map.
4137a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Result scratch = allocator_->Allocate();
4138a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(scratch.is_valid());
4139a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // if (!object->IsJSValue()) return value.
4140a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ CmpObjectType(object.reg(), JS_VALUE_TYPE, scratch.reg());
4141a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  leave.Branch(not_equal, &value);
4142a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
4143a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Store the value.
4144a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ movq(FieldOperand(object.reg(), JSValue::kValueOffset), value.reg());
4145a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Update the write barrier.  Save the value as it will be
4146a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // overwritten by the write barrier code and is needed afterward.
4147a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Result duplicate_value = allocator_->Allocate();
4148a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(duplicate_value.is_valid());
4149a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ movq(duplicate_value.reg(), value.reg());
4150a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // The object register is also overwritten by the write barrier and
4151a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // possibly aliased in the frame.
4152a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  frame_->Spill(object.reg());
4153a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ RecordWrite(object.reg(), JSValue::kValueOffset, duplicate_value.reg(),
4154a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                 scratch.reg());
4155a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  object.Unuse();
4156a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  scratch.Unuse();
4157a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  duplicate_value.Unuse();
4158a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
4159a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Leave.
4160a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  leave.Bind(&value);
4161a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  frame_->Push(&value);
4162a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
4163a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
4164a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
4165a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CodeGenerator::GenerateValueOf(ZoneList<Expression*>* args) {
4166a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(args->length() == 1);
4167a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  JumpTarget leave;
4168a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Load(args->at(0));  // Load the object.
4169a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  frame_->Dup();
4170a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Result object = frame_->Pop();
4171a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  object.ToRegister();
4172a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(object.is_valid());
4173a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // if (object->IsSmi()) return object.
4174a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Condition is_smi = masm_->CheckSmi(object.reg());
4175a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  leave.Branch(is_smi);
4176a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // It is a heap object - get map.
4177a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Result temp = allocator()->Allocate();
4178a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(temp.is_valid());
4179a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // if (!object->IsJSValue()) return object.
4180a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ CmpObjectType(object.reg(), JS_VALUE_TYPE, temp.reg());
4181a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  leave.Branch(not_equal);
4182a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ movq(temp.reg(), FieldOperand(object.reg(), JSValue::kValueOffset));
4183a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  object.Unuse();
4184a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  frame_->SetElementAt(0, &temp);
4185a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  leave.Bind();
4186a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
4187a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
4188a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
4189a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// -----------------------------------------------------------------------------
4190a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// CodeGenerator implementation of Expressions
4191a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
4192d0582a6c46733687d045e4188a1bcd0123c758a1Steve Blockvoid CodeGenerator::LoadAndSpill(Expression* expression) {
4193a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // TODO(x64): No architecture specific code. Move to shared location.
4194a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(in_spilled_code());
4195a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  set_in_spilled_code(false);
4196d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  Load(expression);
4197a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  frame_->SpillAll();
4198a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  set_in_spilled_code(true);
4199a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
4200a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
4201a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
4202d0582a6c46733687d045e4188a1bcd0123c758a1Steve Blockvoid CodeGenerator::Load(Expression* expr) {
4203a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#ifdef DEBUG
4204a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  int original_height = frame_->height();
4205a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#endif
4206a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(!in_spilled_code());
4207a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  JumpTarget true_target;
4208a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  JumpTarget false_target;
4209a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ControlDestination dest(&true_target, &false_target, true);
4210d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  LoadCondition(expr, &dest, false);
4211a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
4212a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (dest.false_was_fall_through()) {
4213a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // The false target was just bound.
4214a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    JumpTarget loaded;
4215a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    frame_->Push(Factory::false_value());
4216a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // There may be dangling jumps to the true target.
4217a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (true_target.is_linked()) {
4218a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      loaded.Jump();
4219a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      true_target.Bind();
4220a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      frame_->Push(Factory::true_value());
4221a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      loaded.Bind();
4222a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
4223a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
4224a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  } else if (dest.is_used()) {
4225a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // There is true, and possibly false, control flow (with true as
4226a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // the fall through).
4227a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    JumpTarget loaded;
4228a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    frame_->Push(Factory::true_value());
4229a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (false_target.is_linked()) {
4230a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      loaded.Jump();
4231a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      false_target.Bind();
4232a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      frame_->Push(Factory::false_value());
4233a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      loaded.Bind();
4234a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
4235a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
4236a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  } else {
4237a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // We have a valid value on top of the frame, but we still may
4238a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // have dangling jumps to the true and false targets from nested
4239a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // subexpressions (eg, the left subexpressions of the
4240a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // short-circuited boolean operators).
4241a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    ASSERT(has_valid_frame());
4242a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (true_target.is_linked() || false_target.is_linked()) {
4243a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      JumpTarget loaded;
4244a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      loaded.Jump();  // Don't lose the current TOS.
4245a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      if (true_target.is_linked()) {
4246a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        true_target.Bind();
4247a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        frame_->Push(Factory::true_value());
4248a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        if (false_target.is_linked()) {
4249a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block          loaded.Jump();
4250a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        }
4251a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      }
4252a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      if (false_target.is_linked()) {
4253a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        false_target.Bind();
4254a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        frame_->Push(Factory::false_value());
4255a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      }
4256a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      loaded.Bind();
4257a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
4258a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
4259a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
4260a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(has_valid_frame());
4261a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(frame_->height() == original_height + 1);
4262a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
4263a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
4264a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
4265a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// Emit code to load the value of an expression to the top of the
4266a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// frame. If the expression is boolean-valued it may be compiled (or
4267a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// partially compiled) into control flow to the control destination.
4268a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// If force_control is true, control flow is forced.
4269a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CodeGenerator::LoadCondition(Expression* x,
4270a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                  ControlDestination* dest,
4271a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                  bool force_control) {
4272a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(!in_spilled_code());
4273a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  int original_height = frame_->height();
4274a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
4275d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  { CodeGenState new_state(this, dest);
4276a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    Visit(x);
4277a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
4278a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // If we hit a stack overflow, we may not have actually visited
4279a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // the expression.  In that case, we ensure that we have a
4280a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // valid-looking frame state because we will continue to generate
4281a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // code as we unwind the C++ stack.
4282a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    //
4283a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // It's possible to have both a stack overflow and a valid frame
4284a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // state (eg, a subexpression overflowed, visiting it returned
4285a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // with a dummied frame state, and visiting this expression
4286a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // returned with a normal-looking state).
4287a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (HasStackOverflow() &&
4288a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        !dest->is_used() &&
4289a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        frame_->height() == original_height) {
4290a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      dest->Goto(true);
4291a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
4292a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
4293a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
4294a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (force_control && !dest->is_used()) {
4295a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Convert the TOS value into flow to the control destination.
4296a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // TODO(X64): Make control flow to control destinations work.
4297a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    ToBoolean(dest);
4298a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
4299a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
4300a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(!(force_control && !dest->is_used()));
4301a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(dest->is_used() || frame_->height() == original_height + 1);
4302a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
4303a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
4304a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
4305a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// ECMA-262, section 9.2, page 30: ToBoolean(). Pop the top of stack and
4306a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// convert it to a boolean in the condition code register or jump to
4307a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// 'false_target'/'true_target' as appropriate.
4308a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CodeGenerator::ToBoolean(ControlDestination* dest) {
4309a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Comment cmnt(masm_, "[ ToBoolean");
4310a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
4311a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // The value to convert should be popped from the frame.
4312a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Result value = frame_->Pop();
4313a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  value.ToRegister();
4314a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
4315402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  if (value.is_number()) {
4316402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    Comment cmnt(masm_, "ONLY_NUMBER");
4317402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    // Fast case if NumberInfo indicates only numbers.
4318402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    if (FLAG_debug_code) {
4319402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu      __ AbortIfNotNumber(value.reg(), "ToBoolean operand is not a number.");
4320402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    }
4321402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    // Smi => false iff zero.
4322402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    __ SmiCompare(value.reg(), Smi::FromInt(0));
4323402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    dest->false_target()->Branch(equal);
4324402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    Condition is_smi = masm_->CheckSmi(value.reg());
4325402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    dest->true_target()->Branch(is_smi);
4326402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    __ fldz();
4327402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    __ fld_d(FieldOperand(value.reg(), HeapNumber::kValueOffset));
4328402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    __ FCmp();
4329402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    value.Unuse();
4330402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    dest->Split(not_zero);
4331402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  } else {
4332402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    // Fast case checks.
4333402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    // 'false' => false.
4334402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    __ CompareRoot(value.reg(), Heap::kFalseValueRootIndex);
4335402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    dest->false_target()->Branch(equal);
4336a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
4337402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    // 'true' => true.
4338402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    __ CompareRoot(value.reg(), Heap::kTrueValueRootIndex);
4339402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    dest->true_target()->Branch(equal);
4340a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
4341402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    // 'undefined' => false.
4342402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    __ CompareRoot(value.reg(), Heap::kUndefinedValueRootIndex);
4343402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    dest->false_target()->Branch(equal);
4344a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
4345402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    // Smi => false iff zero.
4346402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    __ SmiCompare(value.reg(), Smi::FromInt(0));
4347402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    dest->false_target()->Branch(equal);
4348402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    Condition is_smi = masm_->CheckSmi(value.reg());
4349402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    dest->true_target()->Branch(is_smi);
4350a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
4351402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    // Call the stub for all other cases.
4352402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    frame_->Push(&value);  // Undo the Pop() from above.
4353402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    ToBooleanStub stub;
4354402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    Result temp = frame_->CallStub(&stub, 1);
4355402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    // Convert the result to a condition code.
4356402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    __ testq(temp.reg(), temp.reg());
4357402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    temp.Unuse();
4358402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    dest->Split(not_equal);
4359402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  }
4360a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
4361a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
4362a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
4363a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CodeGenerator::LoadUnsafeSmi(Register target, Handle<Object> value) {
4364a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  UNIMPLEMENTED();
4365a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // TODO(X64): Implement security policy for loads of smis.
4366a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
4367a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
4368a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
4369a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockbool CodeGenerator::IsUnsafeSmi(Handle<Object> value) {
4370a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  return false;
4371a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
4372a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
4373a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block//------------------------------------------------------------------------------
4374a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// CodeGenerator implementation of variables, lookups, and stores.
4375a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
4376d91b9f7d46489a9ee00f9cb415630299c76a502bLeon ClarkeReference::Reference(CodeGenerator* cgen,
4377d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke                     Expression* expression,
4378d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke                     bool  persist_after_get)
4379d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    : cgen_(cgen),
4380d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      expression_(expression),
4381d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      type_(ILLEGAL),
4382d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      persist_after_get_(persist_after_get) {
4383a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  cgen->LoadReference(this);
4384a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
4385a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
4386a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
4387a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockReference::~Reference() {
4388d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  ASSERT(is_unloaded() || is_illegal());
4389a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
4390a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
4391a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
4392a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CodeGenerator::LoadReference(Reference* ref) {
4393a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // References are loaded from both spilled and unspilled code.  Set the
4394a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // state to unspilled to allow that (and explicitly spill after
4395a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // construction at the construction sites).
4396a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  bool was_in_spilled_code = in_spilled_code_;
4397a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  in_spilled_code_ = false;
4398a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
4399a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Comment cmnt(masm_, "[ LoadReference");
4400a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Expression* e = ref->expression();
4401a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Property* property = e->AsProperty();
4402a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Variable* var = e->AsVariableProxy()->AsVariable();
4403a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
4404a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (property != NULL) {
4405a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // The expression is either a property or a variable proxy that rewrites
4406a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // to a property.
4407a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    Load(property->obj());
4408e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke    if (property->key()->IsPropertyName()) {
4409a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      ref->set_type(Reference::NAMED);
4410a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    } else {
4411a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      Load(property->key());
4412a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      ref->set_type(Reference::KEYED);
4413a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
4414a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  } else if (var != NULL) {
4415a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // The expression is a variable proxy that does not rewrite to a
4416a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // property.  Global variables are treated as named property references.
4417a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (var->is_global()) {
4418a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      LoadGlobal();
4419a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      ref->set_type(Reference::NAMED);
4420a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    } else {
4421a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      ASSERT(var->slot() != NULL);
4422a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      ref->set_type(Reference::SLOT);
4423a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
4424a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  } else {
4425a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Anything else is a runtime error.
4426a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    Load(e);
4427a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    frame_->CallRuntime(Runtime::kThrowReferenceError, 1);
4428a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
4429a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
4430a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  in_spilled_code_ = was_in_spilled_code;
4431a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
4432a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
4433a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
4434a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CodeGenerator::UnloadReference(Reference* ref) {
4435a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Pop a reference from the stack while preserving TOS.
4436a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Comment cmnt(masm_, "[ UnloadReference");
4437a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  frame_->Nip(ref->size());
4438d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  ref->set_unloaded();
4439a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
4440a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
4441a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
4442a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockOperand CodeGenerator::SlotOperand(Slot* slot, Register tmp) {
4443a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Currently, this assertion will fail if we try to assign to
4444a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // a constant variable that is constant because it is read-only
4445a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // (such as the variable referring to a named function expression).
4446a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // We need to implement assignments to read-only variables.
4447a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Ideally, we should do this during AST generation (by converting
4448a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // such assignments into expression statements); however, in general
4449a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // we may not be able to make the decision until past AST generation,
4450a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // that is when the entire program is known.
4451a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(slot != NULL);
4452a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  int index = slot->index();
4453a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  switch (slot->type()) {
4454a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    case Slot::PARAMETER:
4455a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      return frame_->ParameterAt(index);
4456a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
4457a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    case Slot::LOCAL:
4458a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      return frame_->LocalAt(index);
4459a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
4460a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    case Slot::CONTEXT: {
4461a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // Follow the context chain if necessary.
4462a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      ASSERT(!tmp.is(rsi));  // do not overwrite context register
4463a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      Register context = rsi;
4464a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      int chain_length = scope()->ContextChainLength(slot->var()->scope());
4465a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      for (int i = 0; i < chain_length; i++) {
4466a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        // Load the closure.
4467a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        // (All contexts, even 'with' contexts, have a closure,
4468a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        // and it is the same for all contexts inside a function.
4469a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        // There is no need to go to the function context first.)
4470a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        __ movq(tmp, ContextOperand(context, Context::CLOSURE_INDEX));
4471a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        // Load the function context (which is the incoming, outer context).
4472a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        __ movq(tmp, FieldOperand(tmp, JSFunction::kContextOffset));
4473a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        context = tmp;
4474a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      }
4475a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // We may have a 'with' context now. Get the function context.
4476a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // (In fact this mov may never be the needed, since the scope analysis
4477a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // may not permit a direct context access in this case and thus we are
4478a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // always at a function context. However it is safe to dereference be-
4479a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // cause the function context of a function context is itself. Before
4480a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // deleting this mov we should try to create a counter-example first,
4481a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // though...)
4482a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      __ movq(tmp, ContextOperand(context, Context::FCONTEXT_INDEX));
4483a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      return ContextOperand(tmp, index);
4484a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
4485a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
4486a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    default:
4487a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      UNREACHABLE();
4488a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      return Operand(rsp, 0);
4489a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
4490a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
4491a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
4492a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
4493a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockOperand CodeGenerator::ContextSlotOperandCheckExtensions(Slot* slot,
4494a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                                         Result tmp,
4495a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                                         JumpTarget* slow) {
4496a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(slot->type() == Slot::CONTEXT);
4497a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(tmp.is_register());
4498a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Register context = rsi;
4499a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
4500a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  for (Scope* s = scope(); s != slot->var()->scope(); s = s->outer_scope()) {
4501a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (s->num_heap_slots() > 0) {
4502a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      if (s->calls_eval()) {
4503a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        // Check that extension is NULL.
4504a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        __ cmpq(ContextOperand(context, Context::EXTENSION_INDEX),
4505a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                Immediate(0));
4506a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        slow->Branch(not_equal, not_taken);
4507a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      }
4508a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      __ movq(tmp.reg(), ContextOperand(context, Context::CLOSURE_INDEX));
4509a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      __ movq(tmp.reg(), FieldOperand(tmp.reg(), JSFunction::kContextOffset));
4510a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      context = tmp.reg();
4511a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
4512a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
4513a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check that last extension is NULL.
4514a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ cmpq(ContextOperand(context, Context::EXTENSION_INDEX), Immediate(0));
4515a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  slow->Branch(not_equal, not_taken);
4516a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ movq(tmp.reg(), ContextOperand(context, Context::FCONTEXT_INDEX));
4517a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  return ContextOperand(tmp.reg(), slot->index());
4518a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
4519a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
4520a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
4521a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CodeGenerator::LoadFromSlot(Slot* slot, TypeofState typeof_state) {
4522a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (slot->type() == Slot::LOOKUP) {
4523a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    ASSERT(slot->var()->is_dynamic());
4524a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
4525a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    JumpTarget slow;
4526a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    JumpTarget done;
4527a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    Result value;
4528a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
4529a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Generate fast-case code for variables that might be shadowed by
4530a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // eval-introduced variables.  Eval is used a lot without
4531a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // introducing variables.  In those cases, we do not want to
4532a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // perform a runtime call for all variables in the scope
4533a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // containing the eval.
4534a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (slot->var()->mode() == Variable::DYNAMIC_GLOBAL) {
4535a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      value = LoadFromGlobalSlotCheckExtensions(slot, typeof_state, &slow);
4536a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // If there was no control flow to slow, we can exit early.
4537a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      if (!slow.is_linked()) {
4538a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        frame_->Push(&value);
4539a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        return;
4540a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      }
4541a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
4542a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      done.Jump(&value);
4543a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
4544a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    } else if (slot->var()->mode() == Variable::DYNAMIC_LOCAL) {
4545a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      Slot* potential_slot = slot->var()->local_if_not_shadowed()->slot();
4546a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // Only generate the fast case for locals that rewrite to slots.
4547a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // This rules out argument loads.
4548a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      if (potential_slot != NULL) {
4549a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        // Allocate a fresh register to use as a temp in
4550a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        // ContextSlotOperandCheckExtensions and to hold the result
4551a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        // value.
4552a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        value = allocator_->Allocate();
4553a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        ASSERT(value.is_valid());
4554a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        __ movq(value.reg(),
4555a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block               ContextSlotOperandCheckExtensions(potential_slot,
4556a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                                 value,
4557a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                                 &slow));
4558a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        if (potential_slot->var()->mode() == Variable::CONST) {
4559a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block          __ CompareRoot(value.reg(), Heap::kTheHoleValueRootIndex);
4560a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block          done.Branch(not_equal, &value);
4561a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block          __ LoadRoot(value.reg(), Heap::kUndefinedValueRootIndex);
4562a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        }
4563a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        // There is always control flow to slow from
4564a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        // ContextSlotOperandCheckExtensions so we have to jump around
4565a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        // it.
4566a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        done.Jump(&value);
4567a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      }
4568a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
4569a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
4570a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    slow.Bind();
4571a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // A runtime call is inevitable.  We eagerly sync frame elements
4572a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // to memory so that we can push the arguments directly into place
4573a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // on top of the frame.
4574a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    frame_->SyncRange(0, frame_->element_count() - 1);
4575a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    frame_->EmitPush(rsi);
4576a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ movq(kScratchRegister, slot->var()->name(), RelocInfo::EMBEDDED_OBJECT);
4577a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    frame_->EmitPush(kScratchRegister);
4578a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (typeof_state == INSIDE_TYPEOF) {
4579a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block       value =
4580a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block         frame_->CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2);
4581a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    } else {
4582a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block       value = frame_->CallRuntime(Runtime::kLoadContextSlot, 2);
4583a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
4584a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
4585a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    done.Bind(&value);
4586a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    frame_->Push(&value);
4587a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
4588a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  } else if (slot->var()->mode() == Variable::CONST) {
4589a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Const slots may contain 'the hole' value (the constant hasn't been
4590a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // initialized yet) which needs to be converted into the 'undefined'
4591a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // value.
4592a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    //
4593a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // We currently spill the virtual frame because constants use the
4594a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // potentially unsafe direct-frame access of SlotOperand.
4595a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    VirtualFrame::SpilledScope spilled_scope;
4596a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    Comment cmnt(masm_, "[ Load const");
4597a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    JumpTarget exit;
4598a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ movq(rcx, SlotOperand(slot, rcx));
4599a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ CompareRoot(rcx, Heap::kTheHoleValueRootIndex);
4600a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    exit.Branch(not_equal);
4601a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ LoadRoot(rcx, Heap::kUndefinedValueRootIndex);
4602a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    exit.Bind();
4603a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    frame_->EmitPush(rcx);
4604a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
4605a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  } else if (slot->type() == Slot::PARAMETER) {
4606a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    frame_->PushParameterAt(slot->index());
4607a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
4608a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  } else if (slot->type() == Slot::LOCAL) {
4609a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    frame_->PushLocalAt(slot->index());
4610a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
4611a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  } else {
4612a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // The other remaining slot types (LOOKUP and GLOBAL) cannot reach
4613a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // here.
4614a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    //
4615a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // The use of SlotOperand below is safe for an unspilled frame
4616a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // because it will always be a context slot.
4617a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    ASSERT(slot->type() == Slot::CONTEXT);
4618a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    Result temp = allocator_->Allocate();
4619a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    ASSERT(temp.is_valid());
4620a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ movq(temp.reg(), SlotOperand(slot, temp.reg()));
4621a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    frame_->Push(&temp);
4622a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
4623a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
4624a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
4625a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
4626a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CodeGenerator::LoadFromSlotCheckForArguments(Slot* slot,
4627a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                                  TypeofState state) {
4628a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  LoadFromSlot(slot, state);
4629a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
4630a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Bail out quickly if we're not using lazy arguments allocation.
4631a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (ArgumentsMode() != LAZY_ARGUMENTS_ALLOCATION) return;
4632a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
4633a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // ... or if the slot isn't a non-parameter arguments slot.
4634a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (slot->type() == Slot::PARAMETER || !slot->is_arguments()) return;
4635a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
4636a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Pop the loaded value from the stack.
4637a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Result value = frame_->Pop();
4638a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
4639a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // If the loaded value is a constant, we know if the arguments
4640a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // object has been lazily loaded yet.
4641a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (value.is_constant()) {
4642a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (value.handle()->IsTheHole()) {
4643a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      Result arguments = StoreArgumentsObject(false);
4644a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      frame_->Push(&arguments);
4645a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    } else {
4646a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      frame_->Push(&value);
4647a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
4648a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    return;
4649a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
4650a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
4651a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // The loaded value is in a register. If it is the sentinel that
4652a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // indicates that we haven't loaded the arguments object yet, we
4653a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // need to do it now.
4654a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  JumpTarget exit;
4655a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ CompareRoot(value.reg(), Heap::kTheHoleValueRootIndex);
4656a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  frame_->Push(&value);
4657a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  exit.Branch(not_equal);
4658a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Result arguments = StoreArgumentsObject(false);
4659a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  frame_->SetElementAt(0, &arguments);
4660a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  exit.Bind();
4661a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
4662a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
4663a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
4664a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CodeGenerator::StoreToSlot(Slot* slot, InitState init_state) {
4665a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (slot->type() == Slot::LOOKUP) {
4666a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    ASSERT(slot->var()->is_dynamic());
4667a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
4668a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // For now, just do a runtime call.  Since the call is inevitable,
4669a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // we eagerly sync the virtual frame so we can directly push the
4670a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // arguments into place.
4671a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    frame_->SyncRange(0, frame_->element_count() - 1);
4672a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
4673a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    frame_->EmitPush(rsi);
4674a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    frame_->EmitPush(slot->var()->name());
4675a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
4676a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    Result value;
4677a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (init_state == CONST_INIT) {
4678a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // Same as the case for a normal store, but ignores attribute
4679a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // (e.g. READ_ONLY) of context slot so that we can initialize const
4680a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // properties (introduced via eval("const foo = (some expr);")). Also,
4681a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // uses the current function context instead of the top context.
4682a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      //
4683a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // Note that we must declare the foo upon entry of eval(), via a
4684a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // context slot declaration, but we cannot initialize it at the same
4685a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // time, because the const declaration may be at the end of the eval
4686a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // code (sigh...) and the const variable may have been used before
4687a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // (where its value is 'undefined'). Thus, we can only do the
4688a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // initialization when we actually encounter the expression and when
4689a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // the expression operands are defined and valid, and thus we need the
4690a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // split into 2 operations: declaration of the context slot followed
4691a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // by initialization.
4692a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      value = frame_->CallRuntime(Runtime::kInitializeConstContextSlot, 3);
4693a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    } else {
4694a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      value = frame_->CallRuntime(Runtime::kStoreContextSlot, 3);
4695a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
4696a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Storing a variable must keep the (new) value on the expression
4697a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // stack. This is necessary for compiling chained assignment
4698a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // expressions.
4699a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    frame_->Push(&value);
4700a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  } else {
4701a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    ASSERT(!slot->var()->is_dynamic());
4702a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
4703a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    JumpTarget exit;
4704a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (init_state == CONST_INIT) {
4705a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      ASSERT(slot->var()->mode() == Variable::CONST);
4706a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // Only the first const initialization must be executed (the slot
4707a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // still contains 'the hole' value). When the assignment is executed,
4708a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // the code is identical to a normal store (see below).
4709a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      //
4710a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // We spill the frame in the code below because the direct-frame
4711a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // access of SlotOperand is potentially unsafe with an unspilled
4712a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // frame.
4713a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      VirtualFrame::SpilledScope spilled_scope;
4714a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      Comment cmnt(masm_, "[ Init const");
4715a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      __ movq(rcx, SlotOperand(slot, rcx));
4716a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      __ CompareRoot(rcx, Heap::kTheHoleValueRootIndex);
4717a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      exit.Branch(not_equal);
4718a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
4719a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
4720a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // We must execute the store.  Storing a variable must keep the (new)
4721a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // value on the stack. This is necessary for compiling assignment
4722a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // expressions.
4723a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    //
4724a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Note: We will reach here even with slot->var()->mode() ==
4725a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Variable::CONST because of const declarations which will initialize
4726a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // consts to 'the hole' value and by doing so, end up calling this code.
4727a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (slot->type() == Slot::PARAMETER) {
4728a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      frame_->StoreToParameterAt(slot->index());
4729a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    } else if (slot->type() == Slot::LOCAL) {
4730a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      frame_->StoreToLocalAt(slot->index());
4731a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    } else {
4732a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // The other slot types (LOOKUP and GLOBAL) cannot reach here.
4733a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      //
4734a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // The use of SlotOperand below is safe for an unspilled frame
4735a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // because the slot is a context slot.
4736a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      ASSERT(slot->type() == Slot::CONTEXT);
4737a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      frame_->Dup();
4738a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      Result value = frame_->Pop();
4739a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      value.ToRegister();
4740a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      Result start = allocator_->Allocate();
4741a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      ASSERT(start.is_valid());
4742a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      __ movq(SlotOperand(slot, start.reg()), value.reg());
4743a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // RecordWrite may destroy the value registers.
4744a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      //
4745a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // TODO(204): Avoid actually spilling when the value is not
4746a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // needed (probably the common case).
4747a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      frame_->Spill(value.reg());
4748a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize;
4749a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      Result temp = allocator_->Allocate();
4750a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      ASSERT(temp.is_valid());
4751a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      __ RecordWrite(start.reg(), offset, value.reg(), temp.reg());
4752a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // The results start, value, and temp are unused by going out of
4753a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // scope.
4754a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
4755a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
4756a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    exit.Bind();
4757a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
4758a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
4759a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
4760a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
4761a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockResult CodeGenerator::LoadFromGlobalSlotCheckExtensions(
4762a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    Slot* slot,
4763a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    TypeofState typeof_state,
4764a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    JumpTarget* slow) {
4765a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check that no extension objects have been created by calls to
4766a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // eval from the current scope to the global scope.
4767a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Register context = rsi;
4768a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Result tmp = allocator_->Allocate();
4769a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(tmp.is_valid());  // All non-reserved registers were available.
4770a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
4771a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Scope* s = scope();
4772a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  while (s != NULL) {
4773a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (s->num_heap_slots() > 0) {
4774a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      if (s->calls_eval()) {
4775a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        // Check that extension is NULL.
4776a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        __ cmpq(ContextOperand(context, Context::EXTENSION_INDEX),
4777a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block               Immediate(0));
4778a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        slow->Branch(not_equal, not_taken);
4779a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      }
4780a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // Load next context in chain.
4781a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      __ movq(tmp.reg(), ContextOperand(context, Context::CLOSURE_INDEX));
4782a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      __ movq(tmp.reg(), FieldOperand(tmp.reg(), JSFunction::kContextOffset));
4783a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      context = tmp.reg();
4784a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
4785a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // If no outer scope calls eval, we do not need to check more
4786a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // context extensions.  If we have reached an eval scope, we check
4787a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // all extensions from this point.
4788a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (!s->outer_scope_calls_eval() || s->is_eval_scope()) break;
4789a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    s = s->outer_scope();
4790a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
4791a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
4792a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (s->is_eval_scope()) {
4793a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Loop up the context chain.  There is no frame effect so it is
4794a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // safe to use raw labels here.
4795a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    Label next, fast;
4796a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (!context.is(tmp.reg())) {
4797a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      __ movq(tmp.reg(), context);
4798a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
4799a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Load map for comparison into register, outside loop.
4800a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ LoadRoot(kScratchRegister, Heap::kGlobalContextMapRootIndex);
4801a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ bind(&next);
4802a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Terminate at global context.
4803a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ cmpq(kScratchRegister, FieldOperand(tmp.reg(), HeapObject::kMapOffset));
4804a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ j(equal, &fast);
4805a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Check that extension is NULL.
4806a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ cmpq(ContextOperand(tmp.reg(), Context::EXTENSION_INDEX), Immediate(0));
4807a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    slow->Branch(not_equal);
4808a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Load next context in chain.
4809a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ movq(tmp.reg(), ContextOperand(tmp.reg(), Context::CLOSURE_INDEX));
4810a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ movq(tmp.reg(), FieldOperand(tmp.reg(), JSFunction::kContextOffset));
4811a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ jmp(&next);
4812a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ bind(&fast);
4813a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
4814a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  tmp.Unuse();
4815a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
4816a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // All extension objects were empty and it is safe to use a global
4817a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // load IC call.
4818a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  LoadGlobal();
4819a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  frame_->Push(slot->var()->name());
4820a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  RelocInfo::Mode mode = (typeof_state == INSIDE_TYPEOF)
4821a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                         ? RelocInfo::CODE_TARGET
4822a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                         : RelocInfo::CODE_TARGET_CONTEXT;
4823a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Result answer = frame_->CallLoadIC(mode);
4824a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // A test rax instruction following the call signals that the inobject
4825a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // property case was inlined.  Ensure that there is not a test rax
4826a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // instruction here.
4827a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  masm_->nop();
4828a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Discard the global object. The result is in answer.
4829a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  frame_->Drop();
4830a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  return answer;
4831a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
4832a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
4833a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
4834a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CodeGenerator::LoadGlobal() {
4835a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (in_spilled_code()) {
4836a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    frame_->EmitPush(GlobalObject());
4837a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  } else {
4838a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    Result temp = allocator_->Allocate();
4839a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ movq(temp.reg(), GlobalObject());
4840a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    frame_->Push(&temp);
4841a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
4842a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
4843a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
4844a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
4845a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CodeGenerator::LoadGlobalReceiver() {
4846a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Result temp = allocator_->Allocate();
4847a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Register reg = temp.reg();
4848a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ movq(reg, GlobalObject());
4849a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ movq(reg, FieldOperand(reg, GlobalObject::kGlobalReceiverOffset));
4850a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  frame_->Push(&temp);
4851a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
4852a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
4853a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
48543100271588b61cbc1dc472a3f2f105d2eed8497fAndrei PopescuArgumentsAllocationMode CodeGenerator::ArgumentsMode() {
48553100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  if (scope()->arguments() == NULL) return NO_ARGUMENTS_ALLOCATION;
48563100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  ASSERT(scope()->arguments_shadow() != NULL);
4857a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // We don't want to do lazy arguments allocation for functions that
4858a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // have heap-allocated contexts, because it interfers with the
4859a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // uninitialized const tracking in the context objects.
48603100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  return (scope()->num_heap_slots() > 0)
4861a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      ? EAGER_ARGUMENTS_ALLOCATION
4862a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      : LAZY_ARGUMENTS_ALLOCATION;
4863a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
4864a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
4865a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
4866a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockResult CodeGenerator::StoreArgumentsObject(bool initial) {
4867a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ArgumentsAllocationMode mode = ArgumentsMode();
4868a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(mode != NO_ARGUMENTS_ALLOCATION);
4869a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
4870a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Comment cmnt(masm_, "[ store arguments object");
4871a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (mode == LAZY_ARGUMENTS_ALLOCATION && initial) {
4872a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // When using lazy arguments allocation, we store the hole value
4873a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // as a sentinel indicating that the arguments object hasn't been
4874a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // allocated yet.
4875a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    frame_->Push(Factory::the_hole_value());
4876a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  } else {
4877a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    ArgumentsAccessStub stub(ArgumentsAccessStub::NEW_OBJECT);
4878a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    frame_->PushFunction();
4879a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    frame_->PushReceiverSlotAddress();
48803100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    frame_->Push(Smi::FromInt(scope()->num_parameters()));
4881a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    Result result = frame_->CallStub(&stub, 3);
4882a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    frame_->Push(&result);
4883a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
4884a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
4885e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
48863100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  Variable* arguments = scope()->arguments()->var();
48873100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu  Variable* shadow = scope()->arguments_shadow()->var();
4888e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  ASSERT(arguments != NULL && arguments->slot() != NULL);
4889e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  ASSERT(shadow != NULL && shadow->slot() != NULL);
4890e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  JumpTarget done;
4891e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  bool skip_arguments = false;
4892e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  if (mode == LAZY_ARGUMENTS_ALLOCATION && !initial) {
4893e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke    // We have to skip storing into the arguments slot if it has
4894e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke    // already been written to. This can happen if the a function
4895e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke    // has a local variable named 'arguments'.
48963100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu    LoadFromSlot(scope()->arguments()->var()->slot(), NOT_INSIDE_TYPEOF);
4897e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke    Result probe = frame_->Pop();
4898e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke    if (probe.is_constant()) {
4899e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke      // We have to skip updating the arguments object if it has been
4900e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke      // assigned a proper value.
4901e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke      skip_arguments = !probe.handle()->IsTheHole();
4902e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke    } else {
4903e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke      __ CompareRoot(probe.reg(), Heap::kTheHoleValueRootIndex);
4904e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke      probe.Unuse();
4905e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke      done.Branch(not_equal);
4906a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
4907a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
4908e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  if (!skip_arguments) {
4909e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke    StoreToSlot(arguments->slot(), NOT_CONST_INIT);
4910e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke    if (mode == LAZY_ARGUMENTS_ALLOCATION) done.Bind();
4911e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  }
4912e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  StoreToSlot(shadow->slot(), NOT_CONST_INIT);
4913a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  return frame_->Pop();
4914a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
4915a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
4916a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
4917d0582a6c46733687d045e4188a1bcd0123c758a1Steve Blockvoid CodeGenerator::LoadTypeofExpression(Expression* expr) {
4918d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  // Special handling of identifiers as subexpressions of typeof.
4919d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  Variable* variable = expr->AsVariableProxy()->AsVariable();
4920a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (variable != NULL && !variable->is_this() && variable->is_global()) {
4921d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    // For a global variable we build the property reference
4922d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    // <global>.<variable> and perform a (regular non-contextual) property
4923d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    // load to make sure we do not get reference errors.
4924a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    Slot global(variable, Slot::CONTEXT, Context::GLOBAL_INDEX);
4925a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    Literal key(variable->name());
4926a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    Property property(&global, &key, RelocInfo::kNoPosition);
4927d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    Reference ref(this, &property);
4928d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    ref.GetValue();
4929d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  } else if (variable != NULL && variable->slot() != NULL) {
4930d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    // For a variable that rewrites to a slot, we signal it is the immediate
4931d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    // subexpression of a typeof.
4932d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    LoadFromSlotCheckForArguments(variable->slot(), INSIDE_TYPEOF);
4933a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  } else {
4934d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    // Anything else can be handled normally.
4935d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    Load(expr);
4936a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
4937a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
4938a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
4939a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
4940402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescuvoid CodeGenerator::Comparison(AstNode* node,
4941402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu                               Condition cc,
4942a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                               bool strict,
4943a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                               ControlDestination* dest) {
4944a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Strict only makes sense for equality comparisons.
4945a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(!strict || cc == equal);
4946a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
4947a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Result left_side;
4948a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Result right_side;
4949a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Implement '>' and '<=' by reversal to obtain ECMA-262 conversion order.
4950a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (cc == greater || cc == less_equal) {
4951a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    cc = ReverseCondition(cc);
4952a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    left_side = frame_->Pop();
4953a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    right_side = frame_->Pop();
4954a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  } else {
4955a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    right_side = frame_->Pop();
4956a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    left_side = frame_->Pop();
4957a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
4958a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(cc == less || cc == equal || cc == greater_equal);
4959a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
4960a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // If either side is a constant smi, optimize the comparison.
4961a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  bool left_side_constant_smi =
4962a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      left_side.is_constant() && left_side.handle()->IsSmi();
4963a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  bool right_side_constant_smi =
4964a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      right_side.is_constant() && right_side.handle()->IsSmi();
4965a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  bool left_side_constant_null =
4966a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      left_side.is_constant() && left_side.handle()->IsNull();
4967a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  bool right_side_constant_null =
4968a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      right_side.is_constant() && right_side.handle()->IsNull();
4969a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
4970a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (left_side_constant_smi || right_side_constant_smi) {
4971a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (left_side_constant_smi && right_side_constant_smi) {
4972a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // Trivial case, comparing two constants.
4973a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      int left_value = Smi::cast(*left_side.handle())->value();
4974a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      int right_value = Smi::cast(*right_side.handle())->value();
4975a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      switch (cc) {
4976a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        case less:
4977a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block          dest->Goto(left_value < right_value);
4978a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block          break;
4979a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        case equal:
4980a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block          dest->Goto(left_value == right_value);
4981a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block          break;
4982a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        case greater_equal:
4983a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block          dest->Goto(left_value >= right_value);
4984a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block          break;
4985a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        default:
4986a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block          UNREACHABLE();
4987a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      }
4988402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    } else {
4989402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu      // Only one side is a constant Smi.
4990a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // If left side is a constant Smi, reverse the operands.
4991a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // Since one side is a constant Smi, conversion order does not matter.
4992a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      if (left_side_constant_smi) {
4993a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        Result temp = left_side;
4994a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        left_side = right_side;
4995a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        right_side = temp;
4996a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        cc = ReverseCondition(cc);
4997a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        // This may reintroduce greater or less_equal as the value of cc.
4998a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        // CompareStub and the inline code both support all values of cc.
4999a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      }
5000a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // Implement comparison against a constant Smi, inlining the case
5001a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // where both sides are Smis.
5002a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      left_side.ToRegister();
5003402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu      Register left_reg = left_side.reg();
5004402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu      Handle<Object> right_val = right_side.handle();
5005a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
5006a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // Here we split control flow to the stub call and inlined cases
5007a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // before finally splitting it to the control destination.  We use
5008a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // a jump target and branching to duplicate the virtual frame at
5009a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // the first split.  We manually handle the off-frame references
5010a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // by reconstituting them on the non-fall-through path.
5011a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      JumpTarget is_smi;
5012a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
5013a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      Condition left_is_smi = masm_->CheckSmi(left_side.reg());
5014a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      is_smi.Branch(left_is_smi);
5015a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
5016402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu      bool is_for_loop_compare = (node->AsCompareOperation() != NULL)
5017402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu          && node->AsCompareOperation()->is_for_loop_condition();
5018402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu      if (!is_for_loop_compare && right_val->IsSmi()) {
5019402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu        // Right side is a constant smi and left side has been checked
5020402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu        // not to be a smi.
5021402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu        JumpTarget not_number;
5022402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu        __ Cmp(FieldOperand(left_reg, HeapObject::kMapOffset),
5023402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu               Factory::heap_number_map());
5024402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu        not_number.Branch(not_equal, &left_side);
5025402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu        __ movsd(xmm1,
5026402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu                 FieldOperand(left_reg, HeapNumber::kValueOffset));
5027402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu        int value = Smi::cast(*right_val)->value();
5028402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu        if (value == 0) {
5029402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu          __ xorpd(xmm0, xmm0);
5030402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu        } else {
5031402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu          Result temp = allocator()->Allocate();
5032402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu          __ movl(temp.reg(), Immediate(value));
5033402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu          __ cvtlsi2sd(xmm0, temp.reg());
5034402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu          temp.Unuse();
5035402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu        }
5036402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu        __ ucomisd(xmm1, xmm0);
5037402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu        // Jump to builtin for NaN.
5038402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu        not_number.Branch(parity_even, &left_side);
5039402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu        left_side.Unuse();
5040402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu        Condition double_cc = cc;
5041402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu        switch (cc) {
5042402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu          case less:          double_cc = below;       break;
5043402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu          case equal:         double_cc = equal;       break;
5044402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu          case less_equal:    double_cc = below_equal; break;
5045402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu          case greater:       double_cc = above;       break;
5046402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu          case greater_equal: double_cc = above_equal; break;
5047402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu          default: UNREACHABLE();
5048402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu        }
5049402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu        dest->true_target()->Branch(double_cc);
5050402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu        dest->false_target()->Jump();
5051402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu        not_number.Bind(&left_side);
5052402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu      }
5053402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu
5054a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // Setup and call the compare stub.
5055a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      CompareStub stub(cc, strict);
5056a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      Result result = frame_->CallStub(&stub, &left_side, &right_side);
5057a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      result.ToRegister();
5058a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      __ testq(result.reg(), result.reg());
5059a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      result.Unuse();
5060a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      dest->true_target()->Branch(cc);
5061a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      dest->false_target()->Jump();
5062a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
5063a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      is_smi.Bind();
5064a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      left_side = Result(left_reg);
5065a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      right_side = Result(right_val);
5066a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // Test smi equality and comparison by signed int comparison.
5067a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // Both sides are smis, so we can use an Immediate.
50683ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      __ SmiCompare(left_side.reg(), Smi::cast(*right_side.handle()));
5069a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      left_side.Unuse();
5070a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      right_side.Unuse();
5071a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      dest->Split(cc);
5072a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
5073a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  } else if (cc == equal &&
5074a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block             (left_side_constant_null || right_side_constant_null)) {
5075a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // To make null checks efficient, we check if either the left side or
5076a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // the right side is the constant 'null'.
5077a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // If so, we optimize the code by inlining a null check instead of
5078a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // calling the (very) general runtime routine for checking equality.
5079a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    Result operand = left_side_constant_null ? right_side : left_side;
5080a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    right_side.Unuse();
5081a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    left_side.Unuse();
5082a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    operand.ToRegister();
5083a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ CompareRoot(operand.reg(), Heap::kNullValueRootIndex);
5084a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (strict) {
5085a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      operand.Unuse();
5086a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      dest->Split(equal);
5087a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    } else {
5088a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // The 'null' value is only equal to 'undefined' if using non-strict
5089a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // comparisons.
5090a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      dest->true_target()->Branch(equal);
5091a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      __ CompareRoot(operand.reg(), Heap::kUndefinedValueRootIndex);
5092a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      dest->true_target()->Branch(equal);
5093a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      Condition is_smi = masm_->CheckSmi(operand.reg());
5094a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      dest->false_target()->Branch(is_smi);
5095a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
5096a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // It can be an undetectable object.
5097a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // Use a scratch register in preference to spilling operand.reg().
5098a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      Result temp = allocator()->Allocate();
5099a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      ASSERT(temp.is_valid());
5100a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      __ movq(temp.reg(),
51013ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block              FieldOperand(operand.reg(), HeapObject::kMapOffset));
5102a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      __ testb(FieldOperand(temp.reg(), Map::kBitFieldOffset),
5103a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block               Immediate(1 << Map::kIsUndetectable));
5104a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      temp.Unuse();
5105a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      operand.Unuse();
5106a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      dest->Split(not_zero);
5107a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
5108a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  } else {  // Neither side is a constant Smi or null.
5109a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // If either side is a non-smi constant, skip the smi check.
5110a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    bool known_non_smi =
5111a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        (left_side.is_constant() && !left_side.handle()->IsSmi()) ||
5112a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        (right_side.is_constant() && !right_side.handle()->IsSmi());
5113a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    left_side.ToRegister();
5114a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    right_side.ToRegister();
5115a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
5116a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (known_non_smi) {
5117a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // When non-smi, call out to the compare stub.
5118a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      CompareStub stub(cc, strict);
5119a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      Result answer = frame_->CallStub(&stub, &left_side, &right_side);
5120a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // The result is a Smi, which is negative, zero, or positive.
51213ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      __ SmiTest(answer.reg());  // Sets both zero and sign flag.
5122a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      answer.Unuse();
5123a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      dest->Split(cc);
5124a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    } else {
5125a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // Here we split control flow to the stub call and inlined cases
5126a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // before finally splitting it to the control destination.  We use
5127a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // a jump target and branching to duplicate the virtual frame at
5128a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // the first split.  We manually handle the off-frame references
5129a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // by reconstituting them on the non-fall-through path.
5130a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      JumpTarget is_smi;
5131a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      Register left_reg = left_side.reg();
5132a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      Register right_reg = right_side.reg();
5133a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
5134a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      Condition both_smi = masm_->CheckBothSmi(left_reg, right_reg);
5135a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      is_smi.Branch(both_smi);
5136a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // When non-smi, call out to the compare stub.
5137a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      CompareStub stub(cc, strict);
5138a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      Result answer = frame_->CallStub(&stub, &left_side, &right_side);
51393ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      __ SmiTest(answer.reg());  // Sets both zero and sign flags.
5140a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      answer.Unuse();
5141a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      dest->true_target()->Branch(cc);
5142a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      dest->false_target()->Jump();
5143a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
5144a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      is_smi.Bind();
5145a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      left_side = Result(left_reg);
5146a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      right_side = Result(right_reg);
51473ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      __ SmiCompare(left_side.reg(), right_side.reg());
5148a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      right_side.Unuse();
5149a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      left_side.Unuse();
5150a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      dest->Split(cc);
5151a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
5152a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
5153a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
5154a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
5155a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
5156a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockclass DeferredInlineBinaryOperation: public DeferredCode {
5157a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block public:
5158a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  DeferredInlineBinaryOperation(Token::Value op,
5159a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                Register dst,
5160a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                Register left,
5161a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                Register right,
5162a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                OverwriteMode mode)
5163a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      : op_(op), dst_(dst), left_(left), right_(right), mode_(mode) {
5164a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    set_comment("[ DeferredInlineBinaryOperation");
5165a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
5166a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
5167a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  virtual void Generate();
5168a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
5169a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block private:
5170a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Token::Value op_;
5171a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Register dst_;
5172a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Register left_;
5173a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Register right_;
5174a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  OverwriteMode mode_;
5175a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block};
5176a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
5177a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
5178a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid DeferredInlineBinaryOperation::Generate() {
5179d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  GenericBinaryOpStub stub(op_, mode_, NO_SMI_CODE_IN_STUB);
5180d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  stub.GenerateCall(masm_, left_, right_);
5181a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (!dst_.is(rax)) __ movq(dst_, rax);
5182a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
5183a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
5184a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
5185a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CodeGenerator::GenericBinaryOperation(Token::Value op,
5186e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke                                           StaticType* type,
5187a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                           OverwriteMode overwrite_mode) {
5188a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Comment cmnt(masm_, "[ BinaryOperation");
5189a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Comment cmnt_token(masm_, Token::String(op));
5190a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
5191a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (op == Token::COMMA) {
5192a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Simply discard left value.
5193a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    frame_->Nip(1);
5194a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    return;
5195a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
5196a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
5197a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Result right = frame_->Pop();
5198a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Result left = frame_->Pop();
5199a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
5200a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (op == Token::ADD) {
5201a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    bool left_is_string = left.is_constant() && left.handle()->IsString();
5202a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    bool right_is_string = right.is_constant() && right.handle()->IsString();
5203a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (left_is_string || right_is_string) {
5204a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      frame_->Push(&left);
5205a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      frame_->Push(&right);
5206a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      Result answer;
5207a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      if (left_is_string) {
5208a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        if (right_is_string) {
5209a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block          // TODO(lrn): if both are constant strings
5210a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block          // -- do a compile time cons, if allocation during codegen is allowed.
5211a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block          answer = frame_->CallRuntime(Runtime::kStringAdd, 2);
5212a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        } else {
5213a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block          answer =
5214a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block            frame_->InvokeBuiltin(Builtins::STRING_ADD_LEFT, CALL_FUNCTION, 2);
5215a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        }
5216a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      } else if (right_is_string) {
5217a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        answer =
5218a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block          frame_->InvokeBuiltin(Builtins::STRING_ADD_RIGHT, CALL_FUNCTION, 2);
5219a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      }
5220a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      frame_->Push(&answer);
5221a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      return;
5222a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
5223a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Neither operand is known to be a string.
5224a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
5225a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
5226402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  bool left_is_smi_constant = left.is_constant() && left.handle()->IsSmi();
5227402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  bool left_is_non_smi_constant = left.is_constant() && !left.handle()->IsSmi();
5228402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  bool right_is_smi_constant = right.is_constant() && right.handle()->IsSmi();
5229402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  bool right_is_non_smi_constant =
5230402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu      right.is_constant() && !right.handle()->IsSmi();
5231a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
5232402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  if (left_is_smi_constant && right_is_smi_constant) {
5233a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Compute the constant result at compile time, and leave it on the frame.
5234a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    int left_int = Smi::cast(*left.handle())->value();
5235a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    int right_int = Smi::cast(*right.handle())->value();
5236a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (FoldConstantSmis(op, left_int, right_int)) return;
5237a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
5238a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
5239402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // Get number type of left and right sub-expressions.
5240402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  NumberInfo::Type operands_type =
5241402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu      NumberInfo::Combine(left.number_info(), right.number_info());
5242402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu
5243d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  Result answer;
5244402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  if (left_is_non_smi_constant || right_is_non_smi_constant) {
5245402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    GenericBinaryOpStub stub(op,
5246402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu                             overwrite_mode,
5247402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu                             NO_SMI_CODE_IN_STUB,
5248402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu                             operands_type);
52494515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke    answer = stub.GenerateCall(masm_, frame_, &left, &right);
5250402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  } else if (right_is_smi_constant) {
5251d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    answer = ConstantSmiBinaryOperation(op, &left, right.handle(),
5252d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke                                        type, false, overwrite_mode);
5253402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  } else if (left_is_smi_constant) {
5254d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    answer = ConstantSmiBinaryOperation(op, &right, left.handle(),
5255d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke                                        type, true, overwrite_mode);
5256a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  } else {
5257d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    // Set the flags based on the operation, type and loop nesting level.
5258d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    // Bit operations always assume they likely operate on Smis. Still only
5259d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    // generate the inline Smi check code if this operation is part of a loop.
5260d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    // For all other operations only inline the Smi check code for likely smis
5261d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    // if the operation is part of a loop.
5262d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    if (loop_nesting() > 0 && (Token::IsBitOp(op) || type->IsLikelySmi())) {
5263d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      answer = LikelySmiBinaryOperation(op, &left, &right, overwrite_mode);
5264d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    } else {
5265402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu      GenericBinaryOpStub stub(op,
5266402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu                               overwrite_mode,
5267402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu                               NO_GENERIC_BINARY_FLAGS,
5268402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu                               operands_type);
52694515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke      answer = stub.GenerateCall(masm_, frame_, &left, &right);
5270a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
5271a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
5272402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu
5273402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // Set NumberInfo of result according to the operation performed.
5274402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // We rely on the fact that smis have a 32 bit payload on x64.
5275402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  ASSERT(kSmiValueSize == 32);
5276402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  NumberInfo::Type result_type = NumberInfo::kUnknown;
5277402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  switch (op) {
5278402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    case Token::COMMA:
5279402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu      result_type = right.number_info();
5280402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu      break;
5281402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    case Token::OR:
5282402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    case Token::AND:
5283402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu      // Result type can be either of the two input types.
5284402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu      result_type = operands_type;
5285402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu      break;
5286402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    case Token::BIT_OR:
5287402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    case Token::BIT_XOR:
5288402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    case Token::BIT_AND:
5289402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu      // Result is always a smi.
5290402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu      result_type = NumberInfo::kSmi;
5291402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu      break;
5292402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    case Token::SAR:
5293402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    case Token::SHL:
5294402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu      // Result is always a smi.
5295402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu      result_type = NumberInfo::kSmi;
5296402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu      break;
5297402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    case Token::SHR:
5298402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu      // Result of x >>> y is always a smi if y >= 1, otherwise a number.
5299402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu      result_type = (right.is_constant() && right.handle()->IsSmi()
5300402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu                     && Smi::cast(*right.handle())->value() >= 1)
5301402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu          ? NumberInfo::kSmi
5302402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu          : NumberInfo::kNumber;
5303402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu      break;
5304402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    case Token::ADD:
5305402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu      // Result could be a string or a number. Check types of inputs.
5306402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu      result_type = NumberInfo::IsNumber(operands_type)
5307402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu          ? NumberInfo::kNumber
5308402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu          : NumberInfo::kUnknown;
5309402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu      break;
5310402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    case Token::SUB:
5311402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    case Token::MUL:
5312402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    case Token::DIV:
5313402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    case Token::MOD:
5314402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu      // Result is always a number.
5315402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu      result_type = NumberInfo::kNumber;
5316402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu      break;
5317402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    default:
5318402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu      UNREACHABLE();
5319402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  }
5320402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  answer.set_number_info(result_type);
5321d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  frame_->Push(&answer);
5322a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
5323a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
5324a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
5325a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// Emit a LoadIC call to get the value from receiver and leave it in
5326a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// dst.  The receiver register is restored after the call.
5327a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockclass DeferredReferenceGetNamedValue: public DeferredCode {
5328a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block public:
5329a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  DeferredReferenceGetNamedValue(Register dst,
5330a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                 Register receiver,
5331a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                 Handle<String> name)
5332a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      : dst_(dst), receiver_(receiver),  name_(name) {
5333a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    set_comment("[ DeferredReferenceGetNamedValue");
5334a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
5335a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
5336a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  virtual void Generate();
5337a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
5338a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Label* patch_site() { return &patch_site_; }
5339a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
5340a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block private:
5341a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Label patch_site_;
5342a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Register dst_;
5343a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Register receiver_;
5344a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Handle<String> name_;
5345a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block};
5346a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
5347a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
5348a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid DeferredReferenceGetNamedValue::Generate() {
5349a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ push(receiver_);
5350a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ Move(rcx, name_);
5351a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
5352a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ Call(ic, RelocInfo::CODE_TARGET);
5353a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // The call must be followed by a test rax instruction to indicate
5354a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // that the inobject property case was inlined.
5355a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //
5356a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Store the delta to the map check instruction here in the test
5357a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // instruction.  Use masm_-> instead of the __ macro since the
5358a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // latter can't return a value.
5359a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  int delta_to_patch_site = masm_->SizeOfCodeGeneratedSince(patch_site());
5360a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Here we use masm_-> instead of the __ macro because this is the
5361a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // instruction that gets patched and coverage code gets in the way.
5362a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  masm_->testl(rax, Immediate(-delta_to_patch_site));
5363a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ IncrementCounter(&Counters::named_load_inline_miss, 1);
5364a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
5365a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (!dst_.is(rax)) __ movq(dst_, rax);
5366a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ pop(receiver_);
5367a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
5368a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
5369a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
5370a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid DeferredInlineSmiAdd::Generate() {
5371d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  GenericBinaryOpStub igostub(Token::ADD, overwrite_mode_, NO_SMI_CODE_IN_STUB);
5372d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  igostub.GenerateCall(masm_, dst_, value_);
5373a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (!dst_.is(rax)) __ movq(dst_, rax);
5374a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
5375a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
5376a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
5377a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid DeferredInlineSmiAddReversed::Generate() {
5378d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  GenericBinaryOpStub igostub(Token::ADD, overwrite_mode_, NO_SMI_CODE_IN_STUB);
5379d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  igostub.GenerateCall(masm_, value_, dst_);
5380a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (!dst_.is(rax)) __ movq(dst_, rax);
5381a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
5382a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
5383a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
5384a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid DeferredInlineSmiSub::Generate() {
5385d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  GenericBinaryOpStub igostub(Token::SUB, overwrite_mode_, NO_SMI_CODE_IN_STUB);
5386d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  igostub.GenerateCall(masm_, dst_, value_);
5387a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (!dst_.is(rax)) __ movq(dst_, rax);
5388a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
5389a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
5390a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
5391a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid DeferredInlineSmiOperation::Generate() {
5392a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // For mod we don't generate all the Smi code inline.
5393a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  GenericBinaryOpStub stub(
5394a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      op_,
5395a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      overwrite_mode_,
5396d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block      (op_ == Token::MOD) ? NO_GENERIC_BINARY_FLAGS : NO_SMI_CODE_IN_STUB);
5397d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  stub.GenerateCall(masm_, src_, value_);
5398a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (!dst_.is(rax)) __ movq(dst_, rax);
5399a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
5400a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
5401a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
5402d91b9f7d46489a9ee00f9cb415630299c76a502bLeon ClarkeResult CodeGenerator::ConstantSmiBinaryOperation(Token::Value op,
5403d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke                                                 Result* operand,
5404d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke                                                 Handle<Object> value,
5405d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke                                                 StaticType* type,
5406d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke                                                 bool reversed,
5407d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke                                                 OverwriteMode overwrite_mode) {
5408a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // NOTE: This is an attempt to inline (a bit) more of the code for
5409a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // some possible smi operations (like + and -) when (at least) one
5410a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // of the operands is a constant smi.
5411a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Consumes the argument "operand".
5412a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
5413a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // TODO(199): Optimize some special cases of operations involving a
5414a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // smi literal (multiply by 2, shift by 0, etc.).
5415a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (IsUnsafeSmi(value)) {
5416a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    Result unsafe_operand(value);
5417a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (reversed) {
5418d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      return LikelySmiBinaryOperation(op, &unsafe_operand, operand,
5419a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                               overwrite_mode);
5420a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    } else {
5421d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      return LikelySmiBinaryOperation(op, operand, &unsafe_operand,
5422a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                               overwrite_mode);
5423a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
5424a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
5425a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
5426a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Get the literal value.
5427a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Smi* smi_value = Smi::cast(*value);
5428a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  int int_value = smi_value->value();
5429a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
5430d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  Result answer;
5431a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  switch (op) {
5432a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    case Token::ADD: {
5433a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      operand->ToRegister();
5434a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      frame_->Spill(operand->reg());
5435a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      DeferredCode* deferred = NULL;
5436a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      if (reversed) {
5437a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        deferred = new DeferredInlineSmiAddReversed(operand->reg(),
5438a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                                    smi_value,
5439a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                                    overwrite_mode);
5440a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      } else {
5441a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        deferred = new DeferredInlineSmiAdd(operand->reg(),
5442a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                            smi_value,
5443a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                            overwrite_mode);
5444a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      }
5445a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      __ JumpIfNotSmi(operand->reg(), deferred->entry_label());
5446a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      __ SmiAddConstant(operand->reg(),
5447a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                        operand->reg(),
54483ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block                        smi_value,
5449a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                        deferred->entry_label());
5450a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      deferred->BindExit();
5451d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      answer = *operand;
5452a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      break;
5453a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
5454a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
5455a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    case Token::SUB: {
5456a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      if (reversed) {
5457a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        Result constant_operand(value);
5458d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke        answer = LikelySmiBinaryOperation(op, &constant_operand, operand,
5459d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke                                          overwrite_mode);
5460a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      } else {
5461a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        operand->ToRegister();
5462a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        frame_->Spill(operand->reg());
5463a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        DeferredCode* deferred = new DeferredInlineSmiSub(operand->reg(),
5464a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                                          smi_value,
5465a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                                          overwrite_mode);
5466a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        __ JumpIfNotSmi(operand->reg(), deferred->entry_label());
5467a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        // A smi currently fits in a 32-bit Immediate.
5468a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        __ SmiSubConstant(operand->reg(),
5469a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                          operand->reg(),
54703ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block                          smi_value,
5471a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                          deferred->entry_label());
5472a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        deferred->BindExit();
5473d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke        answer = *operand;
5474a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      }
5475a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      break;
5476a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
5477a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
5478a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    case Token::SAR:
5479a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      if (reversed) {
5480a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        Result constant_operand(value);
5481d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke        answer = LikelySmiBinaryOperation(op, &constant_operand, operand,
5482d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke                                          overwrite_mode);
5483a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      } else {
5484a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        // Only the least significant 5 bits of the shift value are used.
5485a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        // In the slow case, this masking is done inside the runtime call.
5486a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        int shift_value = int_value & 0x1f;
5487a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        operand->ToRegister();
5488a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        frame_->Spill(operand->reg());
5489a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        DeferredInlineSmiOperation* deferred =
5490a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block            new DeferredInlineSmiOperation(op,
5491a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                           operand->reg(),
5492a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                           operand->reg(),
5493a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                           smi_value,
5494a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                           overwrite_mode);
5495a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        __ JumpIfNotSmi(operand->reg(), deferred->entry_label());
5496a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        __ SmiShiftArithmeticRightConstant(operand->reg(),
5497a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                           operand->reg(),
5498a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                           shift_value);
5499a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        deferred->BindExit();
5500d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke        answer = *operand;
5501a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      }
5502a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      break;
5503a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
5504a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    case Token::SHR:
5505a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      if (reversed) {
5506a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        Result constant_operand(value);
5507d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke        answer = LikelySmiBinaryOperation(op, &constant_operand, operand,
5508d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke                                          overwrite_mode);
5509a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      } else {
5510a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        // Only the least significant 5 bits of the shift value are used.
5511a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        // In the slow case, this masking is done inside the runtime call.
5512a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        int shift_value = int_value & 0x1f;
5513a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        operand->ToRegister();
5514d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke        answer = allocator()->Allocate();
5515a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        ASSERT(answer.is_valid());
5516a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        DeferredInlineSmiOperation* deferred =
5517a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block            new DeferredInlineSmiOperation(op,
5518a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                           answer.reg(),
5519a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                           operand->reg(),
5520a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                           smi_value,
5521a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                           overwrite_mode);
5522a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        __ JumpIfNotSmi(operand->reg(), deferred->entry_label());
5523a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        __ SmiShiftLogicalRightConstant(answer.reg(),
55243ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block                                        operand->reg(),
55253ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block                                        shift_value,
55263ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block                                        deferred->entry_label());
5527a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        deferred->BindExit();
5528a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        operand->Unuse();
5529a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      }
5530a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      break;
5531a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
5532a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    case Token::SHL:
5533a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      if (reversed) {
5534a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        Result constant_operand(value);
5535d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke        answer = LikelySmiBinaryOperation(op, &constant_operand, operand,
5536d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke                                          overwrite_mode);
5537a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      } else {
5538a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        // Only the least significant 5 bits of the shift value are used.
5539a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        // In the slow case, this masking is done inside the runtime call.
5540a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        int shift_value = int_value & 0x1f;
5541a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        operand->ToRegister();
5542a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        if (shift_value == 0) {
5543a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block          // Spill operand so it can be overwritten in the slow case.
5544a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block          frame_->Spill(operand->reg());
5545a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block          DeferredInlineSmiOperation* deferred =
5546a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block              new DeferredInlineSmiOperation(op,
5547a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                             operand->reg(),
5548a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                             operand->reg(),
5549a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                             smi_value,
5550a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                             overwrite_mode);
5551a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block          __ JumpIfNotSmi(operand->reg(), deferred->entry_label());
5552a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block          deferred->BindExit();
5553d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke          answer = *operand;
5554a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        } else {
5555a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block          // Use a fresh temporary for nonzero shift values.
5556d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke          answer = allocator()->Allocate();
5557a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block          ASSERT(answer.is_valid());
5558a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block          DeferredInlineSmiOperation* deferred =
5559a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block              new DeferredInlineSmiOperation(op,
5560a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                             answer.reg(),
5561a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                             operand->reg(),
5562a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                             smi_value,
5563a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                             overwrite_mode);
5564a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block          __ JumpIfNotSmi(operand->reg(), deferred->entry_label());
5565a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block          __ SmiShiftLeftConstant(answer.reg(),
5566a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                  operand->reg(),
5567a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                  shift_value,
5568a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                  deferred->entry_label());
5569a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block          deferred->BindExit();
5570a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block          operand->Unuse();
5571a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        }
5572a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      }
5573a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      break;
5574a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
5575a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    case Token::BIT_OR:
5576a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    case Token::BIT_XOR:
5577a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    case Token::BIT_AND: {
5578a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      operand->ToRegister();
5579a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      frame_->Spill(operand->reg());
5580a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      if (reversed) {
5581a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        // Bit operations with a constant smi are commutative.
5582a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        // We can swap left and right operands with no problem.
5583a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        // Swap left and right overwrite modes.  0->0, 1->2, 2->1.
5584a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        overwrite_mode = static_cast<OverwriteMode>((2 * overwrite_mode) % 3);
5585a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      }
5586a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      DeferredCode* deferred =  new DeferredInlineSmiOperation(op,
5587a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                                               operand->reg(),
5588a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                                               operand->reg(),
5589a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                                               smi_value,
5590a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                                               overwrite_mode);
5591a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      __ JumpIfNotSmi(operand->reg(), deferred->entry_label());
5592a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      if (op == Token::BIT_AND) {
55933ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block        __ SmiAndConstant(operand->reg(), operand->reg(), smi_value);
5594a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      } else if (op == Token::BIT_XOR) {
5595a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        if (int_value != 0) {
55963ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block          __ SmiXorConstant(operand->reg(), operand->reg(), smi_value);
5597a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        }
5598a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      } else {
5599a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        ASSERT(op == Token::BIT_OR);
5600a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        if (int_value != 0) {
56013ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block          __ SmiOrConstant(operand->reg(), operand->reg(), smi_value);
5602a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        }
5603a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      }
5604a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      deferred->BindExit();
5605d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      answer = *operand;
5606a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      break;
5607a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
5608a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
5609a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Generate inline code for mod of powers of 2 and negative powers of 2.
5610a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    case Token::MOD:
5611a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      if (!reversed &&
5612a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block          int_value != 0 &&
5613a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block          (IsPowerOf2(int_value) || IsPowerOf2(-int_value))) {
5614a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        operand->ToRegister();
5615a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        frame_->Spill(operand->reg());
56163ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block        DeferredCode* deferred =
56173ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block            new DeferredInlineSmiOperation(op,
56183ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block                                           operand->reg(),
56193ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block                                           operand->reg(),
56203ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block                                           smi_value,
56213ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block                                           overwrite_mode);
5622a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        // Check for negative or non-Smi left hand side.
5623a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        __ JumpIfNotPositiveSmi(operand->reg(), deferred->entry_label());
5624a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        if (int_value < 0) int_value = -int_value;
5625a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        if (int_value == 1) {
56263ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block          __ Move(operand->reg(), Smi::FromInt(0));
5627a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        } else {
56283ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block          __ SmiAndConstant(operand->reg(),
56293ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block                            operand->reg(),
56303ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block                            Smi::FromInt(int_value - 1));
5631a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        }
5632a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        deferred->BindExit();
5633d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke        answer = *operand;
5634a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        break;  // This break only applies if we generated code for MOD.
5635a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      }
5636a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // Fall through if we did not find a power of 2 on the right hand side!
5637a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // The next case must be the default.
5638a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
5639a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    default: {
5640a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      Result constant_operand(value);
5641a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      if (reversed) {
5642d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke        answer = LikelySmiBinaryOperation(op, &constant_operand, operand,
5643d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke                                          overwrite_mode);
5644a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      } else {
5645d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke        answer = LikelySmiBinaryOperation(op, operand, &constant_operand,
5646d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke                                          overwrite_mode);
5647a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      }
5648a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      break;
5649a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
5650a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
5651d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  ASSERT(answer.is_valid());
5652d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  return answer;
5653a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
5654a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
5655d91b9f7d46489a9ee00f9cb415630299c76a502bLeon ClarkeResult CodeGenerator::LikelySmiBinaryOperation(Token::Value op,
5656d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke                                               Result* left,
5657d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke                                               Result* right,
5658d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke                                               OverwriteMode overwrite_mode) {
5659d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  Result answer;
5660a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Special handling of div and mod because they use fixed registers.
5661a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (op == Token::DIV || op == Token::MOD) {
5662a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // We need rax as the quotient register, rdx as the remainder
5663a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // register, neither left nor right in rax or rdx, and left copied
5664a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // to rax.
5665a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    Result quotient;
5666a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    Result remainder;
5667a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    bool left_is_in_rax = false;
5668a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Step 1: get rax for quotient.
5669a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if ((left->is_register() && left->reg().is(rax)) ||
5670a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        (right->is_register() && right->reg().is(rax))) {
5671a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // One or both is in rax.  Use a fresh non-rdx register for
5672a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // them.
5673a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      Result fresh = allocator_->Allocate();
5674a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      ASSERT(fresh.is_valid());
5675a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      if (fresh.reg().is(rdx)) {
5676a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        remainder = fresh;
5677a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        fresh = allocator_->Allocate();
5678a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        ASSERT(fresh.is_valid());
5679a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      }
5680a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      if (left->is_register() && left->reg().is(rax)) {
5681a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        quotient = *left;
5682a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        *left = fresh;
5683a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        left_is_in_rax = true;
5684a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      }
5685a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      if (right->is_register() && right->reg().is(rax)) {
5686a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        quotient = *right;
5687a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        *right = fresh;
5688a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      }
5689a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      __ movq(fresh.reg(), rax);
5690a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    } else {
5691a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // Neither left nor right is in rax.
5692a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      quotient = allocator_->Allocate(rax);
5693a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
5694a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    ASSERT(quotient.is_register() && quotient.reg().is(rax));
5695a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    ASSERT(!(left->is_register() && left->reg().is(rax)));
5696a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    ASSERT(!(right->is_register() && right->reg().is(rax)));
5697a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
5698a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Step 2: get rdx for remainder if necessary.
5699a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (!remainder.is_valid()) {
5700a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      if ((left->is_register() && left->reg().is(rdx)) ||
5701a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block          (right->is_register() && right->reg().is(rdx))) {
5702a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        Result fresh = allocator_->Allocate();
5703a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        ASSERT(fresh.is_valid());
5704a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        if (left->is_register() && left->reg().is(rdx)) {
5705a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block          remainder = *left;
5706a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block          *left = fresh;
5707a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        }
5708a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        if (right->is_register() && right->reg().is(rdx)) {
5709a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block          remainder = *right;
5710a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block          *right = fresh;
5711a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        }
5712a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        __ movq(fresh.reg(), rdx);
5713a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      } else {
5714a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        // Neither left nor right is in rdx.
5715a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        remainder = allocator_->Allocate(rdx);
5716a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      }
5717a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
5718a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    ASSERT(remainder.is_register() && remainder.reg().is(rdx));
5719a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    ASSERT(!(left->is_register() && left->reg().is(rdx)));
5720a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    ASSERT(!(right->is_register() && right->reg().is(rdx)));
5721a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
5722a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    left->ToRegister();
5723a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    right->ToRegister();
5724a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    frame_->Spill(rax);
5725a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    frame_->Spill(rdx);
5726a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
5727a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Check that left and right are smi tagged.
5728a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    DeferredInlineBinaryOperation* deferred =
5729a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        new DeferredInlineBinaryOperation(op,
5730a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                          (op == Token::DIV) ? rax : rdx,
5731a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                          left->reg(),
5732a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                          right->reg(),
5733a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                          overwrite_mode);
5734a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ JumpIfNotBothSmi(left->reg(), right->reg(), deferred->entry_label());
5735a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
5736a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (op == Token::DIV) {
5737a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      __ SmiDiv(rax, left->reg(), right->reg(), deferred->entry_label());
5738a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      deferred->BindExit();
5739a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      left->Unuse();
5740a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      right->Unuse();
5741d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      answer = quotient;
5742a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    } else {
5743a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      ASSERT(op == Token::MOD);
5744a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      __ SmiMod(rdx, left->reg(), right->reg(), deferred->entry_label());
5745a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      deferred->BindExit();
5746a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      left->Unuse();
5747a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      right->Unuse();
5748d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      answer = remainder;
5749a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
5750d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    ASSERT(answer.is_valid());
5751d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    return answer;
5752a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
5753a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
5754a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Special handling of shift operations because they use fixed
5755a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // registers.
5756a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (op == Token::SHL || op == Token::SHR || op == Token::SAR) {
5757a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Move left out of rcx if necessary.
5758a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (left->is_register() && left->reg().is(rcx)) {
5759a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      *left = allocator_->Allocate();
5760a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      ASSERT(left->is_valid());
5761a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      __ movq(left->reg(), rcx);
5762a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
5763a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    right->ToRegister(rcx);
5764a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    left->ToRegister();
5765a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    ASSERT(left->is_register() && !left->reg().is(rcx));
5766a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    ASSERT(right->is_register() && right->reg().is(rcx));
5767a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
5768a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // We will modify right, it must be spilled.
5769a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    frame_->Spill(rcx);
5770a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
5771a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Use a fresh answer register to avoid spilling the left operand.
5772d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    answer = allocator_->Allocate();
5773a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    ASSERT(answer.is_valid());
5774a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Check that both operands are smis using the answer register as a
5775a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // temporary.
5776a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    DeferredInlineBinaryOperation* deferred =
5777a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        new DeferredInlineBinaryOperation(op,
5778a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                          answer.reg(),
5779a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                          left->reg(),
5780a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                          rcx,
5781a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                          overwrite_mode);
5782a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ movq(answer.reg(), left->reg());
5783a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ or_(answer.reg(), rcx);
5784a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ JumpIfNotSmi(answer.reg(), deferred->entry_label());
5785a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
5786a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Perform the operation.
5787a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    switch (op) {
5788a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      case Token::SAR:
5789a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        __ SmiShiftArithmeticRight(answer.reg(), left->reg(), rcx);
5790a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        break;
5791a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      case Token::SHR: {
5792a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        __ SmiShiftLogicalRight(answer.reg(),
5793a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                              left->reg(),
5794a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                              rcx,
5795a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                              deferred->entry_label());
5796a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        break;
5797a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      }
5798a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      case Token::SHL: {
5799a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        __ SmiShiftLeft(answer.reg(),
5800a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                        left->reg(),
5801a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                        rcx,
5802a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                        deferred->entry_label());
5803a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        break;
5804a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      }
5805a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      default:
5806a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        UNREACHABLE();
5807a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
5808a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    deferred->BindExit();
5809a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    left->Unuse();
5810a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    right->Unuse();
5811d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    ASSERT(answer.is_valid());
5812d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    return answer;
5813a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
5814a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
5815a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Handle the other binary operations.
5816a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  left->ToRegister();
5817a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  right->ToRegister();
5818a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // A newly allocated register answer is used to hold the answer.  The
5819a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // registers containing left and right are not modified so they don't
5820a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // need to be spilled in the fast case.
5821d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  answer = allocator_->Allocate();
5822a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(answer.is_valid());
5823a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
5824a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Perform the smi tag check.
5825a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  DeferredInlineBinaryOperation* deferred =
5826a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      new DeferredInlineBinaryOperation(op,
5827a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                        answer.reg(),
5828a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                        left->reg(),
5829a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                        right->reg(),
5830a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                        overwrite_mode);
5831a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ JumpIfNotBothSmi(left->reg(), right->reg(), deferred->entry_label());
5832a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
5833a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  switch (op) {
5834a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    case Token::ADD:
5835a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      __ SmiAdd(answer.reg(),
5836a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                left->reg(),
5837a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                right->reg(),
5838a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                deferred->entry_label());
5839a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      break;
5840a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
5841a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    case Token::SUB:
5842a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      __ SmiSub(answer.reg(),
5843a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                left->reg(),
5844a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                right->reg(),
5845a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                deferred->entry_label());
5846a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      break;
5847a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
5848a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    case Token::MUL: {
5849a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      __ SmiMul(answer.reg(),
5850a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                left->reg(),
5851a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                right->reg(),
5852a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                deferred->entry_label());
5853a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      break;
5854a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
5855a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
5856a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    case Token::BIT_OR:
5857a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      __ SmiOr(answer.reg(), left->reg(), right->reg());
5858a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      break;
5859a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
5860a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    case Token::BIT_AND:
5861a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      __ SmiAnd(answer.reg(), left->reg(), right->reg());
5862a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      break;
5863a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
5864a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    case Token::BIT_XOR:
5865a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      __ SmiXor(answer.reg(), left->reg(), right->reg());
5866a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      break;
5867a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
5868a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    default:
5869a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      UNREACHABLE();
5870a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      break;
5871a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
5872a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  deferred->BindExit();
5873a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  left->Unuse();
5874a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  right->Unuse();
5875d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  ASSERT(answer.is_valid());
5876d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  return answer;
5877d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke}
5878d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke
5879d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke
5880d91b9f7d46489a9ee00f9cb415630299c76a502bLeon ClarkeResult CodeGenerator::EmitKeyedLoad(bool is_global) {
5881d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  Comment cmnt(masm_, "[ Load from keyed Property");
5882d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  // Inline array load code if inside of a loop.  We do not know
5883d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  // the receiver map yet, so we initially generate the code with
5884d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  // a check against an invalid map.  In the inline cache code, we
5885d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  // patch the map check if appropriate.
5886d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  if (loop_nesting() > 0) {
5887d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    Comment cmnt(masm_, "[ Inlined load from keyed Property");
5888d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke
5889d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    Result key = frame_->Pop();
5890d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    Result receiver = frame_->Pop();
5891d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    key.ToRegister();
5892d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    receiver.ToRegister();
5893d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke
5894d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    // Use a fresh temporary to load the elements without destroying
5895d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    // the receiver which is needed for the deferred slow case.
5896d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    Result elements = allocator()->Allocate();
5897d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    ASSERT(elements.is_valid());
5898d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke
5899d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    // Use a fresh temporary for the index and later the loaded
5900d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    // value.
5901d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    Result index = allocator()->Allocate();
5902d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    ASSERT(index.is_valid());
5903d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke
5904d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    DeferredReferenceGetKeyedValue* deferred =
5905d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke        new DeferredReferenceGetKeyedValue(index.reg(),
5906d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke                                           receiver.reg(),
5907d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke                                           key.reg(),
5908d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke                                           is_global);
5909d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke
5910d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    // Check that the receiver is not a smi (only needed if this
5911d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    // is not a load from the global context) and that it has the
5912d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    // expected map.
5913d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    if (!is_global) {
5914d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      __ JumpIfSmi(receiver.reg(), deferred->entry_label());
5915d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    }
5916d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke
5917d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    // Initially, use an invalid map. The map is patched in the IC
5918d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    // initialization code.
5919d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    __ bind(deferred->patch_site());
5920d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    // Use masm-> here instead of the double underscore macro since extra
5921d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    // coverage code can interfere with the patching.  Do not use
5922d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    // root array to load null_value, since it must be patched with
5923d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    // the expected receiver map.
5924d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    masm_->movq(kScratchRegister, Factory::null_value(),
5925d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke                RelocInfo::EMBEDDED_OBJECT);
5926d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    masm_->cmpq(FieldOperand(receiver.reg(), HeapObject::kMapOffset),
5927d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke                kScratchRegister);
5928d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    deferred->Branch(not_equal);
5929d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke
5930d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    // Check that the key is a non-negative smi.
5931d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    __ JumpIfNotPositiveSmi(key.reg(), deferred->entry_label());
5932d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke
5933d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    // Get the elements array from the receiver and check that it
5934d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    // is not a dictionary.
5935d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    __ movq(elements.reg(),
5936d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke            FieldOperand(receiver.reg(), JSObject::kElementsOffset));
5937d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    __ Cmp(FieldOperand(elements.reg(), HeapObject::kMapOffset),
5938d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke           Factory::fixed_array_map());
5939d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    deferred->Branch(not_equal);
5940d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke
5941d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    // Shift the key to get the actual index value and check that
5942d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    // it is within bounds.
5943d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    __ SmiToInteger32(index.reg(), key.reg());
5944d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    __ cmpl(index.reg(),
5945d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke            FieldOperand(elements.reg(), FixedArray::kLengthOffset));
5946d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    deferred->Branch(above_equal);
5947d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke
5948d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    // The index register holds the un-smi-tagged key. It has been
5949d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    // zero-extended to 64-bits, so it can be used directly as index in the
5950d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    // operand below.
5951d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    // Load and check that the result is not the hole.  We could
5952d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    // reuse the index or elements register for the value.
5953d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    //
5954d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    // TODO(206): Consider whether it makes sense to try some
5955d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    // heuristic about which register to reuse.  For example, if
5956d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    // one is rax, the we can reuse that one because the value
5957d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    // coming from the deferred code will be in rax.
5958d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    Result value = index;
5959d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    __ movq(value.reg(),
5960d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke            Operand(elements.reg(),
5961d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke                    index.reg(),
5962d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke                    times_pointer_size,
5963d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke                    FixedArray::kHeaderSize - kHeapObjectTag));
5964d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    elements.Unuse();
5965d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    index.Unuse();
5966d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    __ CompareRoot(value.reg(), Heap::kTheHoleValueRootIndex);
5967d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    deferred->Branch(equal);
5968d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    __ IncrementCounter(&Counters::keyed_load_inline, 1);
5969d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke
5970d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    deferred->BindExit();
5971d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    // Restore the receiver and key to the frame and push the
5972d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    // result on top of it.
5973d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    frame_->Push(&receiver);
5974d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    frame_->Push(&key);
5975d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    return value;
5976d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke
5977d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  } else {
5978d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    Comment cmnt(masm_, "[ Load from keyed Property");
5979d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    RelocInfo::Mode mode = is_global
5980d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke        ? RelocInfo::CODE_TARGET_CONTEXT
5981d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke        : RelocInfo::CODE_TARGET;
5982d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    Result answer = frame_->CallKeyedLoadIC(mode);
5983d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    // Make sure that we do not have a test instruction after the
5984d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    // call.  A test instruction after the call is used to
5985d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    // indicate that we have generated an inline version of the
5986d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    // keyed load.  The explicit nop instruction is here because
5987d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    // the push that follows might be peep-hole optimized away.
5988d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    __ nop();
5989d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    return answer;
5990d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  }
5991a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
5992a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
5993a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
5994a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#undef __
5995a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#define __ ACCESS_MASM(masm)
5996a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
5997a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
5998a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockHandle<String> Reference::GetName() {
5999a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(type_ == NAMED);
6000a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Property* property = expression_->AsProperty();
6001a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (property == NULL) {
6002a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Global variable reference treated as a named property reference.
6003a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    VariableProxy* proxy = expression_->AsVariableProxy();
6004a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    ASSERT(proxy->AsVariable() != NULL);
6005a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    ASSERT(proxy->AsVariable()->is_global());
6006a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    return proxy->name();
6007a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  } else {
6008a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    Literal* raw_name = property->key()->AsLiteral();
6009a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    ASSERT(raw_name != NULL);
6010a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    return Handle<String>(String::cast(*raw_name->handle()));
6011a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
6012a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
6013a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
6014a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
6015d0582a6c46733687d045e4188a1bcd0123c758a1Steve Blockvoid Reference::GetValue() {
6016a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(!cgen_->in_spilled_code());
6017a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(cgen_->HasValidEntryRegisters());
6018a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(!is_illegal());
6019a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  MacroAssembler* masm = cgen_->masm();
6020a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
6021a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Record the source position for the property load.
6022a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Property* property = expression_->AsProperty();
6023a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (property != NULL) {
6024a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    cgen_->CodeForSourcePosition(property->position());
6025a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
6026a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
6027a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  switch (type_) {
6028a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    case SLOT: {
6029a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      Comment cmnt(masm, "[ Load from Slot");
6030a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      Slot* slot = expression_->AsVariableProxy()->AsVariable()->slot();
6031a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      ASSERT(slot != NULL);
6032d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block      cgen_->LoadFromSlotCheckForArguments(slot, NOT_INSIDE_TYPEOF);
6033a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      break;
6034a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
6035a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
6036a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    case NAMED: {
6037a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      Variable* var = expression_->AsVariableProxy()->AsVariable();
6038a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      bool is_global = var != NULL;
6039a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      ASSERT(!is_global || var->is_global());
6040a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
6041a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // Do not inline the inobject property case for loads from the global
6042a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // object.  Also do not inline for unoptimized code.  This saves time
6043a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // in the code generator.  Unoptimized code is toplevel code or code
6044a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // that is not in a loop.
6045a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      if (is_global ||
6046a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block          cgen_->scope()->is_global_scope() ||
6047a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block          cgen_->loop_nesting() == 0) {
6048a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        Comment cmnt(masm, "[ Load from named Property");
6049a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        cgen_->frame()->Push(GetName());
6050a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
6051a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        RelocInfo::Mode mode = is_global
6052a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                               ? RelocInfo::CODE_TARGET_CONTEXT
6053a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                               : RelocInfo::CODE_TARGET;
6054a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        Result answer = cgen_->frame()->CallLoadIC(mode);
6055a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        // A test rax instruction following the call signals that the
6056a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        // inobject property case was inlined.  Ensure that there is not
6057a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        // a test rax instruction here.
6058a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        __ nop();
6059a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        cgen_->frame()->Push(&answer);
6060a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      } else {
6061a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        // Inline the inobject property case.
6062a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        Comment cmnt(masm, "[ Inlined named property load");
6063a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        Result receiver = cgen_->frame()->Pop();
6064a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        receiver.ToRegister();
6065a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        Result value = cgen_->allocator()->Allocate();
6066a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        ASSERT(value.is_valid());
6067a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        // Cannot use r12 for receiver, because that changes
6068a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        // the distance between a call and a fixup location,
6069a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        // due to a special encoding of r12 as r/m in a ModR/M byte.
6070a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        if (receiver.reg().is(r12)) {
6071a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block          // Swap receiver and value.
6072a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block          __ movq(value.reg(), receiver.reg());
6073a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block          Result temp = receiver;
6074a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block          receiver = value;
6075a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block          value = temp;
6076a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block          cgen_->frame()->Spill(value.reg());  // r12 may have been shared.
6077a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        }
6078a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
6079a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        DeferredReferenceGetNamedValue* deferred =
6080a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block            new DeferredReferenceGetNamedValue(value.reg(),
6081a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                               receiver.reg(),
6082a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                               GetName());
6083a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
6084a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        // Check that the receiver is a heap object.
6085a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        __ JumpIfSmi(receiver.reg(), deferred->entry_label());
6086a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
6087a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        __ bind(deferred->patch_site());
6088a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        // This is the map check instruction that will be patched (so we can't
6089a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        // use the double underscore macro that may insert instructions).
6090a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        // Initially use an invalid map to force a failure.
6091a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        masm->Move(kScratchRegister, Factory::null_value());
6092a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        masm->cmpq(FieldOperand(receiver.reg(), HeapObject::kMapOffset),
6093a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                   kScratchRegister);
6094a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        // This branch is always a forwards branch so it's always a fixed
6095a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        // size which allows the assert below to succeed and patching to work.
6096a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        // Don't use deferred->Branch(...), since that might add coverage code.
6097a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        masm->j(not_equal, deferred->entry_label());
6098a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
6099a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        // The delta from the patch label to the load offset must be
6100a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        // statically known.
6101a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        ASSERT(masm->SizeOfCodeGeneratedSince(deferred->patch_site()) ==
6102a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block               LoadIC::kOffsetToLoadInstruction);
6103a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        // The initial (invalid) offset has to be large enough to force
6104a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        // a 32-bit instruction encoding to allow patching with an
6105a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        // arbitrary offset.  Use kMaxInt (minus kHeapObjectTag).
6106a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        int offset = kMaxInt;
6107a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        masm->movq(value.reg(), FieldOperand(receiver.reg(), offset));
6108a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
6109a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        __ IncrementCounter(&Counters::named_load_inline, 1);
6110a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        deferred->BindExit();
6111a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        cgen_->frame()->Push(&receiver);
6112a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        cgen_->frame()->Push(&value);
6113a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      }
6114a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      break;
6115a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
6116a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
6117a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    case KEYED: {
6118a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      Comment cmnt(masm, "[ Load from keyed Property");
6119a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      Variable* var = expression_->AsVariableProxy()->AsVariable();
6120a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      bool is_global = var != NULL;
6121a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      ASSERT(!is_global || var->is_global());
6122a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
6123d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      Result value = cgen_->EmitKeyedLoad(is_global);
6124d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      cgen_->frame()->Push(&value);
6125a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      break;
6126a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
6127a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
6128a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    default:
6129a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      UNREACHABLE();
6130a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
6131d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke
6132d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  if (!persist_after_get_) {
6133d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    cgen_->UnloadReference(this);
6134d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  }
6135a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
6136a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
6137a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
6138d0582a6c46733687d045e4188a1bcd0123c758a1Steve Blockvoid Reference::TakeValue() {
6139a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // TODO(X64): This function is completely architecture independent. Move
6140a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // it somewhere shared.
6141a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
6142a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // For non-constant frame-allocated slots, we invalidate the value in the
6143a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // slot.  For all others, we fall back on GetValue.
6144a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(!cgen_->in_spilled_code());
6145a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(!is_illegal());
6146a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (type_ != SLOT) {
6147d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    GetValue();
6148a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    return;
6149a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
6150a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
6151a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Slot* slot = expression_->AsVariableProxy()->AsVariable()->slot();
6152a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(slot != NULL);
6153a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (slot->type() == Slot::LOOKUP ||
6154a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      slot->type() == Slot::CONTEXT ||
6155a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      slot->var()->mode() == Variable::CONST ||
6156a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      slot->is_arguments()) {
6157d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    GetValue();
6158a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    return;
6159a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
6160a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
6161a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Only non-constant, frame-allocated parameters and locals can reach
6162a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // here.  Be careful not to use the optimizations for arguments
6163a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // object access since it may not have been initialized yet.
6164a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(!slot->is_arguments());
6165a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (slot->type() == Slot::PARAMETER) {
6166a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    cgen_->frame()->TakeParameterAt(slot->index());
6167a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  } else {
6168a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    ASSERT(slot->type() == Slot::LOCAL);
6169a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    cgen_->frame()->TakeLocalAt(slot->index());
6170a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
6171d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke
6172d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  ASSERT(persist_after_get_);
6173d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  // Do not unload the reference, because it is used in SetValue.
6174a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
6175a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
6176a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
6177a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid Reference::SetValue(InitState init_state) {
6178a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(cgen_->HasValidEntryRegisters());
6179a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(!is_illegal());
6180a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  MacroAssembler* masm = cgen_->masm();
6181a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  switch (type_) {
6182a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    case SLOT: {
6183a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      Comment cmnt(masm, "[ Store to Slot");
6184a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      Slot* slot = expression_->AsVariableProxy()->AsVariable()->slot();
6185a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      ASSERT(slot != NULL);
6186a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      cgen_->StoreToSlot(slot, init_state);
61874515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke      cgen_->UnloadReference(this);
6188a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      break;
6189a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
6190a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
6191a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    case NAMED: {
6192a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      Comment cmnt(masm, "[ Store to named Property");
6193a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      cgen_->frame()->Push(GetName());
6194a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      Result answer = cgen_->frame()->CallStoreIC();
6195a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      cgen_->frame()->Push(&answer);
61964515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke      set_unloaded();
6197a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      break;
6198a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
6199a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
6200a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    case KEYED: {
6201a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      Comment cmnt(masm, "[ Store to keyed Property");
6202a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
6203a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // Generate inlined version of the keyed store if the code is in
6204a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // a loop and the key is likely to be a smi.
6205a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      Property* property = expression()->AsProperty();
6206a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      ASSERT(property != NULL);
6207e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke      StaticType* key_smi_analysis = property->key()->type();
6208a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
6209a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      if (cgen_->loop_nesting() > 0 && key_smi_analysis->IsLikelySmi()) {
6210a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        Comment cmnt(masm, "[ Inlined store to keyed Property");
6211a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
6212a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        // Get the receiver, key and value into registers.
6213a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        Result value = cgen_->frame()->Pop();
6214a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        Result key = cgen_->frame()->Pop();
6215a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        Result receiver = cgen_->frame()->Pop();
6216a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
6217a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        Result tmp = cgen_->allocator_->Allocate();
6218a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        ASSERT(tmp.is_valid());
6219a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
6220a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        // Determine whether the value is a constant before putting it
6221a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        // in a register.
6222a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        bool value_is_constant = value.is_constant();
6223a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
6224a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        // Make sure that value, key and receiver are in registers.
6225a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        value.ToRegister();
6226a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        key.ToRegister();
6227a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        receiver.ToRegister();
6228a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
6229a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        DeferredReferenceSetKeyedValue* deferred =
6230a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block            new DeferredReferenceSetKeyedValue(value.reg(),
6231a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                               key.reg(),
6232a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                               receiver.reg());
6233a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
6234a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        // Check that the value is a smi if it is not a constant.
6235a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        // We can skip the write barrier for smis and constants.
6236a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        if (!value_is_constant) {
6237a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block          __ JumpIfNotSmi(value.reg(), deferred->entry_label());
6238a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        }
6239a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
6240a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        // Check that the key is a non-negative smi.
6241a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        __ JumpIfNotPositiveSmi(key.reg(), deferred->entry_label());
6242a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
6243a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        // Check that the receiver is not a smi.
6244a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        __ JumpIfSmi(receiver.reg(), deferred->entry_label());
6245a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
6246a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        // Check that the receiver is a JSArray.
6247a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        __ CmpObjectType(receiver.reg(), JS_ARRAY_TYPE, kScratchRegister);
6248a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        deferred->Branch(not_equal);
6249a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
6250a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        // Check that the key is within bounds.  Both the key and the
62513ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block        // length of the JSArray are smis.
62523ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block        __ SmiCompare(FieldOperand(receiver.reg(), JSArray::kLengthOffset),
62533ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block                      key.reg());
62543ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block        deferred->Branch(less_equal);
6255a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
6256a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        // Get the elements array from the receiver and check that it
6257a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        // is a flat array (not a dictionary).
6258a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        __ movq(tmp.reg(),
6259a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                FieldOperand(receiver.reg(), JSObject::kElementsOffset));
6260a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        // Bind the deferred code patch site to be able to locate the
6261a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        // fixed array map comparison.  When debugging, we patch this
6262a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        // comparison to always fail so that we will hit the IC call
6263a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        // in the deferred code which will allow the debugger to
6264a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        // break for fast case stores.
6265a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        __ bind(deferred->patch_site());
6266a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        // Avoid using __ to ensure the distance from patch_site
6267a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        // to the map address is always the same.
6268a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        masm->movq(kScratchRegister, Factory::fixed_array_map(),
6269a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                   RelocInfo::EMBEDDED_OBJECT);
6270a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        __ cmpq(FieldOperand(tmp.reg(), HeapObject::kMapOffset),
6271a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                kScratchRegister);
6272a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        deferred->Branch(not_equal);
6273a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
6274a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        // Store the value.
6275a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        SmiIndex index =
6276a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block            masm->SmiToIndex(kScratchRegister, key.reg(), kPointerSizeLog2);
6277a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block              __ movq(Operand(tmp.reg(),
6278a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                        index.reg,
6279a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                        index.scale,
6280a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                        FixedArray::kHeaderSize - kHeapObjectTag),
6281a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                value.reg());
6282a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        __ IncrementCounter(&Counters::keyed_store_inline, 1);
6283a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
6284a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        deferred->BindExit();
6285a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
6286a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        cgen_->frame()->Push(&receiver);
6287a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        cgen_->frame()->Push(&key);
6288a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        cgen_->frame()->Push(&value);
6289a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      } else {
6290a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        Result answer = cgen_->frame()->CallKeyedStoreIC();
6291a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        // Make sure that we do not have a test instruction after the
6292a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        // call.  A test instruction after the call is used to
6293a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        // indicate that we have generated an inline version of the
6294a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        // keyed store.
6295a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        masm->nop();
6296a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        cgen_->frame()->Push(&answer);
6297a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      }
62984515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke      cgen_->UnloadReference(this);
6299a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      break;
6300a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
6301a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
6302a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    default:
6303a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      UNREACHABLE();
6304a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
6305a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
6306a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
6307a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
6308e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarkevoid FastNewClosureStub::Generate(MacroAssembler* masm) {
6309e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // Clone the boilerplate in new space. Set the context to the
6310e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // current context in rsi.
6311e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  Label gc;
6312e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ AllocateInNewSpace(JSFunction::kSize, rax, rbx, rcx, &gc, TAG_OBJECT);
6313e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
6314e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // Get the boilerplate function from the stack.
6315e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ movq(rdx, Operand(rsp, 1 * kPointerSize));
6316e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
6317e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // Compute the function map in the current global context and set that
6318e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // as the map of the allocated object.
6319e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ movq(rcx, Operand(rsi, Context::SlotOffset(Context::GLOBAL_INDEX)));
6320e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ movq(rcx, FieldOperand(rcx, GlobalObject::kGlobalContextOffset));
6321e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ movq(rcx, Operand(rcx, Context::SlotOffset(Context::FUNCTION_MAP_INDEX)));
6322e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ movq(FieldOperand(rax, JSObject::kMapOffset), rcx);
6323e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
6324e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // Clone the rest of the boilerplate fields. We don't have to update
6325e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // the write barrier because the allocated object is in new space.
6326e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  for (int offset = kPointerSize;
6327e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke       offset < JSFunction::kSize;
6328e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke       offset += kPointerSize) {
6329e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke    if (offset == JSFunction::kContextOffset) {
6330e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke      __ movq(FieldOperand(rax, offset), rsi);
6331e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke    } else {
6332e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke      __ movq(rbx, FieldOperand(rdx, offset));
6333e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke      __ movq(FieldOperand(rax, offset), rbx);
6334e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke    }
6335e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  }
6336e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
6337e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // Return and remove the on-stack parameter.
6338e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ ret(1 * kPointerSize);
6339e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
6340e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // Create a new closure through the slower runtime call.
6341e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ bind(&gc);
6342e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ pop(rcx);  // Temporarily remove return address.
6343e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ pop(rdx);
6344e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ push(rsi);
6345e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ push(rdx);
6346e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ push(rcx);  // Restore return address.
6347e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ TailCallRuntime(ExternalReference(Runtime::kNewClosure), 2, 1);
6348e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke}
6349e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
6350e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
6351e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarkevoid FastNewContextStub::Generate(MacroAssembler* masm) {
6352e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // Try to allocate the context in new space.
6353e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  Label gc;
6354e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  int length = slots_ + Context::MIN_CONTEXT_SLOTS;
6355e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ AllocateInNewSpace((length * kPointerSize) + FixedArray::kHeaderSize,
6356e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke                        rax, rbx, rcx, &gc, TAG_OBJECT);
6357e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
6358e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // Get the function from the stack.
6359e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ movq(rcx, Operand(rsp, 1 * kPointerSize));
6360e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
6361e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // Setup the object header.
6362e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ LoadRoot(kScratchRegister, Heap::kContextMapRootIndex);
6363e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ movq(FieldOperand(rax, HeapObject::kMapOffset), kScratchRegister);
6364e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ movl(FieldOperand(rax, Array::kLengthOffset), Immediate(length));
6365e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
6366e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // Setup the fixed slots.
6367e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ xor_(rbx, rbx);  // Set to NULL.
6368e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ movq(Operand(rax, Context::SlotOffset(Context::CLOSURE_INDEX)), rcx);
6369e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ movq(Operand(rax, Context::SlotOffset(Context::FCONTEXT_INDEX)), rax);
6370e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ movq(Operand(rax, Context::SlotOffset(Context::PREVIOUS_INDEX)), rbx);
6371e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ movq(Operand(rax, Context::SlotOffset(Context::EXTENSION_INDEX)), rbx);
6372e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
6373e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // Copy the global object from the surrounding context.
6374e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ movq(rbx, Operand(rsi, Context::SlotOffset(Context::GLOBAL_INDEX)));
6375e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ movq(Operand(rax, Context::SlotOffset(Context::GLOBAL_INDEX)), rbx);
6376e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
6377e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // Initialize the rest of the slots to undefined.
6378e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ LoadRoot(rbx, Heap::kUndefinedValueRootIndex);
6379e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  for (int i = Context::MIN_CONTEXT_SLOTS; i < length; i++) {
6380e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke    __ movq(Operand(rax, Context::SlotOffset(i)), rbx);
6381e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  }
6382e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
6383e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // Return and remove the on-stack parameter.
6384e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ movq(rsi, rax);
6385e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ ret(1 * kPointerSize);
6386e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
6387e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // Need to collect. Call into runtime system.
6388e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ bind(&gc);
6389e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ TailCallRuntime(ExternalReference(Runtime::kNewContext), 1, 1);
6390e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke}
6391e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
6392e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
6393402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescuvoid FastCloneShallowArrayStub::Generate(MacroAssembler* masm) {
6394402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // Stack layout on entry:
6395402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  //
6396402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // [rsp + kPointerSize]: constant elements.
6397402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // [rsp + (2 * kPointerSize)]: literal index.
6398402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // [rsp + (3 * kPointerSize)]: literals array.
6399402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu
6400402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // All sizes here are multiples of kPointerSize.
6401402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  int elements_size = (length_ > 0) ? FixedArray::SizeFor(length_) : 0;
6402402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  int size = JSArray::kSize + elements_size;
6403402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu
6404402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // Load boilerplate object into rcx and check if we need to create a
6405402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // boilerplate.
6406402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  Label slow_case;
6407402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ movq(rcx, Operand(rsp, 3 * kPointerSize));
6408402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ movq(rax, Operand(rsp, 2 * kPointerSize));
6409402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  SmiIndex index = masm->SmiToIndex(rax, rax, kPointerSizeLog2);
6410402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ movq(rcx,
6411402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu          FieldOperand(rcx, index.reg, index.scale, FixedArray::kHeaderSize));
6412402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ CompareRoot(rcx, Heap::kUndefinedValueRootIndex);
6413402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ j(equal, &slow_case);
6414402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu
6415402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // Allocate both the JS array and the elements array in one big
6416402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // allocation. This avoids multiple limit checks.
6417402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ AllocateInNewSpace(size, rax, rbx, rdx, &slow_case, TAG_OBJECT);
6418402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu
6419402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // Copy the JS array part.
6420402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  for (int i = 0; i < JSArray::kSize; i += kPointerSize) {
6421402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    if ((i != JSArray::kElementsOffset) || (length_ == 0)) {
6422402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu      __ movq(rbx, FieldOperand(rcx, i));
6423402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu      __ movq(FieldOperand(rax, i), rbx);
6424402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    }
6425402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  }
6426402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu
6427402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  if (length_ > 0) {
6428402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    // Get hold of the elements array of the boilerplate and setup the
6429402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    // elements pointer in the resulting object.
6430402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    __ movq(rcx, FieldOperand(rcx, JSArray::kElementsOffset));
6431402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    __ lea(rdx, Operand(rax, JSArray::kSize));
6432402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    __ movq(FieldOperand(rax, JSArray::kElementsOffset), rdx);
6433402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu
6434402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    // Copy the elements array.
6435402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    for (int i = 0; i < elements_size; i += kPointerSize) {
6436402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu      __ movq(rbx, FieldOperand(rcx, i));
6437402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu      __ movq(FieldOperand(rdx, i), rbx);
6438402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    }
6439402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  }
6440402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu
6441402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // Return and remove the on-stack parameters.
6442402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ ret(3 * kPointerSize);
6443402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu
6444402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ bind(&slow_case);
6445402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  ExternalReference runtime(Runtime::kCreateArrayLiteralShallow);
6446402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ TailCallRuntime(runtime, 3, 1);
6447402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu}
6448402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu
6449402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu
6450a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid ToBooleanStub::Generate(MacroAssembler* masm) {
6451a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Label false_result, true_result, not_string;
6452a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ movq(rax, Operand(rsp, 1 * kPointerSize));
6453a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
6454a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // 'null' => false.
6455a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ CompareRoot(rax, Heap::kNullValueRootIndex);
6456a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(equal, &false_result);
6457a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
6458a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Get the map and type of the heap object.
6459a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // We don't use CmpObjectType because we manipulate the type field.
6460a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ movq(rdx, FieldOperand(rax, HeapObject::kMapOffset));
6461a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ movzxbq(rcx, FieldOperand(rdx, Map::kInstanceTypeOffset));
6462a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
6463a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Undetectable => false.
6464a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ movzxbq(rbx, FieldOperand(rdx, Map::kBitFieldOffset));
6465a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ and_(rbx, Immediate(1 << Map::kIsUndetectable));
6466a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(not_zero, &false_result);
6467a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
6468a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // JavaScript object => true.
6469a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ cmpq(rcx, Immediate(FIRST_JS_OBJECT_TYPE));
6470a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(above_equal, &true_result);
6471a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
6472a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // String value => false iff empty.
6473a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ cmpq(rcx, Immediate(FIRST_NONSTRING_TYPE));
6474a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(above_equal, &not_string);
6475a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ movl(rdx, FieldOperand(rax, String::kLengthOffset));
6476d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  __ testl(rdx, rdx);
6477a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(zero, &false_result);
6478a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ jmp(&true_result);
6479a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
6480a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&not_string);
6481a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // HeapNumber => false iff +0, -0, or NaN.
6482a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // These three cases set C3 when compared to zero in the FPU.
6483a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ CompareRoot(rdx, Heap::kHeapNumberMapRootIndex);
6484a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(not_equal, &true_result);
6485a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ fldz();  // Load zero onto fp stack
6486a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Load heap-number double value onto fp stack
6487a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ fld_d(FieldOperand(rax, HeapNumber::kValueOffset));
64883ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  __ FCmp();
64893ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  __ j(zero, &false_result);
6490a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Fall through to |true_result|.
6491a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
6492a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Return 1/0 for true/false in rax.
6493a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&true_result);
6494a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ movq(rax, Immediate(1));
6495a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ ret(1 * kPointerSize);
6496a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&false_result);
6497a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ xor_(rax, rax);
6498a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ ret(1 * kPointerSize);
6499a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
6500a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
6501a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
6502a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockbool CodeGenerator::FoldConstantSmis(Token::Value op, int left, int right) {
6503a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Object* answer_object = Heap::undefined_value();
6504a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  switch (op) {
6505a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    case Token::ADD:
6506d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      // Use intptr_t to detect overflow of 32-bit int.
6507d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      if (Smi::IsValid(static_cast<intptr_t>(left) + right)) {
6508a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        answer_object = Smi::FromInt(left + right);
6509a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      }
6510a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      break;
6511a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    case Token::SUB:
6512d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      // Use intptr_t to detect overflow of 32-bit int.
6513d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      if (Smi::IsValid(static_cast<intptr_t>(left) - right)) {
6514a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        answer_object = Smi::FromInt(left - right);
6515a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      }
6516a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      break;
6517a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    case Token::MUL: {
6518a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        double answer = static_cast<double>(left) * right;
6519a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        if (answer >= Smi::kMinValue && answer <= Smi::kMaxValue) {
6520a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block          // If the product is zero and the non-zero factor is negative,
6521a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block          // the spec requires us to return floating point negative zero.
6522a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block          if (answer != 0 || (left + right) >= 0) {
6523a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block            answer_object = Smi::FromInt(static_cast<int>(answer));
6524a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block          }
6525a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        }
6526a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      }
6527a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      break;
6528a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    case Token::DIV:
6529a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    case Token::MOD:
6530a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      break;
6531a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    case Token::BIT_OR:
6532a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      answer_object = Smi::FromInt(left | right);
6533a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      break;
6534a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    case Token::BIT_AND:
6535a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      answer_object = Smi::FromInt(left & right);
6536a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      break;
6537a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    case Token::BIT_XOR:
6538a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      answer_object = Smi::FromInt(left ^ right);
6539a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      break;
6540a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
6541a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    case Token::SHL: {
6542a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        int shift_amount = right & 0x1F;
6543a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        if (Smi::IsValid(left << shift_amount)) {
6544a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block          answer_object = Smi::FromInt(left << shift_amount);
6545a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        }
6546a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        break;
6547a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      }
6548a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    case Token::SHR: {
6549a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        int shift_amount = right & 0x1F;
6550a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        unsigned int unsigned_left = left;
6551a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        unsigned_left >>= shift_amount;
6552a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        if (unsigned_left <= static_cast<unsigned int>(Smi::kMaxValue)) {
6553a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block          answer_object = Smi::FromInt(unsigned_left);
6554a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        }
6555a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        break;
6556a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      }
6557a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    case Token::SAR: {
6558a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        int shift_amount = right & 0x1F;
6559a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        unsigned int unsigned_left = left;
6560a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        if (left < 0) {
6561a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block          // Perform arithmetic shift of a negative number by
6562a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block          // complementing number, logical shifting, complementing again.
6563a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block          unsigned_left = ~unsigned_left;
6564a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block          unsigned_left >>= shift_amount;
6565a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block          unsigned_left = ~unsigned_left;
6566a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        } else {
6567a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block          unsigned_left >>= shift_amount;
6568a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        }
6569a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        ASSERT(Smi::IsValid(static_cast<int32_t>(unsigned_left)));
6570a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        answer_object = Smi::FromInt(static_cast<int32_t>(unsigned_left));
6571a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        break;
6572a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      }
6573a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    default:
6574a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      UNREACHABLE();
6575a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      break;
6576a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
6577a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (answer_object == Heap::undefined_value()) {
6578a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    return false;
6579a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
6580a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  frame_->Push(Handle<Object>(answer_object));
6581a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  return true;
6582a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
6583a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
6584a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
6585a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// End of CodeGenerator implementation.
6586a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
6587d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke// Get the integer part of a heap number.  Surprisingly, all this bit twiddling
6588d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke// is faster than using the built-in instructions on floating point registers.
6589d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke// Trashes rdi and rbx.  Dest is rcx.  Source cannot be rcx or one of the
6590d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke// trashed registers.
6591d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarkevoid IntegerConvert(MacroAssembler* masm,
6592d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke                    Register source,
6593d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke                    bool use_sse3,
6594d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke                    Label* conversion_failure) {
6595d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  ASSERT(!source.is(rcx) && !source.is(rdi) && !source.is(rbx));
6596d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  Label done, right_exponent, normal_exponent;
6597d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  Register scratch = rbx;
6598d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  Register scratch2 = rdi;
6599d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  // Get exponent word.
6600d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  __ movl(scratch, FieldOperand(source, HeapNumber::kExponentOffset));
6601d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  // Get exponent alone in scratch2.
6602d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  __ movl(scratch2, scratch);
6603d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  __ and_(scratch2, Immediate(HeapNumber::kExponentMask));
6604d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  if (use_sse3) {
6605d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    CpuFeatures::Scope scope(SSE3);
6606d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    // Check whether the exponent is too big for a 64 bit signed integer.
6607d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    static const uint32_t kTooBigExponent =
6608d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke        (HeapNumber::kExponentBias + 63) << HeapNumber::kExponentShift;
6609d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    __ cmpl(scratch2, Immediate(kTooBigExponent));
6610d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    __ j(greater_equal, conversion_failure);
6611d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    // Load x87 register with heap number.
6612d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    __ fld_d(FieldOperand(source, HeapNumber::kValueOffset));
6613d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    // Reserve space for 64 bit answer.
6614d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    __ subq(rsp, Immediate(sizeof(uint64_t)));  // Nolint.
6615d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    // Do conversion, which cannot fail because we checked the exponent.
6616d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    __ fisttp_d(Operand(rsp, 0));
6617d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    __ movl(rcx, Operand(rsp, 0));  // Load low word of answer into rcx.
6618d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    __ addq(rsp, Immediate(sizeof(uint64_t)));  // Nolint.
6619d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  } else {
6620d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    // Load rcx with zero.  We use this either for the final shift or
6621d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    // for the answer.
6622d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    __ xor_(rcx, rcx);
6623d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    // Check whether the exponent matches a 32 bit signed int that cannot be
6624d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    // represented by a Smi.  A non-smi 32 bit integer is 1.xxx * 2^30 so the
6625d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    // exponent is 30 (biased).  This is the exponent that we are fastest at and
6626d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    // also the highest exponent we can handle here.
6627d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    const uint32_t non_smi_exponent =
6628d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke        (HeapNumber::kExponentBias + 30) << HeapNumber::kExponentShift;
6629d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    __ cmpl(scratch2, Immediate(non_smi_exponent));
6630d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    // If we have a match of the int32-but-not-Smi exponent then skip some
6631d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    // logic.
6632d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    __ j(equal, &right_exponent);
6633d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    // If the exponent is higher than that then go to slow case.  This catches
6634d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    // numbers that don't fit in a signed int32, infinities and NaNs.
6635d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    __ j(less, &normal_exponent);
6636d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke
6637d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    {
6638d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      // Handle a big exponent.  The only reason we have this code is that the
6639d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      // >>> operator has a tendency to generate numbers with an exponent of 31.
6640d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      const uint32_t big_non_smi_exponent =
6641d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke          (HeapNumber::kExponentBias + 31) << HeapNumber::kExponentShift;
6642d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      __ cmpl(scratch2, Immediate(big_non_smi_exponent));
6643d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      __ j(not_equal, conversion_failure);
6644d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      // We have the big exponent, typically from >>>.  This means the number is
6645d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      // in the range 2^31 to 2^32 - 1.  Get the top bits of the mantissa.
6646d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      __ movl(scratch2, scratch);
6647d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      __ and_(scratch2, Immediate(HeapNumber::kMantissaMask));
6648d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      // Put back the implicit 1.
6649d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      __ or_(scratch2, Immediate(1 << HeapNumber::kExponentShift));
6650d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      // Shift up the mantissa bits to take up the space the exponent used to
6651d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      // take. We just orred in the implicit bit so that took care of one and
6652d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      // we want to use the full unsigned range so we subtract 1 bit from the
6653d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      // shift distance.
6654d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      const int big_shift_distance = HeapNumber::kNonMantissaBitsInTopWord - 1;
6655d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      __ shl(scratch2, Immediate(big_shift_distance));
6656d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      // Get the second half of the double.
6657d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      __ movl(rcx, FieldOperand(source, HeapNumber::kMantissaOffset));
6658d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      // Shift down 21 bits to get the most significant 11 bits or the low
6659d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      // mantissa word.
6660d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      __ shr(rcx, Immediate(32 - big_shift_distance));
6661d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      __ or_(rcx, scratch2);
6662d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      // We have the answer in rcx, but we may need to negate it.
6663d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      __ testl(scratch, scratch);
6664d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      __ j(positive, &done);
6665d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      __ neg(rcx);
6666d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      __ jmp(&done);
6667d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    }
6668d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke
6669d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    __ bind(&normal_exponent);
6670d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    // Exponent word in scratch, exponent part of exponent word in scratch2.
6671d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    // Zero in rcx.
6672d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    // We know the exponent is smaller than 30 (biased).  If it is less than
6673d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    // 0 (biased) then the number is smaller in magnitude than 1.0 * 2^0, ie
6674d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    // it rounds to zero.
6675d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    const uint32_t zero_exponent =
6676d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke        (HeapNumber::kExponentBias + 0) << HeapNumber::kExponentShift;
6677d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    __ subl(scratch2, Immediate(zero_exponent));
6678d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    // rcx already has a Smi zero.
6679d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    __ j(less, &done);
6680d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke
6681d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    // We have a shifted exponent between 0 and 30 in scratch2.
6682d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    __ shr(scratch2, Immediate(HeapNumber::kExponentShift));
6683d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    __ movl(rcx, Immediate(30));
6684d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    __ subl(rcx, scratch2);
6685d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke
6686d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    __ bind(&right_exponent);
6687d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    // Here rcx is the shift, scratch is the exponent word.
6688d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    // Get the top bits of the mantissa.
6689d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    __ and_(scratch, Immediate(HeapNumber::kMantissaMask));
6690d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    // Put back the implicit 1.
6691d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    __ or_(scratch, Immediate(1 << HeapNumber::kExponentShift));
6692d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    // Shift up the mantissa bits to take up the space the exponent used to
6693d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    // take. We have kExponentShift + 1 significant bits int he low end of the
6694d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    // word.  Shift them to the top bits.
6695d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    const int shift_distance = HeapNumber::kNonMantissaBitsInTopWord - 2;
6696d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    __ shl(scratch, Immediate(shift_distance));
6697d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    // Get the second half of the double. For some exponents we don't
6698d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    // actually need this because the bits get shifted out again, but
6699d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    // it's probably slower to test than just to do it.
6700d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    __ movl(scratch2, FieldOperand(source, HeapNumber::kMantissaOffset));
6701d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    // Shift down 22 bits to get the most significant 10 bits or the low
6702d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    // mantissa word.
6703d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    __ shr(scratch2, Immediate(32 - shift_distance));
6704d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    __ or_(scratch2, scratch);
6705d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    // Move down according to the exponent.
6706d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    __ shr_cl(scratch2);
6707d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    // Now the unsigned answer is in scratch2.  We need to move it to rcx and
6708d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    // we may need to fix the sign.
6709d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    Label negative;
6710d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    __ xor_(rcx, rcx);
6711d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    __ cmpl(rcx, FieldOperand(source, HeapNumber::kExponentOffset));
6712d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    __ j(greater, &negative);
6713d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    __ movl(rcx, scratch2);
6714d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    __ jmp(&done);
6715d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    __ bind(&negative);
6716d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    __ subl(rcx, scratch2);
6717d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    __ bind(&done);
6718d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  }
6719d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke}
6720d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke
6721d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke
6722e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarkevoid GenericUnaryOpStub::Generate(MacroAssembler* masm) {
6723d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  Label slow, done;
6724d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke
6725d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  if (op_ == Token::SUB) {
6726d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    // Check whether the value is a smi.
6727d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    Label try_float;
6728d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    __ JumpIfNotSmi(rax, &try_float);
6729d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke
6730d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    // Enter runtime system if the value of the smi is zero
6731d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    // to make sure that we switch between 0 and -0.
6732d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    // Also enter it if the value of the smi is Smi::kMinValue.
6733d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    __ SmiNeg(rax, rax, &done);
6734d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke
6735d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    // Either zero or Smi::kMinValue, neither of which become a smi when
6736d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    // negated.
6737d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    __ SmiCompare(rax, Smi::FromInt(0));
6738d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    __ j(not_equal, &slow);
6739d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    __ Move(rax, Factory::minus_zero_value());
6740d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    __ jmp(&done);
6741d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke
6742d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    // Try floating point case.
6743d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    __ bind(&try_float);
6744d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    __ movq(rdx, FieldOperand(rax, HeapObject::kMapOffset));
6745d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    __ CompareRoot(rdx, Heap::kHeapNumberMapRootIndex);
6746d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    __ j(not_equal, &slow);
6747d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    // Operand is a float, negate its value by flipping sign bit.
6748d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    __ movq(rdx, FieldOperand(rax, HeapNumber::kValueOffset));
6749d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    __ movq(kScratchRegister, Immediate(0x01));
6750d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    __ shl(kScratchRegister, Immediate(63));
6751d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    __ xor_(rdx, kScratchRegister);  // Flip sign.
6752d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    // rdx is value to store.
6753d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    if (overwrite_) {
6754d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      __ movq(FieldOperand(rax, HeapNumber::kValueOffset), rdx);
6755d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    } else {
6756d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      __ AllocateHeapNumber(rcx, rbx, &slow);
6757d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      // rcx: allocated 'empty' number
6758d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      __ movq(FieldOperand(rcx, HeapNumber::kValueOffset), rdx);
6759d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      __ movq(rax, rcx);
6760d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    }
6761d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  } else if (op_ == Token::BIT_NOT) {
6762d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    // Check if the operand is a heap number.
6763d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    __ movq(rdx, FieldOperand(rax, HeapObject::kMapOffset));
6764d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    __ CompareRoot(rdx, Heap::kHeapNumberMapRootIndex);
6765d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    __ j(not_equal, &slow);
6766e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
6767d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    // Convert the heap number in rax to an untagged integer in rcx.
6768d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    IntegerConvert(masm, rax, CpuFeatures::IsSupported(SSE3), &slow);
6769a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
6770d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    // Do the bitwise operation and check if the result fits in a smi.
6771d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    Label try_float;
6772d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    __ not_(rcx);
6773d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    // Tag the result as a smi and we're done.
6774d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    ASSERT(kSmiTagSize == 1);
6775d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    __ Integer32ToSmi(rax, rcx);
6776d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  }
6777a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
6778d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  // Return from the stub.
6779d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  __ bind(&done);
6780d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  __ StubReturn(1);
6781a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
6782d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  // Handle the slow case by jumping to the JavaScript builtin.
6783a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&slow);
6784a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ pop(rcx);  // pop return address
6785a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ push(rax);
6786a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ push(rcx);  // push return address
6787d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  switch (op_) {
6788d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    case Token::SUB:
6789d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      __ InvokeBuiltin(Builtins::UNARY_MINUS, JUMP_FUNCTION);
6790d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      break;
6791d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    case Token::BIT_NOT:
6792d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      __ InvokeBuiltin(Builtins::BIT_NOT, JUMP_FUNCTION);
6793d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      break;
6794d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    default:
6795d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      UNREACHABLE();
6796a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
6797a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
6798a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
6799a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
68004515c472dc3e5ed2448a564600976759e569a0a8Leon Clarkevoid RegExpExecStub::Generate(MacroAssembler* masm) {
68014515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  // Just jump directly to runtime if native RegExp is not selected at compile
68024515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  // time or if regexp entry in generated code is turned off runtime switch or
68034515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  // at compilation.
68044515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke#ifndef V8_NATIVE_REGEXP
68054515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ TailCallRuntime(ExternalReference(Runtime::kRegExpExec), 4, 1);
68064515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke#else  // V8_NATIVE_REGEXP
68074515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  if (!FLAG_regexp_entry_native) {
68084515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke    __ TailCallRuntime(ExternalReference(Runtime::kRegExpExec), 4, 1);
68094515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke    return;
68104515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  }
68114515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke
68124515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  // Stack frame on entry.
68134515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  //  esp[0]: return address
68144515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  //  esp[8]: last_match_info (expected JSArray)
68154515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  //  esp[16]: previous index
68164515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  //  esp[24]: subject string
68174515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  //  esp[32]: JSRegExp object
68184515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke
68194515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  static const int kLastMatchInfoOffset = 1 * kPointerSize;
68204515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  static const int kPreviousIndexOffset = 2 * kPointerSize;
68214515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  static const int kSubjectOffset = 3 * kPointerSize;
68224515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  static const int kJSRegExpOffset = 4 * kPointerSize;
68234515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke
68244515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  Label runtime;
68254515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke
68264515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  // Ensure that a RegExp stack is allocated.
68274515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  ExternalReference address_of_regexp_stack_memory_address =
68284515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke      ExternalReference::address_of_regexp_stack_memory_address();
68294515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  ExternalReference address_of_regexp_stack_memory_size =
68304515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke      ExternalReference::address_of_regexp_stack_memory_size();
68314515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ movq(kScratchRegister, address_of_regexp_stack_memory_size);
68324515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ movq(kScratchRegister, Operand(kScratchRegister, 0));
68334515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ testq(kScratchRegister, kScratchRegister);
68344515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ j(zero, &runtime);
68354515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke
68364515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke
68374515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  // Check that the first argument is a JSRegExp object.
68384515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ movq(rax, Operand(rsp, kJSRegExpOffset));
68394515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ JumpIfSmi(rax, &runtime);
68404515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ CmpObjectType(rax, JS_REGEXP_TYPE, kScratchRegister);
68414515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ j(not_equal, &runtime);
68424515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  // Check that the RegExp has been compiled (data contains a fixed array).
68434515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ movq(rcx, FieldOperand(rax, JSRegExp::kDataOffset));
68444515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  if (FLAG_debug_code) {
68454515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke    Condition is_smi = masm->CheckSmi(rcx);
68464515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke    __ Check(NegateCondition(is_smi),
68474515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke        "Unexpected type for RegExp data, FixedArray expected");
68484515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke    __ CmpObjectType(rcx, FIXED_ARRAY_TYPE, kScratchRegister);
68494515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke    __ Check(equal, "Unexpected type for RegExp data, FixedArray expected");
68504515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  }
68514515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke
68524515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  // rcx: RegExp data (FixedArray)
68534515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  // Check the type of the RegExp. Only continue if type is JSRegExp::IRREGEXP.
68544515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ movq(rbx, FieldOperand(rcx, JSRegExp::kDataTagOffset));
68554515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ SmiCompare(rbx, Smi::FromInt(JSRegExp::IRREGEXP));
68564515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ j(not_equal, &runtime);
68574515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke
68584515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  // rcx: RegExp data (FixedArray)
68594515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  // Check that the number of captures fit in the static offsets vector buffer.
68604515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ movq(rdx, FieldOperand(rcx, JSRegExp::kIrregexpCaptureCountOffset));
68614515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  // Calculate number of capture registers (number_of_captures + 1) * 2.
68624515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ PositiveSmiTimesPowerOfTwoToInteger64(rdx, rdx, 1);
68634515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ addq(rdx, Immediate(2));  // rdx was number_of_captures * 2.
68644515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  // Check that the static offsets vector buffer is large enough.
68654515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ cmpq(rdx, Immediate(OffsetsVector::kStaticOffsetsVectorSize));
68664515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ j(above, &runtime);
68674515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke
68684515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  // rcx: RegExp data (FixedArray)
68694515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  // rdx: Number of capture registers
68704515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  // Check that the second argument is a string.
68714515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ movq(rax, Operand(rsp, kSubjectOffset));
68724515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ JumpIfSmi(rax, &runtime);
68734515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  Condition is_string = masm->IsObjectStringType(rax, rbx, rbx);
68744515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ j(NegateCondition(is_string), &runtime);
68754515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  // Get the length of the string to rbx.
68764515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ movl(rbx, FieldOperand(rax, String::kLengthOffset));
68774515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke
68784515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  // rbx: Length of subject string
68794515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  // rcx: RegExp data (FixedArray)
68804515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  // rdx: Number of capture registers
68814515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  // Check that the third argument is a positive smi less than the string
68824515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  // length. A negative value will be greater (usigned comparison).
68834515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ movq(rax, Operand(rsp, kPreviousIndexOffset));
68844515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ SmiToInteger32(rax, rax);
68854515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ cmpl(rax, rbx);
68864515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ j(above, &runtime);
68874515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke
68884515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  // rcx: RegExp data (FixedArray)
68894515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  // rdx: Number of capture registers
68904515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  // Check that the fourth object is a JSArray object.
68914515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ movq(rax, Operand(rsp, kLastMatchInfoOffset));
68924515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ JumpIfSmi(rax, &runtime);
68934515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ CmpObjectType(rax, JS_ARRAY_TYPE, kScratchRegister);
68944515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ j(not_equal, &runtime);
68954515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  // Check that the JSArray is in fast case.
68964515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ movq(rbx, FieldOperand(rax, JSArray::kElementsOffset));
68974515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ movq(rax, FieldOperand(rbx, HeapObject::kMapOffset));
68984515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ Cmp(rax, Factory::fixed_array_map());
68994515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ j(not_equal, &runtime);
69004515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  // Check that the last match info has space for the capture registers and the
69014515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  // additional information. Ensure no overflow in add.
69024515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  ASSERT(FixedArray::kMaxLength < kMaxInt - FixedArray::kLengthOffset);
69034515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ movl(rax, FieldOperand(rbx, FixedArray::kLengthOffset));
69044515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ addl(rdx, Immediate(RegExpImpl::kLastMatchOverhead));
69054515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ cmpl(rdx, rax);
69064515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ j(greater, &runtime);
69074515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke
69084515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  // ecx: RegExp data (FixedArray)
69094515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  // Check the representation and encoding of the subject string.
69104515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  Label seq_string, seq_two_byte_string, check_code;
69114515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  const int kStringRepresentationEncodingMask =
69124515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke      kIsNotStringMask | kStringRepresentationMask | kStringEncodingMask;
69134515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ movq(rax, Operand(rsp, kSubjectOffset));
69144515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ movq(rbx, FieldOperand(rax, HeapObject::kMapOffset));
69154515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ movzxbl(rbx, FieldOperand(rbx, Map::kInstanceTypeOffset));
69164515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ andb(rbx, Immediate(kStringRepresentationEncodingMask));
69174515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  // First check for sequential string.
69184515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  ASSERT_EQ(0, kStringTag);
69194515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  ASSERT_EQ(0, kSeqStringTag);
69204515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ testb(rbx, Immediate(kIsNotStringMask | kStringRepresentationMask));
69214515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ j(zero, &seq_string);
69224515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke
69234515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  // Check for flat cons string.
69244515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  // A flat cons string is a cons string where the second part is the empty
69254515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  // string. In that case the subject string is just the first part of the cons
69264515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  // string. Also in this case the first part of the cons string is known to be
69274515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  // a sequential string or an external string.
69284515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ movl(rdx, rbx);
69294515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ andb(rdx, Immediate(kStringRepresentationMask));
69304515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ cmpb(rdx, Immediate(kConsStringTag));
69314515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ j(not_equal, &runtime);
69324515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ movq(rdx, FieldOperand(rax, ConsString::kSecondOffset));
69334515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ Cmp(rdx, Factory::empty_string());
69344515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ j(not_equal, &runtime);
69354515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ movq(rax, FieldOperand(rax, ConsString::kFirstOffset));
69364515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ movq(rbx, FieldOperand(rax, HeapObject::kMapOffset));
69374515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ movzxbl(rbx, FieldOperand(rbx, Map::kInstanceTypeOffset));
69384515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  ASSERT_EQ(0, kSeqStringTag);
69394515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ testb(rbx, Immediate(kStringRepresentationMask));
69404515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ j(not_zero, &runtime);
69414515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ andb(rbx, Immediate(kStringRepresentationEncodingMask));
69424515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke
69434515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ bind(&seq_string);
69444515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  // rax: subject string (sequential either ascii to two byte)
69454515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  // rbx: suject string type & kStringRepresentationEncodingMask
69464515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  // rcx: RegExp data (FixedArray)
69474515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  // Check that the irregexp code has been generated for an ascii string. If
69484515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  // it has, the field contains a code object otherwise it contains the hole.
69494515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ cmpb(rbx, Immediate(kStringTag | kSeqStringTag | kTwoByteStringTag));
69504515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ j(equal, &seq_two_byte_string);
69514515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  if (FLAG_debug_code) {
69524515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke    __ cmpb(rbx, Immediate(kStringTag | kSeqStringTag | kAsciiStringTag));
69534515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke    __ Check(equal, "Expected sequential ascii string");
69544515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  }
69554515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ movq(r12, FieldOperand(rcx, JSRegExp::kDataAsciiCodeOffset));
69564515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ Set(rdi, 1);  // Type is ascii.
69574515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ jmp(&check_code);
69584515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke
69594515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ bind(&seq_two_byte_string);
69604515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  // rax: subject string
69614515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  // rcx: RegExp data (FixedArray)
69624515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ movq(r12, FieldOperand(rcx, JSRegExp::kDataUC16CodeOffset));
69634515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ Set(rdi, 0);  // Type is two byte.
69644515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke
69654515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ bind(&check_code);
69664515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  // Check that the irregexp code has been generated for the actual string
69674515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  // encoding. If it has, the field contains a code object otherwise it contains
69684515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  // the hole.
69694515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ CmpObjectType(r12, CODE_TYPE, kScratchRegister);
69704515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ j(not_equal, &runtime);
69714515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke
69724515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  // rax: subject string
69734515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  // rdi: encoding of subject string (1 if ascii, 0 if two_byte);
69744515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  // r12: code
69754515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  // Load used arguments before starting to push arguments for call to native
69764515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  // RegExp code to avoid handling changing stack height.
69774515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ movq(rbx, Operand(rsp, kPreviousIndexOffset));
69784515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ SmiToInteger64(rbx, rbx);  // Previous index from smi.
69794515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke
69804515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  // rax: subject string
69814515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  // rbx: previous index
69824515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  // rdi: encoding of subject string (1 if ascii 0 if two_byte);
69834515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  // r12: code
69844515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  // All checks done. Now push arguments for native regexp code.
69854515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ IncrementCounter(&Counters::regexp_entry_native, 1);
69864515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke
69874515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  // rsi is caller save on Windows and used to pass parameter on Linux.
69884515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ push(rsi);
69894515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke
69904515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  static const int kRegExpExecuteArguments = 7;
69914515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ PrepareCallCFunction(kRegExpExecuteArguments);
69924515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  int argument_slots_on_stack =
69934515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke      masm->ArgumentStackSlotsForCFunctionCall(kRegExpExecuteArguments);
69944515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke
69954515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  // Argument 7: Indicate that this is a direct call from JavaScript.
69964515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ movq(Operand(rsp, (argument_slots_on_stack - 1) * kPointerSize),
69974515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke          Immediate(1));
69984515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke
69994515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  // Argument 6: Start (high end) of backtracking stack memory area.
70004515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ movq(kScratchRegister, address_of_regexp_stack_memory_address);
70014515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ movq(r9, Operand(kScratchRegister, 0));
70024515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ movq(kScratchRegister, address_of_regexp_stack_memory_size);
70034515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ addq(r9, Operand(kScratchRegister, 0));
70044515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  // Argument 6 passed in r9 on Linux and on the stack on Windows.
70054515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke#ifdef _WIN64
70064515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ movq(Operand(rsp, (argument_slots_on_stack - 2) * kPointerSize), r9);
70074515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke#endif
70084515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke
70094515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  // Argument 5: static offsets vector buffer.
70104515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ movq(r8, ExternalReference::address_of_static_offsets_vector());
70114515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  // Argument 5 passed in r8 on Linux and on the stack on Windows.
70124515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke#ifdef _WIN64
70134515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ movq(Operand(rsp, (argument_slots_on_stack - 3) * kPointerSize), r8);
70144515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke#endif
70154515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke
70164515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  // First four arguments are passed in registers on both Linux and Windows.
70174515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke#ifdef _WIN64
70184515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  Register arg4 = r9;
70194515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  Register arg3 = r8;
70204515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  Register arg2 = rdx;
70214515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  Register arg1 = rcx;
70224515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke#else
70234515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  Register arg4 = rcx;
70244515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  Register arg3 = rdx;
70254515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  Register arg2 = rsi;
70264515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  Register arg1 = rdi;
70274515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke#endif
70284515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke
70294515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  // Keep track on aliasing between argX defined above and the registers used.
70304515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  // rax: subject string
70314515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  // rbx: previous index
70324515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  // rdi: encoding of subject string (1 if ascii 0 if two_byte);
70334515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  // r12: code
70344515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke
70354515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  // Argument 4: End of string data
70364515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  // Argument 3: Start of string data
70374515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  Label setup_two_byte, setup_rest;
70384515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ testb(rdi, rdi);
70394515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ movl(rdi, FieldOperand(rax, String::kLengthOffset));
70404515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ j(zero, &setup_two_byte);
70414515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ lea(arg4, FieldOperand(rax, rdi, times_1, SeqAsciiString::kHeaderSize));
70424515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ lea(arg3, FieldOperand(rax, rbx, times_1, SeqAsciiString::kHeaderSize));
70434515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ jmp(&setup_rest);
70444515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ bind(&setup_two_byte);
70454515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ lea(arg4, FieldOperand(rax, rdi, times_2, SeqTwoByteString::kHeaderSize));
70464515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ lea(arg3, FieldOperand(rax, rbx, times_2, SeqTwoByteString::kHeaderSize));
70474515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke
70484515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ bind(&setup_rest);
70494515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  // Argument 2: Previous index.
70504515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ movq(arg2, rbx);
70514515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke
70524515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  // Argument 1: Subject string.
70534515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ movq(arg1, rax);
70544515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke
70554515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  // Locate the code entry and call it.
70564515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ addq(r12, Immediate(Code::kHeaderSize - kHeapObjectTag));
70574515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ CallCFunction(r12, kRegExpExecuteArguments);
70584515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke
70594515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  // rsi is caller save, as it is used to pass parameter.
70604515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ pop(rsi);
70614515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke
70624515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  // Check the result.
70634515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  Label success;
70644515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ cmpq(rax, Immediate(NativeRegExpMacroAssembler::SUCCESS));
70654515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ j(equal, &success);
70664515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  Label failure;
70674515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ cmpq(rax, Immediate(NativeRegExpMacroAssembler::FAILURE));
70684515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ j(equal, &failure);
70694515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ cmpq(rax, Immediate(NativeRegExpMacroAssembler::EXCEPTION));
70704515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  // If not exception it can only be retry. Handle that in the runtime system.
70714515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ j(not_equal, &runtime);
70724515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  // Result must now be exception. If there is no pending exception already a
70734515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  // stack overflow (on the backtrack stack) was detected in RegExp code but
70744515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  // haven't created the exception yet. Handle that in the runtime system.
70754515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  // TODO(592) Rerunning the RegExp to get the stack overflow exception.
70764515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  ExternalReference pending_exception_address(Top::k_pending_exception_address);
70774515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ movq(kScratchRegister, pending_exception_address);
70784515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ Cmp(kScratchRegister, Factory::the_hole_value());
70794515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ j(equal, &runtime);
70804515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ bind(&failure);
70814515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  // For failure and exception return null.
70824515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ Move(rax, Factory::null_value());
70834515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ ret(4 * kPointerSize);
70844515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke
70854515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  // Load RegExp data.
70864515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ bind(&success);
70874515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ movq(rax, Operand(rsp, kJSRegExpOffset));
70884515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ movq(rcx, FieldOperand(rax, JSRegExp::kDataOffset));
70894515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ movq(rdx, FieldOperand(rcx, JSRegExp::kIrregexpCaptureCountOffset));
70904515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  // Calculate number of capture registers (number_of_captures + 1) * 2.
70914515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ PositiveSmiTimesPowerOfTwoToInteger64(rdx, rdx, 1);
70924515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ addq(rdx, Immediate(2));  // rdx was number_of_captures * 2.
70934515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke
70944515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  // rdx: Number of capture registers
70954515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  // Load last_match_info which is still known to be a fast case JSArray.
70964515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ movq(rax, Operand(rsp, kLastMatchInfoOffset));
70974515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ movq(rbx, FieldOperand(rax, JSArray::kElementsOffset));
70984515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke
70994515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  // rbx: last_match_info backing store (FixedArray)
71004515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  // rdx: number of capture registers
71014515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  // Store the capture count.
71024515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ Integer32ToSmi(kScratchRegister, rdx);
71034515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ movq(FieldOperand(rbx, RegExpImpl::kLastCaptureCountOffset),
71044515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke          kScratchRegister);
71054515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  // Store last subject and last input.
71064515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ movq(rax, Operand(rsp, kSubjectOffset));
71074515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ movq(FieldOperand(rbx, RegExpImpl::kLastSubjectOffset), rax);
71084515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ movq(rcx, rbx);
71094515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ RecordWrite(rcx, RegExpImpl::kLastSubjectOffset, rax, rdi);
71104515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ movq(rax, Operand(rsp, kSubjectOffset));
71114515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ movq(FieldOperand(rbx, RegExpImpl::kLastInputOffset), rax);
71124515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ movq(rcx, rbx);
71134515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ RecordWrite(rcx, RegExpImpl::kLastInputOffset, rax, rdi);
71144515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke
71154515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  // Get the static offsets vector filled by the native regexp code.
71164515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ movq(rcx, ExternalReference::address_of_static_offsets_vector());
71174515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke
71184515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  // rbx: last_match_info backing store (FixedArray)
71194515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  // rcx: offsets vector
71204515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  // rdx: number of capture registers
71214515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  Label next_capture, done;
71224515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ movq(rax, Operand(rsp, kPreviousIndexOffset));
71234515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  // Capture register counter starts from number of capture registers and
71244515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  // counts down until wraping after zero.
71254515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ bind(&next_capture);
71264515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ subq(rdx, Immediate(1));
71274515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ j(negative, &done);
71284515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  // Read the value from the static offsets vector buffer and make it a smi.
71294515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ movl(rdi, Operand(rcx, rdx, times_int_size, 0));
71304515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ Integer32ToSmi(rdi, rdi, &runtime);
71314515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  // Add previous index (from its stack slot) if value is not negative.
71324515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  Label capture_negative;
71334515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  // Negative flag set by smi convertion above.
71344515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ j(negative, &capture_negative);
71354515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ SmiAdd(rdi, rdi, rax, &runtime);  // Add previous index.
71364515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ bind(&capture_negative);
71374515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  // Store the smi value in the last match info.
71384515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ movq(FieldOperand(rbx,
71394515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke                       rdx,
71404515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke                       times_pointer_size,
71414515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke                       RegExpImpl::kFirstCaptureOffset),
71424515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke                       rdi);
71434515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ jmp(&next_capture);
71444515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ bind(&done);
71454515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke
71464515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  // Return last match info.
71474515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ movq(rax, Operand(rsp, kLastMatchInfoOffset));
71484515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ ret(4 * kPointerSize);
71494515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke
71504515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  // Do the runtime call to execute the regexp.
71514515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ bind(&runtime);
71524515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ TailCallRuntime(ExternalReference(Runtime::kRegExpExec), 4, 1);
71534515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke#endif  // V8_NATIVE_REGEXP
71544515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke}
71554515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke
71564515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke
7157a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CompareStub::Generate(MacroAssembler* masm) {
7158a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Label call_builtin, done;
7159a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
7160a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // NOTICE! This code is only reached after a smi-fast-case check, so
7161a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // it is certain that at least one operand isn't a smi.
7162a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
7163a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (cc_ == equal) {  // Both strict and non-strict.
7164a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    Label slow;  // Fallthrough label.
7165a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Equality is almost reflexive (everything but NaN), so start by testing
7166a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // for "identity and not NaN".
7167a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    {
7168a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      Label not_identical;
7169a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      __ cmpq(rax, rdx);
7170a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      __ j(not_equal, &not_identical);
7171a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // Test for NaN. Sadly, we can't just compare to Factory::nan_value(),
7172a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // so we do the second best thing - test it ourselves.
7173a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
7174e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke      if (never_nan_nan_) {
7175e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke        __ xor_(rax, rax);
7176e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke        __ ret(0);
7177e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke      } else {
7178e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke        Label return_equal;
7179e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke        Label heap_number;
7180e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke        // If it's not a heap number, then return equal.
7181e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke        __ Cmp(FieldOperand(rdx, HeapObject::kMapOffset),
7182e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke               Factory::heap_number_map());
7183e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke        __ j(equal, &heap_number);
7184e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke        __ bind(&return_equal);
7185e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke        __ xor_(rax, rax);
7186e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke        __ ret(0);
7187a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
7188e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke        __ bind(&heap_number);
7189e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke        // It is a heap number, so return non-equal if it's NaN and equal if
7190e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke        // it's not NaN.
7191e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke        // The representation of NaN values has all exponent bits (52..62) set,
7192e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke        // and not all mantissa bits (0..51) clear.
7193e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke        // We only allow QNaNs, which have bit 51 set (which also rules out
7194e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke        // the value being Infinity).
7195e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
7196e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke        // Value is a QNaN if value & kQuietNaNMask == kQuietNaNMask, i.e.,
7197e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke        // all bits in the mask are set. We only need to check the word
7198e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke        // that contains the exponent and high bit of the mantissa.
7199e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke        ASSERT_NE(0, (kQuietNaNHighBitsMask << 1) & 0x80000000u);
7200e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke        __ movl(rdx, FieldOperand(rdx, HeapNumber::kExponentOffset));
7201e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke        __ xorl(rax, rax);
7202e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke        __ addl(rdx, rdx);  // Shift value and mask so mask applies to top bits.
7203e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke        __ cmpl(rdx, Immediate(kQuietNaNHighBitsMask << 1));
7204e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke        __ setcc(above_equal, rax);
7205e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke        __ ret(0);
7206e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke      }
7207a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
7208a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      __ bind(&not_identical);
7209a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
7210a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
7211a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // If we're doing a strict equality comparison, we don't have to do
7212a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // type conversion, so we generate code to do fast comparison for objects
7213a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // and oddballs. Non-smi numbers and strings still go through the usual
7214a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // slow-case code.
7215a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (strict_) {
7216a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // If either is a Smi (we know that not both are), then they can only
7217a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // be equal if the other is a HeapNumber. If so, use the slow case.
7218a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      {
7219a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        Label not_smis;
7220a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        __ SelectNonSmi(rbx, rax, rdx, &not_smis);
7221a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
7222a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        // Check if the non-smi operand is a heap number.
7223a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        __ Cmp(FieldOperand(rbx, HeapObject::kMapOffset),
7224a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block               Factory::heap_number_map());
7225a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        // If heap number, handle it in the slow case.
7226a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        __ j(equal, &slow);
7227a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        // Return non-equal.  ebx (the lower half of rbx) is not zero.
7228a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        __ movq(rax, rbx);
7229a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        __ ret(0);
7230a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
7231a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        __ bind(&not_smis);
7232a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      }
7233a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
7234a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // If either operand is a JSObject or an oddball value, then they are not
7235a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // equal since their pointers are different
7236a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // There is no test for undetectability in strict equality.
7237a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
7238a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // If the first object is a JS object, we have done pointer comparison.
7239a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      ASSERT(LAST_TYPE == JS_FUNCTION_TYPE);
7240a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      Label first_non_object;
7241a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      __ CmpObjectType(rax, FIRST_JS_OBJECT_TYPE, rcx);
7242a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      __ j(below, &first_non_object);
7243a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // Return non-zero (eax (not rax) is not zero)
7244a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      Label return_not_equal;
7245a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      ASSERT(kHeapObjectTag != 0);
7246a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      __ bind(&return_not_equal);
7247a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      __ ret(0);
7248a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
7249a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      __ bind(&first_non_object);
7250a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // Check for oddballs: true, false, null, undefined.
7251a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      __ CmpInstanceType(rcx, ODDBALL_TYPE);
7252a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      __ j(equal, &return_not_equal);
7253a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
7254a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      __ CmpObjectType(rdx, FIRST_JS_OBJECT_TYPE, rcx);
7255a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      __ j(above_equal, &return_not_equal);
7256a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
7257a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // Check for oddballs: true, false, null, undefined.
7258a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      __ CmpInstanceType(rcx, ODDBALL_TYPE);
7259a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      __ j(equal, &return_not_equal);
7260a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
7261a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // Fall through to the general case.
7262a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
7263a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ bind(&slow);
7264a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
7265a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
7266a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Push arguments below the return address to prepare jump to builtin.
7267a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ pop(rcx);
7268a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ push(rax);
7269a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ push(rdx);
7270a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ push(rcx);
7271a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
7272a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Inlined floating point compare.
7273a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Call builtin if operands are not floating point or smi.
7274a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Label check_for_symbols;
7275a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Push arguments on stack, for helper functions.
72763ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  FloatingPointHelper::CheckNumberOperands(masm, &check_for_symbols);
7277a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  FloatingPointHelper::LoadFloatOperands(masm, rax, rdx);
7278a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ FCmp();
7279a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
7280a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Jump to builtin for NaN.
7281a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(parity_even, &call_builtin);
7282a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
7283a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // TODO(1243847): Use cmov below once CpuFeatures are properly hooked up.
7284a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Label below_lbl, above_lbl;
7285a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // use rdx, rax to convert unsigned to signed comparison
7286a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(below, &below_lbl);
7287a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(above, &above_lbl);
7288a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
7289a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ xor_(rax, rax);  // equal
7290a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ ret(2 * kPointerSize);
7291a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
7292a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&below_lbl);
7293a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ movq(rax, Immediate(-1));
7294a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ ret(2 * kPointerSize);
7295a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
7296a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&above_lbl);
7297a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ movq(rax, Immediate(1));
7298a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ ret(2 * kPointerSize);  // rax, rdx were pushed
7299a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
7300a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Fast negative check for symbol-to-symbol equality.
7301a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&check_for_symbols);
7302e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  Label check_for_strings;
7303a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (cc_ == equal) {
7304e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke    BranchIfNonSymbol(masm, &check_for_strings, rax, kScratchRegister);
7305e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke    BranchIfNonSymbol(masm, &check_for_strings, rdx, kScratchRegister);
7306a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
7307a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // We've already checked for object identity, so if both operands
7308a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // are symbols they aren't equal. Register eax (not rax) already holds a
7309a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // non-zero value, which indicates not equal, so just return.
7310a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ ret(2 * kPointerSize);
7311a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
7312a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
7313e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ bind(&check_for_strings);
7314e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
7315e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ JumpIfNotBothSequentialAsciiStrings(rdx, rax, rcx, rbx, &call_builtin);
7316e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
7317e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // Inline comparison of ascii strings.
7318e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  StringCompareStub::GenerateCompareFlatAsciiStrings(masm,
7319e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke                                                     rdx,
7320e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke                                                     rax,
7321e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke                                                     rcx,
7322e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke                                                     rbx,
7323e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke                                                     rdi,
7324e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke                                                     r8);
7325e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
7326e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke#ifdef DEBUG
7327e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ Abort("Unexpected fall-through from string comparison");
7328e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke#endif
7329e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
7330a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&call_builtin);
7331a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // must swap argument order
7332a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ pop(rcx);
7333a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ pop(rdx);
7334a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ pop(rax);
7335a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ push(rdx);
7336a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ push(rax);
7337a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
7338a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Figure out which native to call and setup the arguments.
7339a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Builtins::JavaScript builtin;
7340a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (cc_ == equal) {
7341a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    builtin = strict_ ? Builtins::STRICT_EQUALS : Builtins::EQUALS;
7342a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  } else {
7343a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    builtin = Builtins::COMPARE;
7344a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    int ncr;  // NaN compare result
7345a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (cc_ == less || cc_ == less_equal) {
7346a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      ncr = GREATER;
7347a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    } else {
7348a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      ASSERT(cc_ == greater || cc_ == greater_equal);  // remaining cases
7349a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      ncr = LESS;
7350a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
73513ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    __ Push(Smi::FromInt(ncr));
7352a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
7353a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
7354a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Restore return address on the stack.
7355a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ push(rcx);
7356a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
7357a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Call the native; it returns -1 (less), 0 (equal), or 1 (greater)
7358a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // tagged as a small integer.
7359a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ InvokeBuiltin(builtin, JUMP_FUNCTION);
7360a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
7361a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
7362a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
7363a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CompareStub::BranchIfNonSymbol(MacroAssembler* masm,
7364a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                    Label* label,
7365a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                    Register object,
7366a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                    Register scratch) {
7367a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ JumpIfSmi(object, label);
7368a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ movq(scratch, FieldOperand(object, HeapObject::kMapOffset));
7369a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ movzxbq(scratch,
7370a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block             FieldOperand(scratch, Map::kInstanceTypeOffset));
7371e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // Ensure that no non-strings have the symbol bit set.
7372e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  ASSERT(kNotStringTag + kIsSymbolMask > LAST_TYPE);
7373e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  ASSERT(kSymbolTag != 0);
7374e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ testb(scratch, Immediate(kIsSymbolMask));
7375e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ j(zero, label);
7376a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
7377a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
7378a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
7379a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// Call the function just below TOS on the stack with the given
7380a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// arguments. The receiver is the TOS.
7381a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CodeGenerator::CallWithArguments(ZoneList<Expression*>* args,
7382e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke                                      CallFunctionFlags flags,
7383a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                      int position) {
7384a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Push the arguments ("left-to-right") on the stack.
7385a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  int arg_count = args->length();
7386a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  for (int i = 0; i < arg_count; i++) {
7387a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    Load(args->at(i));
7388a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
7389a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
7390a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Record the position for debugging purposes.
7391a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CodeForSourcePosition(position);
7392a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
7393a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Use the shared code stub to call the function.
7394a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  InLoopFlag in_loop = loop_nesting() > 0 ? IN_LOOP : NOT_IN_LOOP;
7395e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  CallFunctionStub call_function(arg_count, in_loop, flags);
7396a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Result answer = frame_->CallStub(&call_function, arg_count + 1);
7397a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Restore context and replace function on the stack with the
7398a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // result of the stub invocation.
7399a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  frame_->RestoreContextRegister();
7400a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  frame_->SetElementAt(0, &answer);
7401a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
7402a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
7403a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
7404a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid InstanceofStub::Generate(MacroAssembler* masm) {
7405a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Implements "value instanceof function" operator.
7406a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Expected input state:
7407a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //   rsp[0] : return address
7408a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //   rsp[1] : function pointer
7409a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //   rsp[2] : value
7410a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
7411a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Get the object - go slow case if it's a smi.
7412a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Label slow;
7413a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ movq(rax, Operand(rsp, 2 * kPointerSize));
7414a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ JumpIfSmi(rax, &slow);
7415a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
7416a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check that the left hand is a JS object. Leave its map in rax.
7417a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ CmpObjectType(rax, FIRST_JS_OBJECT_TYPE, rax);
7418a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(below, &slow);
7419a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ CmpInstanceType(rax, LAST_JS_OBJECT_TYPE);
7420a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(above, &slow);
7421a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
7422a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Get the prototype of the function.
7423a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ movq(rdx, Operand(rsp, 1 * kPointerSize));
7424a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ TryGetFunctionPrototype(rdx, rbx, &slow);
7425a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
7426a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check that the function prototype is a JS object.
7427a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ JumpIfSmi(rbx, &slow);
7428a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ CmpObjectType(rbx, FIRST_JS_OBJECT_TYPE, kScratchRegister);
7429a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(below, &slow);
7430a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ CmpInstanceType(kScratchRegister, LAST_JS_OBJECT_TYPE);
7431a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(above, &slow);
7432a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
7433a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Register mapping: rax is object map and rbx is function prototype.
7434a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ movq(rcx, FieldOperand(rax, Map::kPrototypeOffset));
7435a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
7436a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Loop through the prototype chain looking for the function prototype.
7437a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Label loop, is_instance, is_not_instance;
7438a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ LoadRoot(kScratchRegister, Heap::kNullValueRootIndex);
7439a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&loop);
7440a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ cmpq(rcx, rbx);
7441a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(equal, &is_instance);
7442a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ cmpq(rcx, kScratchRegister);
7443a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(equal, &is_not_instance);
7444a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ movq(rcx, FieldOperand(rcx, HeapObject::kMapOffset));
7445a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ movq(rcx, FieldOperand(rcx, Map::kPrototypeOffset));
7446a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ jmp(&loop);
7447a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
7448a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&is_instance);
7449d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  __ xorl(rax, rax);
7450a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ ret(2 * kPointerSize);
7451a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
7452a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&is_not_instance);
7453d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  __ movl(rax, Immediate(1));
7454a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ ret(2 * kPointerSize);
7455a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
7456a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Slow-case: Go through the JavaScript implementation.
7457a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&slow);
7458a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION);
7459a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
7460a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
7461a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
7462a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid ArgumentsAccessStub::GenerateNewObject(MacroAssembler* masm) {
7463402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // rsp[0] : return address
7464402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // rsp[8] : number of parameters
7465402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // rsp[16] : receiver displacement
7466402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // rsp[24] : function
7467402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu
7468a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // The displacement is used for skipping the return address and the
7469a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // frame pointer on the stack. It is the offset of the last
7470a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // parameter (if any) relative to the frame pointer.
7471a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  static const int kDisplacement = 2 * kPointerSize;
7472a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
7473a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check if the calling frame is an arguments adaptor frame.
7474402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  Label adaptor_frame, try_allocate, runtime;
7475a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ movq(rdx, Operand(rbp, StandardFrameConstants::kCallerFPOffset));
74763ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  __ SmiCompare(Operand(rdx, StandardFrameConstants::kContextOffset),
74773ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block                Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR));
7478402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ j(equal, &adaptor_frame);
7479402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu
7480402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // Get the length from the frame.
7481402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ movq(rcx, Operand(rsp, 1 * kPointerSize));
7482402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ jmp(&try_allocate);
7483a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
7484a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Patch the arguments.length and the parameters pointer.
7485402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ bind(&adaptor_frame);
7486a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ movq(rcx, Operand(rdx, ArgumentsAdaptorFrameConstants::kLengthOffset));
7487a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ movq(Operand(rsp, 1 * kPointerSize), rcx);
7488402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // Do not clobber the length index for the indexing operation since
7489402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // it is used compute the size for allocation later.
7490402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  SmiIndex index = masm->SmiToIndex(rbx, rcx, kPointerSizeLog2);
7491a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ lea(rdx, Operand(rdx, index.reg, index.scale, kDisplacement));
7492a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ movq(Operand(rsp, 2 * kPointerSize), rdx);
7493a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
7494402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // Try the new space allocation. Start out with computing the size of
7495402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // the arguments object and the elements array.
7496402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  Label add_arguments_object;
7497402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ bind(&try_allocate);
7498402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ testq(rcx, rcx);
7499402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ j(zero, &add_arguments_object);
7500402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  index = masm->SmiToIndex(rcx, rcx, kPointerSizeLog2);
7501402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ lea(rcx, Operand(index.reg, index.scale, FixedArray::kHeaderSize));
7502402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ bind(&add_arguments_object);
7503402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ addq(rcx, Immediate(Heap::kArgumentsObjectSize));
7504402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu
7505402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // Do the allocation of both objects in one go.
7506402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ AllocateInNewSpace(rcx, rax, rdx, rbx, &runtime, TAG_OBJECT);
7507402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu
7508402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // Get the arguments boilerplate from the current (global) context.
7509402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  int offset = Context::SlotOffset(Context::ARGUMENTS_BOILERPLATE_INDEX);
7510402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ movq(rdi, Operand(rsi, Context::SlotOffset(Context::GLOBAL_INDEX)));
7511402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ movq(rdi, FieldOperand(rdi, GlobalObject::kGlobalContextOffset));
7512402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ movq(rdi, Operand(rdi, offset));
7513402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu
7514402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // Copy the JS object part.
7515402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  for (int i = 0; i < JSObject::kHeaderSize; i += kPointerSize) {
7516402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    __ movq(kScratchRegister, FieldOperand(rdi, i));
7517402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    __ movq(FieldOperand(rax, i), kScratchRegister);
7518402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  }
7519402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu
7520402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // Setup the callee in-object property.
7521402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  ASSERT(Heap::arguments_callee_index == 0);
7522402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ movq(kScratchRegister, Operand(rsp, 3 * kPointerSize));
7523402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ movq(FieldOperand(rax, JSObject::kHeaderSize), kScratchRegister);
7524402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu
7525402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // Get the length (smi tagged) and set that as an in-object property too.
7526402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  ASSERT(Heap::arguments_length_index == 1);
7527402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ movq(rcx, Operand(rsp, 1 * kPointerSize));
7528402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ movq(FieldOperand(rax, JSObject::kHeaderSize + kPointerSize), rcx);
7529402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu
7530402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // If there are no actual arguments, we're done.
7531402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  Label done;
7532402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ testq(rcx, rcx);
7533402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ j(zero, &done);
7534402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu
7535402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // Get the parameters pointer from the stack and untag the length.
7536402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ movq(rdx, Operand(rsp, 2 * kPointerSize));
7537402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ SmiToInteger32(rcx, rcx);
7538402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu
7539402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // Setup the elements pointer in the allocated arguments object and
7540402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // initialize the header in the elements fixed array.
7541402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ lea(rdi, Operand(rax, Heap::kArgumentsObjectSize));
7542402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ movq(FieldOperand(rax, JSObject::kElementsOffset), rdi);
7543402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ LoadRoot(kScratchRegister, Heap::kFixedArrayMapRootIndex);
7544402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ movq(FieldOperand(rdi, FixedArray::kMapOffset), kScratchRegister);
7545402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ movq(FieldOperand(rdi, FixedArray::kLengthOffset), rcx);
7546402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu
7547402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // Copy the fixed array slots.
7548402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  Label loop;
7549402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ bind(&loop);
7550402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ movq(kScratchRegister, Operand(rdx, -1 * kPointerSize));  // Skip receiver.
7551402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ movq(FieldOperand(rdi, FixedArray::kHeaderSize), kScratchRegister);
7552402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ addq(rdi, Immediate(kPointerSize));
7553402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ subq(rdx, Immediate(kPointerSize));
7554402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ decq(rcx);
7555402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ j(not_zero, &loop);
7556402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu
7557402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // Return and remove the on-stack parameters.
7558402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ bind(&done);
7559402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ ret(3 * kPointerSize);
7560402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu
7561a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Do the runtime call to allocate the arguments object.
7562a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&runtime);
7563402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ TailCallRuntime(ExternalReference(Runtime::kNewArgumentsFast), 3, 1);
7564a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
7565a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
7566a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
7567a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid ArgumentsAccessStub::GenerateReadElement(MacroAssembler* masm) {
7568a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // The key is in rdx and the parameter count is in rax.
7569a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
7570a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // The displacement is used for skipping the frame pointer on the
7571a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // stack. It is the offset of the last parameter (if any) relative
7572a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // to the frame pointer.
7573a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  static const int kDisplacement = 1 * kPointerSize;
7574a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
7575a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check that the key is a smi.
7576a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Label slow;
7577a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ JumpIfNotSmi(rdx, &slow);
7578a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
7579a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check if the calling frame is an arguments adaptor frame.
7580a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Label adaptor;
7581a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ movq(rbx, Operand(rbp, StandardFrameConstants::kCallerFPOffset));
75823ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  __ SmiCompare(Operand(rbx, StandardFrameConstants::kContextOffset),
75833ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block                Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR));
7584a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(equal, &adaptor);
7585a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
7586a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check index against formal parameters count limit passed in
7587a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // through register rax. Use unsigned comparison to get negative
7588a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // check for free.
7589a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ cmpq(rdx, rax);
7590a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(above_equal, &slow);
7591a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
7592a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Read the argument from the stack and return it.
7593a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  SmiIndex index = masm->SmiToIndex(rax, rax, kPointerSizeLog2);
7594a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ lea(rbx, Operand(rbp, index.reg, index.scale, 0));
7595a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  index = masm->SmiToNegativeIndex(rdx, rdx, kPointerSizeLog2);
7596a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ movq(rax, Operand(rbx, index.reg, index.scale, kDisplacement));
7597a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ Ret();
7598a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
7599a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Arguments adaptor case: Check index against actual arguments
7600a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // limit found in the arguments adaptor frame. Use unsigned
7601a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // comparison to get negative check for free.
7602a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&adaptor);
7603a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ movq(rcx, Operand(rbx, ArgumentsAdaptorFrameConstants::kLengthOffset));
7604a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ cmpq(rdx, rcx);
7605a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(above_equal, &slow);
7606a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
7607a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Read the argument from the stack and return it.
7608a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  index = masm->SmiToIndex(rax, rcx, kPointerSizeLog2);
7609a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ lea(rbx, Operand(rbx, index.reg, index.scale, 0));
7610a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  index = masm->SmiToNegativeIndex(rdx, rdx, kPointerSizeLog2);
7611a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ movq(rax, Operand(rbx, index.reg, index.scale, kDisplacement));
7612a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ Ret();
7613a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
7614a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Slow-case: Handle non-smi or out-of-bounds access to arguments
7615a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // by calling the runtime system.
7616a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&slow);
7617a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ pop(rbx);  // Return address.
7618a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ push(rdx);
7619a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ push(rbx);
7620a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Runtime::Function* f =
7621a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      Runtime::FunctionForId(Runtime::kGetArgumentsProperty);
7622a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ TailCallRuntime(ExternalReference(f), 1, f->result_size);
7623a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
7624a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
7625a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
7626a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid ArgumentsAccessStub::GenerateReadLength(MacroAssembler* masm) {
7627a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check if the calling frame is an arguments adaptor frame.
7628a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Label adaptor;
7629a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ movq(rdx, Operand(rbp, StandardFrameConstants::kCallerFPOffset));
76303ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  __ SmiCompare(Operand(rdx, StandardFrameConstants::kContextOffset),
76313ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block                Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR));
7632a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
7633a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Arguments adaptor case: Read the arguments length from the
7634a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // adaptor frame and return it.
7635e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // Otherwise nothing to do: The number of formal parameters has already been
7636e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // passed in register eax by calling function. Just return it.
7637e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ cmovq(equal, rax,
7638e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke           Operand(rdx, ArgumentsAdaptorFrameConstants::kLengthOffset));
7639a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ ret(0);
7640a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
7641a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
7642a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
7643a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CEntryStub::GenerateThrowTOS(MacroAssembler* masm) {
7644a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check that stack should contain next handler, frame pointer, state and
7645a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // return address in that order.
7646a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT_EQ(StackHandlerConstants::kFPOffset + kPointerSize,
7647a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block            StackHandlerConstants::kStateOffset);
7648a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT_EQ(StackHandlerConstants::kStateOffset + kPointerSize,
7649a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block            StackHandlerConstants::kPCOffset);
7650a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
7651a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ExternalReference handler_address(Top::k_handler_address);
7652a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ movq(kScratchRegister, handler_address);
7653a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ movq(rsp, Operand(kScratchRegister, 0));
7654a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // get next in chain
7655a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ pop(rcx);
7656a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ movq(Operand(kScratchRegister, 0), rcx);
7657a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ pop(rbp);  // pop frame pointer
7658a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ pop(rdx);  // remove state
7659a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
7660a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Before returning we restore the context from the frame pointer if not NULL.
7661a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // The frame pointer is NULL in the exception handler of a JS entry frame.
7662a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ xor_(rsi, rsi);  // tentatively set context pointer to NULL
7663a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Label skip;
7664a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ cmpq(rbp, Immediate(0));
7665a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(equal, &skip);
7666a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
7667a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&skip);
7668a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ ret(0);
7669a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
7670a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
7671a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
7672a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CEntryStub::GenerateCore(MacroAssembler* masm,
7673a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                              Label* throw_normal_exception,
7674a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                              Label* throw_termination_exception,
7675a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                              Label* throw_out_of_memory_exception,
7676a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                              bool do_gc,
7677a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                              bool always_allocate_scope) {
7678a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // rax: result parameter for PerformGC, if any.
7679a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // rbx: pointer to C function  (C callee-saved).
7680a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // rbp: frame pointer  (restored after C call).
7681a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // rsp: stack pointer  (restored after C call).
7682a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // r14: number of arguments including receiver (C callee-saved).
7683a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // r15: pointer to the first argument (C callee-saved).
7684a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //      This pointer is reused in LeaveExitFrame(), so it is stored in a
7685a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //      callee-saved register.
7686a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
76874515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  // Simple results returned in rax (both AMD64 and Win64 calling conventions).
76884515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  // Complex results must be written to address passed as first argument.
76894515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  // AMD64 calling convention: a struct of two pointers in rax+rdx
76904515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke
7691a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (do_gc) {
7692a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Pass failure code returned from last attempt as first argument to GC.
7693a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#ifdef _WIN64
7694a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ movq(rcx, rax);
7695a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#else  // ! defined(_WIN64)
7696a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ movq(rdi, rax);
7697a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#endif
7698a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ movq(kScratchRegister,
7699a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block            FUNCTION_ADDR(Runtime::PerformGC),
7700a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block            RelocInfo::RUNTIME_ENTRY);
7701a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ call(kScratchRegister);
7702a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
7703a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
7704a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ExternalReference scope_depth =
7705a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      ExternalReference::heap_always_allocate_scope_depth();
7706a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (always_allocate_scope) {
7707a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ movq(kScratchRegister, scope_depth);
7708a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ incl(Operand(kScratchRegister, 0));
7709a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
7710a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
7711a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Call C function.
7712a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#ifdef _WIN64
7713a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Windows 64-bit ABI passes arguments in rcx, rdx, r8, r9
7714a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Store Arguments object on stack, below the 4 WIN64 ABI parameter slots.
7715a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ movq(Operand(rsp, 4 * kPointerSize), r14);  // argc.
7716a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ movq(Operand(rsp, 5 * kPointerSize), r15);  // argv.
7717a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (result_size_ < 2) {
7718a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Pass a pointer to the Arguments object as the first argument.
7719a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Return result in single register (rax).
7720a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ lea(rcx, Operand(rsp, 4 * kPointerSize));
7721a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  } else {
7722a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    ASSERT_EQ(2, result_size_);
7723a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Pass a pointer to the result location as the first argument.
7724a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ lea(rcx, Operand(rsp, 6 * kPointerSize));
7725a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Pass a pointer to the Arguments object as the second argument.
7726a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ lea(rdx, Operand(rsp, 4 * kPointerSize));
7727a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
7728a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
7729a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#else  // ! defined(_WIN64)
7730a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // GCC passes arguments in rdi, rsi, rdx, rcx, r8, r9.
7731a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ movq(rdi, r14);  // argc.
7732a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ movq(rsi, r15);  // argv.
7733a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#endif
7734a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ call(rbx);
7735a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Result is in rax - do not destroy this register!
7736a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
7737a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (always_allocate_scope) {
7738a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ movq(kScratchRegister, scope_depth);
7739a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ decl(Operand(kScratchRegister, 0));
7740a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
7741a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
7742a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check for failure result.
7743a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Label failure_returned;
7744a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(((kFailureTag + 1) & kFailureTagMask) == 0);
77453ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block#ifdef _WIN64
77463ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // If return value is on the stack, pop it to registers.
77473ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  if (result_size_ > 1) {
77483ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    ASSERT_EQ(2, result_size_);
7749d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    // Read result values stored on stack. Result is stored
7750d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    // above the four argument mirror slots and the two
7751d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    // Arguments object slots.
77523ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    __ movq(rax, Operand(rsp, 6 * kPointerSize));
77533ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    __ movq(rdx, Operand(rsp, 7 * kPointerSize));
77543ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  }
77553ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block#endif
7756a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ lea(rcx, Operand(rax, 1));
7757a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Lower 2 bits of rcx are 0 iff rax has failure tag.
7758a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ testl(rcx, Immediate(kFailureTagMask));
7759a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(zero, &failure_returned);
7760a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
7761a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Exit the JavaScript to C++ exit frame.
77624515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ LeaveExitFrame(mode_, result_size_);
7763a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ ret(0);
7764a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
7765a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Handling of failure.
7766a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&failure_returned);
7767a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
7768a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Label retry;
7769a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // If the returned exception is RETRY_AFTER_GC continue at retry label
7770a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(Failure::RETRY_AFTER_GC == 0);
7771a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ testl(rax, Immediate(((1 << kFailureTypeTagSize) - 1) << kFailureTagSize));
7772a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(zero, &retry);
7773a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
7774a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Special handling of out of memory exceptions.
7775a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ movq(kScratchRegister, Failure::OutOfMemoryException(), RelocInfo::NONE);
7776a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ cmpq(rax, kScratchRegister);
7777a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(equal, throw_out_of_memory_exception);
7778a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
7779a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Retrieve the pending exception and clear the variable.
7780a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ExternalReference pending_exception_address(Top::k_pending_exception_address);
7781a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ movq(kScratchRegister, pending_exception_address);
7782a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ movq(rax, Operand(kScratchRegister, 0));
7783a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ movq(rdx, ExternalReference::the_hole_value_location());
7784a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ movq(rdx, Operand(rdx, 0));
7785a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ movq(Operand(kScratchRegister, 0), rdx);
7786a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
7787a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Special handling of termination exceptions which are uncatchable
7788a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // by javascript code.
7789a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ CompareRoot(rax, Heap::kTerminationExceptionRootIndex);
7790a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(equal, throw_termination_exception);
7791a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
7792a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Handle normal exception.
7793a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ jmp(throw_normal_exception);
7794a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
7795a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Retry.
7796a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&retry);
7797a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
7798a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
7799a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
7800a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CEntryStub::GenerateThrowUncatchable(MacroAssembler* masm,
7801a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                          UncatchableExceptionType type) {
7802a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Fetch top stack handler.
7803a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ExternalReference handler_address(Top::k_handler_address);
7804a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ movq(kScratchRegister, handler_address);
7805a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ movq(rsp, Operand(kScratchRegister, 0));
7806a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
7807a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Unwind the handlers until the ENTRY handler is found.
7808a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Label loop, done;
7809a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&loop);
7810a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Load the type of the current stack handler.
7811a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  const int kStateOffset = StackHandlerConstants::kStateOffset;
7812a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ cmpq(Operand(rsp, kStateOffset), Immediate(StackHandler::ENTRY));
7813a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(equal, &done);
7814a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Fetch the next handler in the list.
7815a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  const int kNextOffset = StackHandlerConstants::kNextOffset;
7816a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ movq(rsp, Operand(rsp, kNextOffset));
7817a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ jmp(&loop);
7818a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&done);
7819a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
7820a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Set the top handler address to next handler past the current ENTRY handler.
7821a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ movq(kScratchRegister, handler_address);
7822a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ pop(Operand(kScratchRegister, 0));
7823a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
7824a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (type == OUT_OF_MEMORY) {
7825a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Set external caught exception to false.
7826a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    ExternalReference external_caught(Top::k_external_caught_exception_address);
7827a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ movq(rax, Immediate(false));
7828a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ store_rax(external_caught);
7829a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
7830a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Set pending exception and rax to out of memory exception.
7831a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    ExternalReference pending_exception(Top::k_pending_exception_address);
7832a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ movq(rax, Failure::OutOfMemoryException(), RelocInfo::NONE);
7833a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ store_rax(pending_exception);
7834a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
7835a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
7836a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Clear the context pointer.
7837a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ xor_(rsi, rsi);
7838a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
7839a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Restore registers from handler.
7840a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT_EQ(StackHandlerConstants::kNextOffset + kPointerSize,
7841a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block            StackHandlerConstants::kFPOffset);
7842a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ pop(rbp);  // FP
7843a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT_EQ(StackHandlerConstants::kFPOffset + kPointerSize,
7844a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block            StackHandlerConstants::kStateOffset);
7845a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ pop(rdx);  // State
7846a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
7847a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT_EQ(StackHandlerConstants::kStateOffset + kPointerSize,
7848a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block            StackHandlerConstants::kPCOffset);
7849a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ ret(0);
7850a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
7851a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
7852a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
7853a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CallFunctionStub::Generate(MacroAssembler* masm) {
7854a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Label slow;
7855a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
7856e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // If the receiver might be a value (string, number or boolean) check for this
7857e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // and box it if it is.
7858e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  if (ReceiverMightBeValue()) {
7859e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke    // Get the receiver from the stack.
7860e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke    // +1 ~ return address
7861e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke    Label receiver_is_value, receiver_is_js_object;
7862e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke    __ movq(rax, Operand(rsp, (argc_ + 1) * kPointerSize));
7863e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
7864e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke    // Check if receiver is a smi (which is a number value).
7865e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke    __ JumpIfSmi(rax, &receiver_is_value);
7866e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
7867e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke    // Check if the receiver is a valid JS object.
7868e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke    __ CmpObjectType(rax, FIRST_JS_OBJECT_TYPE, rdi);
7869e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke    __ j(above_equal, &receiver_is_js_object);
7870e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
7871e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke    // Call the runtime to box the value.
7872e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke    __ bind(&receiver_is_value);
7873e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke    __ EnterInternalFrame();
7874e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke    __ push(rax);
7875e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke    __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
7876e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke    __ LeaveInternalFrame();
7877e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke    __ movq(Operand(rsp, (argc_ + 1) * kPointerSize), rax);
7878e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
7879e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke    __ bind(&receiver_is_js_object);
7880e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  }
7881e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
7882a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Get the function to call from the stack.
7883a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // +2 ~ receiver, return address
7884a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ movq(rdi, Operand(rsp, (argc_ + 2) * kPointerSize));
7885a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
7886a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check that the function really is a JavaScript function.
7887a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ JumpIfSmi(rdi, &slow);
7888a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Goto slow case if we do not have a function.
7889a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ CmpObjectType(rdi, JS_FUNCTION_TYPE, rcx);
7890a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(not_equal, &slow);
7891a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
7892a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Fast-case: Just invoke the function.
7893a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ParameterCount actual(argc_);
7894a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ InvokeFunction(rdi, actual, JUMP_FUNCTION);
7895a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
7896a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Slow-case: Non-function called.
7897a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&slow);
7898402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // CALL_NON_FUNCTION expects the non-function callee as receiver (instead
7899402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // of the original receiver from the call site).
7900402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ movq(Operand(rsp, (argc_ + 1) * kPointerSize), rdi);
7901a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ Set(rax, argc_);
7902a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ Set(rbx, 0);
7903a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ GetBuiltinEntry(rdx, Builtins::CALL_NON_FUNCTION);
7904a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Handle<Code> adaptor(Builtins::builtin(Builtins::ArgumentsAdaptorTrampoline));
7905a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ Jump(adaptor, RelocInfo::CODE_TARGET);
7906a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
7907a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
7908a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
79094515c472dc3e5ed2448a564600976759e569a0a8Leon Clarkevoid CEntryStub::Generate(MacroAssembler* masm) {
7910a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // rax: number of arguments including receiver
7911a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // rbx: pointer to C function  (C callee-saved)
7912a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // rbp: frame pointer of calling JS frame (restored after C call)
7913a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // rsp: stack pointer  (restored after C call)
7914a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // rsi: current context (restored)
7915a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
7916a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // NOTE: Invocations of builtins may return failure objects
7917a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // instead of a proper result. The builtin entry handles
7918a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // this by performing a garbage collection and retrying the
7919a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // builtin once.
7920a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
7921a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Enter the exit frame that transitions from JavaScript to C++.
79224515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ EnterExitFrame(mode_, result_size_);
7923a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
7924a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // rax: Holds the context at this point, but should not be used.
7925a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //      On entry to code generated by GenerateCore, it must hold
7926a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //      a failure result if the collect_garbage argument to GenerateCore
7927a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //      is true.  This failure result can be the result of code
7928a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //      generated by a previous call to GenerateCore.  The value
7929a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //      of rax is then passed to Runtime::PerformGC.
7930a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // rbx: pointer to builtin function  (C callee-saved).
7931a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // rbp: frame pointer of exit frame  (restored after C call).
7932a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // rsp: stack pointer (restored after C call).
7933a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // r14: number of arguments including receiver (C callee-saved).
7934a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // r15: argv pointer (C callee-saved).
7935a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
7936a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Label throw_normal_exception;
7937a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Label throw_termination_exception;
7938a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Label throw_out_of_memory_exception;
7939a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
7940a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Call into the runtime system.
7941a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  GenerateCore(masm,
7942a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block               &throw_normal_exception,
7943a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block               &throw_termination_exception,
7944a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block               &throw_out_of_memory_exception,
7945a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block               false,
7946a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block               false);
7947a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
7948a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Do space-specific GC and retry runtime call.
7949a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  GenerateCore(masm,
7950a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block               &throw_normal_exception,
7951a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block               &throw_termination_exception,
7952a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block               &throw_out_of_memory_exception,
7953a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block               true,
7954a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block               false);
7955a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
7956a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Do full GC and retry runtime call one final time.
7957a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Failure* failure = Failure::InternalError();
7958a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ movq(rax, failure, RelocInfo::NONE);
7959a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  GenerateCore(masm,
7960a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block               &throw_normal_exception,
7961a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block               &throw_termination_exception,
7962a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block               &throw_out_of_memory_exception,
7963a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block               true,
7964a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block               true);
7965a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
7966a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&throw_out_of_memory_exception);
7967a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  GenerateThrowUncatchable(masm, OUT_OF_MEMORY);
7968a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
7969a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&throw_termination_exception);
7970a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  GenerateThrowUncatchable(masm, TERMINATION);
7971a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
7972a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&throw_normal_exception);
7973a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  GenerateThrowTOS(masm);
7974a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
7975a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
7976a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
7977d0582a6c46733687d045e4188a1bcd0123c758a1Steve Blockvoid ApiGetterEntryStub::Generate(MacroAssembler* masm) {
7978d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  UNREACHABLE();
7979d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block}
7980d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
7981d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
7982a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid JSEntryStub::GenerateBody(MacroAssembler* masm, bool is_construct) {
7983a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Label invoke, exit;
7984a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#ifdef ENABLE_LOGGING_AND_PROFILING
7985a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Label not_outermost_js, not_outermost_js_2;
7986a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#endif
7987a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
7988a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Setup frame.
7989a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ push(rbp);
7990a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ movq(rbp, rsp);
7991a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
7992a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Push the stack frame type marker twice.
7993a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  int marker = is_construct ? StackFrame::ENTRY_CONSTRUCT : StackFrame::ENTRY;
79943ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  __ Push(Smi::FromInt(marker));  // context slot
79953ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  __ Push(Smi::FromInt(marker));  // function slot
7996a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Save callee-saved registers (X64 calling conventions).
7997a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ push(r12);
7998a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ push(r13);
7999a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ push(r14);
8000a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ push(r15);
8001a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ push(rdi);
8002a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ push(rsi);
8003a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ push(rbx);
8004a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // TODO(X64): Push XMM6-XMM15 (low 64 bits) as well, or make them
8005a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // callee-save in JS code as well.
8006a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
8007a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Save copies of the top frame descriptor on the stack.
8008a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ExternalReference c_entry_fp(Top::k_c_entry_fp_address);
8009a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ load_rax(c_entry_fp);
8010a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ push(rax);
8011a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
8012a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#ifdef ENABLE_LOGGING_AND_PROFILING
8013a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // If this is the outermost JS call, set js_entry_sp value.
8014a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ExternalReference js_entry_sp(Top::k_js_entry_sp_address);
8015a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ load_rax(js_entry_sp);
8016a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ testq(rax, rax);
8017a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(not_zero, &not_outermost_js);
8018a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ movq(rax, rbp);
8019a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ store_rax(js_entry_sp);
8020a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&not_outermost_js);
8021a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#endif
8022a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
8023a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Call a faked try-block that does the invoke.
8024a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ call(&invoke);
8025a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
8026a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Caught exception: Store result (exception) in the pending
8027a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // exception field in the JSEnv and return a failure sentinel.
8028a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ExternalReference pending_exception(Top::k_pending_exception_address);
8029a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ store_rax(pending_exception);
8030a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ movq(rax, Failure::Exception(), RelocInfo::NONE);
8031a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ jmp(&exit);
8032a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
8033a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Invoke: Link this frame into the handler chain.
8034a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&invoke);
8035a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ PushTryHandler(IN_JS_ENTRY, JS_ENTRY_HANDLER);
8036a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
8037a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Clear any pending exceptions.
8038a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ load_rax(ExternalReference::the_hole_value_location());
8039a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ store_rax(pending_exception);
8040a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
8041a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Fake a receiver (NULL).
8042a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ push(Immediate(0));  // receiver
8043a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
8044a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Invoke the function by calling through JS entry trampoline
8045a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // builtin and pop the faked function when we return. We load the address
8046a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // from an external reference instead of inlining the call target address
8047a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // directly in the code, because the builtin stubs may not have been
8048a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // generated yet at the time this code is generated.
8049a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (is_construct) {
8050a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    ExternalReference construct_entry(Builtins::JSConstructEntryTrampoline);
8051a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ load_rax(construct_entry);
8052a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  } else {
8053a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    ExternalReference entry(Builtins::JSEntryTrampoline);
8054a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ load_rax(entry);
8055a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
8056a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ lea(kScratchRegister, FieldOperand(rax, Code::kHeaderSize));
8057a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ call(kScratchRegister);
8058a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
8059a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Unlink this frame from the handler chain.
8060a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ movq(kScratchRegister, ExternalReference(Top::k_handler_address));
8061a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ pop(Operand(kScratchRegister, 0));
8062a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Pop next_sp.
8063a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ addq(rsp, Immediate(StackHandlerConstants::kSize - kPointerSize));
8064a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
8065a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#ifdef ENABLE_LOGGING_AND_PROFILING
8066a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // If current EBP value is the same as js_entry_sp value, it means that
8067a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // the current function is the outermost.
8068a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ movq(kScratchRegister, js_entry_sp);
8069a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ cmpq(rbp, Operand(kScratchRegister, 0));
8070a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(not_equal, &not_outermost_js_2);
8071a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ movq(Operand(kScratchRegister, 0), Immediate(0));
8072a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&not_outermost_js_2);
8073a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#endif
8074a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
8075a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Restore the top frame descriptor from the stack.
8076a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&exit);
8077a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ movq(kScratchRegister, ExternalReference(Top::k_c_entry_fp_address));
8078a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ pop(Operand(kScratchRegister, 0));
8079a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
8080a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Restore callee-saved registers (X64 conventions).
8081a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ pop(rbx);
8082a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ pop(rsi);
8083a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ pop(rdi);
8084a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ pop(r15);
8085a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ pop(r14);
8086a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ pop(r13);
8087a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ pop(r12);
8088a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ addq(rsp, Immediate(2 * kPointerSize));  // remove markers
8089a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
8090a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Restore frame pointer and return.
8091a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ pop(rbp);
8092a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ ret(0);
8093a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
8094a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
8095a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
8096a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// -----------------------------------------------------------------------------
8097a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// Implementation of stubs.
8098a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
8099a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block//  Stub classes have public member named masm, not masm_.
8100a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
8101a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid StackCheckStub::Generate(MacroAssembler* masm) {
8102a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Because builtins always remove the receiver from the stack, we
8103a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // have to fake one to avoid underflowing the stack. The receiver
8104a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // must be inserted below the return address on the stack so we
8105a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // temporarily store that in a register.
8106a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ pop(rax);
81073ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  __ Push(Smi::FromInt(0));
8108a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ push(rax);
8109a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
8110a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Do tail-call to runtime routine.
8111a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Runtime::Function* f = Runtime::FunctionForId(Runtime::kStackGuard);
8112a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ TailCallRuntime(ExternalReference(f), 1, f->result_size);
8113a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
8114a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
8115a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
8116a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid FloatingPointHelper::LoadFloatOperand(MacroAssembler* masm,
8117a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                           Register number) {
8118a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Label load_smi, done;
8119a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
8120a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ JumpIfSmi(number, &load_smi);
8121a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ fld_d(FieldOperand(number, HeapNumber::kValueOffset));
8122a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ jmp(&done);
8123a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
8124a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&load_smi);
8125a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ SmiToInteger32(number, number);
8126a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ push(number);
8127a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ fild_s(Operand(rsp, 0));
8128a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ pop(number);
8129a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
8130a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&done);
8131a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
8132a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
8133a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
8134a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid FloatingPointHelper::LoadFloatOperand(MacroAssembler* masm,
8135a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                           Register src,
8136a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                           XMMRegister dst) {
8137a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Label load_smi, done;
8138a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
8139a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ JumpIfSmi(src, &load_smi);
8140a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ movsd(dst, FieldOperand(src, HeapNumber::kValueOffset));
8141a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ jmp(&done);
8142a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
8143a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&load_smi);
8144a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ SmiToInteger32(src, src);
8145a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ cvtlsi2sd(dst, src);
8146a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
8147a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&done);
8148a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
8149a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
8150a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
8151a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid FloatingPointHelper::LoadFloatOperands(MacroAssembler* masm,
8152a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                            XMMRegister dst1,
8153a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                            XMMRegister dst2) {
81544515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ movq(kScratchRegister, rdx);
8155a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  LoadFloatOperand(masm, kScratchRegister, dst1);
81564515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ movq(kScratchRegister, rax);
8157a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  LoadFloatOperand(masm, kScratchRegister, dst2);
8158a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
8159a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
8160a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
81614515c472dc3e5ed2448a564600976759e569a0a8Leon Clarkevoid FloatingPointHelper::LoadFloatOperandsFromSmis(MacroAssembler* masm,
81624515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke                                                    XMMRegister dst1,
81634515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke                                                    XMMRegister dst2) {
81644515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ SmiToInteger32(kScratchRegister, rdx);
81654515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ cvtlsi2sd(dst1, kScratchRegister);
81664515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ SmiToInteger32(kScratchRegister, rax);
81674515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ cvtlsi2sd(dst2, kScratchRegister);
8168a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
8169a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
8170a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
8171d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke// Input: rdx, rax are the left and right objects of a bit op.
8172d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke// Output: rax, rcx are left and right integers for a bit op.
8173d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarkevoid FloatingPointHelper::LoadAsIntegers(MacroAssembler* masm,
8174d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke                                         bool use_sse3,
8175d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke                                         Label* conversion_failure) {
8176d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  // Check float operands.
8177d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  Label arg1_is_object, check_undefined_arg1;
8178d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  Label arg2_is_object, check_undefined_arg2;
8179d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  Label load_arg2, done;
8180d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke
8181d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  __ JumpIfNotSmi(rdx, &arg1_is_object);
8182d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  __ SmiToInteger32(rdx, rdx);
8183d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  __ jmp(&load_arg2);
8184d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke
8185d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  // If the argument is undefined it converts to zero (ECMA-262, section 9.5).
8186d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  __ bind(&check_undefined_arg1);
8187d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  __ CompareRoot(rdx, Heap::kUndefinedValueRootIndex);
8188d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  __ j(not_equal, conversion_failure);
8189d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  __ movl(rdx, Immediate(0));
8190d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  __ jmp(&load_arg2);
8191d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke
8192d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  __ bind(&arg1_is_object);
8193d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  __ movq(rbx, FieldOperand(rdx, HeapObject::kMapOffset));
8194d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  __ CompareRoot(rbx, Heap::kHeapNumberMapRootIndex);
8195d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  __ j(not_equal, &check_undefined_arg1);
8196d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  // Get the untagged integer version of the edx heap number in rcx.
8197d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  IntegerConvert(masm, rdx, use_sse3, conversion_failure);
8198d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  __ movl(rdx, rcx);
8199d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke
8200d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  // Here edx has the untagged integer, eax has a Smi or a heap number.
8201d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  __ bind(&load_arg2);
8202d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  // Test if arg2 is a Smi.
8203d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  __ JumpIfNotSmi(rax, &arg2_is_object);
8204d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  __ SmiToInteger32(rax, rax);
8205d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  __ movl(rcx, rax);
8206d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  __ jmp(&done);
8207d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke
8208d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  // If the argument is undefined it converts to zero (ECMA-262, section 9.5).
8209d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  __ bind(&check_undefined_arg2);
8210d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  __ CompareRoot(rax, Heap::kUndefinedValueRootIndex);
8211d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  __ j(not_equal, conversion_failure);
8212d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  __ movl(rcx, Immediate(0));
8213d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  __ jmp(&done);
8214d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke
8215d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  __ bind(&arg2_is_object);
8216d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  __ movq(rbx, FieldOperand(rax, HeapObject::kMapOffset));
8217d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  __ CompareRoot(rbx, Heap::kHeapNumberMapRootIndex);
8218d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  __ j(not_equal, &check_undefined_arg2);
8219d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  // Get the untagged integer version of the eax heap number in ecx.
8220d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  IntegerConvert(masm, rax, use_sse3, conversion_failure);
8221d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  __ bind(&done);
8222d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  __ movl(rax, rdx);
8223d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke}
8224d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke
8225d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke
8226a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid FloatingPointHelper::LoadFloatOperands(MacroAssembler* masm,
8227a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                            Register lhs,
8228a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                            Register rhs) {
8229a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Label load_smi_lhs, load_smi_rhs, done_load_lhs, done;
8230a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ JumpIfSmi(lhs, &load_smi_lhs);
8231a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ fld_d(FieldOperand(lhs, HeapNumber::kValueOffset));
8232a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&done_load_lhs);
8233a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
8234a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ JumpIfSmi(rhs, &load_smi_rhs);
8235a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ fld_d(FieldOperand(rhs, HeapNumber::kValueOffset));
8236a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ jmp(&done);
8237a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
8238a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&load_smi_lhs);
8239a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ SmiToInteger64(kScratchRegister, lhs);
8240a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ push(kScratchRegister);
8241a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ fild_d(Operand(rsp, 0));
8242a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ pop(kScratchRegister);
8243a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ jmp(&done_load_lhs);
8244a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
8245a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&load_smi_rhs);
8246a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ SmiToInteger64(kScratchRegister, rhs);
8247a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ push(kScratchRegister);
8248a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ fild_d(Operand(rsp, 0));
8249a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ pop(kScratchRegister);
8250a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
8251a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&done);
8252a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
8253a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
8254a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
82553ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Blockvoid FloatingPointHelper::CheckNumberOperands(MacroAssembler* masm,
82563ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block                                              Label* non_float) {
8257a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Label test_other, done;
8258a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Test if both operands are numbers (heap_numbers or smis).
8259a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // If not, jump to label non_float.
8260a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ JumpIfSmi(rdx, &test_other);  // argument in rdx is OK
8261a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ Cmp(FieldOperand(rdx, HeapObject::kMapOffset), Factory::heap_number_map());
8262a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(not_equal, non_float);  // The argument in rdx is not a number.
8263a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
8264a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&test_other);
8265a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ JumpIfSmi(rax, &done);  // argument in rax is OK
8266a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ Cmp(FieldOperand(rax, HeapObject::kMapOffset), Factory::heap_number_map());
8267a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(not_equal, non_float);  // The argument in rax is not a number.
8268a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
8269a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Fall-through: Both operands are numbers.
8270a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&done);
8271a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
8272a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
8273a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
8274a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockconst char* GenericBinaryOpStub::GetName() {
8275e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  if (name_ != NULL) return name_;
8276e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  const int len = 100;
8277e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  name_ = Bootstrapper::AllocateAutoDeletedArray(len);
8278e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  if (name_ == NULL) return "OOM";
8279e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  const char* op_name = Token::Name(op_);
8280e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  const char* overwrite_name;
8281e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  switch (mode_) {
8282e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke    case NO_OVERWRITE: overwrite_name = "Alloc"; break;
8283e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke    case OVERWRITE_RIGHT: overwrite_name = "OverwriteRight"; break;
8284e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke    case OVERWRITE_LEFT: overwrite_name = "OverwriteLeft"; break;
8285e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke    default: overwrite_name = "UnknownOverwrite"; break;
8286e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  }
8287e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
8288e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  OS::SNPrintF(Vector<char>(name_, len),
8289402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu               "GenericBinaryOpStub_%s_%s%s_%s%s_%s%s",
8290e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke               op_name,
8291e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke               overwrite_name,
8292e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke               (flags_ & NO_SMI_CODE_IN_STUB) ? "_NoSmiInStub" : "",
8293e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke               args_in_registers_ ? "RegArgs" : "StackArgs",
8294e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke               args_reversed_ ? "_R" : "",
8295402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu               use_sse3_ ? "SSE3" : "SSE2",
8296402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu               NumberInfo::ToString(operands_type_));
8297e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  return name_;
8298a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
8299a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
8300a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
8301d0582a6c46733687d045e4188a1bcd0123c758a1Steve Blockvoid GenericBinaryOpStub::GenerateCall(
8302d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    MacroAssembler* masm,
8303d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    Register left,
8304d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    Register right) {
8305d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  if (!ArgsInRegistersSupported()) {
8306d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    // Pass arguments on the stack.
8307d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    __ push(left);
8308d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    __ push(right);
8309d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  } else {
8310d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    // The calling convention with registers is left in rdx and right in rax.
8311d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    Register left_arg = rdx;
8312d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    Register right_arg = rax;
8313d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    if (!(left.is(left_arg) && right.is(right_arg))) {
8314d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block      if (left.is(right_arg) && right.is(left_arg)) {
8315d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block        if (IsOperationCommutative()) {
8316d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block          SetArgsReversed();
8317d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block        } else {
8318d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block          __ xchg(left, right);
8319d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block        }
8320d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block      } else if (left.is(left_arg)) {
8321d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block        __ movq(right_arg, right);
8322402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu      } else if (right.is(right_arg)) {
8323402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu        __ movq(left_arg, left);
8324d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block      } else if (left.is(right_arg)) {
8325d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block        if (IsOperationCommutative()) {
8326d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block          __ movq(left_arg, right);
8327d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block          SetArgsReversed();
8328d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block        } else {
8329d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block          // Order of moves important to avoid destroying left argument.
8330d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block          __ movq(left_arg, left);
8331d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block          __ movq(right_arg, right);
8332d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block        }
8333d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block      } else if (right.is(left_arg)) {
8334d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block        if (IsOperationCommutative()) {
8335d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block          __ movq(right_arg, left);
8336d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block          SetArgsReversed();
8337d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block        } else {
8338d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block          // Order of moves important to avoid destroying right argument.
8339d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block          __ movq(right_arg, right);
8340d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block          __ movq(left_arg, left);
8341d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block        }
8342d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block      } else {
8343d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block        // Order of moves is not important.
8344d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block        __ movq(left_arg, left);
8345d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block        __ movq(right_arg, right);
8346d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block      }
8347d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    }
8348d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
8349d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    // Update flags to indicate that arguments are in registers.
8350d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    SetArgsInRegisters();
8351d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    __ IncrementCounter(&Counters::generic_binary_stub_calls_regs, 1);
8352d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  }
8353d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
8354d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  // Call the stub.
8355d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  __ CallStub(this);
8356d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block}
8357d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
8358d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
8359d0582a6c46733687d045e4188a1bcd0123c758a1Steve Blockvoid GenericBinaryOpStub::GenerateCall(
8360d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    MacroAssembler* masm,
8361d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    Register left,
8362d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    Smi* right) {
8363d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  if (!ArgsInRegistersSupported()) {
8364d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    // Pass arguments on the stack.
8365d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    __ push(left);
8366d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    __ Push(right);
8367d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  } else {
8368d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    // The calling convention with registers is left in rdx and right in rax.
8369d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    Register left_arg = rdx;
8370d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    Register right_arg = rax;
8371d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    if (left.is(left_arg)) {
8372d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block      __ Move(right_arg, right);
8373d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    } else if (left.is(right_arg) && IsOperationCommutative()) {
8374d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block      __ Move(left_arg, right);
8375d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block      SetArgsReversed();
8376d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    } else {
8377402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu      // For non-commutative operations, left and right_arg might be
8378402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu      // the same register.  Therefore, the order of the moves is
8379402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu      // important here in order to not overwrite left before moving
8380402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu      // it to left_arg.
8381d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block      __ movq(left_arg, left);
8382d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block      __ Move(right_arg, right);
8383d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    }
8384d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
8385d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    // Update flags to indicate that arguments are in registers.
8386d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    SetArgsInRegisters();
8387d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    __ IncrementCounter(&Counters::generic_binary_stub_calls_regs, 1);
8388d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  }
8389d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
8390d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  // Call the stub.
8391d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  __ CallStub(this);
8392d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block}
8393d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
8394d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
8395d0582a6c46733687d045e4188a1bcd0123c758a1Steve Blockvoid GenericBinaryOpStub::GenerateCall(
8396d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    MacroAssembler* masm,
8397d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    Smi* left,
8398d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    Register right) {
8399d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  if (!ArgsInRegistersSupported()) {
8400d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    // Pass arguments on the stack.
8401d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    __ Push(left);
8402d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    __ push(right);
8403d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  } else {
8404d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    // The calling convention with registers is left in rdx and right in rax.
8405d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    Register left_arg = rdx;
8406d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    Register right_arg = rax;
8407d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    if (right.is(right_arg)) {
8408d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block      __ Move(left_arg, left);
8409d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    } else if (right.is(left_arg) && IsOperationCommutative()) {
8410d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block      __ Move(right_arg, left);
8411d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block      SetArgsReversed();
8412d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    } else {
8413402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu      // For non-commutative operations, right and left_arg might be
8414402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu      // the same register.  Therefore, the order of the moves is
8415402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu      // important here in order to not overwrite right before moving
8416402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu      // it to right_arg.
8417d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block      __ movq(right_arg, right);
8418402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu      __ Move(left_arg, left);
8419d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    }
8420d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    // Update flags to indicate that arguments are in registers.
8421d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    SetArgsInRegisters();
8422d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    __ IncrementCounter(&Counters::generic_binary_stub_calls_regs, 1);
8423d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  }
8424d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
8425d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  // Call the stub.
8426d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  __ CallStub(this);
8427d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block}
8428d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
8429d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
84304515c472dc3e5ed2448a564600976759e569a0a8Leon ClarkeResult GenericBinaryOpStub::GenerateCall(MacroAssembler* masm,
84314515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke                                         VirtualFrame* frame,
84324515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke                                         Result* left,
84334515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke                                         Result* right) {
84344515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  if (ArgsInRegistersSupported()) {
84354515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke    SetArgsInRegisters();
84364515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke    return frame->CallStub(this, left, right);
84374515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  } else {
84384515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke    frame->Push(left);
84394515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke    frame->Push(right);
84404515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke    return frame->CallStub(this, 2);
84414515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  }
84424515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke}
84434515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke
84444515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke
8445a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid GenericBinaryOpStub::GenerateSmiCode(MacroAssembler* masm, Label* slow) {
84464515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  // 1. Move arguments into edx, eax except for DIV and MOD, which need the
84474515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  // dividend in eax and edx free for the division.  Use eax, ebx for those.
84484515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  Comment load_comment(masm, "-- Load arguments");
84494515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  Register left = rdx;
84504515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  Register right = rax;
84514515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  if (op_ == Token::DIV || op_ == Token::MOD) {
84524515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke    left = rax;
84534515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke    right = rbx;
84544515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke    if (HasArgsInRegisters()) {
84554515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke      __ movq(rbx, rax);
84564515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke      __ movq(rax, rdx);
84574515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke    }
84584515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  }
84594515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  if (!HasArgsInRegisters()) {
84604515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke    __ movq(right, Operand(rsp, 1 * kPointerSize));
84614515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke    __ movq(left, Operand(rsp, 2 * kPointerSize));
84624515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  }
8463a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
84644515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  // 2. Smi check both operands. Skip the check for OR as it is better combined
84654515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  // with the actual operation.
84664515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  Label not_smis;
84674515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  if (op_ != Token::BIT_OR) {
84684515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke    Comment smi_check_comment(masm, "-- Smi check arguments");
84694515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke    __ JumpIfNotBothSmi(left, right, &not_smis);
84704515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  }
8471a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
84724515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  // 3. Operands are both smis (except for OR), perform the operation leaving
84734515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  // the result in rax and check the result if necessary.
84744515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  Comment perform_smi(masm, "-- Perform smi operation");
84754515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  Label use_fp_on_smis;
8476a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  switch (op_) {
8477a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    case Token::ADD: {
84784515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke      ASSERT(right.is(rax));
84794515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke      __ SmiAdd(right, right, left, &use_fp_on_smis);  // ADD is commutative.
8480a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      break;
8481a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
8482a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
8483a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    case Token::SUB: {
84844515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke      __ SmiSub(left, left, right, &use_fp_on_smis);
84854515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke      __ movq(rax, left);
8486a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      break;
8487a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
8488a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
8489a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    case Token::MUL:
84904515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke      ASSERT(right.is(rax));
84914515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke      __ SmiMul(right, right, left, &use_fp_on_smis);  // MUL is commutative.
8492a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      break;
8493a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
8494a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    case Token::DIV:
84954515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke      ASSERT(left.is(rax));
84964515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke      __ SmiDiv(left, left, right, &use_fp_on_smis);
8497a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      break;
8498a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
8499a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    case Token::MOD:
85004515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke      ASSERT(left.is(rax));
85014515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke      __ SmiMod(left, left, right, slow);
8502a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      break;
8503a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
8504a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    case Token::BIT_OR:
85054515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke      ASSERT(right.is(rax));
85064515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke      __ movq(rcx, right);  // Save the right operand.
85074515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke      __ SmiOr(right, right, left);  // BIT_OR is commutative.
85084515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke      __ testb(right, Immediate(kSmiTagMask));
85094515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke      __ j(not_zero, &not_smis);
8510a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      break;
8511a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
8512a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    case Token::BIT_AND:
85134515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke      ASSERT(right.is(rax));
85144515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke      __ SmiAnd(right, right, left);  // BIT_AND is commutative.
8515a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      break;
8516a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
8517a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    case Token::BIT_XOR:
85184515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke      ASSERT(right.is(rax));
85194515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke      __ SmiXor(right, right, left);  // BIT_XOR is commutative.
8520a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      break;
8521a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
8522a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    case Token::SHL:
8523a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    case Token::SHR:
8524a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    case Token::SAR:
8525a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      switch (op_) {
8526a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        case Token::SAR:
85274515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke          __ SmiShiftArithmeticRight(left, left, right);
8528a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block          break;
8529a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        case Token::SHR:
85304515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke          __ SmiShiftLogicalRight(left, left, right, slow);
8531a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block          break;
8532a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        case Token::SHL:
85334515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke          __ SmiShiftLeft(left, left, right, slow);
8534a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block          break;
8535a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        default:
8536a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block          UNREACHABLE();
8537a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      }
85384515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke      __ movq(rax, left);
8539a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      break;
8540a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
8541a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    default:
8542a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      UNREACHABLE();
8543a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      break;
8544a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
85454515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke
85464515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  // 4. Emit return of result in eax.
85474515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  GenerateReturn(masm);
85484515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke
85494515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  // 5. For some operations emit inline code to perform floating point
85504515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  // operations on known smis (e.g., if the result of the operation
85514515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  // overflowed the smi range).
85524515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  switch (op_) {
85534515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke    case Token::ADD:
85544515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke    case Token::SUB:
85554515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke    case Token::MUL:
85564515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke    case Token::DIV: {
85574515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke      __ bind(&use_fp_on_smis);
85584515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke      if (op_ == Token::DIV) {
85594515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke        __ movq(rdx, rax);
85604515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke        __ movq(rax, rbx);
85614515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke      }
85624515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke      // left is rdx, right is rax.
85634515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke      __ AllocateHeapNumber(rbx, rcx, slow);
85644515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke      FloatingPointHelper::LoadFloatOperandsFromSmis(masm, xmm4, xmm5);
85654515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke      switch (op_) {
85664515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke        case Token::ADD: __ addsd(xmm4, xmm5); break;
85674515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke        case Token::SUB: __ subsd(xmm4, xmm5); break;
85684515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke        case Token::MUL: __ mulsd(xmm4, xmm5); break;
85694515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke        case Token::DIV: __ divsd(xmm4, xmm5); break;
85704515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke        default: UNREACHABLE();
85714515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke      }
85724515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke      __ movsd(FieldOperand(rbx, HeapNumber::kValueOffset), xmm4);
85734515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke      __ movq(rax, rbx);
85744515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke      GenerateReturn(masm);
85754515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke    }
85764515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke    default:
85774515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke      break;
85784515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  }
85794515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke
85804515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  // 6. Non-smi operands, fall out to the non-smi code with the operands in
85814515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  // rdx and rax.
85824515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  Comment done_comment(masm, "-- Enter non-smi code");
85834515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ bind(&not_smis);
85844515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke
85854515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  switch (op_) {
85864515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke    case Token::DIV:
85874515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke    case Token::MOD:
85884515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke      // Operands are in rax, rbx at this point.
85894515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke      __ movq(rdx, rax);
85904515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke      __ movq(rax, rbx);
85914515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke      break;
85924515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke
85934515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke    case Token::BIT_OR:
85944515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke      // Right operand is saved in rcx and rax was destroyed by the smi
85954515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke      // operation.
85964515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke      __ movq(rax, rcx);
85974515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke      break;
85984515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke
85994515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke    default:
86004515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke      break;
86014515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  }
8602a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
8603a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
8604a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
8605a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid GenericBinaryOpStub::Generate(MacroAssembler* masm) {
8606a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Label call_runtime;
8607d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  if (HasSmiCodeInStub()) {
86084515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke    GenerateSmiCode(masm, &call_runtime);
86094515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  } else if (op_ != Token::MOD) {
86104515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke    GenerateLoadArguments(masm);
8611a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
8612a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Floating point case.
8613a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  switch (op_) {
8614a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    case Token::ADD:
8615a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    case Token::SUB:
8616a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    case Token::MUL:
8617a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    case Token::DIV: {
8618a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // rax: y
8619a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // rdx: x
8620402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu      if (NumberInfo::IsNumber(operands_type_)) {
8621402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu        if (FLAG_debug_code) {
8622402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu          // Assert at runtime that inputs are only numbers.
8623402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu          __ AbortIfNotNumber(rdx, "GenericBinaryOpStub operand not a number.");
8624402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu          __ AbortIfNotNumber(rax, "GenericBinaryOpStub operand not a number.");
8625402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu        }
8626402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu      } else {
8627402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu        FloatingPointHelper::CheckNumberOperands(masm, &call_runtime);
8628402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu      }
8629a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // Fast-case: Both operands are numbers.
86304515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke      // xmm4 and xmm5 are volatile XMM registers.
86314515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke      FloatingPointHelper::LoadFloatOperands(masm, xmm4, xmm5);
86324515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke
86334515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke      switch (op_) {
86344515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke        case Token::ADD: __ addsd(xmm4, xmm5); break;
86354515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke        case Token::SUB: __ subsd(xmm4, xmm5); break;
86364515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke        case Token::MUL: __ mulsd(xmm4, xmm5); break;
86374515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke        case Token::DIV: __ divsd(xmm4, xmm5); break;
86384515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke        default: UNREACHABLE();
86394515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke      }
8640a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // Allocate a heap number, if needed.
8641a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      Label skip_allocation;
86424515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke      OverwriteMode mode = mode_;
86434515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke      if (HasArgsReversed()) {
86444515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke        if (mode == OVERWRITE_RIGHT) {
86454515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke          mode = OVERWRITE_LEFT;
86464515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke        } else if (mode == OVERWRITE_LEFT) {
86474515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke          mode = OVERWRITE_RIGHT;
86484515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke        }
86494515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke      }
86504515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke      switch (mode) {
8651a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        case OVERWRITE_LEFT:
86524515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke          __ JumpIfNotSmi(rdx, &skip_allocation);
86534515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke          __ AllocateHeapNumber(rbx, rcx, &call_runtime);
86544515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke          __ movq(rdx, rbx);
86554515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke          __ bind(&skip_allocation);
8656a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block          __ movq(rax, rdx);
86574515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke          break;
8658a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        case OVERWRITE_RIGHT:
8659a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block          // If the argument in rax is already an object, we skip the
8660a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block          // allocation of a heap number.
8661a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block          __ JumpIfNotSmi(rax, &skip_allocation);
8662a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block          // Fall through!
8663a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        case NO_OVERWRITE:
8664d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block          // Allocate a heap number for the result. Keep rax and rdx intact
8665d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block          // for the possible runtime call.
8666d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block          __ AllocateHeapNumber(rbx, rcx, &call_runtime);
8667d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block          __ movq(rax, rbx);
8668a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block          __ bind(&skip_allocation);
8669a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block          break;
8670a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        default: UNREACHABLE();
8671a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      }
8672a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      __ movsd(FieldOperand(rax, HeapNumber::kValueOffset), xmm4);
8673d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block      GenerateReturn(masm);
8674a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
8675a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    case Token::MOD: {
8676a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // For MOD we go directly to runtime in the non-smi case.
8677a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      break;
8678a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
8679a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    case Token::BIT_OR:
8680a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    case Token::BIT_AND:
8681a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    case Token::BIT_XOR:
8682a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    case Token::SAR:
8683a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    case Token::SHL:
8684a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    case Token::SHR: {
8685d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      Label skip_allocation, non_smi_result;
8686d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      FloatingPointHelper::LoadAsIntegers(masm, use_sse3_, &call_runtime);
8687a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      switch (op_) {
86883ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block        case Token::BIT_OR:  __ orl(rax, rcx); break;
86893ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block        case Token::BIT_AND: __ andl(rax, rcx); break;
86903ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block        case Token::BIT_XOR: __ xorl(rax, rcx); break;
8691d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block        case Token::SAR: __ sarl_cl(rax); break;
8692d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block        case Token::SHL: __ shll_cl(rax); break;
8693d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block        case Token::SHR: __ shrl_cl(rax); break;
8694a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        default: UNREACHABLE();
8695a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      }
8696a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      if (op_ == Token::SHR) {
86973ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block        // Check if result is non-negative. This can only happen for a shift
86983ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block        // by zero, which also doesn't update the sign flag.
86993ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block        __ testl(rax, rax);
8700a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        __ j(negative, &non_smi_result);
8701a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      }
87023ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      __ JumpIfNotValidSmiValue(rax, &non_smi_result);
87033ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      // Tag smi result, if possible, and return.
8704a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      __ Integer32ToSmi(rax, rax);
8705d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block      GenerateReturn(masm);
8706a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
8707a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // All ops except SHR return a signed int32 that we load in a HeapNumber.
87083ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      if (op_ != Token::SHR && non_smi_result.is_linked()) {
8709a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        __ bind(&non_smi_result);
8710a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        // Allocate a heap number if needed.
8711a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        __ movsxlq(rbx, rax);  // rbx: sign extended 32-bit result
8712a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        switch (mode_) {
8713a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block          case OVERWRITE_LEFT:
8714a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block          case OVERWRITE_RIGHT:
8715a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block            // If the operand was an object, we skip the
8716a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block            // allocation of a heap number.
8717a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block            __ movq(rax, Operand(rsp, mode_ == OVERWRITE_RIGHT ?
8718a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                 1 * kPointerSize : 2 * kPointerSize));
8719a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block            __ JumpIfNotSmi(rax, &skip_allocation);
8720a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block            // Fall through!
8721a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block          case NO_OVERWRITE:
87223ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block            __ AllocateHeapNumber(rax, rcx, &call_runtime);
8723a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block            __ bind(&skip_allocation);
8724a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block            break;
8725a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block          default: UNREACHABLE();
8726a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        }
8727a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        // Store the result in the HeapNumber and return.
8728a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        __ movq(Operand(rsp, 1 * kPointerSize), rbx);
8729a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        __ fild_s(Operand(rsp, 1 * kPointerSize));
8730a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        __ fstp_d(FieldOperand(rax, HeapNumber::kValueOffset));
8731d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block        GenerateReturn(masm);
8732a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      }
8733a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
8734a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      // SHR should return uint32 - go to runtime for non-smi/negative result.
8735a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      if (op_ == Token::SHR) {
8736a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        __ bind(&non_smi_result);
8737a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      }
8738a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      break;
8739a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
8740a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    default: UNREACHABLE(); break;
8741a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
8742a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
8743a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // If all else fails, use the runtime system to get the correct
8744d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  // result. If arguments was passed in registers now place them on the
8745d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  // stack in the correct order below the return address.
8746a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&call_runtime);
87474515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  if (HasArgsInRegisters()) {
8748d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    __ pop(rcx);
87494515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke    if (HasArgsReversed()) {
8750d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block      __ push(rax);
8751d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block      __ push(rdx);
8752d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    } else {
8753d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block      __ push(rdx);
8754d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block      __ push(rax);
8755d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    }
8756d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    __ push(rcx);
8757d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  }
8758a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  switch (op_) {
8759d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    case Token::ADD: {
8760d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block      // Test for string arguments before calling runtime.
8761d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block      Label not_strings, both_strings, not_string1, string1;
8762d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block      Condition is_smi;
8763d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block      Result answer;
8764d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block      is_smi = masm->CheckSmi(rdx);
8765d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block      __ j(is_smi, &not_string1);
8766d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block      __ CmpObjectType(rdx, FIRST_NONSTRING_TYPE, rdx);
8767d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block      __ j(above_equal, &not_string1);
8768d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
8769d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block      // First argument is a a string, test second.
8770d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block      is_smi = masm->CheckSmi(rax);
8771d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block      __ j(is_smi, &string1);
8772d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block      __ CmpObjectType(rax, FIRST_NONSTRING_TYPE, rax);
8773d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block      __ j(above_equal, &string1);
8774d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
8775d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block      // First and second argument are strings.
8776e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke      StringAddStub stub(NO_STRING_CHECK_IN_STUB);
8777e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke      __ TailCallStub(&stub);
8778d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
8779d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block      // Only first argument is a string.
8780d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block      __ bind(&string1);
87814515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke      __ InvokeBuiltin(
87824515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke          HasArgsReversed() ?
87834515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke              Builtins::STRING_ADD_RIGHT :
87844515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke              Builtins::STRING_ADD_LEFT,
87854515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke          JUMP_FUNCTION);
8786d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
8787d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block      // First argument was not a string, test second.
8788d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block      __ bind(&not_string1);
8789d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block      is_smi = masm->CheckSmi(rax);
8790d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block      __ j(is_smi, &not_strings);
8791d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block      __ CmpObjectType(rax, FIRST_NONSTRING_TYPE, rax);
8792d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block      __ j(above_equal, &not_strings);
8793d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
8794d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block      // Only second argument is a string.
87954515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke      __ InvokeBuiltin(
87964515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke          HasArgsReversed() ?
87974515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke              Builtins::STRING_ADD_LEFT :
87984515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke              Builtins::STRING_ADD_RIGHT,
87994515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke          JUMP_FUNCTION);
8800d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
8801d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block      __ bind(&not_strings);
8802d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block      // Neither argument is a string.
8803a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      __ InvokeBuiltin(Builtins::ADD, JUMP_FUNCTION);
8804a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      break;
8805d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    }
8806a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    case Token::SUB:
8807a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      __ InvokeBuiltin(Builtins::SUB, JUMP_FUNCTION);
8808a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      break;
8809a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    case Token::MUL:
8810a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      __ InvokeBuiltin(Builtins::MUL, JUMP_FUNCTION);
88114515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke      break;
8812a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    case Token::DIV:
8813a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      __ InvokeBuiltin(Builtins::DIV, JUMP_FUNCTION);
8814a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      break;
8815a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    case Token::MOD:
8816a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      __ InvokeBuiltin(Builtins::MOD, JUMP_FUNCTION);
8817a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      break;
8818a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    case Token::BIT_OR:
8819a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      __ InvokeBuiltin(Builtins::BIT_OR, JUMP_FUNCTION);
8820a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      break;
8821a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    case Token::BIT_AND:
8822a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      __ InvokeBuiltin(Builtins::BIT_AND, JUMP_FUNCTION);
8823a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      break;
8824a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    case Token::BIT_XOR:
8825a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      __ InvokeBuiltin(Builtins::BIT_XOR, JUMP_FUNCTION);
8826a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      break;
8827a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    case Token::SAR:
8828a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      __ InvokeBuiltin(Builtins::SAR, JUMP_FUNCTION);
8829a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      break;
8830a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    case Token::SHL:
8831a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      __ InvokeBuiltin(Builtins::SHL, JUMP_FUNCTION);
8832a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      break;
8833a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    case Token::SHR:
8834a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      __ InvokeBuiltin(Builtins::SHR, JUMP_FUNCTION);
8835a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      break;
8836a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    default:
8837a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      UNREACHABLE();
8838a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
8839a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
8840a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
8841a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
8842d0582a6c46733687d045e4188a1bcd0123c758a1Steve Blockvoid GenericBinaryOpStub::GenerateLoadArguments(MacroAssembler* masm) {
8843d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  // If arguments are not passed in registers read them from the stack.
88444515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  if (!HasArgsInRegisters()) {
8845d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    __ movq(rax, Operand(rsp, 1 * kPointerSize));
8846d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    __ movq(rdx, Operand(rsp, 2 * kPointerSize));
8847d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  }
8848d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block}
8849d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
8850d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
8851d0582a6c46733687d045e4188a1bcd0123c758a1Steve Blockvoid GenericBinaryOpStub::GenerateReturn(MacroAssembler* masm) {
8852d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  // If arguments are not passed in registers remove them from the stack before
8853d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  // returning.
88544515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  if (!HasArgsInRegisters()) {
8855d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    __ ret(2 * kPointerSize);  // Remove both operands
8856d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  } else {
8857d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    __ ret(0);
8858d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  }
8859d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block}
8860d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
8861d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
8862a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockint CompareStub::MinorKey() {
8863e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // Encode the three parameters in a unique 16 bit value.
8864e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  ASSERT(static_cast<unsigned>(cc_) < (1 << 14));
8865e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  int nnn_value = (never_nan_nan_ ? 2 : 0);
8866e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  if (cc_ != equal) nnn_value = 0;  // Avoid duplicate stubs.
8867e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  return (static_cast<unsigned>(cc_) << 2) | nnn_value | (strict_ ? 1 : 0);
8868e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke}
8869e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
8870e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
8871e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarkeconst char* CompareStub::GetName() {
8872e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  switch (cc_) {
8873e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke    case less: return "CompareStub_LT";
8874e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke    case greater: return "CompareStub_GT";
8875e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke    case less_equal: return "CompareStub_LE";
8876e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke    case greater_equal: return "CompareStub_GE";
8877e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke    case not_equal: {
8878e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke      if (strict_) {
8879e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke        if (never_nan_nan_) {
8880e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke          return "CompareStub_NE_STRICT_NO_NAN";
8881e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke        } else {
8882e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke          return "CompareStub_NE_STRICT";
8883e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke        }
8884e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke      } else {
8885e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke        if (never_nan_nan_) {
8886e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke          return "CompareStub_NE_NO_NAN";
8887e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke        } else {
8888e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke          return "CompareStub_NE";
8889e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke        }
8890e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke      }
8891e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke    }
8892e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke    case equal: {
8893e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke      if (strict_) {
8894e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke        if (never_nan_nan_) {
8895e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke          return "CompareStub_EQ_STRICT_NO_NAN";
8896e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke        } else {
8897e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke          return "CompareStub_EQ_STRICT";
8898e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke        }
8899e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke      } else {
8900e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke        if (never_nan_nan_) {
8901e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke          return "CompareStub_EQ_NO_NAN";
8902e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke        } else {
8903e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke          return "CompareStub_EQ";
8904e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke        }
8905e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke      }
8906e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke    }
8907e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke    default: return "CompareStub";
8908e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  }
8909e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke}
8910e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
8911e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
8912e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarkevoid StringAddStub::Generate(MacroAssembler* masm) {
8913e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  Label string_add_runtime;
8914e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
8915e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // Load the two arguments.
8916e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ movq(rax, Operand(rsp, 2 * kPointerSize));  // First argument.
8917e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ movq(rdx, Operand(rsp, 1 * kPointerSize));  // Second argument.
8918e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
8919e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // Make sure that both arguments are strings if not known in advance.
8920e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  if (string_check_) {
8921e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke    Condition is_smi;
8922e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke    is_smi = masm->CheckSmi(rax);
8923e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke    __ j(is_smi, &string_add_runtime);
8924e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke    __ CmpObjectType(rax, FIRST_NONSTRING_TYPE, r8);
8925e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke    __ j(above_equal, &string_add_runtime);
8926e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
8927e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke    // First argument is a a string, test second.
8928e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke    is_smi = masm->CheckSmi(rdx);
8929e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke    __ j(is_smi, &string_add_runtime);
8930e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke    __ CmpObjectType(rdx, FIRST_NONSTRING_TYPE, r9);
8931e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke    __ j(above_equal, &string_add_runtime);
8932e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  }
8933e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
8934e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // Both arguments are strings.
8935e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // rax: first string
8936e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // rdx: second string
8937e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // Check if either of the strings are empty. In that case return the other.
8938e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  Label second_not_zero_length, both_not_zero_length;
8939e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ movl(rcx, FieldOperand(rdx, String::kLengthOffset));
8940e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ testl(rcx, rcx);
8941e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ j(not_zero, &second_not_zero_length);
8942e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // Second string is empty, result is first string which is already in rax.
8943e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ IncrementCounter(&Counters::string_add_native, 1);
8944e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ ret(2 * kPointerSize);
8945e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ bind(&second_not_zero_length);
8946e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ movl(rbx, FieldOperand(rax, String::kLengthOffset));
8947e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ testl(rbx, rbx);
8948e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ j(not_zero, &both_not_zero_length);
8949e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // First string is empty, result is second string which is in rdx.
8950e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ movq(rax, rdx);
8951e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ IncrementCounter(&Counters::string_add_native, 1);
8952e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ ret(2 * kPointerSize);
8953e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
8954e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // Both strings are non-empty.
8955e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // rax: first string
8956e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // rbx: length of first string
8957d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  // rcx: length of second string
8958d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  // rdx: second string
8959e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // r8: instance type of first string if string check was performed above
8960e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // r9: instance type of first string if string check was performed above
8961e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  Label string_add_flat_result;
8962e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ bind(&both_not_zero_length);
8963e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // Look at the length of the result of adding the two strings.
8964e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ addl(rbx, rcx);
8965e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // Use the runtime system when adding two one character strings, as it
8966e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // contains optimizations for this specific case using the symbol table.
8967e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ cmpl(rbx, Immediate(2));
8968e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ j(equal, &string_add_runtime);
8969e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // If arguments where known to be strings, maps are not loaded to r8 and r9
8970e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // by the code above.
8971e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  if (!string_check_) {
8972e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke    __ movq(r8, FieldOperand(rax, HeapObject::kMapOffset));
8973e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke    __ movq(r9, FieldOperand(rdx, HeapObject::kMapOffset));
8974e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  }
8975e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // Get the instance types of the two strings as they will be needed soon.
8976e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ movzxbl(r8, FieldOperand(r8, Map::kInstanceTypeOffset));
8977e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ movzxbl(r9, FieldOperand(r9, Map::kInstanceTypeOffset));
8978e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // Check if resulting string will be flat.
8979e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ cmpl(rbx, Immediate(String::kMinNonFlatLength));
8980e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ j(below, &string_add_flat_result);
8981e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // Handle exceptionally long strings in the runtime system.
8982e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  ASSERT((String::kMaxLength & 0x80000000) == 0);
8983e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ cmpl(rbx, Immediate(String::kMaxLength));
8984e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ j(above, &string_add_runtime);
8985e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
8986e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // If result is not supposed to be flat, allocate a cons string object. If
8987e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // both strings are ascii the result is an ascii cons string.
8988e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // rax: first string
8989e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // ebx: length of resulting flat string
8990e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // rdx: second string
8991e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // r8: instance type of first string
8992e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // r9: instance type of second string
8993e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  Label non_ascii, allocated;
8994e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ movl(rcx, r8);
8995e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ and_(rcx, r9);
8996e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  ASSERT(kStringEncodingMask == kAsciiStringTag);
8997e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ testl(rcx, Immediate(kAsciiStringTag));
8998e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ j(zero, &non_ascii);
8999e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // Allocate an acsii cons string.
9000e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ AllocateAsciiConsString(rcx, rdi, no_reg, &string_add_runtime);
9001e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ bind(&allocated);
9002e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // Fill the fields of the cons string.
9003e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ movl(FieldOperand(rcx, ConsString::kLengthOffset), rbx);
9004e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ movl(FieldOperand(rcx, ConsString::kHashFieldOffset),
9005e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke          Immediate(String::kEmptyHashField));
9006e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ movq(FieldOperand(rcx, ConsString::kFirstOffset), rax);
9007e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ movq(FieldOperand(rcx, ConsString::kSecondOffset), rdx);
9008e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ movq(rax, rcx);
9009e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ IncrementCounter(&Counters::string_add_native, 1);
9010e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ ret(2 * kPointerSize);
9011e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ bind(&non_ascii);
9012e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // Allocate a two byte cons string.
9013e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ AllocateConsString(rcx, rdi, no_reg, &string_add_runtime);
9014e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ jmp(&allocated);
9015e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
9016e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // Handle creating a flat result. First check that both strings are not
9017e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // external strings.
9018e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // rax: first string
9019e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // ebx: length of resulting flat string
9020e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // rdx: second string
9021e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // r8: instance type of first string
9022e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // r9: instance type of first string
9023e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ bind(&string_add_flat_result);
9024e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ movl(rcx, r8);
9025e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ and_(rcx, Immediate(kStringRepresentationMask));
9026e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ cmpl(rcx, Immediate(kExternalStringTag));
9027e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ j(equal, &string_add_runtime);
9028e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ movl(rcx, r9);
9029e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ and_(rcx, Immediate(kStringRepresentationMask));
9030e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ cmpl(rcx, Immediate(kExternalStringTag));
9031e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ j(equal, &string_add_runtime);
9032e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // Now check if both strings are ascii strings.
9033e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // rax: first string
9034e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // ebx: length of resulting flat string
9035e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // rdx: second string
9036e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // r8: instance type of first string
9037e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // r9: instance type of second string
9038e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  Label non_ascii_string_add_flat_result;
9039e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  ASSERT(kStringEncodingMask == kAsciiStringTag);
9040e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ testl(r8, Immediate(kAsciiStringTag));
9041e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ j(zero, &non_ascii_string_add_flat_result);
9042e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ testl(r9, Immediate(kAsciiStringTag));
9043e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ j(zero, &string_add_runtime);
9044e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // Both strings are ascii strings. As they are short they are both flat.
9045e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ AllocateAsciiString(rcx, rbx, rdi, r14, r15, &string_add_runtime);
9046e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // rcx: result string
9047e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ movq(rbx, rcx);
9048e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // Locate first character of result.
9049e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ addq(rcx, Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag));
9050e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // Locate first character of first argument
9051e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ movl(rdi, FieldOperand(rax, String::kLengthOffset));
9052e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ addq(rax, Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag));
9053e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // rax: first char of first argument
9054e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // rbx: result string
9055e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // rcx: first character of result
9056e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // rdx: second string
9057e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // rdi: length of first argument
9058e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  GenerateCopyCharacters(masm, rcx, rax, rdi, true);
9059e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // Locate first character of second argument.
9060e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ movl(rdi, FieldOperand(rdx, String::kLengthOffset));
9061e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ addq(rdx, Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag));
9062e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // rbx: result string
9063e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // rcx: next character of result
9064e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // rdx: first char of second argument
9065e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // rdi: length of second argument
9066e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  GenerateCopyCharacters(masm, rcx, rdx, rdi, true);
9067e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ movq(rax, rbx);
9068e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ IncrementCounter(&Counters::string_add_native, 1);
9069e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ ret(2 * kPointerSize);
9070e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
9071e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // Handle creating a flat two byte result.
9072e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // rax: first string - known to be two byte
9073e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // rbx: length of resulting flat string
9074e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // rdx: second string
9075e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // r8: instance type of first string
9076e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // r9: instance type of first string
9077e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ bind(&non_ascii_string_add_flat_result);
9078e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ and_(r9, Immediate(kAsciiStringTag));
9079e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ j(not_zero, &string_add_runtime);
9080e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // Both strings are two byte strings. As they are short they are both
9081e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // flat.
9082e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ AllocateTwoByteString(rcx, rbx, rdi, r14, r15, &string_add_runtime);
9083e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // rcx: result string
9084e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ movq(rbx, rcx);
9085e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // Locate first character of result.
9086e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ addq(rcx, Immediate(SeqTwoByteString::kHeaderSize - kHeapObjectTag));
9087e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // Locate first character of first argument.
9088e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ movl(rdi, FieldOperand(rax, String::kLengthOffset));
9089e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ addq(rax, Immediate(SeqTwoByteString::kHeaderSize - kHeapObjectTag));
9090e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // rax: first char of first argument
9091e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // rbx: result string
9092e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // rcx: first character of result
9093e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // rdx: second argument
9094e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // rdi: length of first argument
9095e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  GenerateCopyCharacters(masm, rcx, rax, rdi, false);
9096e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // Locate first character of second argument.
9097e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ movl(rdi, FieldOperand(rdx, String::kLengthOffset));
9098e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ addq(rdx, Immediate(SeqTwoByteString::kHeaderSize - kHeapObjectTag));
9099e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // rbx: result string
9100e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // rcx: next character of result
9101e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // rdx: first char of second argument
9102e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // rdi: length of second argument
9103e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  GenerateCopyCharacters(masm, rcx, rdx, rdi, false);
9104e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ movq(rax, rbx);
9105e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ IncrementCounter(&Counters::string_add_native, 1);
9106e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ ret(2 * kPointerSize);
9107e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
9108e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // Just jump to runtime to add the two strings.
9109e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ bind(&string_add_runtime);
9110e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ TailCallRuntime(ExternalReference(Runtime::kStringAdd), 2, 1);
9111e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke}
9112e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
9113e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
9114d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarkevoid StringStubBase::GenerateCopyCharacters(MacroAssembler* masm,
9115d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke                                            Register dest,
9116d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke                                            Register src,
9117d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke                                            Register count,
9118d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke                                            bool ascii) {
9119e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  Label loop;
9120e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ bind(&loop);
9121e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // This loop just copies one character at a time, as it is only used for very
9122e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // short strings.
9123e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  if (ascii) {
9124e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke    __ movb(kScratchRegister, Operand(src, 0));
9125e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke    __ movb(Operand(dest, 0), kScratchRegister);
9126e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke    __ addq(src, Immediate(1));
9127e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke    __ addq(dest, Immediate(1));
9128e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  } else {
9129e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke    __ movzxwl(kScratchRegister, Operand(src, 0));
9130e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke    __ movw(Operand(dest, 0), kScratchRegister);
9131e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke    __ addq(src, Immediate(2));
9132e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke    __ addq(dest, Immediate(2));
9133e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  }
9134e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ subl(count, Immediate(1));
9135e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ j(not_zero, &loop);
9136e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke}
9137e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
9138e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
9139d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarkevoid StringStubBase::GenerateCopyCharactersREP(MacroAssembler* masm,
9140d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke                                               Register dest,
9141d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke                                               Register src,
9142d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke                                               Register count,
9143d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke                                               bool ascii) {
9144d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  // Copy characters using rep movs of doublewords. Align destination on 4 byte
9145d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  // boundary before starting rep movs. Copy remaining characters after running
9146d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  // rep movs.
9147d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  ASSERT(dest.is(rdi));  // rep movs destination
9148d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  ASSERT(src.is(rsi));  // rep movs source
9149d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  ASSERT(count.is(rcx));  // rep movs count
9150d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke
9151d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  // Nothing to do for zero characters.
9152d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  Label done;
9153d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  __ testq(count, count);
9154d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  __ j(zero, &done);
9155d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke
9156d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  // Make count the number of bytes to copy.
9157d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  if (!ascii) {
9158d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    ASSERT_EQ(2, sizeof(uc16));  // NOLINT
9159d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    __ addq(count, count);
9160d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  }
9161d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke
9162d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  // Don't enter the rep movs if there are less than 4 bytes to copy.
9163d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  Label last_bytes;
9164d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  __ testq(count, Immediate(~7));
9165d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  __ j(zero, &last_bytes);
9166d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke
9167d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  // Copy from edi to esi using rep movs instruction.
9168d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  __ movq(kScratchRegister, count);
9169d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  __ sar(count, Immediate(3));  // Number of doublewords to copy.
9170d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  __ repmovsq();
9171d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke
9172d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  // Find number of bytes left.
9173d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  __ movq(count, kScratchRegister);
9174d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  __ and_(count, Immediate(7));
9175d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke
9176d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  // Check if there are more bytes to copy.
9177d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  __ bind(&last_bytes);
9178d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  __ testq(count, count);
9179d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  __ j(zero, &done);
9180d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke
9181d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  // Copy remaining characters.
9182d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  Label loop;
9183d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  __ bind(&loop);
9184d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  __ movb(kScratchRegister, Operand(src, 0));
9185d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  __ movb(Operand(dest, 0), kScratchRegister);
9186d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  __ addq(src, Immediate(1));
9187d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  __ addq(dest, Immediate(1));
9188d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  __ subq(count, Immediate(1));
9189d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  __ j(not_zero, &loop);
9190d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke
9191d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  __ bind(&done);
9192d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke}
9193d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke
9194d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke
9195d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarkevoid SubStringStub::Generate(MacroAssembler* masm) {
9196d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  Label runtime;
9197d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke
9198d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  // Stack frame on entry.
9199d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  //  rsp[0]: return address
9200d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  //  rsp[8]: to
9201d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  //  rsp[16]: from
9202d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  //  rsp[24]: string
9203d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke
9204d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  const int kToOffset = 1 * kPointerSize;
9205d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  const int kFromOffset = kToOffset + kPointerSize;
9206d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  const int kStringOffset = kFromOffset + kPointerSize;
9207d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  const int kArgumentsSize = (kStringOffset + kPointerSize) - kToOffset;
9208d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke
9209d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  // Make sure first argument is a string.
9210d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  __ movq(rax, Operand(rsp, kStringOffset));
9211d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  ASSERT_EQ(0, kSmiTag);
9212d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  __ testl(rax, Immediate(kSmiTagMask));
9213d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  __ j(zero, &runtime);
9214d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  Condition is_string = masm->IsObjectStringType(rax, rbx, rbx);
9215d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  __ j(NegateCondition(is_string), &runtime);
9216d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke
9217d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  // rax: string
9218d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  // rbx: instance type
9219d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  // Calculate length of sub string using the smi values.
9220d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  __ movq(rcx, Operand(rsp, kToOffset));
9221d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  __ movq(rdx, Operand(rsp, kFromOffset));
9222d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  __ JumpIfNotBothPositiveSmi(rcx, rdx, &runtime);
9223d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke
9224d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  __ SmiSub(rcx, rcx, rdx, NULL);  // Overflow doesn't happen.
9225d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  __ j(negative, &runtime);
9226d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  // Handle sub-strings of length 2 and less in the runtime system.
9227d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  __ SmiToInteger32(rcx, rcx);
9228d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  __ cmpl(rcx, Immediate(2));
9229d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  __ j(below_equal, &runtime);
9230d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke
9231d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  // rax: string
9232d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  // rbx: instance type
9233d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  // rcx: result string length
9234d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  // Check for flat ascii string
9235d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  Label non_ascii_flat;
9236d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  __ and_(rbx, Immediate(kStringRepresentationMask | kStringEncodingMask));
9237d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  __ cmpb(rbx, Immediate(kSeqStringTag | kAsciiStringTag));
9238d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  __ j(not_equal, &non_ascii_flat);
9239d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke
9240d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  // Allocate the result.
9241d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  __ AllocateAsciiString(rax, rcx, rbx, rdx, rdi, &runtime);
9242d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke
9243d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  // rax: result string
9244d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  // rcx: result string length
9245d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  __ movq(rdx, rsi);  // esi used by following code.
9246d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  // Locate first character of result.
9247d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  __ lea(rdi, FieldOperand(rax, SeqAsciiString::kHeaderSize));
9248d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  // Load string argument and locate character of sub string start.
9249d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  __ movq(rsi, Operand(rsp, kStringOffset));
9250d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  __ movq(rbx, Operand(rsp, kFromOffset));
9251d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  {
9252d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    SmiIndex smi_as_index = masm->SmiToIndex(rbx, rbx, times_1);
9253d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    __ lea(rsi, Operand(rsi, smi_as_index.reg, smi_as_index.scale,
9254d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke                        SeqAsciiString::kHeaderSize - kHeapObjectTag));
9255d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  }
9256d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke
9257d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  // rax: result string
9258d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  // rcx: result length
9259d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  // rdx: original value of rsi
9260d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  // rdi: first character of result
9261d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  // rsi: character of sub string start
9262d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  GenerateCopyCharactersREP(masm, rdi, rsi, rcx, true);
9263d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  __ movq(rsi, rdx);  // Restore rsi.
9264d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  __ IncrementCounter(&Counters::sub_string_native, 1);
9265d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  __ ret(kArgumentsSize);
9266d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke
9267d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  __ bind(&non_ascii_flat);
9268d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  // rax: string
9269d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  // rbx: instance type & kStringRepresentationMask | kStringEncodingMask
9270d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  // rcx: result string length
9271d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  // Check for sequential two byte string
9272d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  __ cmpb(rbx, Immediate(kSeqStringTag | kTwoByteStringTag));
9273d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  __ j(not_equal, &runtime);
9274d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke
9275d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  // Allocate the result.
9276d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  __ AllocateTwoByteString(rax, rcx, rbx, rdx, rdi, &runtime);
9277d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke
9278d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  // rax: result string
9279d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  // rcx: result string length
9280d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  __ movq(rdx, rsi);  // esi used by following code.
9281d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  // Locate first character of result.
9282d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  __ lea(rdi, FieldOperand(rax, SeqTwoByteString::kHeaderSize));
9283d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  // Load string argument and locate character of sub string start.
9284d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  __ movq(rsi, Operand(rsp, kStringOffset));
9285d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  __ movq(rbx, Operand(rsp, kFromOffset));
9286d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  {
9287d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    SmiIndex smi_as_index = masm->SmiToIndex(rbx, rbx, times_2);
9288d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke    __ lea(rsi, Operand(rsi, smi_as_index.reg, smi_as_index.scale,
9289d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke                        SeqAsciiString::kHeaderSize - kHeapObjectTag));
9290d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  }
9291d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke
9292d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  // rax: result string
9293d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  // rcx: result length
9294d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  // rdx: original value of rsi
9295d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  // rdi: first character of result
9296d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  // rsi: character of sub string start
9297d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  GenerateCopyCharactersREP(masm, rdi, rsi, rcx, false);
9298d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  __ movq(rsi, rdx);  // Restore esi.
9299d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  __ IncrementCounter(&Counters::sub_string_native, 1);
9300d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  __ ret(kArgumentsSize);
9301d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke
9302d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  // Just jump to runtime to create the sub string.
9303d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  __ bind(&runtime);
9304d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  __ TailCallRuntime(ExternalReference(Runtime::kSubString), 3, 1);
9305d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke}
9306d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke
9307e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
9308e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarkevoid StringCompareStub::GenerateCompareFlatAsciiStrings(MacroAssembler* masm,
9309e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke                                                        Register left,
9310e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke                                                        Register right,
9311e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke                                                        Register scratch1,
9312e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke                                                        Register scratch2,
9313e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke                                                        Register scratch3,
9314e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke                                                        Register scratch4) {
9315e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // Ensure that you can always subtract a string length from a non-negative
9316e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // number (e.g. another length).
9317e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  ASSERT(String::kMaxLength < 0x7fffffff);
9318e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
9319e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // Find minimum length and length difference.
9320e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ movl(scratch1, FieldOperand(left, String::kLengthOffset));
9321e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ movl(scratch4, scratch1);
9322e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ subl(scratch4, FieldOperand(right, String::kLengthOffset));
9323e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // Register scratch4 now holds left.length - right.length.
9324e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  const Register length_difference = scratch4;
9325e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  Label left_shorter;
9326e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ j(less, &left_shorter);
9327e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // The right string isn't longer that the left one.
9328e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // Get the right string's length by subtracting the (non-negative) difference
9329e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // from the left string's length.
9330e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ subl(scratch1, length_difference);
9331e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ bind(&left_shorter);
9332e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // Register scratch1 now holds Min(left.length, right.length).
9333e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  const Register min_length = scratch1;
9334e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
9335e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  Label compare_lengths;
9336e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // If min-length is zero, go directly to comparing lengths.
9337e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ testl(min_length, min_length);
9338e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ j(zero, &compare_lengths);
9339e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
9340e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // Registers scratch2 and scratch3 are free.
9341e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  Label result_not_equal;
9342e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  Label loop;
9343e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  {
9344e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke    // Check characters 0 .. min_length - 1 in a loop.
9345e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke    // Use scratch3 as loop index, min_length as limit and scratch2
9346e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke    // for computation.
9347e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke    const Register index = scratch3;
9348e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke    __ movl(index, Immediate(0));  // Index into strings.
9349e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke    __ bind(&loop);
9350e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke    // Compare characters.
9351e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke    // TODO(lrn): Could we load more than one character at a time?
9352e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke    __ movb(scratch2, FieldOperand(left,
9353e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke                                   index,
9354e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke                                   times_1,
9355e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke                                   SeqAsciiString::kHeaderSize));
9356e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke    // Increment index and use -1 modifier on next load to give
9357e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke    // the previous load extra time to complete.
9358e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke    __ addl(index, Immediate(1));
9359e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke    __ cmpb(scratch2, FieldOperand(right,
9360e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke                                   index,
9361e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke                                   times_1,
9362e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke                                   SeqAsciiString::kHeaderSize - 1));
9363e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke    __ j(not_equal, &result_not_equal);
9364e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke    __ cmpl(index, min_length);
9365e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke    __ j(not_equal, &loop);
9366e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  }
9367e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // Completed loop without finding different characters.
9368e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // Compare lengths (precomputed).
9369e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ bind(&compare_lengths);
9370e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ testl(length_difference, length_difference);
9371e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ j(not_zero, &result_not_equal);
9372e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
9373e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // Result is EQUAL.
9374e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ Move(rax, Smi::FromInt(EQUAL));
9375e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ ret(2 * kPointerSize);
9376e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
9377e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  Label result_greater;
9378e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ bind(&result_not_equal);
9379e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // Unequal comparison of left to right, either character or length.
9380e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ j(greater, &result_greater);
9381e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
9382e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // Result is LESS.
9383e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ Move(rax, Smi::FromInt(LESS));
9384e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ ret(2 * kPointerSize);
9385e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
9386e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // Result is GREATER.
9387e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ bind(&result_greater);
9388e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ Move(rax, Smi::FromInt(GREATER));
9389e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ ret(2 * kPointerSize);
9390e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke}
9391e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
9392e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
9393e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarkevoid StringCompareStub::Generate(MacroAssembler* masm) {
9394e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  Label runtime;
9395e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
9396e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // Stack frame on entry.
9397e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  //  rsp[0]: return address
9398e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  //  rsp[8]: right string
9399e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  //  rsp[16]: left string
9400e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
9401e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ movq(rdx, Operand(rsp, 2 * kPointerSize));  // left
9402e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ movq(rax, Operand(rsp, 1 * kPointerSize));  // right
9403e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
9404e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // Check for identity.
9405e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  Label not_same;
9406e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ cmpq(rdx, rax);
9407e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ j(not_equal, &not_same);
9408e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ Move(rax, Smi::FromInt(EQUAL));
9409e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ IncrementCounter(&Counters::string_compare_native, 1);
9410e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ ret(2 * kPointerSize);
9411e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
9412e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ bind(&not_same);
9413e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
9414e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // Check that both are sequential ASCII strings.
9415e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ JumpIfNotBothSequentialAsciiStrings(rdx, rax, rcx, rbx, &runtime);
9416e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
9417e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // Inline comparison of ascii strings.
9418d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  __ IncrementCounter(&Counters::string_compare_native, 1);
9419e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  GenerateCompareFlatAsciiStrings(masm, rdx, rax, rcx, rbx, rdi, r8);
9420e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
9421e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // Call the runtime; it returns -1 (less), 0 (equal), or 1 (greater)
9422e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // tagged as a small integer.
9423e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ bind(&runtime);
9424e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ TailCallRuntime(ExternalReference(Runtime::kStringCompare), 2, 1);
9425a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
9426a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
94273ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block#undef __
94283ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block
94293ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block#define __ masm.
94303ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block
94313ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block#ifdef _WIN64
94323ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Blocktypedef double (*ModuloFunction)(double, double);
94333ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block// Define custom fmod implementation.
94343ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve BlockModuloFunction CreateModuloFunction() {
94353ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  size_t actual_size;
94363ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize,
94373ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block                                                 &actual_size,
94383ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block                                                 true));
94393ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  CHECK(buffer);
9440d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  Assembler masm(buffer, static_cast<int>(actual_size));
94413ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // Generated code is put into a fixed, unmovable, buffer, and not into
94423ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // the V8 heap. We can't, and don't, refer to any relocatable addresses
94433ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // (e.g. the JavaScript nan-object).
94443ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block
94453ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // Windows 64 ABI passes double arguments in xmm0, xmm1 and
94463ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // returns result in xmm0.
94473ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // Argument backing space is allocated on the stack above
94483ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // the return address.
94493ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block
94503ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // Compute x mod y.
94513ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // Load y and x (use argument backing store as temporary storage).
94523ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  __ movsd(Operand(rsp, kPointerSize * 2), xmm1);
94533ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  __ movsd(Operand(rsp, kPointerSize), xmm0);
94543ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  __ fld_d(Operand(rsp, kPointerSize * 2));
94553ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  __ fld_d(Operand(rsp, kPointerSize));
94563ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block
94573ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // Clear exception flags before operation.
94583ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  {
94593ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    Label no_exceptions;
94603ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    __ fwait();
94613ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    __ fnstsw_ax();
94623ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    // Clear if Illegal Operand or Zero Division exceptions are set.
94633ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    __ testb(rax, Immediate(5));
94643ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    __ j(zero, &no_exceptions);
94653ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    __ fnclex();
94663ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    __ bind(&no_exceptions);
94673ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  }
94683ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block
94693ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // Compute st(0) % st(1)
94703ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  {
94713ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    Label partial_remainder_loop;
94723ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    __ bind(&partial_remainder_loop);
94733ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    __ fprem();
94743ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    __ fwait();
94753ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    __ fnstsw_ax();
94763ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    __ testl(rax, Immediate(0x400 /* C2 */));
94773ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    // If C2 is set, computation only has partial result. Loop to
94783ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    // continue computation.
94793ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    __ j(not_zero, &partial_remainder_loop);
94803ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  }
94813ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block
94823ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  Label valid_result;
94833ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  Label return_result;
94843ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // If Invalid Operand or Zero Division exceptions are set,
94853ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // return NaN.
94863ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  __ testb(rax, Immediate(5));
94873ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  __ j(zero, &valid_result);
94883ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  __ fstp(0);  // Drop result in st(0).
94893ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  int64_t kNaNValue = V8_INT64_C(0x7ff8000000000000);
94903ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  __ movq(rcx, kNaNValue, RelocInfo::NONE);
94913ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  __ movq(Operand(rsp, kPointerSize), rcx);
94923ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  __ movsd(xmm0, Operand(rsp, kPointerSize));
94933ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  __ jmp(&return_result);
94943ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block
94953ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // If result is valid, return that.
94963ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  __ bind(&valid_result);
94973ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  __ fstp_d(Operand(rsp, kPointerSize));
94983ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  __ movsd(xmm0, Operand(rsp, kPointerSize));
94993ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block
95003ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // Clean up FPU stack and exceptions and return xmm0
95013ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  __ bind(&return_result);
95023ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  __ fstp(0);  // Unload y.
95033ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block
95043ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  Label clear_exceptions;
95053ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  __ testb(rax, Immediate(0x3f /* Any Exception*/));
95063ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  __ j(not_zero, &clear_exceptions);
95073ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  __ ret(0);
95083ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  __ bind(&clear_exceptions);
95093ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  __ fnclex();
95103ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  __ ret(0);
95113ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block
95123ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  CodeDesc desc;
95133ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  masm.GetCode(&desc);
95143ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // Call the function from C++.
95153ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  return FUNCTION_CAST<ModuloFunction>(buffer);
95163ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block}
95173ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block
95183ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block#endif
9519a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
9520e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
9521a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#undef __
9522a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
9523a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} }  // namespace v8::internal
9524