13ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch// Copyright 2012 the V8 project authors. All rights reserved.
244f0eee88ff00398ff7f715fab053374d808c90dSteve Block// Redistribution and use in source and binary forms, with or without
344f0eee88ff00398ff7f715fab053374d808c90dSteve Block// modification, are permitted provided that the following conditions are
444f0eee88ff00398ff7f715fab053374d808c90dSteve Block// met:
544f0eee88ff00398ff7f715fab053374d808c90dSteve Block//
644f0eee88ff00398ff7f715fab053374d808c90dSteve Block//     * Redistributions of source code must retain the above copyright
744f0eee88ff00398ff7f715fab053374d808c90dSteve Block//       notice, this list of conditions and the following disclaimer.
844f0eee88ff00398ff7f715fab053374d808c90dSteve Block//     * Redistributions in binary form must reproduce the above
944f0eee88ff00398ff7f715fab053374d808c90dSteve Block//       copyright notice, this list of conditions and the following
1044f0eee88ff00398ff7f715fab053374d808c90dSteve Block//       disclaimer in the documentation and/or other materials provided
1144f0eee88ff00398ff7f715fab053374d808c90dSteve Block//       with the distribution.
1244f0eee88ff00398ff7f715fab053374d808c90dSteve Block//     * Neither the name of Google Inc. nor the names of its
1344f0eee88ff00398ff7f715fab053374d808c90dSteve Block//       contributors may be used to endorse or promote products derived
1444f0eee88ff00398ff7f715fab053374d808c90dSteve Block//       from this software without specific prior written permission.
1544f0eee88ff00398ff7f715fab053374d808c90dSteve Block//
1644f0eee88ff00398ff7f715fab053374d808c90dSteve Block// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
1744f0eee88ff00398ff7f715fab053374d808c90dSteve Block// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
1844f0eee88ff00398ff7f715fab053374d808c90dSteve Block// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
1944f0eee88ff00398ff7f715fab053374d808c90dSteve Block// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
2044f0eee88ff00398ff7f715fab053374d808c90dSteve Block// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
2144f0eee88ff00398ff7f715fab053374d808c90dSteve Block// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
2244f0eee88ff00398ff7f715fab053374d808c90dSteve Block// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2344f0eee88ff00398ff7f715fab053374d808c90dSteve Block// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2444f0eee88ff00398ff7f715fab053374d808c90dSteve Block// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2544f0eee88ff00398ff7f715fab053374d808c90dSteve Block// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
2644f0eee88ff00398ff7f715fab053374d808c90dSteve Block// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2744f0eee88ff00398ff7f715fab053374d808c90dSteve Block
2844f0eee88ff00398ff7f715fab053374d808c90dSteve Block#include "v8.h"
2944f0eee88ff00398ff7f715fab053374d808c90dSteve Block
3044f0eee88ff00398ff7f715fab053374d808c90dSteve Block#if defined(V8_TARGET_ARCH_MIPS)
3144f0eee88ff00398ff7f715fab053374d808c90dSteve Block
3244f0eee88ff00398ff7f715fab053374d808c90dSteve Block#include "bootstrapper.h"
3344f0eee88ff00398ff7f715fab053374d808c90dSteve Block#include "code-stubs.h"
34257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch#include "codegen.h"
3544f0eee88ff00398ff7f715fab053374d808c90dSteve Block#include "regexp-macro-assembler.h"
3644f0eee88ff00398ff7f715fab053374d808c90dSteve Block
3744f0eee88ff00398ff7f715fab053374d808c90dSteve Blocknamespace v8 {
3844f0eee88ff00398ff7f715fab053374d808c90dSteve Blocknamespace internal {
3944f0eee88ff00398ff7f715fab053374d808c90dSteve Block
4044f0eee88ff00398ff7f715fab053374d808c90dSteve Block
4144f0eee88ff00398ff7f715fab053374d808c90dSteve Block#define __ ACCESS_MASM(masm)
4244f0eee88ff00398ff7f715fab053374d808c90dSteve Block
43257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochstatic void EmitIdenticalObjectComparison(MacroAssembler* masm,
44257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                          Label* slow,
45257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                          Condition cc,
46257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                          bool never_nan_nan);
47257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochstatic void EmitSmiNonsmiComparison(MacroAssembler* masm,
48257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                    Register lhs,
49257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                    Register rhs,
50257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                    Label* rhs_not_nan,
51257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                    Label* slow,
52257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                    bool strict);
53257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochstatic void EmitTwoNonNanDoubleComparison(MacroAssembler* masm, Condition cc);
54257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochstatic void EmitStrictTwoHeapObjectCompare(MacroAssembler* masm,
55257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                           Register lhs,
56257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                           Register rhs);
57257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
58257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
59257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// Check if the operand is a heap number.
60257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochstatic void EmitCheckForHeapNumber(MacroAssembler* masm, Register operand,
61257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                   Register scratch1, Register scratch2,
62257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                   Label* not_a_heap_number) {
63257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ lw(scratch1, FieldMemOperand(operand, HeapObject::kMapOffset));
64257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ LoadRoot(scratch2, Heap::kHeapNumberMapRootIndex);
65257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Branch(not_a_heap_number, ne, scratch1, Operand(scratch2));
66257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch}
67257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6844f0eee88ff00398ff7f715fab053374d808c90dSteve Block
6944f0eee88ff00398ff7f715fab053374d808c90dSteve Blockvoid ToNumberStub::Generate(MacroAssembler* masm) {
70257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // The ToNumber stub takes one argument in a0.
71257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label check_heap_number, call_builtin;
72257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ JumpIfNotSmi(a0, &check_heap_number);
733ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ Ret(USE_DELAY_SLOT);
74257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ mov(v0, a0);
75257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
76257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&check_heap_number);
77257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  EmitCheckForHeapNumber(masm, a0, a1, t0, &call_builtin);
783ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ Ret(USE_DELAY_SLOT);
79257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ mov(v0, a0);
80257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
81257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&call_builtin);
82257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ push(a0);
83257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ InvokeBuiltin(Builtins::TO_NUMBER, JUMP_FUNCTION);
8444f0eee88ff00398ff7f715fab053374d808c90dSteve Block}
8544f0eee88ff00398ff7f715fab053374d808c90dSteve Block
8644f0eee88ff00398ff7f715fab053374d808c90dSteve Block
8744f0eee88ff00398ff7f715fab053374d808c90dSteve Blockvoid FastNewClosureStub::Generate(MacroAssembler* masm) {
88257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Create a new closure from the given function info in new
89257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // space. Set the context to the current context in cp.
90257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label gc;
91257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
92257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Pop the function info from the stack.
93257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ pop(a3);
94257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
95257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Attempt to allocate new JSFunction in new space.
96257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ AllocateInNewSpace(JSFunction::kSize,
97257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                        v0,
98257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                        a1,
99257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                        a2,
100257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                        &gc,
101257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                        TAG_OBJECT);
102257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1033ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  int map_index = (language_mode_ == CLASSIC_MODE)
1043ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      ? Context::FUNCTION_MAP_INDEX
1053ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      : Context::STRICT_MODE_FUNCTION_MAP_INDEX;
106257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
107257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Compute the function map in the current global context and set that
108257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // as the map of the allocated object.
109257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ lw(a2, MemOperand(cp, Context::SlotOffset(Context::GLOBAL_INDEX)));
110257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ lw(a2, FieldMemOperand(a2, GlobalObject::kGlobalContextOffset));
111257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ lw(a2, MemOperand(a2, Context::SlotOffset(map_index)));
112257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ sw(a2, FieldMemOperand(v0, HeapObject::kMapOffset));
113257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
114257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Initialize the rest of the function. We don't have to update the
115257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // write barrier because the allocated object is in new space.
116257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ LoadRoot(a1, Heap::kEmptyFixedArrayRootIndex);
117257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ LoadRoot(a2, Heap::kTheHoleValueRootIndex);
118257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ LoadRoot(t0, Heap::kUndefinedValueRootIndex);
119257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ sw(a1, FieldMemOperand(v0, JSObject::kPropertiesOffset));
120257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ sw(a1, FieldMemOperand(v0, JSObject::kElementsOffset));
121257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ sw(a2, FieldMemOperand(v0, JSFunction::kPrototypeOrInitialMapOffset));
122257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ sw(a3, FieldMemOperand(v0, JSFunction::kSharedFunctionInfoOffset));
123257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ sw(cp, FieldMemOperand(v0, JSFunction::kContextOffset));
124257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ sw(a1, FieldMemOperand(v0, JSFunction::kLiteralsOffset));
125257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ sw(t0, FieldMemOperand(v0, JSFunction::kNextFunctionLinkOffset));
126257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
127257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Initialize the code pointer in the function to be the one
128257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // found in the shared function info object.
129257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ lw(a3, FieldMemOperand(a3, SharedFunctionInfo::kCodeOffset));
130257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Addu(a3, a3, Operand(Code::kHeaderSize - kHeapObjectTag));
131257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
132257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Return result. The argument function info has been popped already.
1333ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ sw(a3, FieldMemOperand(v0, JSFunction::kCodeEntryOffset));
134257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Ret();
135257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
136257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Create a new closure through the slower runtime call.
137257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&gc);
138257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ LoadRoot(t0, Heap::kFalseValueRootIndex);
139257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Push(cp, a3, t0);
140257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ TailCallRuntime(Runtime::kNewClosure, 3, 1);
14144f0eee88ff00398ff7f715fab053374d808c90dSteve Block}
14244f0eee88ff00398ff7f715fab053374d808c90dSteve Block
14344f0eee88ff00398ff7f715fab053374d808c90dSteve Block
14444f0eee88ff00398ff7f715fab053374d808c90dSteve Blockvoid FastNewContextStub::Generate(MacroAssembler* masm) {
145257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Try to allocate the context in new space.
146257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label gc;
147257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  int length = slots_ + Context::MIN_CONTEXT_SLOTS;
148257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
149257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Attempt to allocate the context in new space.
150257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ AllocateInNewSpace(FixedArray::SizeFor(length),
151257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                        v0,
152257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                        a1,
153257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                        a2,
154257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                        &gc,
155257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                        TAG_OBJECT);
156257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
157257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Load the function from the stack.
158257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ lw(a3, MemOperand(sp, 0));
159257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1603ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Set up the object header.
1613ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ LoadRoot(a1, Heap::kFunctionContextMapRootIndex);
162257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ li(a2, Operand(Smi::FromInt(length)));
163257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ sw(a2, FieldMemOperand(v0, FixedArray::kLengthOffset));
1643ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ sw(a1, FieldMemOperand(v0, HeapObject::kMapOffset));
165257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1663ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Set up the fixed slots, copy the global object from the previous context.
1673ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ lw(a2, MemOperand(cp, Context::SlotOffset(Context::GLOBAL_INDEX)));
168257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ li(a1, Operand(Smi::FromInt(0)));
169257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ sw(a3, MemOperand(v0, Context::SlotOffset(Context::CLOSURE_INDEX)));
1703fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ sw(cp, MemOperand(v0, Context::SlotOffset(Context::PREVIOUS_INDEX)));
171257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ sw(a1, MemOperand(v0, Context::SlotOffset(Context::EXTENSION_INDEX)));
1723ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ sw(a2, MemOperand(v0, Context::SlotOffset(Context::GLOBAL_INDEX)));
173257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
174257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Initialize the rest of the slots to undefined.
175257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ LoadRoot(a1, Heap::kUndefinedValueRootIndex);
176257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  for (int i = Context::MIN_CONTEXT_SLOTS; i < length; i++) {
177257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ sw(a1, MemOperand(v0, Context::SlotOffset(i)));
178257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
179257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
180257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Remove the on-stack argument and return.
181257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ mov(cp, v0);
1823ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ DropAndRet(1);
183257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
184257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Need to collect. Call into runtime system.
185257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&gc);
1863fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ TailCallRuntime(Runtime::kNewFunctionContext, 1, 1);
18744f0eee88ff00398ff7f715fab053374d808c90dSteve Block}
18844f0eee88ff00398ff7f715fab053374d808c90dSteve Block
18944f0eee88ff00398ff7f715fab053374d808c90dSteve Block
1903ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochvoid FastNewBlockContextStub::Generate(MacroAssembler* masm) {
1913ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Stack layout on entry:
1923ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  //
1933ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // [sp]: function.
1943ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // [sp + kPointerSize]: serialized scope info
1953ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
1963ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Try to allocate the context in new space.
1973ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  Label gc;
1983ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  int length = slots_ + Context::MIN_CONTEXT_SLOTS;
1993ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ AllocateInNewSpace(FixedArray::SizeFor(length),
2003ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                        v0, a1, a2, &gc, TAG_OBJECT);
2013ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
2023ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Load the function from the stack.
2033ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ lw(a3, MemOperand(sp, 0));
2043ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
2053ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Load the serialized scope info from the stack.
2063ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ lw(a1, MemOperand(sp, 1 * kPointerSize));
2073ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
2083ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Set up the object header.
2093ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ LoadRoot(a2, Heap::kBlockContextMapRootIndex);
2103ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ sw(a2, FieldMemOperand(v0, HeapObject::kMapOffset));
2113ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ li(a2, Operand(Smi::FromInt(length)));
2123ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ sw(a2, FieldMemOperand(v0, FixedArray::kLengthOffset));
2133ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
2143ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // If this block context is nested in the global context we get a smi
2153ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // sentinel instead of a function. The block context should get the
2163ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // canonical empty function of the global context as its closure which
2173ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // we still have to look up.
2183ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  Label after_sentinel;
2193ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ JumpIfNotSmi(a3, &after_sentinel);
2203ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  if (FLAG_debug_code) {
2213ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    const char* message = "Expected 0 as a Smi sentinel";
2223ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ Assert(eq, message, a3, Operand(zero_reg));
2233ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  }
2243ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ lw(a3, GlobalObjectOperand());
2253ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ lw(a3, FieldMemOperand(a3, GlobalObject::kGlobalContextOffset));
2263ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ lw(a3, ContextOperand(a3, Context::CLOSURE_INDEX));
2273ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ bind(&after_sentinel);
2283ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
2293ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Set up the fixed slots, copy the global object from the previous context.
2303ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ lw(a2, ContextOperand(cp, Context::GLOBAL_INDEX));
2313ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ sw(a3, ContextOperand(v0, Context::CLOSURE_INDEX));
2323ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ sw(cp, ContextOperand(v0, Context::PREVIOUS_INDEX));
2333ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ sw(a1, ContextOperand(v0, Context::EXTENSION_INDEX));
2343ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ sw(a2, ContextOperand(v0, Context::GLOBAL_INDEX));
2353ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
2363ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Initialize the rest of the slots to the hole value.
2373ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ LoadRoot(a1, Heap::kTheHoleValueRootIndex);
2383ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  for (int i = 0; i < slots_; i++) {
2393ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ sw(a1, ContextOperand(v0, i + Context::MIN_CONTEXT_SLOTS));
2403ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  }
2413ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
2423ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Remove the on-stack argument and return.
2433ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ mov(cp, v0);
2443ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ DropAndRet(2);
2453ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
2463ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Need to collect. Call into runtime system.
2473ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ bind(&gc);
2483ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ TailCallRuntime(Runtime::kPushBlockContext, 2, 1);
2493ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch}
2503ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
2513ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
2523ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochstatic void GenerateFastCloneShallowArrayCommon(
2533ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    MacroAssembler* masm,
2543ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    int length,
2553ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    FastCloneShallowArrayStub::Mode mode,
2563ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    Label* fail) {
2573ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Registers on entry:
2583ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // a3: boilerplate literal array.
2593ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  ASSERT(mode != FastCloneShallowArrayStub::CLONE_ANY_ELEMENTS);
2603ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
2613ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // All sizes here are multiples of kPointerSize.
2623ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  int elements_size = 0;
2633ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  if (length > 0) {
2643ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    elements_size = mode == FastCloneShallowArrayStub::CLONE_DOUBLE_ELEMENTS
2653ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch        ? FixedDoubleArray::SizeFor(length)
2663ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch        : FixedArray::SizeFor(length);
2673ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  }
2683ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  int size = JSArray::kSize + elements_size;
2693ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
2703ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Allocate both the JS array and the elements array in one big
2713ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // allocation. This avoids multiple limit checks.
2723ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ AllocateInNewSpace(size,
2733ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                        v0,
2743ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                        a1,
2753ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                        a2,
2763ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                        fail,
2773ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                        TAG_OBJECT);
2783ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
2793ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Copy the JS array part.
2803ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  for (int i = 0; i < JSArray::kSize; i += kPointerSize) {
2813ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    if ((i != JSArray::kElementsOffset) || (length == 0)) {
2823ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      __ lw(a1, FieldMemOperand(a3, i));
2833ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      __ sw(a1, FieldMemOperand(v0, i));
2843ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    }
2853ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  }
2863ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
2873ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  if (length > 0) {
2883ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    // Get hold of the elements array of the boilerplate and setup the
2893ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    // elements pointer in the resulting object.
2903ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ lw(a3, FieldMemOperand(a3, JSArray::kElementsOffset));
2913ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ Addu(a2, v0, Operand(JSArray::kSize));
2923ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ sw(a2, FieldMemOperand(v0, JSArray::kElementsOffset));
2933ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
2943ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    // Copy the elements array.
2953ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    ASSERT((elements_size % kPointerSize) == 0);
2963ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ CopyFields(a2, a3, a1.bit(), elements_size / kPointerSize);
2973ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  }
2983ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch}
2993ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
30044f0eee88ff00398ff7f715fab053374d808c90dSteve Blockvoid FastCloneShallowArrayStub::Generate(MacroAssembler* masm) {
301257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Stack layout on entry:
3023ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  //
303257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // [sp]: constant elements.
304257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // [sp + kPointerSize]: literal index.
305257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // [sp + (2 * kPointerSize)]: literals array.
306257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
307257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Load boilerplate object into r3 and check if we need to create a
308257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // boilerplate.
309257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label slow_case;
310257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ lw(a3, MemOperand(sp, 2 * kPointerSize));
311257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ lw(a0, MemOperand(sp, 1 * kPointerSize));
312257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Addu(a3, a3, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
313257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ sll(t0, a0, kPointerSizeLog2 - kSmiTagSize);
314257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Addu(t0, a3, t0);
315257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ lw(a3, MemOperand(t0));
316257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ LoadRoot(t1, Heap::kUndefinedValueRootIndex);
317257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Branch(&slow_case, eq, a3, Operand(t1));
318257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
3193ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  FastCloneShallowArrayStub::Mode mode = mode_;
3203ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  if (mode == CLONE_ANY_ELEMENTS) {
3213ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    Label double_elements, check_fast_elements;
3223ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ lw(v0, FieldMemOperand(a3, JSArray::kElementsOffset));
3233ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ lw(v0, FieldMemOperand(v0, HeapObject::kMapOffset));
3243ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ LoadRoot(t1, Heap::kFixedCOWArrayMapRootIndex);
3253ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ Branch(&check_fast_elements, ne, v0, Operand(t1));
3263ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    GenerateFastCloneShallowArrayCommon(masm, 0,
3273ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                                        COPY_ON_WRITE_ELEMENTS, &slow_case);
3283ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    // Return and remove the on-stack parameters.
3293ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ DropAndRet(3);
3303ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
3313ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ bind(&check_fast_elements);
3323ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ LoadRoot(t1, Heap::kFixedArrayMapRootIndex);
3333ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ Branch(&double_elements, ne, v0, Operand(t1));
3343ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    GenerateFastCloneShallowArrayCommon(masm, length_,
3353ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                                        CLONE_ELEMENTS, &slow_case);
3363ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    // Return and remove the on-stack parameters.
3373ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ DropAndRet(3);
3383ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
3393ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ bind(&double_elements);
3403ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    mode = CLONE_DOUBLE_ELEMENTS;
3413ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    // Fall through to generate the code to handle double elements.
3423ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  }
3433ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
344257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  if (FLAG_debug_code) {
345257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    const char* message;
346257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Heap::RootListIndex expected_map_index;
3473ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    if (mode == CLONE_ELEMENTS) {
348257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      message = "Expected (writable) fixed array";
349257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      expected_map_index = Heap::kFixedArrayMapRootIndex;
3503ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    } else if (mode == CLONE_DOUBLE_ELEMENTS) {
3513ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      message = "Expected (writable) fixed double array";
3523ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      expected_map_index = Heap::kFixedDoubleArrayMapRootIndex;
353257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    } else {
3543ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      ASSERT(mode == COPY_ON_WRITE_ELEMENTS);
355257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      message = "Expected copy-on-write fixed array";
356257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      expected_map_index = Heap::kFixedCOWArrayMapRootIndex;
357257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    }
358257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ push(a3);
359257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ lw(a3, FieldMemOperand(a3, JSArray::kElementsOffset));
360257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ lw(a3, FieldMemOperand(a3, HeapObject::kMapOffset));
361257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ LoadRoot(at, expected_map_index);
362257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ Assert(eq, message, a3, Operand(at));
363257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ pop(a3);
364257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
365257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
3663ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  GenerateFastCloneShallowArrayCommon(masm, length_, mode, &slow_case);
367257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
3683ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Return and remove the on-stack parameters.
3693ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ DropAndRet(3);
370592a9fc1d8ea420377a2e7efd0600e20b058be2bBen Murdoch
3713ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ bind(&slow_case);
3723ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ TailCallRuntime(Runtime::kCreateArrayLiteralShallow, 3, 1);
3733ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch}
374592a9fc1d8ea420377a2e7efd0600e20b058be2bBen Murdoch
3753ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
3763ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochvoid FastCloneShallowObjectStub::Generate(MacroAssembler* masm) {
3773ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Stack layout on entry:
3783ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  //
3793ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // [sp]: object literal flags.
3803ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // [sp + kPointerSize]: constant properties.
3813ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // [sp + (2 * kPointerSize)]: literal index.
3823ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // [sp + (3 * kPointerSize)]: literals array.
3833ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
3843ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Load boilerplate object into a3 and check if we need to create a
3853ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // boilerplate.
3863ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  Label slow_case;
3873ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ lw(a3, MemOperand(sp, 3 * kPointerSize));
3883ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ lw(a0, MemOperand(sp, 2 * kPointerSize));
3893ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ Addu(a3, a3, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
3903ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ sll(t0, a0, kPointerSizeLog2 - kSmiTagSize);
3913ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ Addu(a3, t0, a3);
3923ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ lw(a3, MemOperand(a3));
3933ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ LoadRoot(t0, Heap::kUndefinedValueRootIndex);
3943ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ Branch(&slow_case, eq, a3, Operand(t0));
3953ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
3963ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Check that the boilerplate contains only fast properties and we can
3973ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // statically determine the instance size.
3983ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  int size = JSObject::kHeaderSize + length_ * kPointerSize;
3993ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ lw(a0, FieldMemOperand(a3, HeapObject::kMapOffset));
4003ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ lbu(a0, FieldMemOperand(a0, Map::kInstanceSizeOffset));
4013ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ Branch(&slow_case, ne, a0, Operand(size >> kPointerSizeLog2));
4023ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
4033ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Allocate the JS object and copy header together with all in-object
4043ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // properties from the boilerplate.
4053ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ AllocateInNewSpace(size, v0, a1, a2, &slow_case, TAG_OBJECT);
4063ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  for (int i = 0; i < size; i += kPointerSize) {
4073ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ lw(a1, FieldMemOperand(a3, i));
4083ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ sw(a1, FieldMemOperand(v0, i));
409257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
410257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
411257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Return and remove the on-stack parameters.
4123ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ DropAndRet(4);
413257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
414257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&slow_case);
4153ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ TailCallRuntime(Runtime::kCreateObjectLiteralShallow, 4, 1);
41644f0eee88ff00398ff7f715fab053374d808c90dSteve Block}
41744f0eee88ff00398ff7f715fab053374d808c90dSteve Block
41844f0eee88ff00398ff7f715fab053374d808c90dSteve Block
41944f0eee88ff00398ff7f715fab053374d808c90dSteve Block// Takes a Smi and converts to an IEEE 64 bit floating point value in two
42044f0eee88ff00398ff7f715fab053374d808c90dSteve Block// registers.  The format is 1 sign bit, 11 exponent bits (biased 1023) and
42144f0eee88ff00398ff7f715fab053374d808c90dSteve Block// 52 fraction bits (20 in the first word, 32 in the second).  Zeros is a
42244f0eee88ff00398ff7f715fab053374d808c90dSteve Block// scratch register.  Destroys the source register.  No GC occurs during this
42344f0eee88ff00398ff7f715fab053374d808c90dSteve Block// stub so you don't have to set up the frame.
42444f0eee88ff00398ff7f715fab053374d808c90dSteve Blockclass ConvertToDoubleStub : public CodeStub {
42544f0eee88ff00398ff7f715fab053374d808c90dSteve Block public:
42644f0eee88ff00398ff7f715fab053374d808c90dSteve Block  ConvertToDoubleStub(Register result_reg_1,
42744f0eee88ff00398ff7f715fab053374d808c90dSteve Block                      Register result_reg_2,
42844f0eee88ff00398ff7f715fab053374d808c90dSteve Block                      Register source_reg,
42944f0eee88ff00398ff7f715fab053374d808c90dSteve Block                      Register scratch_reg)
43044f0eee88ff00398ff7f715fab053374d808c90dSteve Block      : result1_(result_reg_1),
43144f0eee88ff00398ff7f715fab053374d808c90dSteve Block        result2_(result_reg_2),
43244f0eee88ff00398ff7f715fab053374d808c90dSteve Block        source_(source_reg),
43344f0eee88ff00398ff7f715fab053374d808c90dSteve Block        zeros_(scratch_reg) { }
43444f0eee88ff00398ff7f715fab053374d808c90dSteve Block
43544f0eee88ff00398ff7f715fab053374d808c90dSteve Block private:
43644f0eee88ff00398ff7f715fab053374d808c90dSteve Block  Register result1_;
43744f0eee88ff00398ff7f715fab053374d808c90dSteve Block  Register result2_;
43844f0eee88ff00398ff7f715fab053374d808c90dSteve Block  Register source_;
43944f0eee88ff00398ff7f715fab053374d808c90dSteve Block  Register zeros_;
44044f0eee88ff00398ff7f715fab053374d808c90dSteve Block
44144f0eee88ff00398ff7f715fab053374d808c90dSteve Block  // Minor key encoding in 16 bits.
44244f0eee88ff00398ff7f715fab053374d808c90dSteve Block  class ModeBits: public BitField<OverwriteMode, 0, 2> {};
44344f0eee88ff00398ff7f715fab053374d808c90dSteve Block  class OpBits: public BitField<Token::Value, 2, 14> {};
44444f0eee88ff00398ff7f715fab053374d808c90dSteve Block
44544f0eee88ff00398ff7f715fab053374d808c90dSteve Block  Major MajorKey() { return ConvertToDouble; }
44644f0eee88ff00398ff7f715fab053374d808c90dSteve Block  int MinorKey() {
44744f0eee88ff00398ff7f715fab053374d808c90dSteve Block    // Encode the parameters in a unique 16 bit value.
44844f0eee88ff00398ff7f715fab053374d808c90dSteve Block    return  result1_.code() +
44944f0eee88ff00398ff7f715fab053374d808c90dSteve Block           (result2_.code() << 4) +
45044f0eee88ff00398ff7f715fab053374d808c90dSteve Block           (source_.code() << 8) +
45144f0eee88ff00398ff7f715fab053374d808c90dSteve Block           (zeros_.code() << 12);
45244f0eee88ff00398ff7f715fab053374d808c90dSteve Block  }
45344f0eee88ff00398ff7f715fab053374d808c90dSteve Block
45444f0eee88ff00398ff7f715fab053374d808c90dSteve Block  void Generate(MacroAssembler* masm);
45544f0eee88ff00398ff7f715fab053374d808c90dSteve Block};
45644f0eee88ff00398ff7f715fab053374d808c90dSteve Block
45744f0eee88ff00398ff7f715fab053374d808c90dSteve Block
45844f0eee88ff00398ff7f715fab053374d808c90dSteve Blockvoid ConvertToDoubleStub::Generate(MacroAssembler* masm) {
459257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch#ifndef BIG_ENDIAN_FLOATING_POINT
460257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Register exponent = result1_;
461257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Register mantissa = result2_;
462257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch#else
463257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Register exponent = result2_;
464257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Register mantissa = result1_;
465257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch#endif
466257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label not_special;
467257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Convert from Smi to integer.
468257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ sra(source_, source_, kSmiTagSize);
469257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Move sign bit from source to destination.  This works because the sign bit
470257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // in the exponent word of the double has the same position and polarity as
471257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // the 2's complement sign bit in a Smi.
472257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  STATIC_ASSERT(HeapNumber::kSignMask == 0x80000000u);
473257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ And(exponent, source_, Operand(HeapNumber::kSignMask));
474257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Subtract from 0 if source was negative.
475257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ subu(at, zero_reg, source_);
4763ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ Movn(source_, at, exponent);
477257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
478257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // We have -1, 0 or 1, which we treat specially. Register source_ contains
479257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // absolute value: it is either equal to 1 (special case of -1 and 1),
480257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // greater than 1 (not a special case) or less than 1 (special case of 0).
481257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Branch(&not_special, gt, source_, Operand(1));
482257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
483257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // For 1 or -1 we need to or in the 0 exponent (biased to 1023).
484db1b4389239a7132c9cde0915dbd3f775dc1027aBen Murdoch  const uint32_t exponent_word_for_1 =
485257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      HeapNumber::kExponentBias << HeapNumber::kExponentShift;
486257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Safe to use 'at' as dest reg here.
487257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Or(at, exponent, Operand(exponent_word_for_1));
4883ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ Movn(exponent, at, source_);  // Write exp when source not 0.
489257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // 1, 0 and -1 all have 0 for the second word.
4903ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ Ret(USE_DELAY_SLOT);
491257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ mov(mantissa, zero_reg);
492257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
493257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&not_special);
494257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Count leading zeros.
495257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Gets the wrong answer for 0, but we already checked for that case above.
4963ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ Clz(zeros_, source_);
497257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Compute exponent and or it into the exponent register.
498257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // We use mantissa as a scratch register here.
499257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ li(mantissa, Operand(31 + HeapNumber::kExponentBias));
500257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ subu(mantissa, mantissa, zeros_);
501257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ sll(mantissa, mantissa, HeapNumber::kExponentShift);
502257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Or(exponent, exponent, mantissa);
503257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
504257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Shift up the source chopping the top bit off.
505257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Addu(zeros_, zeros_, Operand(1));
506257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // This wouldn't work for 1.0 or -1.0 as the shift would be 32 which means 0.
507257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ sllv(source_, source_, zeros_);
508257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Compute lower part of fraction (last 12 bits).
509257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ sll(mantissa, source_, HeapNumber::kMantissaBitsInTopWord);
510257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // And the top (top 20 bits).
511257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ srl(source_, source_, 32 - HeapNumber::kMantissaBitsInTopWord);
51285b71799222b55eb5dd74ea26efe0c64ab655c8cBen Murdoch
5133ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ Ret(USE_DELAY_SLOT);
5143ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ or_(exponent, exponent, source_);
51544f0eee88ff00398ff7f715fab053374d808c90dSteve Block}
51644f0eee88ff00398ff7f715fab053374d808c90dSteve Block
51744f0eee88ff00398ff7f715fab053374d808c90dSteve Block
51844f0eee88ff00398ff7f715fab053374d808c90dSteve Blockvoid FloatingPointHelper::LoadSmis(MacroAssembler* masm,
51944f0eee88ff00398ff7f715fab053374d808c90dSteve Block                                   FloatingPointHelper::Destination destination,
52044f0eee88ff00398ff7f715fab053374d808c90dSteve Block                                   Register scratch1,
52144f0eee88ff00398ff7f715fab053374d808c90dSteve Block                                   Register scratch2) {
522257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  if (CpuFeatures::IsSupported(FPU)) {
523257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    CpuFeatures::Scope scope(FPU);
524257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ sra(scratch1, a0, kSmiTagSize);
525257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ mtc1(scratch1, f14);
526257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ cvt_d_w(f14, f14);
527257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ sra(scratch1, a1, kSmiTagSize);
528257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ mtc1(scratch1, f12);
529257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ cvt_d_w(f12, f12);
530257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    if (destination == kCoreRegisters) {
531257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ Move(a2, a3, f14);
532257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ Move(a0, a1, f12);
533257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    }
534257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  } else {
535257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    ASSERT(destination == kCoreRegisters);
536257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Write Smi from a0 to a3 and a2 in double format.
537257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ mov(scratch1, a0);
538257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    ConvertToDoubleStub stub1(a3, a2, scratch1, scratch2);
539257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ push(ra);
5403fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    __ Call(stub1.GetCode());
541257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Write Smi from a1 to a1 and a0 in double format.
542257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ mov(scratch1, a1);
543257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    ConvertToDoubleStub stub2(a1, a0, scratch1, scratch2);
5443fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    __ Call(stub2.GetCode());
545257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ pop(ra);
546257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
54744f0eee88ff00398ff7f715fab053374d808c90dSteve Block}
54844f0eee88ff00398ff7f715fab053374d808c90dSteve Block
54944f0eee88ff00398ff7f715fab053374d808c90dSteve Block
55044f0eee88ff00398ff7f715fab053374d808c90dSteve Blockvoid FloatingPointHelper::LoadOperands(
55144f0eee88ff00398ff7f715fab053374d808c90dSteve Block    MacroAssembler* masm,
55244f0eee88ff00398ff7f715fab053374d808c90dSteve Block    FloatingPointHelper::Destination destination,
55344f0eee88ff00398ff7f715fab053374d808c90dSteve Block    Register heap_number_map,
55444f0eee88ff00398ff7f715fab053374d808c90dSteve Block    Register scratch1,
55544f0eee88ff00398ff7f715fab053374d808c90dSteve Block    Register scratch2,
55644f0eee88ff00398ff7f715fab053374d808c90dSteve Block    Label* slow) {
557257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
558257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Load right operand (a0) to f12 or a2/a3.
559257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  LoadNumber(masm, destination,
560257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch             a0, f14, a2, a3, heap_number_map, scratch1, scratch2, slow);
561257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
562257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Load left operand (a1) to f14 or a0/a1.
563257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  LoadNumber(masm, destination,
564257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch             a1, f12, a0, a1, heap_number_map, scratch1, scratch2, slow);
56544f0eee88ff00398ff7f715fab053374d808c90dSteve Block}
56644f0eee88ff00398ff7f715fab053374d808c90dSteve Block
56744f0eee88ff00398ff7f715fab053374d808c90dSteve Block
56844f0eee88ff00398ff7f715fab053374d808c90dSteve Blockvoid FloatingPointHelper::LoadNumber(MacroAssembler* masm,
56944f0eee88ff00398ff7f715fab053374d808c90dSteve Block                                     Destination destination,
57044f0eee88ff00398ff7f715fab053374d808c90dSteve Block                                     Register object,
57144f0eee88ff00398ff7f715fab053374d808c90dSteve Block                                     FPURegister dst,
57244f0eee88ff00398ff7f715fab053374d808c90dSteve Block                                     Register dst1,
57344f0eee88ff00398ff7f715fab053374d808c90dSteve Block                                     Register dst2,
57444f0eee88ff00398ff7f715fab053374d808c90dSteve Block                                     Register heap_number_map,
57544f0eee88ff00398ff7f715fab053374d808c90dSteve Block                                     Register scratch1,
57644f0eee88ff00398ff7f715fab053374d808c90dSteve Block                                     Register scratch2,
57744f0eee88ff00398ff7f715fab053374d808c90dSteve Block                                     Label* not_number) {
578257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  if (FLAG_debug_code) {
579257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ AbortIfNotRootValue(heap_number_map,
580257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                           Heap::kHeapNumberMapRootIndex,
581257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                           "HeapNumberMap register clobbered.");
582257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
583257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
584257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label is_smi, done;
585257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5863ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Smi-check
5873ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ UntagAndJumpIfSmi(scratch1, object, &is_smi);
5883ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Heap number check
589257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ JumpIfNotHeapNumber(object, heap_number_map, scratch1, not_number);
590257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
591257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Handle loading a double from a heap number.
592257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  if (CpuFeatures::IsSupported(FPU) &&
593257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      destination == kFPURegisters) {
594257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    CpuFeatures::Scope scope(FPU);
595257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Load the double from tagged HeapNumber to double register.
596257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
597257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // ARM uses a workaround here because of the unaligned HeapNumber
598257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // kValueOffset. On MIPS this workaround is built into ldc1 so there's no
599257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // point in generating even more instructions.
600257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ ldc1(dst, FieldMemOperand(object, HeapNumber::kValueOffset));
601257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  } else {
602257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    ASSERT(destination == kCoreRegisters);
603257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Load the double from heap number to dst1 and dst2 in double format.
604257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ lw(dst1, FieldMemOperand(object, HeapNumber::kValueOffset));
605257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ lw(dst2, FieldMemOperand(object,
606257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        HeapNumber::kValueOffset + kPointerSize));
607257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
608257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Branch(&done);
609257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
610257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Handle loading a double from a smi.
611257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&is_smi);
612257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  if (CpuFeatures::IsSupported(FPU)) {
613257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    CpuFeatures::Scope scope(FPU);
614257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Convert smi to double using FPU instructions.
615257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ mtc1(scratch1, dst);
616257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ cvt_d_w(dst, dst);
617257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    if (destination == kCoreRegisters) {
618257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // Load the converted smi to dst1 and dst2 in double format.
619257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ Move(dst1, dst2, dst);
620257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    }
621257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  } else {
622257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    ASSERT(destination == kCoreRegisters);
623257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Write smi to dst1 and dst2 double format.
624257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ mov(scratch1, object);
625257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    ConvertToDoubleStub stub(dst2, dst1, scratch1, scratch2);
626257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ push(ra);
6273fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    __ Call(stub.GetCode());
628257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ pop(ra);
629257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
630257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
631257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&done);
63244f0eee88ff00398ff7f715fab053374d808c90dSteve Block}
63344f0eee88ff00398ff7f715fab053374d808c90dSteve Block
63444f0eee88ff00398ff7f715fab053374d808c90dSteve Block
635257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid FloatingPointHelper::ConvertNumberToInt32(MacroAssembler* masm,
636257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                               Register object,
637257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                               Register dst,
638257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                               Register heap_number_map,
639257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                               Register scratch1,
640257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                               Register scratch2,
641257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                               Register scratch3,
642257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                               FPURegister double_scratch,
643257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                               Label* not_number) {
644257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  if (FLAG_debug_code) {
645257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ AbortIfNotRootValue(heap_number_map,
646257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                           Heap::kHeapNumberMapRootIndex,
647257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                           "HeapNumberMap register clobbered.");
648257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
649257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label done;
650257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label not_in_int32_range;
651257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6523ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ UntagAndJumpIfSmi(dst, object, &done);
653257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ lw(scratch1, FieldMemOperand(object, HeapNumber::kMapOffset));
654257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Branch(not_number, ne, scratch1, Operand(heap_number_map));
655257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ ConvertToInt32(object,
656257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                    dst,
657257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                    scratch1,
658257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                    scratch2,
659257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                    double_scratch,
660257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                    &not_in_int32_range);
661257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ jmp(&done);
662257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
663257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&not_in_int32_range);
664257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ lw(scratch1, FieldMemOperand(object, HeapNumber::kExponentOffset));
665257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ lw(scratch2, FieldMemOperand(object, HeapNumber::kMantissaOffset));
666257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
667257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ EmitOutOfInt32RangeTruncate(dst,
668257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                 scratch1,
669257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                 scratch2,
670257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                 scratch3);
671257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
672257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&done);
673257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch}
674257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
675257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
676257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid FloatingPointHelper::ConvertIntToDouble(MacroAssembler* masm,
677257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                             Register int_scratch,
678257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                             Destination destination,
679257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                             FPURegister double_dst,
680257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                             Register dst1,
681257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                             Register dst2,
682257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                             Register scratch2,
683257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                             FPURegister single_scratch) {
684257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  ASSERT(!int_scratch.is(scratch2));
685257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  ASSERT(!int_scratch.is(dst1));
686257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  ASSERT(!int_scratch.is(dst2));
687257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
688257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label done;
689257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
690257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  if (CpuFeatures::IsSupported(FPU)) {
691257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    CpuFeatures::Scope scope(FPU);
692257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ mtc1(int_scratch, single_scratch);
693257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ cvt_d_w(double_dst, single_scratch);
694257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    if (destination == kCoreRegisters) {
695257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ Move(dst1, dst2, double_dst);
696257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    }
697257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  } else {
698257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Label fewer_than_20_useful_bits;
699257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Expected output:
700257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // |         dst2            |         dst1            |
701257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // | s |   exp   |              mantissa               |
702257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
703257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Check for zero.
704257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ mov(dst2, int_scratch);
705257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ mov(dst1, int_scratch);
706257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ Branch(&done, eq, int_scratch, Operand(zero_reg));
707257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
708257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Preload the sign of the value.
709257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ And(dst2, int_scratch, Operand(HeapNumber::kSignMask));
710257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Get the absolute value of the object (as an unsigned integer).
711257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Label skip_sub;
712257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ Branch(&skip_sub, ge, dst2, Operand(zero_reg));
713257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ Subu(int_scratch, zero_reg, int_scratch);
714257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ bind(&skip_sub);
715257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
7163ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    // Get mantissa[51:20].
717257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
718257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Get the position of the first set bit.
7193ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ Clz(dst1, int_scratch);
720257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ li(scratch2, 31);
721257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ Subu(dst1, scratch2, dst1);
722257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
723257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Set the exponent.
724257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ Addu(scratch2, dst1, Operand(HeapNumber::kExponentBias));
725257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ Ins(dst2, scratch2,
726257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        HeapNumber::kExponentShift, HeapNumber::kExponentBits);
727257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
728257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Clear the first non null bit.
729257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ li(scratch2, Operand(1));
730257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ sllv(scratch2, scratch2, dst1);
731257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ li(at, -1);
732257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ Xor(scratch2, scratch2, at);
733257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ And(int_scratch, int_scratch, scratch2);
734257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
735257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Get the number of bits to set in the lower part of the mantissa.
736257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ Subu(scratch2, dst1, Operand(HeapNumber::kMantissaBitsInTopWord));
737257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ Branch(&fewer_than_20_useful_bits, lt, scratch2, Operand(zero_reg));
738257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Set the higher 20 bits of the mantissa.
739257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ srlv(at, int_scratch, scratch2);
740257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ or_(dst2, dst2, at);
741257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ li(at, 32);
742257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ subu(scratch2, at, scratch2);
743257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ sllv(dst1, int_scratch, scratch2);
744257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ Branch(&done);
745257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
746257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ bind(&fewer_than_20_useful_bits);
747257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ li(at, HeapNumber::kMantissaBitsInTopWord);
748257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ subu(scratch2, at, dst1);
749257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ sllv(scratch2, int_scratch, scratch2);
750257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ Or(dst2, dst2, scratch2);
751257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Set dst1 to 0.
752257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ mov(dst1, zero_reg);
753257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
754257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&done);
755257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch}
756257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
757257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
758257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid FloatingPointHelper::LoadNumberAsInt32Double(MacroAssembler* masm,
759257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                                  Register object,
760257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                                  Destination destination,
7613ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                                                  DoubleRegister double_dst,
762257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                                  Register dst1,
763257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                                  Register dst2,
764257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                                  Register heap_number_map,
765257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                                  Register scratch1,
766257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                                  Register scratch2,
767257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                                  FPURegister single_scratch,
768257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                                  Label* not_int32) {
769257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  ASSERT(!scratch1.is(object) && !scratch2.is(object));
770257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  ASSERT(!scratch1.is(scratch2));
771257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  ASSERT(!heap_number_map.is(object) &&
772257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch         !heap_number_map.is(scratch1) &&
773257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch         !heap_number_map.is(scratch2));
774257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
775257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label done, obj_is_not_smi;
776257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
777257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ JumpIfNotSmi(object, &obj_is_not_smi);
778257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ SmiUntag(scratch1, object);
779257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  ConvertIntToDouble(masm, scratch1, destination, double_dst, dst1, dst2,
780257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                     scratch2, single_scratch);
781257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Branch(&done);
782257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
783257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&obj_is_not_smi);
784257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  if (FLAG_debug_code) {
785257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ AbortIfNotRootValue(heap_number_map,
786257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                           Heap::kHeapNumberMapRootIndex,
787257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                           "HeapNumberMap register clobbered.");
788257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
789257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ JumpIfNotHeapNumber(object, heap_number_map, scratch1, not_int32);
790257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
791257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Load the number.
792257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  if (CpuFeatures::IsSupported(FPU)) {
793257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    CpuFeatures::Scope scope(FPU);
794257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Load the double value.
795257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ ldc1(double_dst, FieldMemOperand(object, HeapNumber::kValueOffset));
796257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
7973ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    Register except_flag = scratch2;
7983ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ EmitFPUTruncate(kRoundToZero,
7993ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                       single_scratch,
8003ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                       double_dst,
8013ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                       scratch1,
8023ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                       except_flag,
8033ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                       kCheckForInexactConversion);
804257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
805257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Jump to not_int32 if the operation did not succeed.
8063ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ Branch(not_int32, ne, except_flag, Operand(zero_reg));
807257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
808257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    if (destination == kCoreRegisters) {
809257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ Move(dst1, dst2, double_dst);
810257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    }
811257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
812257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  } else {
813257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    ASSERT(!scratch1.is(object) && !scratch2.is(object));
814257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Load the double value in the destination registers.
815257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ lw(dst2, FieldMemOperand(object, HeapNumber::kExponentOffset));
816257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ lw(dst1, FieldMemOperand(object, HeapNumber::kMantissaOffset));
817257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
818257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Check for 0 and -0.
819257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ And(scratch1, dst1, Operand(~HeapNumber::kSignMask));
820257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ Or(scratch1, scratch1, Operand(dst2));
821257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ Branch(&done, eq, scratch1, Operand(zero_reg));
822257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
823257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Check that the value can be exactly represented by a 32-bit integer.
824257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Jump to not_int32 if that's not the case.
825257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    DoubleIs32BitInteger(masm, dst1, dst2, scratch1, scratch2, not_int32);
826257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
827257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // dst1 and dst2 were trashed. Reload the double value.
828257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ lw(dst2, FieldMemOperand(object, HeapNumber::kExponentOffset));
829257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ lw(dst1, FieldMemOperand(object, HeapNumber::kMantissaOffset));
830257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
831257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
832257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&done);
833257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch}
834257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
835257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
836257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid FloatingPointHelper::LoadNumberAsInt32(MacroAssembler* masm,
837257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                            Register object,
838257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                            Register dst,
839257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                            Register heap_number_map,
840257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                            Register scratch1,
841257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                            Register scratch2,
842257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                            Register scratch3,
8433ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                                            DoubleRegister double_scratch,
844257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                            Label* not_int32) {
845257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  ASSERT(!dst.is(object));
846257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  ASSERT(!scratch1.is(object) && !scratch2.is(object) && !scratch3.is(object));
847257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  ASSERT(!scratch1.is(scratch2) &&
848257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch         !scratch1.is(scratch3) &&
849257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch         !scratch2.is(scratch3));
850257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
851257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label done;
852257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
8533ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ UntagAndJumpIfSmi(dst, object, &done);
854257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
855257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  if (FLAG_debug_code) {
856257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ AbortIfNotRootValue(heap_number_map,
857257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                           Heap::kHeapNumberMapRootIndex,
858257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                           "HeapNumberMap register clobbered.");
859257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
860257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ JumpIfNotHeapNumber(object, heap_number_map, scratch1, not_int32);
861257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
862257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Object is a heap number.
863257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Convert the floating point value to a 32-bit integer.
864257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  if (CpuFeatures::IsSupported(FPU)) {
865257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    CpuFeatures::Scope scope(FPU);
866257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Load the double value.
867257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ ldc1(double_scratch, FieldMemOperand(object, HeapNumber::kValueOffset));
868257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
8693ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    FPURegister single_scratch = double_scratch.low();
8703ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    Register except_flag = scratch2;
8713ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ EmitFPUTruncate(kRoundToZero,
8723ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                       single_scratch,
8733ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                       double_scratch,
8743ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                       scratch1,
8753ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                       except_flag,
8763ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                       kCheckForInexactConversion);
877257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
878257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Jump to not_int32 if the operation did not succeed.
8793ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ Branch(not_int32, ne, except_flag, Operand(zero_reg));
880257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Get the result in the destination register.
8813ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ mfc1(dst, single_scratch);
882257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
883257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  } else {
884257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Load the double value in the destination registers.
885257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ lw(scratch2, FieldMemOperand(object, HeapNumber::kExponentOffset));
886257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ lw(scratch1, FieldMemOperand(object, HeapNumber::kMantissaOffset));
887257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
888257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Check for 0 and -0.
889257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ And(dst, scratch1, Operand(~HeapNumber::kSignMask));
890257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ Or(dst, scratch2, Operand(dst));
891257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ Branch(&done, eq, dst, Operand(zero_reg));
892257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
893257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    DoubleIs32BitInteger(masm, scratch1, scratch2, dst, scratch3, not_int32);
894257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
895257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Registers state after DoubleIs32BitInteger.
896257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // dst: mantissa[51:20].
897257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // scratch2: 1
898257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
899257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Shift back the higher bits of the mantissa.
900257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ srlv(dst, dst, scratch3);
901257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Set the implicit first bit.
902257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ li(at, 32);
903257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ subu(scratch3, at, scratch3);
904257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ sllv(scratch2, scratch2, scratch3);
905257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ Or(dst, dst, scratch2);
906257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Set the sign.
907257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ lw(scratch1, FieldMemOperand(object, HeapNumber::kExponentOffset));
908257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ And(scratch1, scratch1, Operand(HeapNumber::kSignMask));
909257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Label skip_sub;
910257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ Branch(&skip_sub, ge, scratch1, Operand(zero_reg));
911257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ Subu(dst, zero_reg, dst);
912257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ bind(&skip_sub);
913257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
914257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
915257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&done);
916257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch}
917257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
918257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
919257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid FloatingPointHelper::DoubleIs32BitInteger(MacroAssembler* masm,
920257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                               Register src1,
921257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                               Register src2,
922257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                               Register dst,
923257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                               Register scratch,
924257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                               Label* not_int32) {
925257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Get exponent alone in scratch.
926257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Ext(scratch,
927257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch         src1,
928257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch         HeapNumber::kExponentShift,
929257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch         HeapNumber::kExponentBits);
930257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
931257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Substract the bias from the exponent.
932257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Subu(scratch, scratch, Operand(HeapNumber::kExponentBias));
933257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
934257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // src1: higher (exponent) part of the double value.
935257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // src2: lower (mantissa) part of the double value.
936257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // scratch: unbiased exponent.
937257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
938257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Fast cases. Check for obvious non 32-bit integer values.
939257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Negative exponent cannot yield 32-bit integers.
940257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Branch(not_int32, lt, scratch, Operand(zero_reg));
941257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Exponent greater than 31 cannot yield 32-bit integers.
942257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Also, a positive value with an exponent equal to 31 is outside of the
943257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // signed 32-bit integer range.
944257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Another way to put it is that if (exponent - signbit) > 30 then the
945257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // number cannot be represented as an int32.
946257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Register tmp = dst;
947257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ srl(at, src1, 31);
948257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ subu(tmp, scratch, at);
949257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Branch(not_int32, gt, tmp, Operand(30));
950257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // - Bits [21:0] in the mantissa are not null.
951257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ And(tmp, src2, 0x3fffff);
952257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Branch(not_int32, ne, tmp, Operand(zero_reg));
953257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
954257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Otherwise the exponent needs to be big enough to shift left all the
955257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // non zero bits left. So we need the (30 - exponent) last bits of the
956257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // 31 higher bits of the mantissa to be null.
957257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Because bits [21:0] are null, we can check instead that the
9583ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // (32 - exponent) last bits of the 32 higher bits of the mantissa are null.
959257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
960257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Get the 32 higher bits of the mantissa in dst.
961257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Ext(dst,
962257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch         src2,
963257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch         HeapNumber::kMantissaBitsInTopWord,
964257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch         32 - HeapNumber::kMantissaBitsInTopWord);
965257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ sll(at, src1, HeapNumber::kNonMantissaBitsInTopWord);
966257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ or_(dst, dst, at);
967257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
968257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Create the mask and test the lower bits (of the higher bits).
969257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ li(at, 32);
970257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ subu(scratch, at, scratch);
971257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ li(src2, 1);
972257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ sllv(src1, src2, scratch);
973257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Subu(src1, src1, Operand(1));
974257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ And(src1, dst, src1);
975257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Branch(not_int32, ne, src1, Operand(zero_reg));
976257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch}
977257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
978257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
979257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid FloatingPointHelper::CallCCodeForDoubleOperation(
980257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    MacroAssembler* masm,
981257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Token::Value op,
982257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Register heap_number_result,
983257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Register scratch) {
984257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Using core registers:
985257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // a0: Left value (least significant part of mantissa).
986257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // a1: Left value (sign, exponent, top of mantissa).
987257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // a2: Right value (least significant part of mantissa).
988257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // a3: Right value (sign, exponent, top of mantissa).
989257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
990257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Assert that heap_number_result is saved.
991257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // We currently always use s0 to pass it.
992257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  ASSERT(heap_number_result.is(s0));
993257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
994257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Push the current return address before the C call.
995257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ push(ra);
996257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ PrepareCallCFunction(4, scratch);  // Two doubles are 4 arguments.
997257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  if (!IsMipsSoftFloatABI) {
998257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    CpuFeatures::Scope scope(FPU);
999257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // We are not using MIPS FPU instructions, and parameters for the runtime
1000257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // function call are prepaired in a0-a3 registers, but function we are
1001257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // calling is compiled with hard-float flag and expecting hard float ABI
1002257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // (parameters in f12/f14 registers). We need to copy parameters from
1003257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // a0-a3 registers to f12/f14 register pairs.
1004257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ Move(f12, a0, a1);
1005257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ Move(f14, a2, a3);
1006257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
10073ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  {
10083ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    AllowExternalCallThatCantCauseGC scope(masm);
10093ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ CallCFunction(
10103ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch        ExternalReference::double_fp_operation(op, masm->isolate()), 0, 2);
10113ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  }
1012257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Store answer in the overwritable heap number.
1013257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  if (!IsMipsSoftFloatABI) {
1014257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    CpuFeatures::Scope scope(FPU);
1015257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Double returned in register f0.
1016257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ sdc1(f0, FieldMemOperand(heap_number_result, HeapNumber::kValueOffset));
1017257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  } else {
1018257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Double returned in registers v0 and v1.
1019257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ sw(v1, FieldMemOperand(heap_number_result, HeapNumber::kExponentOffset));
1020257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ sw(v0, FieldMemOperand(heap_number_result, HeapNumber::kMantissaOffset));
1021257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
1022257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Place heap_number_result in v0 and return to the pushed return address.
102385b71799222b55eb5dd74ea26efe0c64ab655c8cBen Murdoch  __ pop(ra);
10243ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ Ret(USE_DELAY_SLOT);
10253ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ mov(v0, heap_number_result);
10263ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch}
10273ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
10283ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
10293ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochbool WriteInt32ToHeapNumberStub::IsPregenerated() {
10303ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // These variants are compiled ahead of time.  See next method.
10313ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  if (the_int_.is(a1) &&
10323ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      the_heap_number_.is(v0) &&
10333ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      scratch_.is(a2) &&
10343ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      sign_.is(a3)) {
10353ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    return true;
10363ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  }
10373ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  if (the_int_.is(a2) &&
10383ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      the_heap_number_.is(v0) &&
10393ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      scratch_.is(a3) &&
10403ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      sign_.is(a0)) {
10413ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    return true;
10423ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  }
10433ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Other register combinations are generated as and when they are needed,
10443ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // so it is unsafe to call them from stubs (we can't generate a stub while
10453ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // we are generating a stub).
10463ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  return false;
10473ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch}
10483ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
10493ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
10503ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochvoid WriteInt32ToHeapNumberStub::GenerateFixedRegStubsAheadOfTime() {
10513ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  WriteInt32ToHeapNumberStub stub1(a1, v0, a2, a3);
10523ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  WriteInt32ToHeapNumberStub stub2(a2, v0, a3, a0);
10533ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  stub1.GetCode()->set_is_pregenerated(true);
10543ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  stub2.GetCode()->set_is_pregenerated(true);
1055592a9fc1d8ea420377a2e7efd0600e20b058be2bBen Murdoch}
1056592a9fc1d8ea420377a2e7efd0600e20b058be2bBen Murdoch
1057592a9fc1d8ea420377a2e7efd0600e20b058be2bBen Murdoch
105844f0eee88ff00398ff7f715fab053374d808c90dSteve Block// See comment for class, this does NOT work for int32's that are in Smi range.
105944f0eee88ff00398ff7f715fab053374d808c90dSteve Blockvoid WriteInt32ToHeapNumberStub::Generate(MacroAssembler* masm) {
1060257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label max_negative_int;
1061257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // the_int_ has the answer which is a signed int32 but not a Smi.
1062257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // We test for the special value that has a different exponent.
1063257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  STATIC_ASSERT(HeapNumber::kSignMask == 0x80000000u);
1064257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Test sign, and save for later conditionals.
1065257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ And(sign_, the_int_, Operand(0x80000000u));
1066257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Branch(&max_negative_int, eq, the_int_, Operand(0x80000000u));
1067257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1068257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Set up the correct exponent in scratch_.  All non-Smi int32s have the same.
1069257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // A non-Smi integer is 1.xxx * 2^30 so the exponent is 30 (biased).
1070257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  uint32_t non_smi_exponent =
1071257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      (HeapNumber::kExponentBias + 30) << HeapNumber::kExponentShift;
1072257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ li(scratch_, Operand(non_smi_exponent));
1073257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Set the sign bit in scratch_ if the value was negative.
1074257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ or_(scratch_, scratch_, sign_);
1075257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Subtract from 0 if the value was negative.
1076257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ subu(at, zero_reg, the_int_);
10773ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ Movn(the_int_, at, sign_);
1078257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // We should be masking the implict first digit of the mantissa away here,
1079257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // but it just ends up combining harmlessly with the last digit of the
1080257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // exponent that happens to be 1.  The sign bit is 0 so we shift 10 to get
1081257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // the most significant 1 to hit the last bit of the 12 bit sign and exponent.
1082257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  ASSERT(((1 << HeapNumber::kExponentShift) & non_smi_exponent) != 0);
1083257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  const int shift_distance = HeapNumber::kNonMantissaBitsInTopWord - 2;
1084257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ srl(at, the_int_, shift_distance);
1085257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ or_(scratch_, scratch_, at);
1086257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ sw(scratch_, FieldMemOperand(the_heap_number_,
1087257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                   HeapNumber::kExponentOffset));
1088257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ sll(scratch_, the_int_, 32 - shift_distance);
1089257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ sw(scratch_, FieldMemOperand(the_heap_number_,
1090257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                   HeapNumber::kMantissaOffset));
1091257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Ret();
1092257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1093257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&max_negative_int);
1094257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // The max negative int32 is stored as a positive number in the mantissa of
1095257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // a double because it uses a sign bit instead of using two's complement.
1096257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // The actual mantissa bits stored are all 0 because the implicit most
1097257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // significant 1 bit is not stored.
1098257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  non_smi_exponent += 1 << HeapNumber::kExponentShift;
1099257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ li(scratch_, Operand(HeapNumber::kSignMask | non_smi_exponent));
1100257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ sw(scratch_,
1101257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        FieldMemOperand(the_heap_number_, HeapNumber::kExponentOffset));
1102257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ mov(scratch_, zero_reg);
1103257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ sw(scratch_,
1104257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        FieldMemOperand(the_heap_number_, HeapNumber::kMantissaOffset));
1105257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Ret();
1106257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch}
1107257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1108257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1109257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// Handle the case where the lhs and rhs are the same object.
1110257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// Equality is almost reflexive (everything but NaN), so this is a test
1111257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// for "identity and not NaN".
1112257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochstatic void EmitIdenticalObjectComparison(MacroAssembler* masm,
1113257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                          Label* slow,
1114257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                          Condition cc,
1115257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                          bool never_nan_nan) {
1116257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label not_identical;
1117257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label heap_number, return_equal;
1118257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Register exp_mask_reg = t5;
1119257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1120257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Branch(&not_identical, ne, a0, Operand(a1));
1121257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1122257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // The two objects are identical. If we know that one of them isn't NaN then
1123257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // we now know they test equal.
1124257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  if (cc != eq || !never_nan_nan) {
1125257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ li(exp_mask_reg, Operand(HeapNumber::kExponentMask));
1126257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1127257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Test for NaN. Sadly, we can't just compare to factory->nan_value(),
1128257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // so we do the second best thing - test it ourselves.
1129257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // They are both equal and they are not both Smis so both of them are not
1130257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Smis. If it's not a heap number, then return equal.
1131257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    if (cc == less || cc == greater) {
1132257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ GetObjectType(a0, t4, t4);
11333fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch      __ Branch(slow, greater, t4, Operand(FIRST_SPEC_OBJECT_TYPE));
1134257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    } else {
1135257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ GetObjectType(a0, t4, t4);
1136257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ Branch(&heap_number, eq, t4, Operand(HEAP_NUMBER_TYPE));
1137257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // Comparing JS objects with <=, >= is complicated.
1138257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      if (cc != eq) {
11393fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch      __ Branch(slow, greater, t4, Operand(FIRST_SPEC_OBJECT_TYPE));
1140257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        // Normally here we fall through to return_equal, but undefined is
1141257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        // special: (undefined == undefined) == true, but
1142257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        // (undefined <= undefined) == false!  See ECMAScript 11.8.5.
1143257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        if (cc == less_equal || cc == greater_equal) {
1144257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          __ Branch(&return_equal, ne, t4, Operand(ODDBALL_TYPE));
1145257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          __ LoadRoot(t2, Heap::kUndefinedValueRootIndex);
1146257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          __ Branch(&return_equal, ne, a0, Operand(t2));
1147257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          if (cc == le) {
1148257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch            // undefined <= undefined should fail.
1149257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch            __ li(v0, Operand(GREATER));
1150257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          } else  {
1151257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch            // undefined >= undefined should fail.
1152257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch            __ li(v0, Operand(LESS));
1153257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          }
1154257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          __ Ret();
1155257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        }
1156257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      }
1157257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    }
1158257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
1159257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1160257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&return_equal);
11613ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
1162257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  if (cc == less) {
1163257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ li(v0, Operand(GREATER));  // Things aren't less than themselves.
1164257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  } else if (cc == greater) {
1165257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ li(v0, Operand(LESS));     // Things aren't greater than themselves.
1166257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  } else {
1167257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ mov(v0, zero_reg);         // Things are <=, >=, ==, === themselves.
1168257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
1169257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Ret();
1170257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1171257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  if (cc != eq || !never_nan_nan) {
1172257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // For less and greater we don't have to check for NaN since the result of
1173257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // x < x is false regardless.  For the others here is some code to check
1174257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // for NaN.
1175257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    if (cc != lt && cc != gt) {
1176257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ bind(&heap_number);
1177257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // It is a heap number, so return non-equal if it's NaN and equal if it's
1178257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // not NaN.
1179257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1180257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // The representation of NaN values has all exponent bits (52..62) set,
1181257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // and not all mantissa bits (0..51) clear.
1182257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // Read top bits of double representation (second word of value).
1183257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ lw(t2, FieldMemOperand(a0, HeapNumber::kExponentOffset));
1184257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // Test that exponent bits are all set.
1185257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ And(t3, t2, Operand(exp_mask_reg));
1186257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // If all bits not set (ne cond), then not a NaN, objects are equal.
1187257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ Branch(&return_equal, ne, t3, Operand(exp_mask_reg));
1188257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1189257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // Shift out flag and all exponent bits, retaining only mantissa.
1190257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ sll(t2, t2, HeapNumber::kNonMantissaBitsInTopWord);
1191257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // Or with all low-bits of mantissa.
1192257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ lw(t3, FieldMemOperand(a0, HeapNumber::kMantissaOffset));
1193257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ Or(v0, t3, Operand(t2));
1194257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // For equal we already have the right value in v0:  Return zero (equal)
1195257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // if all bits in mantissa are zero (it's an Infinity) and non-zero if
1196257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // not (it's a NaN).  For <= and >= we need to load v0 with the failing
1197257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // value if it's a NaN.
1198257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      if (cc != eq) {
1199257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        // All-zero means Infinity means equal.
1200257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        __ Ret(eq, v0, Operand(zero_reg));
1201257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        if (cc == le) {
1202257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          __ li(v0, Operand(GREATER));  // NaN <= NaN should fail.
1203257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        } else {
1204257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          __ li(v0, Operand(LESS));     // NaN >= NaN should fail.
1205257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        }
1206257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      }
1207257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ Ret();
1208257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    }
1209257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // No fall through here.
1210257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
1211257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1212257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&not_identical);
1213257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch}
1214257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1215257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1216257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochstatic void EmitSmiNonsmiComparison(MacroAssembler* masm,
1217257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                    Register lhs,
1218257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                    Register rhs,
1219257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                    Label* both_loaded_as_doubles,
1220257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                    Label* slow,
1221257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                    bool strict) {
1222257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  ASSERT((lhs.is(a0) && rhs.is(a1)) ||
1223257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch         (lhs.is(a1) && rhs.is(a0)));
1224257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1225257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label lhs_is_smi;
12263ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ JumpIfSmi(lhs, &lhs_is_smi);
1227257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Rhs is a Smi.
1228257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Check whether the non-smi is a heap number.
1229257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ GetObjectType(lhs, t4, t4);
1230257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  if (strict) {
1231257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // If lhs was not a number and rhs was a Smi then strict equality cannot
1232257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // succeed. Return non-equal (lhs is already not zero).
12333ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ Ret(USE_DELAY_SLOT, ne, t4, Operand(HEAP_NUMBER_TYPE));
1234257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ mov(v0, lhs);
1235257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  } else {
1236257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Smi compared non-strictly with a non-Smi non-heap-number. Call
1237257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // the runtime.
1238257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ Branch(slow, ne, t4, Operand(HEAP_NUMBER_TYPE));
1239257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
1240257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1241257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Rhs is a smi, lhs is a number.
1242257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Convert smi rhs to double.
1243257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  if (CpuFeatures::IsSupported(FPU)) {
1244257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    CpuFeatures::Scope scope(FPU);
1245257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ sra(at, rhs, kSmiTagSize);
1246257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ mtc1(at, f14);
1247257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ cvt_d_w(f14, f14);
1248257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ ldc1(f12, FieldMemOperand(lhs, HeapNumber::kValueOffset));
1249257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  } else {
1250257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Load lhs to a double in a2, a3.
1251257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ lw(a3, FieldMemOperand(lhs, HeapNumber::kValueOffset + 4));
1252257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ lw(a2, FieldMemOperand(lhs, HeapNumber::kValueOffset));
1253257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1254257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Write Smi from rhs to a1 and a0 in double format. t5 is scratch.
1255257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ mov(t6, rhs);
1256257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    ConvertToDoubleStub stub1(a1, a0, t6, t5);
1257257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ push(ra);
12583fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    __ Call(stub1.GetCode());
1259257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1260257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ pop(ra);
1261257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
1262257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1263257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // We now have both loaded as doubles.
1264257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ jmp(both_loaded_as_doubles);
1265257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1266257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&lhs_is_smi);
1267257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Lhs is a Smi.  Check whether the non-smi is a heap number.
1268257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ GetObjectType(rhs, t4, t4);
1269257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  if (strict) {
1270257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // If lhs was not a number and rhs was a Smi then strict equality cannot
1271257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // succeed. Return non-equal.
12723ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ Ret(USE_DELAY_SLOT, ne, t4, Operand(HEAP_NUMBER_TYPE));
1273257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ li(v0, Operand(1));
1274257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  } else {
1275257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Smi compared non-strictly with a non-Smi non-heap-number. Call
1276257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // the runtime.
1277257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ Branch(slow, ne, t4, Operand(HEAP_NUMBER_TYPE));
1278257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
1279257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1280257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Lhs is a smi, rhs is a number.
1281257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Convert smi lhs to double.
1282257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  if (CpuFeatures::IsSupported(FPU)) {
1283257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    CpuFeatures::Scope scope(FPU);
1284257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ sra(at, lhs, kSmiTagSize);
1285257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ mtc1(at, f12);
1286257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ cvt_d_w(f12, f12);
1287257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ ldc1(f14, FieldMemOperand(rhs, HeapNumber::kValueOffset));
1288257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  } else {
1289257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Convert lhs to a double format. t5 is scratch.
1290257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ mov(t6, lhs);
1291257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    ConvertToDoubleStub stub2(a3, a2, t6, t5);
1292257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ push(ra);
12933fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    __ Call(stub2.GetCode());
1294257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ pop(ra);
1295257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Load rhs to a double in a1, a0.
1296257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    if (rhs.is(a0)) {
1297257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ lw(a1, FieldMemOperand(rhs, HeapNumber::kValueOffset + 4));
1298257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ lw(a0, FieldMemOperand(rhs, HeapNumber::kValueOffset));
1299257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    } else {
1300257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ lw(a0, FieldMemOperand(rhs, HeapNumber::kValueOffset));
1301257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ lw(a1, FieldMemOperand(rhs, HeapNumber::kValueOffset + 4));
1302257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    }
1303257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
1304257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Fall through to both_loaded_as_doubles.
130544f0eee88ff00398ff7f715fab053374d808c90dSteve Block}
130644f0eee88ff00398ff7f715fab053374d808c90dSteve Block
130744f0eee88ff00398ff7f715fab053374d808c90dSteve Block
130844f0eee88ff00398ff7f715fab053374d808c90dSteve Blockvoid EmitNanCheck(MacroAssembler* masm, Condition cc) {
1309257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  bool exp_first = (HeapNumber::kExponentOffset == HeapNumber::kValueOffset);
1310257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  if (CpuFeatures::IsSupported(FPU)) {
1311257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    CpuFeatures::Scope scope(FPU);
1312257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Lhs and rhs are already loaded to f12 and f14 register pairs.
1313257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ Move(t0, t1, f14);
1314257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ Move(t2, t3, f12);
1315257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  } else {
1316257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Lhs and rhs are already loaded to GP registers.
1317257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ mov(t0, a0);  // a0 has LS 32 bits of rhs.
1318257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ mov(t1, a1);  // a1 has MS 32 bits of rhs.
1319257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ mov(t2, a2);  // a2 has LS 32 bits of lhs.
1320257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ mov(t3, a3);  // a3 has MS 32 bits of lhs.
1321257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
1322257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Register rhs_exponent = exp_first ? t0 : t1;
1323257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Register lhs_exponent = exp_first ? t2 : t3;
1324257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Register rhs_mantissa = exp_first ? t1 : t0;
1325257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Register lhs_mantissa = exp_first ? t3 : t2;
1326257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label one_is_nan, neither_is_nan;
1327257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label lhs_not_nan_exp_mask_is_loaded;
1328257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1329257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Register exp_mask_reg = t4;
1330257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ li(exp_mask_reg, HeapNumber::kExponentMask);
1331257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ and_(t5, lhs_exponent, exp_mask_reg);
1332257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Branch(&lhs_not_nan_exp_mask_is_loaded, ne, t5, Operand(exp_mask_reg));
1333257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1334257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ sll(t5, lhs_exponent, HeapNumber::kNonMantissaBitsInTopWord);
1335257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Branch(&one_is_nan, ne, t5, Operand(zero_reg));
1336257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1337257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Branch(&one_is_nan, ne, lhs_mantissa, Operand(zero_reg));
1338257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1339257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ li(exp_mask_reg, HeapNumber::kExponentMask);
1340257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&lhs_not_nan_exp_mask_is_loaded);
1341257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ and_(t5, rhs_exponent, exp_mask_reg);
1342257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1343257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Branch(&neither_is_nan, ne, t5, Operand(exp_mask_reg));
1344257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1345257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ sll(t5, rhs_exponent, HeapNumber::kNonMantissaBitsInTopWord);
1346257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Branch(&one_is_nan, ne, t5, Operand(zero_reg));
1347257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1348257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Branch(&neither_is_nan, eq, rhs_mantissa, Operand(zero_reg));
1349257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1350257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&one_is_nan);
1351257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // NaN comparisons always fail.
1352257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Load whatever we need in v0 to make the comparison fail.
13533ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
1354257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  if (cc == lt || cc == le) {
1355257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ li(v0, Operand(GREATER));
1356257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  } else {
1357257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ li(v0, Operand(LESS));
1358257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
13593ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ Ret();
1360257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1361257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&neither_is_nan);
1362257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch}
1363257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1364257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1365257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochstatic void EmitTwoNonNanDoubleComparison(MacroAssembler* masm, Condition cc) {
1366257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // f12 and f14 have the two doubles.  Neither is a NaN.
1367257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Call a native function to do a comparison between two non-NaNs.
1368257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Call C routine that may not cause GC or other trouble.
1369257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // We use a call_was and return manually because we need arguments slots to
1370257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // be freed.
1371257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1372257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label return_result_not_equal, return_result_equal;
1373257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  if (cc == eq) {
1374257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Doubles are not equal unless they have the same bit pattern.
1375257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Exception: 0 and -0.
1376257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    bool exp_first = (HeapNumber::kExponentOffset == HeapNumber::kValueOffset);
1377257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    if (CpuFeatures::IsSupported(FPU)) {
1378257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      CpuFeatures::Scope scope(FPU);
1379257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // Lhs and rhs are already loaded to f12 and f14 register pairs.
1380257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ Move(t0, t1, f14);
1381257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ Move(t2, t3, f12);
1382257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    } else {
1383257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // Lhs and rhs are already loaded to GP registers.
1384257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ mov(t0, a0);  // a0 has LS 32 bits of rhs.
1385257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ mov(t1, a1);  // a1 has MS 32 bits of rhs.
1386257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ mov(t2, a2);  // a2 has LS 32 bits of lhs.
1387257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ mov(t3, a3);  // a3 has MS 32 bits of lhs.
1388257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    }
1389257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Register rhs_exponent = exp_first ? t0 : t1;
1390257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Register lhs_exponent = exp_first ? t2 : t3;
1391257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Register rhs_mantissa = exp_first ? t1 : t0;
1392257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Register lhs_mantissa = exp_first ? t3 : t2;
1393257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1394257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ xor_(v0, rhs_mantissa, lhs_mantissa);
1395257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ Branch(&return_result_not_equal, ne, v0, Operand(zero_reg));
1396257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1397257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ subu(v0, rhs_exponent, lhs_exponent);
1398257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ Branch(&return_result_equal, eq, v0, Operand(zero_reg));
1399257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // 0, -0 case.
1400257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ sll(rhs_exponent, rhs_exponent, kSmiTagSize);
1401257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ sll(lhs_exponent, lhs_exponent, kSmiTagSize);
1402257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ or_(t4, rhs_exponent, lhs_exponent);
1403257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ or_(t4, t4, rhs_mantissa);
1404257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1405257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ Branch(&return_result_not_equal, ne, t4, Operand(zero_reg));
1406257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1407257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ bind(&return_result_equal);
14083ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
1409257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ li(v0, Operand(EQUAL));
1410257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ Ret();
1411257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
1412257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1413257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&return_result_not_equal);
1414257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1415257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  if (!CpuFeatures::IsSupported(FPU)) {
1416257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ push(ra);
14173ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ PrepareCallCFunction(0, 2, t4);
1418257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    if (!IsMipsSoftFloatABI) {
1419257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // We are not using MIPS FPU instructions, and parameters for the runtime
1420257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // function call are prepaired in a0-a3 registers, but function we are
1421257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // calling is compiled with hard-float flag and expecting hard float ABI
1422257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // (parameters in f12/f14 registers). We need to copy parameters from
1423257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // a0-a3 registers to f12/f14 register pairs.
1424257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ Move(f12, a0, a1);
1425257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ Move(f14, a2, a3);
1426257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    }
14273ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
14283ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    AllowExternalCallThatCantCauseGC scope(masm);
14293ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ CallCFunction(ExternalReference::compare_doubles(masm->isolate()),
14303ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch       0, 2);
1431257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ pop(ra);  // Because this function returns int, result is in v0.
1432257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ Ret();
1433257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  } else {
1434257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    CpuFeatures::Scope scope(FPU);
1435257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Label equal, less_than;
14363ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ BranchF(&equal, NULL, eq, f12, f14);
14373ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ BranchF(&less_than, NULL, lt, f12, f14);
14385d4cdbf7a67d3662fa0bee4efdb7edd8daec9b0bBen Murdoch
143985b71799222b55eb5dd74ea26efe0c64ab655c8cBen Murdoch    // Not equal, not less, not NaN, must be greater.
14403ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
1441257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ li(v0, Operand(GREATER));
1442257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ Ret();
1443257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1444257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ bind(&equal);
1445257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ li(v0, Operand(EQUAL));
1446257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ Ret();
1447257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1448257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ bind(&less_than);
1449257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ li(v0, Operand(LESS));
1450257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ Ret();
1451257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
1452257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch}
1453257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1454257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1455257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochstatic void EmitStrictTwoHeapObjectCompare(MacroAssembler* masm,
1456257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                           Register lhs,
1457257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                           Register rhs) {
14583fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    // If either operand is a JS object or an oddball value, then they are
1459257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // not equal since their pointers are different.
1460257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // There is no test for undetectability in strict equality.
14613ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    STATIC_ASSERT(LAST_TYPE == LAST_SPEC_OBJECT_TYPE);
1462257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Label first_non_object;
1463257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Get the type of the first operand into a2 and compare it with
14643fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    // FIRST_SPEC_OBJECT_TYPE.
1465257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ GetObjectType(lhs, a2, a2);
14663fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    __ Branch(&first_non_object, less, a2, Operand(FIRST_SPEC_OBJECT_TYPE));
1467257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1468257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Return non-zero.
1469257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Label return_not_equal;
1470257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ bind(&return_not_equal);
14713ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ Ret(USE_DELAY_SLOT);
1472257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ li(v0, Operand(1));
1473257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1474257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ bind(&first_non_object);
1475257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Check for oddballs: true, false, null, undefined.
1476257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ Branch(&return_not_equal, eq, a2, Operand(ODDBALL_TYPE));
1477257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1478257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ GetObjectType(rhs, a3, a3);
14793fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    __ Branch(&return_not_equal, greater, a3, Operand(FIRST_SPEC_OBJECT_TYPE));
1480257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1481257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Check for oddballs: true, false, null, undefined.
1482257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ Branch(&return_not_equal, eq, a3, Operand(ODDBALL_TYPE));
1483257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1484257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Now that we have the types we might as well check for symbol-symbol.
1485257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Ensure that no non-strings have the symbol bit set.
1486257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    STATIC_ASSERT(LAST_TYPE < kNotStringTag + kIsSymbolMask);
1487257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    STATIC_ASSERT(kSymbolTag != 0);
1488257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ And(t2, a2, Operand(a3));
1489257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ And(t0, t2, Operand(kIsSymbolMask));
1490257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ Branch(&return_not_equal, ne, t0, Operand(zero_reg));
1491257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch}
1492257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1493257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1494257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochstatic void EmitCheckForTwoHeapNumbers(MacroAssembler* masm,
1495257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                       Register lhs,
1496257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                       Register rhs,
1497257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                       Label* both_loaded_as_doubles,
1498257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                       Label* not_heap_numbers,
1499257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                       Label* slow) {
1500257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ GetObjectType(lhs, a3, a2);
1501257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Branch(not_heap_numbers, ne, a2, Operand(HEAP_NUMBER_TYPE));
1502257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ lw(a2, FieldMemOperand(rhs, HeapObject::kMapOffset));
1503257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // If first was a heap number & second wasn't, go to slow case.
1504257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Branch(slow, ne, a3, Operand(a2));
1505257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1506257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Both are heap numbers. Load them up then jump to the code we have
1507257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // for that.
1508257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  if (CpuFeatures::IsSupported(FPU)) {
1509257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    CpuFeatures::Scope scope(FPU);
1510257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ ldc1(f12, FieldMemOperand(lhs, HeapNumber::kValueOffset));
1511257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ ldc1(f14, FieldMemOperand(rhs, HeapNumber::kValueOffset));
1512257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  } else {
1513257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ lw(a2, FieldMemOperand(lhs, HeapNumber::kValueOffset));
1514257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ lw(a3, FieldMemOperand(lhs, HeapNumber::kValueOffset + 4));
1515257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    if (rhs.is(a0)) {
1516257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ lw(a1, FieldMemOperand(rhs, HeapNumber::kValueOffset + 4));
1517257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ lw(a0, FieldMemOperand(rhs, HeapNumber::kValueOffset));
1518257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    } else {
1519257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ lw(a0, FieldMemOperand(rhs, HeapNumber::kValueOffset));
1520257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ lw(a1, FieldMemOperand(rhs, HeapNumber::kValueOffset + 4));
1521257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    }
1522257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
1523257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ jmp(both_loaded_as_doubles);
1524257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch}
1525257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1526257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1527257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// Fast negative check for symbol-to-symbol equality.
1528257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochstatic void EmitCheckForSymbolsOrObjects(MacroAssembler* masm,
1529257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                         Register lhs,
1530257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                         Register rhs,
1531257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                         Label* possible_strings,
1532257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                         Label* not_both_strings) {
1533257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  ASSERT((lhs.is(a0) && rhs.is(a1)) ||
1534257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch         (lhs.is(a1) && rhs.is(a0)));
1535257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1536257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // a2 is object type of lhs.
1537257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Ensure that no non-strings have the symbol bit set.
1538257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label object_test;
1539257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  STATIC_ASSERT(kSymbolTag != 0);
1540257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ And(at, a2, Operand(kIsNotStringMask));
1541257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Branch(&object_test, ne, at, Operand(zero_reg));
1542257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ And(at, a2, Operand(kIsSymbolMask));
1543257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Branch(possible_strings, eq, at, Operand(zero_reg));
1544257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ GetObjectType(rhs, a3, a3);
1545257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Branch(not_both_strings, ge, a3, Operand(FIRST_NONSTRING_TYPE));
1546257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ And(at, a3, Operand(kIsSymbolMask));
1547257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Branch(possible_strings, eq, at, Operand(zero_reg));
1548257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1549257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Both are symbols. We already checked they weren't the same pointer
1550257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // so they are not equal.
15513ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ Ret(USE_DELAY_SLOT);
1552257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ li(v0, Operand(1));   // Non-zero indicates not equal.
1553257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1554257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&object_test);
15553fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ Branch(not_both_strings, lt, a2, Operand(FIRST_SPEC_OBJECT_TYPE));
1556257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ GetObjectType(rhs, a2, a3);
15573fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ Branch(not_both_strings, lt, a3, Operand(FIRST_SPEC_OBJECT_TYPE));
1558257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1559257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // If both objects are undetectable, they are equal.  Otherwise, they
1560257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // are not equal, since they are different objects and an object is not
1561257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // equal to undefined.
1562257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ lw(a3, FieldMemOperand(lhs, HeapObject::kMapOffset));
1563257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ lbu(a2, FieldMemOperand(a2, Map::kBitFieldOffset));
1564257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ lbu(a3, FieldMemOperand(a3, Map::kBitFieldOffset));
1565257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ and_(a0, a2, a3);
1566257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ And(a0, a0, Operand(1 << Map::kIsUndetectable));
15673ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ Ret(USE_DELAY_SLOT);
15683ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ xori(v0, a0, 1 << Map::kIsUndetectable);
156944f0eee88ff00398ff7f715fab053374d808c90dSteve Block}
157044f0eee88ff00398ff7f715fab053374d808c90dSteve Block
157144f0eee88ff00398ff7f715fab053374d808c90dSteve Block
157244f0eee88ff00398ff7f715fab053374d808c90dSteve Blockvoid NumberToStringStub::GenerateLookupNumberStringCache(MacroAssembler* masm,
157344f0eee88ff00398ff7f715fab053374d808c90dSteve Block                                                         Register object,
157444f0eee88ff00398ff7f715fab053374d808c90dSteve Block                                                         Register result,
157544f0eee88ff00398ff7f715fab053374d808c90dSteve Block                                                         Register scratch1,
157644f0eee88ff00398ff7f715fab053374d808c90dSteve Block                                                         Register scratch2,
157744f0eee88ff00398ff7f715fab053374d808c90dSteve Block                                                         Register scratch3,
157844f0eee88ff00398ff7f715fab053374d808c90dSteve Block                                                         bool object_is_smi,
157944f0eee88ff00398ff7f715fab053374d808c90dSteve Block                                                         Label* not_found) {
1580257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Use of registers. Register result is used as a temporary.
1581257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Register number_string_cache = result;
1582257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Register mask = scratch3;
1583257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1584257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Load the number string cache.
1585257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ LoadRoot(number_string_cache, Heap::kNumberStringCacheRootIndex);
1586257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1587257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Make the hash mask from the length of the number string cache. It
1588257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // contains two elements (number and string) for each cache entry.
1589257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ lw(mask, FieldMemOperand(number_string_cache, FixedArray::kLengthOffset));
1590257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Divide length by two (length is a smi).
1591257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ sra(mask, mask, kSmiTagSize + 1);
1592257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Addu(mask, mask, -1);  // Make mask.
1593257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1594257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Calculate the entry in the number string cache. The hash value in the
1595257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // number string cache for smis is just the smi value, and the hash for
1596257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // doubles is the xor of the upper and lower words. See
1597257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Heap::GetNumberStringCache.
1598257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Isolate* isolate = masm->isolate();
1599257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label is_smi;
1600257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label load_result_from_cache;
1601257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  if (!object_is_smi) {
1602257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ JumpIfSmi(object, &is_smi);
1603257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    if (CpuFeatures::IsSupported(FPU)) {
1604257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      CpuFeatures::Scope scope(FPU);
1605257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ CheckMap(object,
1606257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                  scratch1,
1607257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                  Heap::kHeapNumberMapRootIndex,
1608257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                  not_found,
1609257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                  DONT_DO_SMI_CHECK);
1610257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1611257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      STATIC_ASSERT(8 == kDoubleSize);
1612257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ Addu(scratch1,
1613257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch              object,
1614257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch              Operand(HeapNumber::kValueOffset - kHeapObjectTag));
1615257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ lw(scratch2, MemOperand(scratch1, kPointerSize));
1616257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ lw(scratch1, MemOperand(scratch1, 0));
1617257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ Xor(scratch1, scratch1, Operand(scratch2));
1618257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ And(scratch1, scratch1, Operand(mask));
1619257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1620257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // Calculate address of entry in string cache: each entry consists
1621257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // of two pointer sized fields.
1622257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ sll(scratch1, scratch1, kPointerSizeLog2 + 1);
1623257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ Addu(scratch1, number_string_cache, scratch1);
1624257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1625257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      Register probe = mask;
1626257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ lw(probe,
1627257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch             FieldMemOperand(scratch1, FixedArray::kHeaderSize));
1628257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ JumpIfSmi(probe, not_found);
1629257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ ldc1(f12, FieldMemOperand(object, HeapNumber::kValueOffset));
1630257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ ldc1(f14, FieldMemOperand(probe, HeapNumber::kValueOffset));
16313ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      __ BranchF(&load_result_from_cache, NULL, eq, f12, f14);
1632257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ Branch(not_found);
1633257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    } else {
1634257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // Note that there is no cache check for non-FPU case, even though
1635257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // it seems there could be. May be a tiny opimization for non-FPU
1636257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // cores.
1637257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ Branch(not_found);
1638257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    }
1639257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
1640257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1641257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&is_smi);
1642257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Register scratch = scratch1;
1643257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ sra(scratch, object, 1);   // Shift away the tag.
1644257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ And(scratch, mask, Operand(scratch));
1645257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1646257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Calculate address of entry in string cache: each entry consists
1647257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // of two pointer sized fields.
1648257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ sll(scratch, scratch, kPointerSizeLog2 + 1);
1649257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Addu(scratch, number_string_cache, scratch);
1650257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1651257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Check if the entry is the smi we are looking for.
1652257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Register probe = mask;
1653257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ lw(probe, FieldMemOperand(scratch, FixedArray::kHeaderSize));
1654257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Branch(not_found, ne, object, Operand(probe));
1655257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1656257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Get the result from the cache.
1657257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&load_result_from_cache);
1658257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ lw(result,
1659257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch         FieldMemOperand(scratch, FixedArray::kHeaderSize + kPointerSize));
1660257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1661257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ IncrementCounter(isolate->counters()->number_to_string_native(),
1662257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                      1,
1663257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                      scratch1,
1664257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                      scratch2);
166544f0eee88ff00398ff7f715fab053374d808c90dSteve Block}
166644f0eee88ff00398ff7f715fab053374d808c90dSteve Block
166744f0eee88ff00398ff7f715fab053374d808c90dSteve Block
166844f0eee88ff00398ff7f715fab053374d808c90dSteve Blockvoid NumberToStringStub::Generate(MacroAssembler* masm) {
1669257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label runtime;
1670257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1671257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ lw(a1, MemOperand(sp, 0));
1672257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1673257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Generate code to lookup number in the number string cache.
1674257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  GenerateLookupNumberStringCache(masm, a1, v0, a2, a3, t0, false, &runtime);
16753ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ DropAndRet(1);
1676257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1677257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&runtime);
1678257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Handle number to string in the runtime system if not found in the cache.
1679257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ TailCallRuntime(Runtime::kNumberToString, 1, 1);
168044f0eee88ff00398ff7f715fab053374d808c90dSteve Block}
168144f0eee88ff00398ff7f715fab053374d808c90dSteve Block
168244f0eee88ff00398ff7f715fab053374d808c90dSteve Block
168344f0eee88ff00398ff7f715fab053374d808c90dSteve Block// On entry lhs_ (lhs) and rhs_ (rhs) are the things to be compared.
168444f0eee88ff00398ff7f715fab053374d808c90dSteve Block// On exit, v0 is 0, positive, or negative (smi) to indicate the result
168544f0eee88ff00398ff7f715fab053374d808c90dSteve Block// of the comparison.
168644f0eee88ff00398ff7f715fab053374d808c90dSteve Blockvoid CompareStub::Generate(MacroAssembler* masm) {
1687257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label slow;  // Call builtin.
1688257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label not_smis, both_loaded_as_doubles;
1689257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1690257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1691257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  if (include_smi_compare_) {
1692257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Label not_two_smis, smi_done;
1693257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ Or(a2, a1, a0);
1694257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ JumpIfNotSmi(a2, &not_two_smis);
1695257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ sra(a1, a1, 1);
1696257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ sra(a0, a0, 1);
16973ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ Ret(USE_DELAY_SLOT);
16983ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ subu(v0, a1, a0);
1699257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ bind(&not_two_smis);
1700257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  } else if (FLAG_debug_code) {
1701257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ Or(a2, a1, a0);
1702257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ And(a2, a2, kSmiTagMask);
1703257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ Assert(ne, "CompareStub: unexpected smi operands.",
1704257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        a2, Operand(zero_reg));
1705257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
1706257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1707257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1708257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // NOTICE! This code is only reached after a smi-fast-case check, so
1709257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // it is certain that at least one operand isn't a smi.
1710257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1711257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Handle the case where the objects are identical.  Either returns the answer
1712257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // or goes to slow.  Only falls through if the objects were not identical.
1713257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  EmitIdenticalObjectComparison(masm, &slow, cc_, never_nan_nan_);
1714257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1715257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // If either is a Smi (we know that not both are), then they can only
1716257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // be strictly equal if the other is a HeapNumber.
1717257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  STATIC_ASSERT(kSmiTag == 0);
1718257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  ASSERT_EQ(0, Smi::FromInt(0));
1719257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ And(t2, lhs_, Operand(rhs_));
1720257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ JumpIfNotSmi(t2, &not_smis, t0);
1721257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // One operand is a smi. EmitSmiNonsmiComparison generates code that can:
1722257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // 1) Return the answer.
1723257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // 2) Go to slow.
1724257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // 3) Fall through to both_loaded_as_doubles.
1725257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // 4) Jump to rhs_not_nan.
1726257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // In cases 3 and 4 we have found out we were dealing with a number-number
1727257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // comparison and the numbers have been loaded into f12 and f14 as doubles,
1728257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // or in GP registers (a0, a1, a2, a3) depending on the presence of the FPU.
1729257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  EmitSmiNonsmiComparison(masm, lhs_, rhs_,
1730257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                          &both_loaded_as_doubles, &slow, strict_);
1731257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1732257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&both_loaded_as_doubles);
1733257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // f12, f14 are the double representations of the left hand side
1734257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // and the right hand side if we have FPU. Otherwise a2, a3 represent
1735257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // left hand side and a0, a1 represent right hand side.
1736257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1737257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Isolate* isolate = masm->isolate();
1738257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  if (CpuFeatures::IsSupported(FPU)) {
1739257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    CpuFeatures::Scope scope(FPU);
1740257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Label nan;
1741257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ li(t0, Operand(LESS));
1742257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ li(t1, Operand(GREATER));
1743257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ li(t2, Operand(EQUAL));
1744257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1745257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Check if either rhs or lhs is NaN.
17463ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ BranchF(NULL, &nan, eq, f12, f14);
1747257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1748257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Check if LESS condition is satisfied. If true, move conditionally
1749257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // result to v0.
1750257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ c(OLT, D, f12, f14);
17513ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ Movt(v0, t0);
1752257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Use previous check to store conditionally to v0 oposite condition
1753257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // (GREATER). If rhs is equal to lhs, this will be corrected in next
1754257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // check.
17553ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ Movf(v0, t1);
1756257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Check if EQUAL condition is satisfied. If true, move conditionally
1757257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // result to v0.
1758257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ c(EQ, D, f12, f14);
17593ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ Movt(v0, t2);
1760257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1761257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ Ret();
1762257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1763257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ bind(&nan);
1764257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // NaN comparisons always fail.
1765257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Load whatever we need in v0 to make the comparison fail.
1766257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    if (cc_ == lt || cc_ == le) {
1767257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ li(v0, Operand(GREATER));
1768257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    } else {
1769257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ li(v0, Operand(LESS));
1770257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    }
1771257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ Ret();
1772257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  } else {
1773257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Checks for NaN in the doubles we have loaded.  Can return the answer or
1774257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // fall through if neither is a NaN.  Also binds rhs_not_nan.
1775257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    EmitNanCheck(masm, cc_);
1776257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1777257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Compares two doubles that are not NaNs. Returns the answer.
1778257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Never falls through.
1779257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    EmitTwoNonNanDoubleComparison(masm, cc_);
1780257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
1781257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1782257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&not_smis);
1783257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // At this point we know we are dealing with two different objects,
1784257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // and neither of them is a Smi. The objects are in lhs_ and rhs_.
1785257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  if (strict_) {
1786257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // This returns non-equal for some object types, or falls through if it
1787257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // was not lucky.
1788257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    EmitStrictTwoHeapObjectCompare(masm, lhs_, rhs_);
1789257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
1790257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1791257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label check_for_symbols;
1792257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label flat_string_check;
1793257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Check for heap-number-heap-number comparison. Can jump to slow case,
1794257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // or load both doubles and jump to the code that handles
1795257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // that case. If the inputs are not doubles then jumps to check_for_symbols.
1796257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // In this case a2 will contain the type of lhs_.
1797257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  EmitCheckForTwoHeapNumbers(masm,
1798257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                             lhs_,
1799257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                             rhs_,
1800257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                             &both_loaded_as_doubles,
1801257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                             &check_for_symbols,
1802257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                             &flat_string_check);
1803257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1804257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&check_for_symbols);
1805257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  if (cc_ == eq && !strict_) {
1806257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Returns an answer for two symbols or two detectable objects.
1807257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Otherwise jumps to string case or not both strings case.
1808257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Assumes that a2 is the type of lhs_ on entry.
1809257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    EmitCheckForSymbolsOrObjects(masm, lhs_, rhs_, &flat_string_check, &slow);
1810257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
1811257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1812257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Check for both being sequential ASCII strings, and inline if that is the
1813257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // case.
1814257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&flat_string_check);
1815257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1816257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ JumpIfNonSmisNotBothSequentialAsciiStrings(lhs_, rhs_, a2, a3, &slow);
1817257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1818257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ IncrementCounter(isolate->counters()->string_compare_native(), 1, a2, a3);
1819257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  if (cc_ == eq) {
1820257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    StringCompareStub::GenerateFlatAsciiStringEquals(masm,
1821257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                                     lhs_,
1822257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                                     rhs_,
1823257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                                     a2,
1824257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                                     a3,
1825257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                                     t0);
1826257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  } else {
1827257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    StringCompareStub::GenerateCompareFlatAsciiStrings(masm,
1828257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                                       lhs_,
1829257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                                       rhs_,
1830257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                                       a2,
1831257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                                       a3,
1832257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                                       t0,
1833257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                                       t1);
1834257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
1835257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Never falls through to here.
1836257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1837257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&slow);
1838257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Prepare for call to builtin. Push object pointers, a0 (lhs) first,
1839257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // a1 (rhs) second.
1840257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Push(lhs_, rhs_);
1841257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Figure out which native to call and setup the arguments.
1842257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Builtins::JavaScript native;
1843257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  if (cc_ == eq) {
1844257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    native = strict_ ? Builtins::STRICT_EQUALS : Builtins::EQUALS;
1845257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  } else {
1846257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    native = Builtins::COMPARE;
1847257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    int ncr;  // NaN compare result.
1848257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    if (cc_ == lt || cc_ == le) {
1849257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      ncr = GREATER;
1850257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    } else {
1851257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      ASSERT(cc_ == gt || cc_ == ge);  // Remaining cases.
1852257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      ncr = LESS;
1853257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    }
1854257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ li(a0, Operand(Smi::FromInt(ncr)));
1855257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ push(a0);
1856257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
1857257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1858257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Call the native; it returns -1 (less), 0 (equal), or 1 (greater)
1859257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // tagged as a small integer.
1860257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ InvokeBuiltin(native, JUMP_FUNCTION);
186144f0eee88ff00398ff7f715fab053374d808c90dSteve Block}
186244f0eee88ff00398ff7f715fab053374d808c90dSteve Block
186344f0eee88ff00398ff7f715fab053374d808c90dSteve Block
18643ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch// The stub expects its argument in the tos_ register and returns its result in
18653ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch// it, too: zero for false, and a non-zero value for true.
186644f0eee88ff00398ff7f715fab053374d808c90dSteve Blockvoid ToBooleanStub::Generate(MacroAssembler* masm) {
1867257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // This stub uses FPU instructions.
1868257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  CpuFeatures::Scope scope(FPU);
1869257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
18703ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  Label patch;
18713ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  const Register map = t5.is(tos_) ? t3 : t5;
1872592a9fc1d8ea420377a2e7efd0600e20b058be2bBen Murdoch
18733ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // undefined -> false.
18743ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  CheckOddball(masm, UNDEFINED, Heap::kUndefinedValueRootIndex, false);
18753ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
18763ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Boolean -> its value.
18773ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  CheckOddball(masm, BOOLEAN, Heap::kFalseValueRootIndex, false);
18783ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  CheckOddball(masm, BOOLEAN, Heap::kTrueValueRootIndex, true);
18793ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
18803ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // 'null' -> false.
18813ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  CheckOddball(masm, NULL_TYPE, Heap::kNullValueRootIndex, false);
18823ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
18833ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  if (types_.Contains(SMI)) {
18843ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    // Smis: 0 -> false, all other -> true
18853ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ And(at, tos_, kSmiTagMask);
18863ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    // tos_ contains the correct return value already
18873ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ Ret(eq, at, Operand(zero_reg));
18883ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  } else if (types_.NeedsMap()) {
18893ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    // If we need a map later and have a Smi -> patch.
18903ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ JumpIfSmi(tos_, &patch);
18913ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  }
18923ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
18933ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  if (types_.NeedsMap()) {
18943ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ lw(map, FieldMemOperand(tos_, HeapObject::kMapOffset));
1895592a9fc1d8ea420377a2e7efd0600e20b058be2bBen Murdoch
18963ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    if (types_.CanBeUndetectable()) {
18973ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      __ lbu(at, FieldMemOperand(map, Map::kBitFieldOffset));
18983ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      __ And(at, at, Operand(1 << Map::kIsUndetectable));
18993ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      // Undetectable -> false.
19003ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      __ Movn(tos_, zero_reg, at);
19013ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      __ Ret(ne, at, Operand(zero_reg));
19023ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    }
19033ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  }
19043ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
19053ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  if (types_.Contains(SPEC_OBJECT)) {
19063ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    // Spec object -> true.
19073ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ lbu(at, FieldMemOperand(map, Map::kInstanceTypeOffset));
19083ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    // tos_ contains the correct non-zero return value already.
19093ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ Ret(ge, at, Operand(FIRST_SPEC_OBJECT_TYPE));
19103ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  }
19113ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
19123ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  if (types_.Contains(STRING)) {
19133ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    // String value -> false iff empty.
19143ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ lbu(at, FieldMemOperand(map, Map::kInstanceTypeOffset));
19153ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    Label skip;
19163ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ Branch(&skip, ge, at, Operand(FIRST_NONSTRING_TYPE));
19173ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ Ret(USE_DELAY_SLOT);  // the string length is OK as the return value
19183ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ lw(tos_, FieldMemOperand(tos_, String::kLengthOffset));
19193ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ bind(&skip);
19203ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  }
19213ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
19223ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  if (types_.Contains(HEAP_NUMBER)) {
19233ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    // Heap number -> false iff +0, -0, or NaN.
19243ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    Label not_heap_number;
19253ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ LoadRoot(at, Heap::kHeapNumberMapRootIndex);
19263ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ Branch(&not_heap_number, ne, map, Operand(at));
19273ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    Label zero_or_nan, number;
19283ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ ldc1(f2, FieldMemOperand(tos_, HeapNumber::kValueOffset));
19293ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ BranchF(&number, &zero_or_nan, ne, f2, kDoubleRegZero);
19303ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    // "tos_" is a register, and contains a non zero value by default.
19313ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    // Hence we only need to overwrite "tos_" with zero to return false for
19323ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    // FP_ZERO or FP_NAN cases. Otherwise, by default it returns true.
19333ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ bind(&zero_or_nan);
19343ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ mov(tos_, zero_reg);
19353ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ bind(&number);
19363ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ Ret();
19373ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ bind(&not_heap_number);
19383ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  }
19393ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
19403ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ bind(&patch);
19413ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  GenerateTypeTransition(masm);
19423ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch}
19433ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
19443ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
19453ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochvoid ToBooleanStub::CheckOddball(MacroAssembler* masm,
19463ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                                 Type type,
19473ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                                 Heap::RootListIndex value,
19483ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                                 bool result) {
19493ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  if (types_.Contains(type)) {
19503ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    // If we see an expected oddball, return its ToBoolean value tos_.
19513ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ LoadRoot(at, value);
19523ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ Subu(at, at, tos_);  // This is a check for equality for the movz below.
19533ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    // The value of a root is never NULL, so we can avoid loading a non-null
19543ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    // value into tos_ when we want to return 'true'.
19553ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    if (!result) {
19563ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      __ Movz(tos_, zero_reg, at);
19573ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    }
19583ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ Ret(eq, at, Operand(zero_reg));
19593ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  }
19603ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch}
19613ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
19623ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
19633ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochvoid ToBooleanStub::GenerateTypeTransition(MacroAssembler* masm) {
19643ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ Move(a3, tos_);
19653ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ li(a2, Operand(Smi::FromInt(tos_.code())));
19663ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ li(a1, Operand(Smi::FromInt(types_.ToByte())));
19673ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ Push(a3, a2, a1);
19683ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Patch the caller to an appropriate specialized stub and return the
19693ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // operation result to the caller of the stub.
19703ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ TailCallExternalReference(
19713ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      ExternalReference(IC_Utility(IC::kToBoolean_Patch), masm->isolate()),
19723ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      3,
19733ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      1);
19743ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch}
19753ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
19763ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
19773ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochvoid StoreBufferOverflowStub::Generate(MacroAssembler* masm) {
19783ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // We don't allow a GC during a store buffer overflow so there is no need to
19793ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // store the registers in any particular way, but we do have to store and
19803ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // restore them.
19813ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ MultiPush(kJSCallerSaved | ra.bit());
19823ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  if (save_doubles_ == kSaveFPRegs) {
19833ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    CpuFeatures::Scope scope(FPU);
19843ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ MultiPushFPU(kCallerSavedFPU);
19853ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  }
19863ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  const int argument_count = 1;
19873ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  const int fp_argument_count = 0;
19883ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  const Register scratch = a1;
19893ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
19903ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  AllowExternalCallThatCantCauseGC scope(masm);
19913ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ PrepareCallCFunction(argument_count, fp_argument_count, scratch);
19923ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ li(a0, Operand(ExternalReference::isolate_address()));
19933ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ CallCFunction(
19943ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      ExternalReference::store_buffer_overflow_function(masm->isolate()),
19953ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      argument_count);
19963ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  if (save_doubles_ == kSaveFPRegs) {
19973ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    CpuFeatures::Scope scope(FPU);
19983ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ MultiPopFPU(kCallerSavedFPU);
19993ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  }
20003ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
20013ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ MultiPop(kJSCallerSaved | ra.bit());
2002257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Ret();
200344f0eee88ff00398ff7f715fab053374d808c90dSteve Block}
200444f0eee88ff00398ff7f715fab053374d808c90dSteve Block
200544f0eee88ff00398ff7f715fab053374d808c90dSteve Block
20063fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdochvoid UnaryOpStub::PrintName(StringStream* stream) {
2007257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  const char* op_name = Token::Name(op_);
2008257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  const char* overwrite_name = NULL;  // Make g++ happy.
2009257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  switch (mode_) {
2010257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case UNARY_NO_OVERWRITE: overwrite_name = "Alloc"; break;
2011257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case UNARY_OVERWRITE: overwrite_name = "Overwrite"; break;
2012257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
20133fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  stream->Add("UnaryOpStub_%s_%s_%s",
20143fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch              op_name,
20153fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch              overwrite_name,
20163fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch              UnaryOpIC::GetName(operand_type_));
201744f0eee88ff00398ff7f715fab053374d808c90dSteve Block}
201844f0eee88ff00398ff7f715fab053374d808c90dSteve Block
201944f0eee88ff00398ff7f715fab053374d808c90dSteve Block
2020257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// TODO(svenpanne): Use virtual functions instead of switch.
2021257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::Generate(MacroAssembler* masm) {
2022257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  switch (operand_type_) {
2023257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case UnaryOpIC::UNINITIALIZED:
2024257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      GenerateTypeTransition(masm);
2025257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      break;
2026257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case UnaryOpIC::SMI:
2027257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      GenerateSmiStub(masm);
2028257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      break;
2029257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case UnaryOpIC::HEAP_NUMBER:
2030257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      GenerateHeapNumberStub(masm);
2031257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      break;
2032257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case UnaryOpIC::GENERIC:
2033257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      GenerateGenericStub(masm);
2034257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      break;
2035257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
203644f0eee88ff00398ff7f715fab053374d808c90dSteve Block}
203744f0eee88ff00398ff7f715fab053374d808c90dSteve Block
203844f0eee88ff00398ff7f715fab053374d808c90dSteve Block
2039257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::GenerateTypeTransition(MacroAssembler* masm) {
2040257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Argument is in a0 and v0 at this point, so we can overwrite a0.
20413fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ li(a2, Operand(Smi::FromInt(op_)));
20423fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ li(a1, Operand(Smi::FromInt(mode_)));
2043257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ li(a0, Operand(Smi::FromInt(operand_type_)));
2044257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Push(v0, a2, a1, a0);
2045257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
2046257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ TailCallExternalReference(
20473fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch      ExternalReference(IC_Utility(IC::kUnaryOp_Patch), masm->isolate()), 4, 1);
204844f0eee88ff00398ff7f715fab053374d808c90dSteve Block}
204944f0eee88ff00398ff7f715fab053374d808c90dSteve Block
205044f0eee88ff00398ff7f715fab053374d808c90dSteve Block
2051257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// TODO(svenpanne): Use virtual functions instead of switch.
2052257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::GenerateSmiStub(MacroAssembler* masm) {
2053257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  switch (op_) {
2054257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case Token::SUB:
2055257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      GenerateSmiStubSub(masm);
2056257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      break;
2057257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case Token::BIT_NOT:
2058257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      GenerateSmiStubBitNot(masm);
2059257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      break;
2060257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    default:
2061257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      UNREACHABLE();
2062257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
2063257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch}
2064257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
2065257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
2066257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::GenerateSmiStubSub(MacroAssembler* masm) {
2067257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label non_smi, slow;
2068257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  GenerateSmiCodeSub(masm, &non_smi, &slow);
2069257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&non_smi);
2070257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&slow);
2071257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  GenerateTypeTransition(masm);
2072257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch}
2073257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
2074257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
2075257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::GenerateSmiStubBitNot(MacroAssembler* masm) {
2076257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label non_smi;
2077257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  GenerateSmiCodeBitNot(masm, &non_smi);
2078257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&non_smi);
2079257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  GenerateTypeTransition(masm);
2080257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch}
2081257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
2082257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
2083257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::GenerateSmiCodeSub(MacroAssembler* masm,
2084257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                     Label* non_smi,
2085257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                     Label* slow) {
2086257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ JumpIfNotSmi(a0, non_smi);
2087257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
2088257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // The result of negating zero or the smallest negative smi is not a smi.
2089257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ And(t0, a0, ~0x80000000);
2090257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Branch(slow, eq, t0, Operand(zero_reg));
2091257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
2092257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Return '0 - value'.
20933ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ Ret(USE_DELAY_SLOT);
20943ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ subu(v0, zero_reg, a0);
2095257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch}
2096257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
2097257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
2098257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::GenerateSmiCodeBitNot(MacroAssembler* masm,
2099257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                        Label* non_smi) {
2100257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ JumpIfNotSmi(a0, non_smi);
2101257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
2102257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Flip bits and revert inverted smi-tag.
2103257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Neg(v0, a0);
2104257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ And(v0, v0, ~kSmiTagMask);
2105257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Ret();
210644f0eee88ff00398ff7f715fab053374d808c90dSteve Block}
210744f0eee88ff00398ff7f715fab053374d808c90dSteve Block
210844f0eee88ff00398ff7f715fab053374d808c90dSteve Block
2109257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// TODO(svenpanne): Use virtual functions instead of switch.
2110257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::GenerateHeapNumberStub(MacroAssembler* masm) {
2111257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  switch (op_) {
2112257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case Token::SUB:
2113257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      GenerateHeapNumberStubSub(masm);
2114257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      break;
2115257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case Token::BIT_NOT:
2116257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      GenerateHeapNumberStubBitNot(masm);
2117257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      break;
2118257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    default:
2119257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      UNREACHABLE();
2120257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
2121257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch}
2122257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
2123257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
2124257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::GenerateHeapNumberStubSub(MacroAssembler* masm) {
2125257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label non_smi, slow, call_builtin;
2126257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  GenerateSmiCodeSub(masm, &non_smi, &call_builtin);
2127257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&non_smi);
2128257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  GenerateHeapNumberCodeSub(masm, &slow);
2129257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&slow);
2130257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  GenerateTypeTransition(masm);
2131257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&call_builtin);
2132257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  GenerateGenericCodeFallback(masm);
2133257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch}
2134257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
2135257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
2136257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::GenerateHeapNumberStubBitNot(MacroAssembler* masm) {
2137257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label non_smi, slow;
2138257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  GenerateSmiCodeBitNot(masm, &non_smi);
2139257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&non_smi);
2140257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  GenerateHeapNumberCodeBitNot(masm, &slow);
2141257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&slow);
2142257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  GenerateTypeTransition(masm);
2143257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch}
2144257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
21453fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
2146257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::GenerateHeapNumberCodeSub(MacroAssembler* masm,
2147257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                            Label* slow) {
2148257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  EmitCheckForHeapNumber(masm, a0, a1, t2, slow);
2149257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // a0 is a heap number.  Get a new heap number in a1.
2150257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  if (mode_ == UNARY_OVERWRITE) {
2151257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ lw(a2, FieldMemOperand(a0, HeapNumber::kExponentOffset));
2152257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ Xor(a2, a2, Operand(HeapNumber::kSignMask));  // Flip sign.
2153257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ sw(a2, FieldMemOperand(a0, HeapNumber::kExponentOffset));
2154257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  } else {
2155257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Label slow_allocate_heapnumber, heapnumber_allocated;
2156257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ AllocateHeapNumber(a1, a2, a3, t2, &slow_allocate_heapnumber);
2157257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ jmp(&heapnumber_allocated);
2158257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
2159257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ bind(&slow_allocate_heapnumber);
21603ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    {
21613ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      FrameScope scope(masm, StackFrame::INTERNAL);
21623ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      __ push(a0);
21633ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      __ CallRuntime(Runtime::kNumberAlloc, 0);
21643ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      __ mov(a1, v0);
21653ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      __ pop(a0);
21663ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    }
2167257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
2168257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ bind(&heapnumber_allocated);
2169257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ lw(a3, FieldMemOperand(a0, HeapNumber::kMantissaOffset));
2170257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ lw(a2, FieldMemOperand(a0, HeapNumber::kExponentOffset));
2171257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ sw(a3, FieldMemOperand(a1, HeapNumber::kMantissaOffset));
2172257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ Xor(a2, a2, Operand(HeapNumber::kSignMask));  // Flip sign.
2173257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ sw(a2, FieldMemOperand(a1, HeapNumber::kExponentOffset));
2174257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ mov(v0, a1);
2175257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
2176257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Ret();
2177257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch}
2178257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
2179257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
2180257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::GenerateHeapNumberCodeBitNot(
2181257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    MacroAssembler* masm,
2182257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Label* slow) {
21833fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  Label impossible;
21843fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
2185257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  EmitCheckForHeapNumber(masm, a0, a1, t2, slow);
2186257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Convert the heap number in a0 to an untagged integer in a1.
2187257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ ConvertToInt32(a0, a1, a2, a3, f0, slow);
2188257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
2189257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Do the bitwise operation and check if the result fits in a smi.
2190257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label try_float;
2191257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Neg(a1, a1);
2192257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Addu(a2, a1, Operand(0x40000000));
2193257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Branch(&try_float, lt, a2, Operand(zero_reg));
2194257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
2195257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Tag the result as a smi and we're done.
2196257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ SmiTag(v0, a1);
2197257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Ret();
2198257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
2199257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Try to store the result in a heap number.
2200257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&try_float);
2201257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  if (mode_ == UNARY_NO_OVERWRITE) {
2202257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Label slow_allocate_heapnumber, heapnumber_allocated;
22033fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    // Allocate a new heap number without zapping v0, which we need if it fails.
22043fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    __ AllocateHeapNumber(a2, a3, t0, t2, &slow_allocate_heapnumber);
2205257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ jmp(&heapnumber_allocated);
2206257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
2207257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ bind(&slow_allocate_heapnumber);
22083ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    {
22093ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      FrameScope scope(masm, StackFrame::INTERNAL);
22103ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      __ push(v0);  // Push the heap number, not the untagged int32.
22113ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      __ CallRuntime(Runtime::kNumberAlloc, 0);
22123ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      __ mov(a2, v0);  // Move the new heap number into a2.
22133ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      // Get the heap number into v0, now that the new heap number is in a2.
22143ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      __ pop(v0);
22153ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    }
2216257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
22173fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    // Convert the heap number in v0 to an untagged integer in a1.
22183fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    // This can't go slow-case because it's the same number we already
22193fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    // converted once again.
22203fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    __ ConvertToInt32(v0, a1, a3, t0, f0, &impossible);
22213fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    // Negate the result.
22223fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    __ Xor(a1, a1, -1);
22233fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
2224257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ bind(&heapnumber_allocated);
22253fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    __ mov(v0, a2);  // Move newly allocated heap number to v0.
2226257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
2227257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
2228257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  if (CpuFeatures::IsSupported(FPU)) {
2229257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Convert the int32 in a1 to the heap number in v0. a2 is corrupted.
2230257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    CpuFeatures::Scope scope(FPU);
2231257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ mtc1(a1, f0);
2232257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ cvt_d_w(f0, f0);
2233257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ sdc1(f0, FieldMemOperand(v0, HeapNumber::kValueOffset));
2234257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ Ret();
2235257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  } else {
2236257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // WriteInt32ToHeapNumberStub does not trigger GC, so we do not
2237257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // have to set up a frame.
2238257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    WriteInt32ToHeapNumberStub stub(a1, v0, a2, a3);
2239257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ Jump(stub.GetCode(), RelocInfo::CODE_TARGET);
2240257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
22413fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
22423fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ bind(&impossible);
22433fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  if (FLAG_debug_code) {
22443fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    __ stop("Incorrect assumption in bit-not stub");
22453fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  }
2246257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch}
2247257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
2248257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
2249257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// TODO(svenpanne): Use virtual functions instead of switch.
2250257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::GenerateGenericStub(MacroAssembler* masm) {
2251257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  switch (op_) {
2252257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case Token::SUB:
2253257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      GenerateGenericStubSub(masm);
2254257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      break;
2255257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case Token::BIT_NOT:
2256257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      GenerateGenericStubBitNot(masm);
2257257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      break;
2258257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    default:
2259257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      UNREACHABLE();
2260257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
2261257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch}
2262257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
2263257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
2264257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::GenerateGenericStubSub(MacroAssembler* masm) {
2265257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label non_smi, slow;
2266257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  GenerateSmiCodeSub(masm, &non_smi, &slow);
2267257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&non_smi);
2268257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  GenerateHeapNumberCodeSub(masm, &slow);
2269257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&slow);
2270257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  GenerateGenericCodeFallback(masm);
2271257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch}
2272257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
2273257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
2274257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::GenerateGenericStubBitNot(MacroAssembler* masm) {
2275257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label non_smi, slow;
2276257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  GenerateSmiCodeBitNot(masm, &non_smi);
2277257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&non_smi);
2278257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  GenerateHeapNumberCodeBitNot(masm, &slow);
2279257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&slow);
2280257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  GenerateGenericCodeFallback(masm);
2281257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch}
2282257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
2283257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
2284257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::GenerateGenericCodeFallback(
2285257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    MacroAssembler* masm) {
2286257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Handle the slow case by jumping to the JavaScript builtin.
2287257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ push(a0);
2288257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  switch (op_) {
2289257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case Token::SUB:
2290257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ InvokeBuiltin(Builtins::UNARY_MINUS, JUMP_FUNCTION);
2291257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      break;
2292257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case Token::BIT_NOT:
2293257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ InvokeBuiltin(Builtins::BIT_NOT, JUMP_FUNCTION);
2294257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      break;
2295257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    default:
2296257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      UNREACHABLE();
2297257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
2298257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch}
2299257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
2300257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
2301257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid BinaryOpStub::GenerateTypeTransition(MacroAssembler* masm) {
2302257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label get_result;
2303257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
2304257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Push(a1, a0);
2305257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
2306257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ li(a2, Operand(Smi::FromInt(MinorKey())));
2307257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ li(a1, Operand(Smi::FromInt(op_)));
2308257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ li(a0, Operand(Smi::FromInt(operands_type_)));
2309257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Push(a2, a1, a0);
2310257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
2311257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ TailCallExternalReference(
2312257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      ExternalReference(IC_Utility(IC::kBinaryOp_Patch),
2313257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                        masm->isolate()),
2314257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      5,
2315257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      1);
231644f0eee88ff00398ff7f715fab053374d808c90dSteve Block}
231744f0eee88ff00398ff7f715fab053374d808c90dSteve Block
231844f0eee88ff00398ff7f715fab053374d808c90dSteve Block
2319257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid BinaryOpStub::GenerateTypeTransitionWithSavedArgs(
232044f0eee88ff00398ff7f715fab053374d808c90dSteve Block    MacroAssembler* masm) {
232144f0eee88ff00398ff7f715fab053374d808c90dSteve Block  UNIMPLEMENTED();
232244f0eee88ff00398ff7f715fab053374d808c90dSteve Block}
232344f0eee88ff00398ff7f715fab053374d808c90dSteve Block
232444f0eee88ff00398ff7f715fab053374d808c90dSteve Block
2325257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid BinaryOpStub::Generate(MacroAssembler* masm) {
23263ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Explicitly allow generation of nested stubs. It is safe here because
23273ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // generation code does not use any raw pointers.
23283ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  AllowStubCallsScope allow_stub_calls(masm, true);
2329257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  switch (operands_type_) {
2330257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case BinaryOpIC::UNINITIALIZED:
2331257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      GenerateTypeTransition(masm);
2332257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      break;
2333257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case BinaryOpIC::SMI:
2334257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      GenerateSmiStub(masm);
2335257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      break;
2336257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case BinaryOpIC::INT32:
2337257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      GenerateInt32Stub(masm);
2338257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      break;
2339257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case BinaryOpIC::HEAP_NUMBER:
2340257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      GenerateHeapNumberStub(masm);
2341257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      break;
2342257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case BinaryOpIC::ODDBALL:
2343257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      GenerateOddballStub(masm);
2344257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      break;
2345257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case BinaryOpIC::BOTH_STRING:
2346257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      GenerateBothStringStub(masm);
2347257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      break;
2348257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case BinaryOpIC::STRING:
2349257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      GenerateStringStub(masm);
2350257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      break;
2351257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case BinaryOpIC::GENERIC:
2352257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      GenerateGeneric(masm);
2353257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      break;
2354257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    default:
2355257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      UNREACHABLE();
2356257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
235744f0eee88ff00398ff7f715fab053374d808c90dSteve Block}
235844f0eee88ff00398ff7f715fab053374d808c90dSteve Block
235944f0eee88ff00398ff7f715fab053374d808c90dSteve Block
23603fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdochvoid BinaryOpStub::PrintName(StringStream* stream) {
2361257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  const char* op_name = Token::Name(op_);
2362257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  const char* overwrite_name;
2363257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  switch (mode_) {
2364257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case NO_OVERWRITE: overwrite_name = "Alloc"; break;
2365257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case OVERWRITE_RIGHT: overwrite_name = "OverwriteRight"; break;
2366257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case OVERWRITE_LEFT: overwrite_name = "OverwriteLeft"; break;
2367257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    default: overwrite_name = "UnknownOverwrite"; break;
2368257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
23693fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  stream->Add("BinaryOpStub_%s_%s_%s",
23703fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch              op_name,
23713fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch              overwrite_name,
23723fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch              BinaryOpIC::GetName(operands_type_));
237344f0eee88ff00398ff7f715fab053374d808c90dSteve Block}
237444f0eee88ff00398ff7f715fab053374d808c90dSteve Block
237544f0eee88ff00398ff7f715fab053374d808c90dSteve Block
237644f0eee88ff00398ff7f715fab053374d808c90dSteve Block
2377257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid BinaryOpStub::GenerateSmiSmiOperation(MacroAssembler* masm) {
2378257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Register left = a1;
2379257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Register right = a0;
2380257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
2381257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Register scratch1 = t0;
2382257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Register scratch2 = t1;
2383257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
2384257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  ASSERT(right.is(a0));
2385257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  STATIC_ASSERT(kSmiTag == 0);
2386257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
2387257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label not_smi_result;
2388257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  switch (op_) {
2389257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case Token::ADD:
2390257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ AdduAndCheckForOverflow(v0, left, right, scratch1);
2391257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ RetOnNoOverflow(scratch1);
2392257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // No need to revert anything - right and left are intact.
2393257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      break;
2394257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case Token::SUB:
2395257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ SubuAndCheckForOverflow(v0, left, right, scratch1);
2396257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ RetOnNoOverflow(scratch1);
2397257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // No need to revert anything - right and left are intact.
2398257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      break;
2399257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case Token::MUL: {
2400257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // Remove tag from one of the operands. This way the multiplication result
2401257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // will be a smi if it fits the smi range.
2402257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ SmiUntag(scratch1, right);
2403257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // Do multiplication.
2404257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // lo = lower 32 bits of scratch1 * left.
2405257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // hi = higher 32 bits of scratch1 * left.
2406257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ Mult(left, scratch1);
2407257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // Check for overflowing the smi range - no overflow if higher 33 bits of
2408257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // the result are identical.
2409257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ mflo(scratch1);
2410257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ mfhi(scratch2);
2411257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ sra(scratch1, scratch1, 31);
2412257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ Branch(&not_smi_result, ne, scratch1, Operand(scratch2));
2413257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // Go slow on zero result to handle -0.
2414257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ mflo(v0);
2415257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ Ret(ne, v0, Operand(zero_reg));
2416257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // We need -0 if we were multiplying a negative number with 0 to get 0.
2417257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // We know one of them was zero.
2418257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ Addu(scratch2, right, left);
2419257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      Label skip;
2420257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // ARM uses the 'pl' condition, which is 'ge'.
2421257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // Negating it results in 'lt'.
2422257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ Branch(&skip, lt, scratch2, Operand(zero_reg));
2423257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      ASSERT(Smi::FromInt(0) == 0);
24243ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      __ Ret(USE_DELAY_SLOT);
24253ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      __ mov(v0, zero_reg);  // Return smi 0 if the non-zero one was positive.
2426257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ bind(&skip);
2427257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // We fall through here if we multiplied a negative number with 0, because
2428257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // that would mean we should produce -0.
2429257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      }
2430257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      break;
2431257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case Token::DIV: {
2432257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      Label done;
2433257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ SmiUntag(scratch2, right);
2434257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ SmiUntag(scratch1, left);
2435257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ Div(scratch1, scratch2);
2436257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // A minor optimization: div may be calculated asynchronously, so we check
2437257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // for division by zero before getting the result.
2438257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ Branch(&not_smi_result, eq, scratch2, Operand(zero_reg));
2439257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // If the result is 0, we need to make sure the dividsor (right) is
2440257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // positive, otherwise it is a -0 case.
2441257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // Quotient is in 'lo', remainder is in 'hi'.
2442257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // Check for no remainder first.
2443257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ mfhi(scratch1);
2444257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ Branch(&not_smi_result, ne, scratch1, Operand(zero_reg));
2445257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ mflo(scratch1);
2446257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ Branch(&done, ne, scratch1, Operand(zero_reg));
2447257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ Branch(&not_smi_result, lt, scratch2, Operand(zero_reg));
2448257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ bind(&done);
2449257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // Check that the signed result fits in a Smi.
2450257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ Addu(scratch2, scratch1, Operand(0x40000000));
2451257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ Branch(&not_smi_result, lt, scratch2, Operand(zero_reg));
2452257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ SmiTag(v0, scratch1);
2453257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ Ret();
2454257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      }
2455257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      break;
2456257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case Token::MOD: {
2457257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      Label done;
2458257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ SmiUntag(scratch2, right);
2459257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ SmiUntag(scratch1, left);
2460257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ Div(scratch1, scratch2);
2461257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // A minor optimization: div may be calculated asynchronously, so we check
2462257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // for division by 0 before calling mfhi.
2463257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // Check for zero on the right hand side.
2464257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ Branch(&not_smi_result, eq, scratch2, Operand(zero_reg));
2465257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // If the result is 0, we need to make sure the dividend (left) is
2466257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // positive (or 0), otherwise it is a -0 case.
2467257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // Remainder is in 'hi'.
2468257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ mfhi(scratch2);
2469257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ Branch(&done, ne, scratch2, Operand(zero_reg));
2470257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ Branch(&not_smi_result, lt, scratch1, Operand(zero_reg));
2471257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ bind(&done);
2472257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // Check that the signed result fits in a Smi.
2473257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ Addu(scratch1, scratch2, Operand(0x40000000));
2474257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ Branch(&not_smi_result, lt, scratch1, Operand(zero_reg));
2475257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ SmiTag(v0, scratch2);
2476257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ Ret();
2477257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      }
2478257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      break;
2479257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case Token::BIT_OR:
24803ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      __ Ret(USE_DELAY_SLOT);
24813ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      __ or_(v0, left, right);
2482257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      break;
2483257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case Token::BIT_AND:
24843ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      __ Ret(USE_DELAY_SLOT);
24853ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      __ and_(v0, left, right);
2486257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      break;
2487257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case Token::BIT_XOR:
24883ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      __ Ret(USE_DELAY_SLOT);
24893ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      __ xor_(v0, left, right);
2490257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      break;
2491257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case Token::SAR:
2492257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // Remove tags from right operand.
2493257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ GetLeastBitsFromSmi(scratch1, right, 5);
2494257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ srav(scratch1, left, scratch1);
2495257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // Smi tag result.
24963ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      __ And(v0, scratch1, ~kSmiTagMask);
2497257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ Ret();
2498257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      break;
2499257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case Token::SHR:
2500257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // Remove tags from operands. We can't do this on a 31 bit number
2501257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // because then the 0s get shifted into bit 30 instead of bit 31.
2502257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ SmiUntag(scratch1, left);
2503257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ GetLeastBitsFromSmi(scratch2, right, 5);
2504257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ srlv(v0, scratch1, scratch2);
2505257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // Unsigned shift is not allowed to produce a negative number, so
2506257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // check the sign bit and the sign bit after Smi tagging.
2507257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ And(scratch1, v0, Operand(0xc0000000));
2508257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ Branch(&not_smi_result, ne, scratch1, Operand(zero_reg));
2509257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // Smi tag result.
2510257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ SmiTag(v0);
2511257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ Ret();
2512257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      break;
2513257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case Token::SHL:
2514257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // Remove tags from operands.
2515257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ SmiUntag(scratch1, left);
2516257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ GetLeastBitsFromSmi(scratch2, right, 5);
2517257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ sllv(scratch1, scratch1, scratch2);
2518257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // Check that the signed result fits in a Smi.
2519257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ Addu(scratch2, scratch1, Operand(0x40000000));
2520257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ Branch(&not_smi_result, lt, scratch2, Operand(zero_reg));
2521257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ SmiTag(v0, scratch1);
2522257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ Ret();
2523257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      break;
2524257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    default:
2525257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      UNREACHABLE();
2526257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
2527257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&not_smi_result);
252844f0eee88ff00398ff7f715fab053374d808c90dSteve Block}
252944f0eee88ff00398ff7f715fab053374d808c90dSteve Block
253044f0eee88ff00398ff7f715fab053374d808c90dSteve Block
2531257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid BinaryOpStub::GenerateFPOperation(MacroAssembler* masm,
2532257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                       bool smi_operands,
2533257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                       Label* not_numbers,
2534257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                       Label* gc_required) {
2535257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Register left = a1;
2536257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Register right = a0;
2537257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Register scratch1 = t3;
2538257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Register scratch2 = t5;
2539257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Register scratch3 = t0;
2540257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
2541257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  ASSERT(smi_operands || (not_numbers != NULL));
2542257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  if (smi_operands && FLAG_debug_code) {
2543257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ AbortIfNotSmi(left);
2544257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ AbortIfNotSmi(right);
2545257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
2546257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
2547257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Register heap_number_map = t2;
2548257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ LoadRoot(heap_number_map, Heap::kHeapNumberMapRootIndex);
2549257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
2550257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  switch (op_) {
2551257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case Token::ADD:
2552257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case Token::SUB:
2553257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case Token::MUL:
2554257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case Token::DIV:
2555257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case Token::MOD: {
2556257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // Load left and right operands into f12 and f14 or a0/a1 and a2/a3
2557257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // depending on whether FPU is available or not.
2558257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      FloatingPointHelper::Destination destination =
2559257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          CpuFeatures::IsSupported(FPU) &&
2560257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          op_ != Token::MOD ?
2561257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch              FloatingPointHelper::kFPURegisters :
2562257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch              FloatingPointHelper::kCoreRegisters;
2563257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
2564257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // Allocate new heap number for result.
2565257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      Register result = s0;
2566257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      GenerateHeapResultAllocation(
2567257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          masm, result, heap_number_map, scratch1, scratch2, gc_required);
2568257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
2569257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // Load the operands.
2570257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      if (smi_operands) {
2571257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        FloatingPointHelper::LoadSmis(masm, destination, scratch1, scratch2);
2572257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      } else {
2573257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        FloatingPointHelper::LoadOperands(masm,
2574257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                          destination,
2575257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                          heap_number_map,
2576257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                          scratch1,
2577257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                          scratch2,
2578257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                          not_numbers);
2579257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      }
2580257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
2581257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // Calculate the result.
2582257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      if (destination == FloatingPointHelper::kFPURegisters) {
2583257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        // Using FPU registers:
2584257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        // f12: Left value.
2585257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        // f14: Right value.
2586257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        CpuFeatures::Scope scope(FPU);
2587257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        switch (op_) {
2588257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        case Token::ADD:
2589257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          __ add_d(f10, f12, f14);
2590257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          break;
2591257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        case Token::SUB:
2592257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          __ sub_d(f10, f12, f14);
2593257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          break;
2594257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        case Token::MUL:
2595257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          __ mul_d(f10, f12, f14);
2596257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          break;
2597257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        case Token::DIV:
2598257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          __ div_d(f10, f12, f14);
2599257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          break;
2600257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        default:
2601257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          UNREACHABLE();
2602257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        }
2603257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
2604257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        // ARM uses a workaround here because of the unaligned HeapNumber
2605257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        // kValueOffset. On MIPS this workaround is built into sdc1 so
2606257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        // there's no point in generating even more instructions.
2607257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        __ sdc1(f10, FieldMemOperand(result, HeapNumber::kValueOffset));
26083ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch        __ Ret(USE_DELAY_SLOT);
2609257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        __ mov(v0, result);
2610257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      } else {
2611257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        // Call the C function to handle the double operation.
2612257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        FloatingPointHelper::CallCCodeForDoubleOperation(masm,
2613257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                                         op_,
2614257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                                         result,
2615257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                                         scratch1);
2616257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        if (FLAG_debug_code) {
2617257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          __ stop("Unreachable code.");
2618257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        }
2619257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      }
2620257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      break;
2621257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    }
2622257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case Token::BIT_OR:
2623257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case Token::BIT_XOR:
2624257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case Token::BIT_AND:
2625257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case Token::SAR:
2626257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case Token::SHR:
2627257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case Token::SHL: {
2628257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      if (smi_operands) {
2629257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        __ SmiUntag(a3, left);
2630257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        __ SmiUntag(a2, right);
2631257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      } else {
2632257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        // Convert operands to 32-bit integers. Right in a2 and left in a3.
2633257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        FloatingPointHelper::ConvertNumberToInt32(masm,
2634257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                                  left,
2635257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                                  a3,
2636257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                                  heap_number_map,
2637257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                                  scratch1,
2638257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                                  scratch2,
2639257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                                  scratch3,
2640257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                                  f0,
2641257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                                  not_numbers);
2642257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        FloatingPointHelper::ConvertNumberToInt32(masm,
2643257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                                  right,
2644257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                                  a2,
2645257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                                  heap_number_map,
2646257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                                  scratch1,
2647257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                                  scratch2,
2648257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                                  scratch3,
2649257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                                  f0,
2650257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                                  not_numbers);
2651257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      }
2652257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      Label result_not_a_smi;
2653257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      switch (op_) {
2654257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        case Token::BIT_OR:
2655257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          __ Or(a2, a3, Operand(a2));
2656257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          break;
2657257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        case Token::BIT_XOR:
2658257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          __ Xor(a2, a3, Operand(a2));
2659257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          break;
2660257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        case Token::BIT_AND:
2661257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          __ And(a2, a3, Operand(a2));
2662257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          break;
2663257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        case Token::SAR:
2664257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          // Use only the 5 least significant bits of the shift count.
2665257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          __ GetLeastBitsFromInt32(a2, a2, 5);
2666257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          __ srav(a2, a3, a2);
2667257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          break;
2668257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        case Token::SHR:
2669257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          // Use only the 5 least significant bits of the shift count.
2670257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          __ GetLeastBitsFromInt32(a2, a2, 5);
2671257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          __ srlv(a2, a3, a2);
2672257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          // SHR is special because it is required to produce a positive answer.
2673257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          // The code below for writing into heap numbers isn't capable of
2674257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          // writing the register as an unsigned int so we go to slow case if we
2675257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          // hit this case.
2676257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          if (CpuFeatures::IsSupported(FPU)) {
2677257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch            __ Branch(&result_not_a_smi, lt, a2, Operand(zero_reg));
2678257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          } else {
2679257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch            __ Branch(not_numbers, lt, a2, Operand(zero_reg));
2680257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          }
2681257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          break;
2682257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        case Token::SHL:
2683257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          // Use only the 5 least significant bits of the shift count.
2684257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          __ GetLeastBitsFromInt32(a2, a2, 5);
2685257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          __ sllv(a2, a3, a2);
2686257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          break;
2687257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        default:
2688257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          UNREACHABLE();
2689257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      }
2690257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // Check that the *signed* result fits in a smi.
2691257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ Addu(a3, a2, Operand(0x40000000));
2692257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ Branch(&result_not_a_smi, lt, a3, Operand(zero_reg));
2693257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ SmiTag(v0, a2);
2694257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ Ret();
2695257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
2696257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // Allocate new heap number for result.
2697257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ bind(&result_not_a_smi);
2698257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      Register result = t1;
2699257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      if (smi_operands) {
2700257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        __ AllocateHeapNumber(
2701257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch            result, scratch1, scratch2, heap_number_map, gc_required);
2702257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      } else {
2703257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        GenerateHeapResultAllocation(
2704257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch            masm, result, heap_number_map, scratch1, scratch2, gc_required);
2705257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      }
2706257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
2707257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // a2: Answer as signed int32.
2708257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // t1: Heap number to write answer into.
2709257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
2710257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // Nothing can go wrong now, so move the heap number to v0, which is the
2711257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // result.
2712257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ mov(v0, t1);
2713257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
2714257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      if (CpuFeatures::IsSupported(FPU)) {
2715257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        // Convert the int32 in a2 to the heap number in a0. As
2716257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        // mentioned above SHR needs to always produce a positive result.
2717257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        CpuFeatures::Scope scope(FPU);
2718257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        __ mtc1(a2, f0);
2719257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        if (op_ == Token::SHR) {
272069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch          __ Cvt_d_uw(f0, f0, f22);
2721257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        } else {
2722257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          __ cvt_d_w(f0, f0);
2723257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        }
2724257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        // ARM uses a workaround here because of the unaligned HeapNumber
2725257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        // kValueOffset. On MIPS this workaround is built into sdc1 so
2726257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        // there's no point in generating even more instructions.
2727257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        __ sdc1(f0, FieldMemOperand(v0, HeapNumber::kValueOffset));
2728257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        __ Ret();
2729257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      } else {
2730257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        // Tail call that writes the int32 in a2 to the heap number in v0, using
2731257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        // a3 and a0 as scratch. v0 is preserved and returned.
2732257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        WriteInt32ToHeapNumberStub stub(a2, v0, a3, a0);
2733257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        __ TailCallStub(&stub);
2734257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      }
2735257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      break;
2736257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    }
2737257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    default:
2738257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      UNREACHABLE();
2739257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
274044f0eee88ff00398ff7f715fab053374d808c90dSteve Block}
274144f0eee88ff00398ff7f715fab053374d808c90dSteve Block
274244f0eee88ff00398ff7f715fab053374d808c90dSteve Block
274344f0eee88ff00398ff7f715fab053374d808c90dSteve Block// Generate the smi code. If the operation on smis are successful this return is
274444f0eee88ff00398ff7f715fab053374d808c90dSteve Block// generated. If the result is not a smi and heap number allocation is not
274544f0eee88ff00398ff7f715fab053374d808c90dSteve Block// requested the code falls through. If number allocation is requested but a
274644f0eee88ff00398ff7f715fab053374d808c90dSteve Block// heap number cannot be allocated the code jumps to the lable gc_required.
2747257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid BinaryOpStub::GenerateSmiCode(
2748257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    MacroAssembler* masm,
2749257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Label* use_runtime,
275044f0eee88ff00398ff7f715fab053374d808c90dSteve Block    Label* gc_required,
275144f0eee88ff00398ff7f715fab053374d808c90dSteve Block    SmiCodeGenerateHeapNumberResults allow_heapnumber_results) {
2752257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label not_smis;
2753257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
2754257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Register left = a1;
2755257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Register right = a0;
2756257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Register scratch1 = t3;
2757257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
2758257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Perform combined smi check on both operands.
2759257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Or(scratch1, left, Operand(right));
2760257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  STATIC_ASSERT(kSmiTag == 0);
2761257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ JumpIfNotSmi(scratch1, &not_smis);
2762257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
2763257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // If the smi-smi operation results in a smi return is generated.
2764257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  GenerateSmiSmiOperation(masm);
2765257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
2766257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // If heap number results are possible generate the result in an allocated
2767257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // heap number.
2768257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  if (allow_heapnumber_results == ALLOW_HEAPNUMBER_RESULTS) {
2769257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    GenerateFPOperation(masm, true, use_runtime, gc_required);
2770257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
2771257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&not_smis);
277244f0eee88ff00398ff7f715fab053374d808c90dSteve Block}
277344f0eee88ff00398ff7f715fab053374d808c90dSteve Block
277444f0eee88ff00398ff7f715fab053374d808c90dSteve Block
2775257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid BinaryOpStub::GenerateSmiStub(MacroAssembler* masm) {
2776257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label not_smis, call_runtime;
2777257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
2778257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  if (result_type_ == BinaryOpIC::UNINITIALIZED ||
2779257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      result_type_ == BinaryOpIC::SMI) {
2780257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Only allow smi results.
2781257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    GenerateSmiCode(masm, &call_runtime, NULL, NO_HEAPNUMBER_RESULTS);
2782257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  } else {
2783257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Allow heap number result and don't make a transition if a heap number
2784257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // cannot be allocated.
2785257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    GenerateSmiCode(masm,
2786257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                    &call_runtime,
2787257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                    &call_runtime,
2788257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                    ALLOW_HEAPNUMBER_RESULTS);
2789257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
2790257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
2791257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Code falls through if the result is not returned as either a smi or heap
2792257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // number.
2793257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  GenerateTypeTransition(masm);
2794257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
2795257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&call_runtime);
2796257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  GenerateCallRuntime(masm);
279744f0eee88ff00398ff7f715fab053374d808c90dSteve Block}
279844f0eee88ff00398ff7f715fab053374d808c90dSteve Block
279944f0eee88ff00398ff7f715fab053374d808c90dSteve Block
2800257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid BinaryOpStub::GenerateStringStub(MacroAssembler* masm) {
2801257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  ASSERT(operands_type_ == BinaryOpIC::STRING);
2802257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Try to add arguments as strings, otherwise, transition to the generic
2803257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // BinaryOpIC type.
2804257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  GenerateAddStrings(masm);
2805257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  GenerateTypeTransition(masm);
280644f0eee88ff00398ff7f715fab053374d808c90dSteve Block}
280744f0eee88ff00398ff7f715fab053374d808c90dSteve Block
280844f0eee88ff00398ff7f715fab053374d808c90dSteve Block
2809257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid BinaryOpStub::GenerateBothStringStub(MacroAssembler* masm) {
2810257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label call_runtime;
2811257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  ASSERT(operands_type_ == BinaryOpIC::BOTH_STRING);
2812257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  ASSERT(op_ == Token::ADD);
2813257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // If both arguments are strings, call the string add stub.
2814257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Otherwise, do a transition.
2815257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
2816257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Registers containing left and right operands respectively.
2817257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Register left = a1;
2818257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Register right = a0;
2819257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
2820257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Test if left operand is a string.
2821257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ JumpIfSmi(left, &call_runtime);
2822257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ GetObjectType(left, a2, a2);
2823257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Branch(&call_runtime, ge, a2, Operand(FIRST_NONSTRING_TYPE));
2824257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
2825257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Test if right operand is a string.
2826257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ JumpIfSmi(right, &call_runtime);
2827257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ GetObjectType(right, a2, a2);
2828257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Branch(&call_runtime, ge, a2, Operand(FIRST_NONSTRING_TYPE));
2829257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
2830257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  StringAddStub string_add_stub(NO_STRING_CHECK_IN_STUB);
2831257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  GenerateRegisterArgsPush(masm);
2832257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ TailCallStub(&string_add_stub);
2833257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
2834257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&call_runtime);
2835257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  GenerateTypeTransition(masm);
283644f0eee88ff00398ff7f715fab053374d808c90dSteve Block}
283744f0eee88ff00398ff7f715fab053374d808c90dSteve Block
283844f0eee88ff00398ff7f715fab053374d808c90dSteve Block
2839257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid BinaryOpStub::GenerateInt32Stub(MacroAssembler* masm) {
2840257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  ASSERT(operands_type_ == BinaryOpIC::INT32);
2841257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
2842257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Register left = a1;
2843257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Register right = a0;
2844257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Register scratch1 = t3;
2845257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Register scratch2 = t5;
2846257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  FPURegister double_scratch = f0;
2847257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  FPURegister single_scratch = f6;
2848257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
2849257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Register heap_number_result = no_reg;
2850257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Register heap_number_map = t2;
2851257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ LoadRoot(heap_number_map, Heap::kHeapNumberMapRootIndex);
2852257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
2853257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label call_runtime;
2854257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Labels for type transition, used for wrong input or output types.
2855257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Both label are currently actually bound to the same position. We use two
2856257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // different label to differentiate the cause leading to type transition.
2857257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label transition;
2858257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
2859257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Smi-smi fast case.
2860257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label skip;
2861257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Or(scratch1, left, right);
2862257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ JumpIfNotSmi(scratch1, &skip);
2863257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  GenerateSmiSmiOperation(masm);
2864257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Fall through if the result is not a smi.
2865257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&skip);
2866257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
2867257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  switch (op_) {
2868257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case Token::ADD:
2869257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case Token::SUB:
2870257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case Token::MUL:
2871257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case Token::DIV:
2872257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case Token::MOD: {
28733fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch      // Load both operands and check that they are 32-bit integer.
28743fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch      // Jump to type transition if they are not. The registers a0 and a1 (right
28753fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch      // and left) are preserved for the runtime call.
28763fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch      FloatingPointHelper::Destination destination =
28773fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch          (CpuFeatures::IsSupported(FPU) && op_ != Token::MOD)
28783fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch              ? FloatingPointHelper::kFPURegisters
28793fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch              : FloatingPointHelper::kCoreRegisters;
28803fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
28813fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch      FloatingPointHelper::LoadNumberAsInt32Double(masm,
28823fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch                                                   right,
28833fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch                                                   destination,
28843fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch                                                   f14,
28853fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch                                                   a2,
28863fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch                                                   a3,
28873fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch                                                   heap_number_map,
28883fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch                                                   scratch1,
28893fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch                                                   scratch2,
28903fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch                                                   f2,
28913fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch                                                   &transition);
28923fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch      FloatingPointHelper::LoadNumberAsInt32Double(masm,
28933fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch                                                   left,
28943fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch                                                   destination,
28953fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch                                                   f12,
28963fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch                                                   t0,
28973fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch                                                   t1,
28983fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch                                                   heap_number_map,
28993fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch                                                   scratch1,
29003fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch                                                   scratch2,
29013fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch                                                   f2,
29023fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch                                                   &transition);
2903257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
2904257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      if (destination == FloatingPointHelper::kFPURegisters) {
2905257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        CpuFeatures::Scope scope(FPU);
2906257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        Label return_heap_number;
2907257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        switch (op_) {
2908257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          case Token::ADD:
2909257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch            __ add_d(f10, f12, f14);
2910257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch            break;
2911257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          case Token::SUB:
2912257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch            __ sub_d(f10, f12, f14);
2913257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch            break;
2914257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          case Token::MUL:
2915257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch            __ mul_d(f10, f12, f14);
2916257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch            break;
2917257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          case Token::DIV:
2918257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch            __ div_d(f10, f12, f14);
2919257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch            break;
2920257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          default:
2921257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch            UNREACHABLE();
2922257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        }
2923257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
2924257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        if (op_ != Token::DIV) {
2925257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          // These operations produce an integer result.
2926257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          // Try to return a smi if we can.
2927257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          // Otherwise return a heap number if allowed, or jump to type
2928257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          // transition.
2929257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
29303ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch          Register except_flag = scratch2;
29313ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch          __ EmitFPUTruncate(kRoundToZero,
29323ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                             single_scratch,
29333ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                             f10,
29343ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                             scratch1,
29353ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                             except_flag);
2936257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
2937257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          if (result_type_ <= BinaryOpIC::INT32) {
29383ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch            // If except_flag != 0, result does not fit in a 32-bit integer.
29393ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch            __ Branch(&transition, ne, except_flag, Operand(zero_reg));
2940257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          }
2941257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
2942257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          // Check if the result fits in a smi.
2943257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          __ mfc1(scratch1, single_scratch);
2944257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          __ Addu(scratch2, scratch1, Operand(0x40000000));
2945257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          // If not try to return a heap number.
2946257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          __ Branch(&return_heap_number, lt, scratch2, Operand(zero_reg));
2947257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          // Check for minus zero. Return heap number for minus zero.
2948257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          Label not_zero;
2949257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          __ Branch(&not_zero, ne, scratch1, Operand(zero_reg));
2950257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          __ mfc1(scratch2, f11);
2951257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          __ And(scratch2, scratch2, HeapNumber::kSignMask);
2952257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          __ Branch(&return_heap_number, ne, scratch2, Operand(zero_reg));
2953257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          __ bind(&not_zero);
2954257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
2955257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          // Tag the result and return.
2956257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          __ SmiTag(v0, scratch1);
2957257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          __ Ret();
2958257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        } else {
2959257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          // DIV just falls through to allocating a heap number.
2960257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        }
2961257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
29623fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch        __ bind(&return_heap_number);
29633fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch        // Return a heap number, or fall through to type transition or runtime
29643fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch        // call if we can't.
29653fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch        if (result_type_ >= ((op_ == Token::DIV) ? BinaryOpIC::HEAP_NUMBER
29663fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch                                                 : BinaryOpIC::INT32)) {
2967257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          // We are using FPU registers so s0 is available.
2968257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          heap_number_result = s0;
2969257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          GenerateHeapResultAllocation(masm,
2970257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                       heap_number_result,
2971257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                       heap_number_map,
2972257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                       scratch1,
2973257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                       scratch2,
2974257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                       &call_runtime);
2975257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          __ mov(v0, heap_number_result);
2976257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          __ sdc1(f10, FieldMemOperand(v0, HeapNumber::kValueOffset));
2977257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          __ Ret();
2978257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        }
2979257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
2980257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        // A DIV operation expecting an integer result falls through
2981257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        // to type transition.
2982257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
2983257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      } else {
2984257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        // We preserved a0 and a1 to be able to call runtime.
2985257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        // Save the left value on the stack.
2986257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        __ Push(t1, t0);
2987257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
2988257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        Label pop_and_call_runtime;
2989257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
2990257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        // Allocate a heap number to store the result.
2991257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        heap_number_result = s0;
2992257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        GenerateHeapResultAllocation(masm,
2993257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                     heap_number_result,
2994257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                     heap_number_map,
2995257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                     scratch1,
2996257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                     scratch2,
2997257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                     &pop_and_call_runtime);
2998257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
2999257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        // Load the left value from the value saved on the stack.
3000257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        __ Pop(a1, a0);
3001257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
3002257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        // Call the C function to handle the double operation.
3003257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        FloatingPointHelper::CallCCodeForDoubleOperation(
3004257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch            masm, op_, heap_number_result, scratch1);
3005257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        if (FLAG_debug_code) {
3006257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          __ stop("Unreachable code.");
3007257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        }
3008257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
3009257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        __ bind(&pop_and_call_runtime);
3010257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        __ Drop(2);
3011257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        __ Branch(&call_runtime);
3012257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      }
3013257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
3014257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      break;
3015257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    }
3016257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
3017257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case Token::BIT_OR:
3018257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case Token::BIT_XOR:
3019257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case Token::BIT_AND:
3020257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case Token::SAR:
3021257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case Token::SHR:
3022257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case Token::SHL: {
3023257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      Label return_heap_number;
3024257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      Register scratch3 = t1;
3025257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // Convert operands to 32-bit integers. Right in a2 and left in a3. The
3026257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // registers a0 and a1 (right and left) are preserved for the runtime
3027257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // call.
3028257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      FloatingPointHelper::LoadNumberAsInt32(masm,
3029257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                             left,
3030257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                             a3,
3031257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                             heap_number_map,
3032257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                             scratch1,
3033257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                             scratch2,
3034257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                             scratch3,
3035257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                             f0,
3036257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                             &transition);
3037257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      FloatingPointHelper::LoadNumberAsInt32(masm,
3038257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                             right,
3039257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                             a2,
3040257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                             heap_number_map,
3041257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                             scratch1,
3042257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                             scratch2,
3043257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                             scratch3,
3044257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                             f0,
3045257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                             &transition);
3046257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
3047257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // The ECMA-262 standard specifies that, for shift operations, only the
3048257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // 5 least significant bits of the shift value should be used.
3049257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      switch (op_) {
3050257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        case Token::BIT_OR:
3051257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          __ Or(a2, a3, Operand(a2));
3052257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          break;
3053257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        case Token::BIT_XOR:
3054257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          __ Xor(a2, a3, Operand(a2));
3055257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          break;
3056257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        case Token::BIT_AND:
3057257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          __ And(a2, a3, Operand(a2));
3058257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          break;
3059257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        case Token::SAR:
3060257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          __ And(a2, a2, Operand(0x1f));
3061257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          __ srav(a2, a3, a2);
3062257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          break;
3063257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        case Token::SHR:
3064257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          __ And(a2, a2, Operand(0x1f));
3065257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          __ srlv(a2, a3, a2);
3066257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          // SHR is special because it is required to produce a positive answer.
3067257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          // We only get a negative result if the shift value (a2) is 0.
3068257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          // This result cannot be respresented as a signed 32-bit integer, try
3069257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          // to return a heap number if we can.
3070257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          // The non FPU code does not support this special case, so jump to
3071257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          // runtime if we don't support it.
3072257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          if (CpuFeatures::IsSupported(FPU)) {
3073257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch            __ Branch((result_type_ <= BinaryOpIC::INT32)
3074257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                        ? &transition
3075257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                        : &return_heap_number,
3076257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                       lt,
3077257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                       a2,
3078257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                       Operand(zero_reg));
3079257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          } else {
3080257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch            __ Branch((result_type_ <= BinaryOpIC::INT32)
3081257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                        ? &transition
3082257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                        : &call_runtime,
3083257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                       lt,
3084257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                       a2,
3085257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                       Operand(zero_reg));
3086257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          }
3087257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          break;
3088257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        case Token::SHL:
3089257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          __ And(a2, a2, Operand(0x1f));
3090257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          __ sllv(a2, a3, a2);
3091257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          break;
3092257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        default:
3093257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          UNREACHABLE();
3094257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      }
3095257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
3096257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // Check if the result fits in a smi.
3097257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ Addu(scratch1, a2, Operand(0x40000000));
3098257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // If not try to return a heap number. (We know the result is an int32.)
3099257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ Branch(&return_heap_number, lt, scratch1, Operand(zero_reg));
3100257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // Tag the result and return.
3101257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ SmiTag(v0, a2);
3102257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ Ret();
3103257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
3104257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ bind(&return_heap_number);
3105257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      heap_number_result = t1;
3106257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      GenerateHeapResultAllocation(masm,
3107257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                   heap_number_result,
3108257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                   heap_number_map,
3109257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                   scratch1,
3110257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                   scratch2,
3111257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                   &call_runtime);
3112257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
3113257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      if (CpuFeatures::IsSupported(FPU)) {
3114257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        CpuFeatures::Scope scope(FPU);
3115257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
3116257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        if (op_ != Token::SHR) {
3117257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          // Convert the result to a floating point value.
3118257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          __ mtc1(a2, double_scratch);
3119257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          __ cvt_d_w(double_scratch, double_scratch);
3120257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        } else {
3121257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          // The result must be interpreted as an unsigned 32-bit integer.
3122257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          __ mtc1(a2, double_scratch);
312369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch          __ Cvt_d_uw(double_scratch, double_scratch, single_scratch);
3124257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        }
3125257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
3126257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        // Store the result.
3127257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        __ mov(v0, heap_number_result);
3128257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        __ sdc1(double_scratch, FieldMemOperand(v0, HeapNumber::kValueOffset));
3129257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        __ Ret();
3130257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      } else {
3131257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        // Tail call that writes the int32 in a2 to the heap number in v0, using
31323ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch        // a3 and a0 as scratch. v0 is preserved and returned.
3133257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        __ mov(a0, t1);
31343ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch        WriteInt32ToHeapNumberStub stub(a2, v0, a3, a0);
3135257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        __ TailCallStub(&stub);
3136257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      }
3137257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
3138257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      break;
3139257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    }
3140257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
3141257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    default:
3142257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      UNREACHABLE();
3143257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
3144257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
31453fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // We never expect DIV to yield an integer result, so we always generate
31463fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // type transition code for DIV operations expecting an integer result: the
31473fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // code will fall through to this type transition.
31483fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  if (transition.is_linked() ||
31493fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch      ((op_ == Token::DIV) && (result_type_ <= BinaryOpIC::INT32))) {
3150257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ bind(&transition);
3151257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    GenerateTypeTransition(masm);
3152257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
3153257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
3154257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&call_runtime);
3155257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  GenerateCallRuntime(masm);
315644f0eee88ff00398ff7f715fab053374d808c90dSteve Block}
315744f0eee88ff00398ff7f715fab053374d808c90dSteve Block
315844f0eee88ff00398ff7f715fab053374d808c90dSteve Block
3159257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid BinaryOpStub::GenerateOddballStub(MacroAssembler* masm) {
3160257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label call_runtime;
3161257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
3162257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  if (op_ == Token::ADD) {
3163257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Handle string addition here, because it is the only operation
3164257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // that does not do a ToNumber conversion on the operands.
3165257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    GenerateAddStrings(masm);
3166257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
3167257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
3168257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Convert oddball arguments to numbers.
3169257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label check, done;
3170257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ LoadRoot(t0, Heap::kUndefinedValueRootIndex);
3171257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Branch(&check, ne, a1, Operand(t0));
3172257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  if (Token::IsBitOp(op_)) {
3173257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ li(a1, Operand(Smi::FromInt(0)));
3174257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  } else {
3175257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ LoadRoot(a1, Heap::kNanValueRootIndex);
3176257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
3177257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ jmp(&done);
3178257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&check);
3179257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ LoadRoot(t0, Heap::kUndefinedValueRootIndex);
3180257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Branch(&done, ne, a0, Operand(t0));
3181257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  if (Token::IsBitOp(op_)) {
3182257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ li(a0, Operand(Smi::FromInt(0)));
3183257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  } else {
3184257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ LoadRoot(a0, Heap::kNanValueRootIndex);
3185257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
3186257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&done);
3187257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
3188257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  GenerateHeapNumberStub(masm);
318944f0eee88ff00398ff7f715fab053374d808c90dSteve Block}
319044f0eee88ff00398ff7f715fab053374d808c90dSteve Block
319144f0eee88ff00398ff7f715fab053374d808c90dSteve Block
3192257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid BinaryOpStub::GenerateHeapNumberStub(MacroAssembler* masm) {
3193257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label call_runtime;
3194257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  GenerateFPOperation(masm, false, &call_runtime, &call_runtime);
3195257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
3196257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&call_runtime);
3197257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  GenerateCallRuntime(masm);
319844f0eee88ff00398ff7f715fab053374d808c90dSteve Block}
319944f0eee88ff00398ff7f715fab053374d808c90dSteve Block
320044f0eee88ff00398ff7f715fab053374d808c90dSteve Block
3201257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid BinaryOpStub::GenerateGeneric(MacroAssembler* masm) {
3202257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label call_runtime, call_string_add_or_runtime;
3203257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
3204257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  GenerateSmiCode(masm, &call_runtime, &call_runtime, ALLOW_HEAPNUMBER_RESULTS);
3205257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
3206257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  GenerateFPOperation(masm, false, &call_string_add_or_runtime, &call_runtime);
3207257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
3208257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&call_string_add_or_runtime);
3209257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  if (op_ == Token::ADD) {
3210257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    GenerateAddStrings(masm);
3211257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
3212257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
3213257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&call_runtime);
3214257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  GenerateCallRuntime(masm);
3215257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch}
3216257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
3217257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
3218257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid BinaryOpStub::GenerateAddStrings(MacroAssembler* masm) {
3219257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  ASSERT(op_ == Token::ADD);
3220257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label left_not_string, call_runtime;
3221257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
3222257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Register left = a1;
3223257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Register right = a0;
3224257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
3225257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Check if left argument is a string.
3226257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ JumpIfSmi(left, &left_not_string);
3227257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ GetObjectType(left, a2, a2);
3228257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Branch(&left_not_string, ge, a2, Operand(FIRST_NONSTRING_TYPE));
3229257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
3230257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  StringAddStub string_add_left_stub(NO_STRING_CHECK_LEFT_IN_STUB);
3231257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  GenerateRegisterArgsPush(masm);
3232257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ TailCallStub(&string_add_left_stub);
3233257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
3234257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Left operand is not a string, test right.
3235257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&left_not_string);
3236257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ JumpIfSmi(right, &call_runtime);
3237257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ GetObjectType(right, a2, a2);
3238257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Branch(&call_runtime, ge, a2, Operand(FIRST_NONSTRING_TYPE));
3239257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
3240257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  StringAddStub string_add_right_stub(NO_STRING_CHECK_RIGHT_IN_STUB);
3241257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  GenerateRegisterArgsPush(masm);
3242257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ TailCallStub(&string_add_right_stub);
3243257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
3244257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // At least one argument is not a string.
3245257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&call_runtime);
3246257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch}
3247257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
3248257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
3249257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid BinaryOpStub::GenerateCallRuntime(MacroAssembler* masm) {
3250257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  GenerateRegisterArgsPush(masm);
3251257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  switch (op_) {
3252257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case Token::ADD:
3253257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ InvokeBuiltin(Builtins::ADD, JUMP_FUNCTION);
3254257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      break;
3255257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case Token::SUB:
3256257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ InvokeBuiltin(Builtins::SUB, JUMP_FUNCTION);
3257257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      break;
3258257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case Token::MUL:
3259257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ InvokeBuiltin(Builtins::MUL, JUMP_FUNCTION);
3260257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      break;
3261257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case Token::DIV:
3262257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ InvokeBuiltin(Builtins::DIV, JUMP_FUNCTION);
3263257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      break;
3264257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case Token::MOD:
3265257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ InvokeBuiltin(Builtins::MOD, JUMP_FUNCTION);
3266257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      break;
3267257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case Token::BIT_OR:
3268257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ InvokeBuiltin(Builtins::BIT_OR, JUMP_FUNCTION);
3269257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      break;
3270257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case Token::BIT_AND:
3271257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ InvokeBuiltin(Builtins::BIT_AND, JUMP_FUNCTION);
3272257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      break;
3273257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case Token::BIT_XOR:
3274257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ InvokeBuiltin(Builtins::BIT_XOR, JUMP_FUNCTION);
3275257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      break;
3276257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case Token::SAR:
3277257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ InvokeBuiltin(Builtins::SAR, JUMP_FUNCTION);
3278257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      break;
3279257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case Token::SHR:
3280257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ InvokeBuiltin(Builtins::SHR, JUMP_FUNCTION);
3281257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      break;
3282257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case Token::SHL:
3283257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ InvokeBuiltin(Builtins::SHL, JUMP_FUNCTION);
3284257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      break;
3285257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    default:
3286257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      UNREACHABLE();
3287257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
328844f0eee88ff00398ff7f715fab053374d808c90dSteve Block}
328944f0eee88ff00398ff7f715fab053374d808c90dSteve Block
329044f0eee88ff00398ff7f715fab053374d808c90dSteve Block
3291257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid BinaryOpStub::GenerateHeapResultAllocation(
329244f0eee88ff00398ff7f715fab053374d808c90dSteve Block    MacroAssembler* masm,
329344f0eee88ff00398ff7f715fab053374d808c90dSteve Block    Register result,
329444f0eee88ff00398ff7f715fab053374d808c90dSteve Block    Register heap_number_map,
329544f0eee88ff00398ff7f715fab053374d808c90dSteve Block    Register scratch1,
329644f0eee88ff00398ff7f715fab053374d808c90dSteve Block    Register scratch2,
329744f0eee88ff00398ff7f715fab053374d808c90dSteve Block    Label* gc_required) {
3298257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
3299257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Code below will scratch result if allocation fails. To keep both arguments
3300257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // intact for the runtime call result cannot be one of these.
3301257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  ASSERT(!result.is(a0) && !result.is(a1));
3302257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
3303257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  if (mode_ == OVERWRITE_LEFT || mode_ == OVERWRITE_RIGHT) {
3304257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Label skip_allocation, allocated;
3305257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Register overwritable_operand = mode_ == OVERWRITE_LEFT ? a1 : a0;
3306257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // If the overwritable operand is already an object, we skip the
3307257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // allocation of a heap number.
3308257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ JumpIfNotSmi(overwritable_operand, &skip_allocation);
3309257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Allocate a heap number for the result.
3310257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ AllocateHeapNumber(
3311257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        result, scratch1, scratch2, heap_number_map, gc_required);
3312257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ Branch(&allocated);
3313257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ bind(&skip_allocation);
3314257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Use object holding the overwritable operand for result.
3315257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ mov(result, overwritable_operand);
3316257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ bind(&allocated);
3317257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  } else {
3318257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    ASSERT(mode_ == NO_OVERWRITE);
3319257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ AllocateHeapNumber(
3320257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        result, scratch1, scratch2, heap_number_map, gc_required);
3321257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
332244f0eee88ff00398ff7f715fab053374d808c90dSteve Block}
332344f0eee88ff00398ff7f715fab053374d808c90dSteve Block
332444f0eee88ff00398ff7f715fab053374d808c90dSteve Block
3325257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid BinaryOpStub::GenerateRegisterArgsPush(MacroAssembler* masm) {
3326257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Push(a1, a0);
332744f0eee88ff00398ff7f715fab053374d808c90dSteve Block}
332844f0eee88ff00398ff7f715fab053374d808c90dSteve Block
332944f0eee88ff00398ff7f715fab053374d808c90dSteve Block
333044f0eee88ff00398ff7f715fab053374d808c90dSteve Block
333144f0eee88ff00398ff7f715fab053374d808c90dSteve Blockvoid TranscendentalCacheStub::Generate(MacroAssembler* masm) {
3332257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Untagged case: double input in f4, double result goes
3333257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  //   into f4.
3334257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Tagged case: tagged input on top of stack and in a0,
3335257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  //   tagged result (heap number) goes into v0.
3336257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
3337257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label input_not_smi;
3338257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label loaded;
3339257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label calculate;
3340257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label invalid_cache;
3341257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  const Register scratch0 = t5;
3342257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  const Register scratch1 = t3;
3343257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  const Register cache_entry = a0;
3344257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  const bool tagged = (argument_type_ == TAGGED);
3345257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
3346257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  if (CpuFeatures::IsSupported(FPU)) {
3347257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    CpuFeatures::Scope scope(FPU);
3348257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
3349257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    if (tagged) {
3350257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // Argument is a number and is on stack and in a0.
3351257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // Load argument and check if it is a smi.
3352257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ JumpIfNotSmi(a0, &input_not_smi);
3353257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
3354257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // Input is a smi. Convert to double and load the low and high words
3355257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // of the double into a2, a3.
3356257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ sra(t0, a0, kSmiTagSize);
3357257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ mtc1(t0, f4);
3358257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ cvt_d_w(f4, f4);
3359257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ Move(a2, a3, f4);
3360257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ Branch(&loaded);
3361257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
3362257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ bind(&input_not_smi);
3363257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // Check if input is a HeapNumber.
3364257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ CheckMap(a0,
3365257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                  a1,
3366257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                  Heap::kHeapNumberMapRootIndex,
3367257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                  &calculate,
3368257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                  DONT_DO_SMI_CHECK);
3369257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // Input is a HeapNumber. Store the
3370257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // low and high words into a2, a3.
3371257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ lw(a2, FieldMemOperand(a0, HeapNumber::kValueOffset));
3372257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ lw(a3, FieldMemOperand(a0, HeapNumber::kValueOffset + 4));
3373257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    } else {
3374257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // Input is untagged double in f4. Output goes to f4.
3375257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ Move(a2, a3, f4);
3376257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    }
3377257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ bind(&loaded);
3378257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // a2 = low 32 bits of double value.
3379257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // a3 = high 32 bits of double value.
3380257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Compute hash (the shifts are arithmetic):
3381257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    //   h = (low ^ high); h ^= h >> 16; h ^= h >> 8; h = h & (cacheSize - 1);
3382257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ Xor(a1, a2, a3);
3383257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ sra(t0, a1, 16);
3384257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ Xor(a1, a1, t0);
3385257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ sra(t0, a1, 8);
3386257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ Xor(a1, a1, t0);
3387257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    ASSERT(IsPowerOf2(TranscendentalCache::SubCache::kCacheSize));
3388257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ And(a1, a1, Operand(TranscendentalCache::SubCache::kCacheSize - 1));
3389257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
3390257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // a2 = low 32 bits of double value.
3391257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // a3 = high 32 bits of double value.
3392257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // a1 = TranscendentalCache::hash(double value).
3393257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ li(cache_entry, Operand(
3394257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        ExternalReference::transcendental_cache_array_address(
3395257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch            masm->isolate())));
3396257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // a0 points to cache array.
3397257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ lw(cache_entry, MemOperand(cache_entry, type_ * sizeof(
3398257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        Isolate::Current()->transcendental_cache()->caches_[0])));
3399257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // a0 points to the cache for the type type_.
3400257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // If NULL, the cache hasn't been initialized yet, so go through runtime.
3401257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ Branch(&invalid_cache, eq, cache_entry, Operand(zero_reg));
3402257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
3403257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch#ifdef DEBUG
3404257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Check that the layout of cache elements match expectations.
3405257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    { TranscendentalCache::SubCache::Element test_elem[2];
3406257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      char* elem_start = reinterpret_cast<char*>(&test_elem[0]);
3407257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      char* elem2_start = reinterpret_cast<char*>(&test_elem[1]);
3408257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      char* elem_in0 = reinterpret_cast<char*>(&(test_elem[0].in[0]));
3409257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      char* elem_in1 = reinterpret_cast<char*>(&(test_elem[0].in[1]));
3410257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      char* elem_out = reinterpret_cast<char*>(&(test_elem[0].output));
3411257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      CHECK_EQ(12, elem2_start - elem_start);  // Two uint_32's and a pointer.
3412257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      CHECK_EQ(0, elem_in0 - elem_start);
3413257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      CHECK_EQ(kIntSize, elem_in1 - elem_start);
3414257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      CHECK_EQ(2 * kIntSize, elem_out - elem_start);
3415257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    }
3416257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch#endif
3417257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
3418257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Find the address of the a1'st entry in the cache, i.e., &a0[a1*12].
3419257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ sll(t0, a1, 1);
3420257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ Addu(a1, a1, t0);
3421257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ sll(t0, a1, 2);
3422257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ Addu(cache_entry, cache_entry, t0);
3423257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
3424257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Check if cache matches: Double value is stored in uint32_t[2] array.
3425257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ lw(t0, MemOperand(cache_entry, 0));
3426257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ lw(t1, MemOperand(cache_entry, 4));
3427257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ lw(t2, MemOperand(cache_entry, 8));
3428257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ Branch(&calculate, ne, a2, Operand(t0));
3429257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ Branch(&calculate, ne, a3, Operand(t1));
3430257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Cache hit. Load result, cleanup and return.
34313ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    Counters* counters = masm->isolate()->counters();
34323ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ IncrementCounter(
34333ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch        counters->transcendental_cache_hit(), 1, scratch0, scratch1);
3434257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    if (tagged) {
3435257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // Pop input value from stack and load result into v0.
3436257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ Drop(1);
3437257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ mov(v0, t2);
3438257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    } else {
3439257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // Load result into f4.
3440257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ ldc1(f4, FieldMemOperand(t2, HeapNumber::kValueOffset));
3441257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    }
3442257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ Ret();
3443257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }  // if (CpuFeatures::IsSupported(FPU))
3444257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
3445257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&calculate);
34463ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  Counters* counters = masm->isolate()->counters();
34473ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ IncrementCounter(
34483ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      counters->transcendental_cache_miss(), 1, scratch0, scratch1);
3449257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  if (tagged) {
3450257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ bind(&invalid_cache);
3451257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ TailCallExternalReference(ExternalReference(RuntimeFunction(),
3452257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                                   masm->isolate()),
3453257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                 1,
3454257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                 1);
3455257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  } else {
3456257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    if (!CpuFeatures::IsSupported(FPU)) UNREACHABLE();
3457257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    CpuFeatures::Scope scope(FPU);
3458257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
3459257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Label no_update;
3460257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Label skip_cache;
3461257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
3462257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Call C function to calculate the result and update the cache.
3463257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Register a0 holds precalculated cache entry address; preserve
3464257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // it on the stack and pop it into register cache_entry after the
3465257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // call.
34663ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ Push(cache_entry, a2, a3);
3467257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    GenerateCallCFunction(masm, scratch0);
3468257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ GetCFunctionDoubleResult(f4);
3469257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
3470257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Try to update the cache. If we cannot allocate a
3471257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // heap number, we return the result without updating.
34723ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ Pop(cache_entry, a2, a3);
3473257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ LoadRoot(t1, Heap::kHeapNumberMapRootIndex);
3474257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ AllocateHeapNumber(t2, scratch0, scratch1, t1, &no_update);
3475257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ sdc1(f4, FieldMemOperand(t2, HeapNumber::kValueOffset));
3476257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
3477257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ sw(a2, MemOperand(cache_entry, 0 * kPointerSize));
3478257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ sw(a3, MemOperand(cache_entry, 1 * kPointerSize));
3479257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ sw(t2, MemOperand(cache_entry, 2 * kPointerSize));
3480257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
34813ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ Ret(USE_DELAY_SLOT);
3482257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ mov(v0, cache_entry);
3483257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
3484257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ bind(&invalid_cache);
3485257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // The cache is invalid. Call runtime which will recreate the
3486257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // cache.
3487257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ LoadRoot(t1, Heap::kHeapNumberMapRootIndex);
3488257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ AllocateHeapNumber(a0, scratch0, scratch1, t1, &skip_cache);
3489257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ sdc1(f4, FieldMemOperand(a0, HeapNumber::kValueOffset));
34903ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    {
34913ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      FrameScope scope(masm, StackFrame::INTERNAL);
34923ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      __ push(a0);
34933ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      __ CallRuntime(RuntimeFunction(), 1);
34943ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    }
3495257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ ldc1(f4, FieldMemOperand(v0, HeapNumber::kValueOffset));
3496257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ Ret();
3497257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
3498257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ bind(&skip_cache);
3499257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Call C function to calculate the result and answer directly
3500257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // without updating the cache.
3501257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    GenerateCallCFunction(masm, scratch0);
3502257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ GetCFunctionDoubleResult(f4);
3503257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ bind(&no_update);
3504257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
3505257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // We return the value in f4 without adding it to the cache, but
3506257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // we cause a scavenging GC so that future allocations will succeed.
35073ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    {
35083ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      FrameScope scope(masm, StackFrame::INTERNAL);
35093ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
35103ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      // Allocate an aligned object larger than a HeapNumber.
35113ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      ASSERT(4 * kPointerSize >= HeapNumber::kSize);
35123ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      __ li(scratch0, Operand(4 * kPointerSize));
35133ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      __ push(scratch0);
35143ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      __ CallRuntimeSaveDoubles(Runtime::kAllocateInNewSpace);
35153ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    }
3516257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ Ret();
3517257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
3518257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch}
3519257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
3520257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
3521257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid TranscendentalCacheStub::GenerateCallCFunction(MacroAssembler* masm,
3522257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                                    Register scratch) {
3523257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ push(ra);
3524257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ PrepareCallCFunction(2, scratch);
3525257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  if (IsMipsSoftFloatABI) {
35263ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ Move(a0, a1, f4);
3527257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  } else {
3528257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ mov_d(f12, f4);
3529257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
35303ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  AllowExternalCallThatCantCauseGC scope(masm);
35313ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  Isolate* isolate = masm->isolate();
3532257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  switch (type_) {
3533257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case TranscendentalCache::SIN:
3534257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ CallCFunction(
35353ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch          ExternalReference::math_sin_double_function(isolate),
35363ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch          0, 1);
3537257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      break;
3538257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case TranscendentalCache::COS:
3539257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ CallCFunction(
35403ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch          ExternalReference::math_cos_double_function(isolate),
35413ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch          0, 1);
35423ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      break;
35433ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    case TranscendentalCache::TAN:
35443ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      __ CallCFunction(ExternalReference::math_tan_double_function(isolate),
35453ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch          0, 1);
3546257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      break;
3547257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case TranscendentalCache::LOG:
3548257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ CallCFunction(
35493ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch          ExternalReference::math_log_double_function(isolate),
35503ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch          0, 1);
3551257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      break;
3552257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    default:
3553257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      UNIMPLEMENTED();
3554257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      break;
3555257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
3556257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ pop(ra);
355744f0eee88ff00398ff7f715fab053374d808c90dSteve Block}
355844f0eee88ff00398ff7f715fab053374d808c90dSteve Block
355944f0eee88ff00398ff7f715fab053374d808c90dSteve Block
356044f0eee88ff00398ff7f715fab053374d808c90dSteve BlockRuntime::FunctionId TranscendentalCacheStub::RuntimeFunction() {
3561257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  switch (type_) {
3562257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Add more cases when necessary.
3563257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case TranscendentalCache::SIN: return Runtime::kMath_sin;
3564257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case TranscendentalCache::COS: return Runtime::kMath_cos;
35653ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    case TranscendentalCache::TAN: return Runtime::kMath_tan;
3566257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case TranscendentalCache::LOG: return Runtime::kMath_log;
3567257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    default:
3568257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      UNIMPLEMENTED();
3569257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      return Runtime::kAbort;
3570257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
357144f0eee88ff00398ff7f715fab053374d808c90dSteve Block}
357244f0eee88ff00398ff7f715fab053374d808c90dSteve Block
357344f0eee88ff00398ff7f715fab053374d808c90dSteve Block
357444f0eee88ff00398ff7f715fab053374d808c90dSteve Blockvoid StackCheckStub::Generate(MacroAssembler* masm) {
3575257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ TailCallRuntime(Runtime::kStackGuard, 0, 1);
357644f0eee88ff00398ff7f715fab053374d808c90dSteve Block}
357744f0eee88ff00398ff7f715fab053374d808c90dSteve Block
357844f0eee88ff00398ff7f715fab053374d808c90dSteve Block
35793ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochvoid InterruptStub::Generate(MacroAssembler* masm) {
35803ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ TailCallRuntime(Runtime::kInterrupt, 0, 1);
35813ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch}
358285b71799222b55eb5dd74ea26efe0c64ab655c8cBen Murdoch
358385b71799222b55eb5dd74ea26efe0c64ab655c8cBen Murdoch
35843ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochvoid MathPowStub::Generate(MacroAssembler* masm) {
35853ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  CpuFeatures::Scope fpu_scope(FPU);
35863ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  const Register base = a1;
35873ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  const Register exponent = a2;
35883ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  const Register heapnumbermap = t1;
35893ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  const Register heapnumber = v0;
35903ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  const DoubleRegister double_base = f2;
35913ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  const DoubleRegister double_exponent = f4;
35923ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  const DoubleRegister double_result = f0;
35933ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  const DoubleRegister double_scratch = f6;
35943ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  const FPURegister single_scratch = f8;
35953ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  const Register scratch = t5;
35963ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  const Register scratch2 = t3;
35973ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
35983ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  Label call_runtime, done, int_exponent;
35993ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  if (exponent_type_ == ON_STACK) {
36003ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    Label base_is_smi, unpack_exponent;
36013ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    // The exponent and base are supplied as arguments on the stack.
36023ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    // This can only happen if the stub is called from non-optimized code.
36033ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    // Load input parameters from stack to double registers.
3604257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ lw(base, MemOperand(sp, 1 * kPointerSize));
3605257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ lw(exponent, MemOperand(sp, 0 * kPointerSize));
3606257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
36073ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ LoadRoot(heapnumbermap, Heap::kHeapNumberMapRootIndex);
3608257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
36093ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ UntagAndJumpIfSmi(scratch, base, &base_is_smi);
3610257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ lw(scratch, FieldMemOperand(base, JSObject::kMapOffset));
3611257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ Branch(&call_runtime, ne, scratch, Operand(heapnumbermap));
36123ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
3613257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ ldc1(double_base, FieldMemOperand(base, HeapNumber::kValueOffset));
36143ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ jmp(&unpack_exponent);
3615257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
36163ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ bind(&base_is_smi);
36173ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ mtc1(scratch, single_scratch);
36183ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ cvt_d_w(double_base, single_scratch);
36193ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ bind(&unpack_exponent);
36203ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
36213ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ UntagAndJumpIfSmi(scratch, exponent, &int_exponent);
3622257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
3623257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ lw(scratch, FieldMemOperand(exponent, JSObject::kMapOffset));
3624257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ Branch(&call_runtime, ne, scratch, Operand(heapnumbermap));
3625257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ ldc1(double_exponent,
3626257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch            FieldMemOperand(exponent, HeapNumber::kValueOffset));
36273ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  } else if (exponent_type_ == TAGGED) {
36283ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    // Base is already in double_base.
36293ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ UntagAndJumpIfSmi(scratch, exponent, &int_exponent);
36303ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
36313ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ ldc1(double_exponent,
36323ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch            FieldMemOperand(exponent, HeapNumber::kValueOffset));
36333ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  }
36343ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
36353ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  if (exponent_type_ != INTEGER) {
36363ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    Label int_exponent_convert;
36373ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    // Detect integer exponents stored as double.
36383ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ EmitFPUTruncate(kRoundToMinusInf,
36393ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                       single_scratch,
36403ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                       double_exponent,
36413ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                       scratch,
36423ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                       scratch2,
36433ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                       kCheckForInexactConversion);
36443ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    // scratch2 == 0 means there was no conversion error.
36453ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ Branch(&int_exponent_convert, eq, scratch2, Operand(zero_reg));
36463ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
36473ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    if (exponent_type_ == ON_STACK) {
36483ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      // Detect square root case.  Crankshaft detects constant +/-0.5 at
36493ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      // compile time and uses DoMathPowHalf instead.  We then skip this check
36503ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      // for non-constant cases of +/-0.5 as these hardly occur.
36513ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      Label not_plus_half;
36523ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
36533ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      // Test for 0.5.
36543ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      __ Move(double_scratch, 0.5);
36553ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      __ BranchF(USE_DELAY_SLOT,
36563ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                 &not_plus_half,
36573ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                 NULL,
36583ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                 ne,
36593ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                 double_exponent,
36603ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                 double_scratch);
36613ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      // double_scratch can be overwritten in the delay slot.
36623ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      // Calculates square root of base.  Check for the special case of
36633ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      // Math.pow(-Infinity, 0.5) == Infinity (ECMA spec, 15.8.2.13).
36643ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      __ Move(double_scratch, -V8_INFINITY);
36653ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      __ BranchF(USE_DELAY_SLOT, &done, NULL, eq, double_base, double_scratch);
36663ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      __ neg_d(double_result, double_scratch);
36673ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
36683ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      // Add +0 to convert -0 to +0.
36693ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      __ add_d(double_scratch, double_base, kDoubleRegZero);
36703ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      __ sqrt_d(double_result, double_scratch);
36713ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      __ jmp(&done);
36723ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
36733ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      __ bind(&not_plus_half);
36743ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      __ Move(double_scratch, -0.5);
36753ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      __ BranchF(USE_DELAY_SLOT,
36763ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                 &call_runtime,
36773ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                 NULL,
36783ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                 ne,
36793ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                 double_exponent,
36803ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                 double_scratch);
36813ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      // double_scratch can be overwritten in the delay slot.
36823ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      // Calculates square root of base.  Check for the special case of
36833ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      // Math.pow(-Infinity, -0.5) == 0 (ECMA spec, 15.8.2.13).
36843ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      __ Move(double_scratch, -V8_INFINITY);
36853ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      __ BranchF(USE_DELAY_SLOT, &done, NULL, eq, double_base, double_scratch);
36863ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      __ Move(double_result, kDoubleRegZero);
36873ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
36883ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      // Add +0 to convert -0 to +0.
36893ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      __ add_d(double_scratch, double_base, kDoubleRegZero);
36903ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      __ Move(double_result, 1);
36913ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      __ sqrt_d(double_scratch, double_scratch);
36923ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      __ div_d(double_result, double_result, double_scratch);
36933ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      __ jmp(&done);
36943ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    }
3695257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
3696257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ push(ra);
36973ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    {
36983ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      AllowExternalCallThatCantCauseGC scope(masm);
36993ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      __ PrepareCallCFunction(0, 2, scratch);
37003ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      __ SetCallCDoubleArguments(double_base, double_exponent);
37013ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      __ CallCFunction(
37023ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch          ExternalReference::power_double_double_function(masm->isolate()),
37033ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch          0, 2);
37043ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    }
3705c7cc028aaeedbbfa11c11d0b7b243b3d9e837ed9Ben Murdoch    __ pop(ra);
3706c7cc028aaeedbbfa11c11d0b7b243b3d9e837ed9Ben Murdoch    __ GetCFunctionDoubleResult(double_result);
37073ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ jmp(&done);
37083ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
37093ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ bind(&int_exponent_convert);
37103ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ mfc1(scratch, single_scratch);
37115d4cdbf7a67d3662fa0bee4efdb7edd8daec9b0bBen Murdoch  }
37125d4cdbf7a67d3662fa0bee4efdb7edd8daec9b0bBen Murdoch
37133ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Calculate power with integer exponent.
37143ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ bind(&int_exponent);
3715c7cc028aaeedbbfa11c11d0b7b243b3d9e837ed9Ben Murdoch
37163ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Get two copies of exponent in the registers scratch and exponent.
37173ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  if (exponent_type_ == INTEGER) {
37183ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ mov(scratch, exponent);
37193ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  } else {
37203ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    // Exponent has previously been stored into scratch as untagged integer.
37213ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ mov(exponent, scratch);
37223ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  }
3723c7cc028aaeedbbfa11c11d0b7b243b3d9e837ed9Ben Murdoch
37243ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ mov_d(double_scratch, double_base);  // Back up base.
37253ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ Move(double_result, 1.0);
3726c7cc028aaeedbbfa11c11d0b7b243b3d9e837ed9Ben Murdoch
37273ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Get absolute value of exponent.
37283ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  Label positive_exponent;
37293ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ Branch(&positive_exponent, ge, scratch, Operand(zero_reg));
37303ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ Subu(scratch, zero_reg, scratch);
37313ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ bind(&positive_exponent);
3732c7cc028aaeedbbfa11c11d0b7b243b3d9e837ed9Ben Murdoch
37333ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  Label while_true, no_carry, loop_end;
37343ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ bind(&while_true);
3735c7cc028aaeedbbfa11c11d0b7b243b3d9e837ed9Ben Murdoch
37363ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ And(scratch2, scratch, 1);
3737c7cc028aaeedbbfa11c11d0b7b243b3d9e837ed9Ben Murdoch
37383ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ Branch(&no_carry, eq, scratch2, Operand(zero_reg));
37393ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ mul_d(double_result, double_result, double_scratch);
37403ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ bind(&no_carry);
3741592a9fc1d8ea420377a2e7efd0600e20b058be2bBen Murdoch
37423ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ sra(scratch, scratch, 1);
3743592a9fc1d8ea420377a2e7efd0600e20b058be2bBen Murdoch
37443ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ Branch(&loop_end, eq, scratch, Operand(zero_reg));
37453ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ mul_d(double_scratch, double_scratch, double_scratch);
37463ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
37473ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ Branch(&while_true);
37483ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
37493ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ bind(&loop_end);
37503ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
37513ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ Branch(&done, ge, exponent, Operand(zero_reg));
37523ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ Move(double_scratch, 1.0);
37533ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ div_d(double_result, double_scratch, double_result);
37543ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Test whether result is zero.  Bail out to check for subnormal result.
37553ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Due to subnormals, x^-y == (1/x)^y does not hold in all cases.
37563ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ BranchF(&done, NULL, ne, double_result, kDoubleRegZero);
37573ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
37583ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // double_exponent may not contain the exponent value if the input was a
37593ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // smi.  We set it with exponent value before bailing out.
37603ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ mtc1(exponent, single_scratch);
37613ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ cvt_d_w(double_exponent, single_scratch);
37623ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
37633ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Returning or bailing out.
37643ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  Counters* counters = masm->isolate()->counters();
37653ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  if (exponent_type_ == ON_STACK) {
37663ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    // The arguments are still on the stack.
37673ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ bind(&call_runtime);
37683ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ TailCallRuntime(Runtime::kMath_pow_cfunction, 2, 1);
37693ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
37703ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    // The stub is called from non-optimized code, which expects the result
37713ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    // as heap number in exponent.
37723ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ bind(&done);
37733ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ AllocateHeapNumber(
37743ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch        heapnumber, scratch, scratch2, heapnumbermap, &call_runtime);
37753ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ sdc1(double_result,
37763ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch            FieldMemOperand(heapnumber, HeapNumber::kValueOffset));
37773ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    ASSERT(heapnumber.is(v0));
37783ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ IncrementCounter(counters->math_pow(), 1, scratch, scratch2);
37793ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ DropAndRet(2);
37803ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  } else {
37813ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ push(ra);
37823ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    {
37833ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      AllowExternalCallThatCantCauseGC scope(masm);
37843ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      __ PrepareCallCFunction(0, 2, scratch);
37853ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      __ SetCallCDoubleArguments(double_base, double_exponent);
37863ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      __ CallCFunction(
37873ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch          ExternalReference::power_double_double_function(masm->isolate()),
37883ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch          0, 2);
37893ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    }
37903ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ pop(ra);
37913ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ GetCFunctionDoubleResult(double_result);
37923ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
37933ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ bind(&done);
37943ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ IncrementCounter(counters->math_pow(), 1, scratch, scratch2);
37953ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ Ret();
37963ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  }
37973ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch}
37983ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
37993ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
38003ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochbool CEntryStub::NeedsImmovableCode() {
38013ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  return true;
38023ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch}
38033ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
38043ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
38053ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochbool CEntryStub::IsPregenerated() {
38063ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  return (!save_doubles_ || ISOLATE->fp_stubs_generated()) &&
38073ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch          result_size_ == 1;
38083ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch}
38093ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
38103ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
38113ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochvoid CodeStub::GenerateStubsAheadOfTime() {
38123ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  CEntryStub::GenerateAheadOfTime();
38133ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  WriteInt32ToHeapNumberStub::GenerateFixedRegStubsAheadOfTime();
38143ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  StoreBufferOverflowStub::GenerateFixedRegStubsAheadOfTime();
38153ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  RecordWriteStub::GenerateFixedRegStubsAheadOfTime();
38163ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch}
38173ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
38183ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
38193ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochvoid CodeStub::GenerateFPStubs() {
38203ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  CEntryStub save_doubles(1, kSaveFPRegs);
38213ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  Handle<Code> code = save_doubles.GetCode();
38223ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  code->set_is_pregenerated(true);
38233ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  StoreBufferOverflowStub stub(kSaveFPRegs);
38243ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  stub.GetCode()->set_is_pregenerated(true);
38253ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  code->GetIsolate()->set_fp_stubs_generated(true);
38263ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch}
38273ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
38283ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
38293ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochvoid CEntryStub::GenerateAheadOfTime() {
38303ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  CEntryStub stub(1, kDontSaveFPRegs);
38313ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  Handle<Code> code = stub.GetCode();
38323ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  code->set_is_pregenerated(true);
38333ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch}
38343ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
38353ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
38363ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochvoid CEntryStub::GenerateCore(MacroAssembler* masm,
38373ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                              Label* throw_normal_exception,
38383ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                              Label* throw_termination_exception,
38393ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                              Label* throw_out_of_memory_exception,
384044f0eee88ff00398ff7f715fab053374d808c90dSteve Block                              bool do_gc,
384144f0eee88ff00398ff7f715fab053374d808c90dSteve Block                              bool always_allocate) {
3842257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // v0: result parameter for PerformGC, if any
3843257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // s0: number of arguments including receiver (C callee-saved)
3844257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // s1: pointer to the first argument          (C callee-saved)
3845257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // s2: pointer to builtin function            (C callee-saved)
3846257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
38473ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  Isolate* isolate = masm->isolate();
38483ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
3849257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  if (do_gc) {
3850257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Move result passed in v0 into a0 to call PerformGC.
3851257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ mov(a0, v0);
38523ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ PrepareCallCFunction(1, 0, a1);
38533ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ CallCFunction(ExternalReference::perform_gc_function(isolate), 1, 0);
3854257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
3855257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
3856257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  ExternalReference scope_depth =
38573ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      ExternalReference::heap_always_allocate_scope_depth(isolate);
3858257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  if (always_allocate) {
3859257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ li(a0, Operand(scope_depth));
3860257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ lw(a1, MemOperand(a0));
3861257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ Addu(a1, a1, Operand(1));
3862257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ sw(a1, MemOperand(a0));
3863257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
3864257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
38653ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Prepare arguments for C routine.
38663ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // a0 = argc
3867257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ mov(a0, s0);
38683ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // a1 = argv (set in the delay slot after find_ra below).
3869257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
3870257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // We are calling compiled C/C++ code. a0 and a1 hold our two arguments. We
3871257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // also need to reserve the 4 argument slots on the stack.
3872257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
3873257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ AssertStackIsAligned();
3874257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
3875257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ li(a2, Operand(ExternalReference::isolate_address()));
3876257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
38773fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // To let the GC traverse the return address of the exit frames, we need to
38783fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // know where the return address is. The CEntryStub is unmovable, so
38793fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // we can store the address on the stack to be able to find it again and
38803fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // we never have to restore it, because it will not change.
3881257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  { Assembler::BlockTrampolinePoolScope block_trampoline_pool(masm);
3882257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // This branch-and-link sequence is needed to find the current PC on mips,
3883257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // saved to the ra register.
3884257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Use masm-> here instead of the double-underscore macro since extra
3885257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // coverage code can interfere with the proper calculation of ra.
3886257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Label find_ra;
3887257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    masm->bal(&find_ra);  // bal exposes branch delay slot.
38883ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    masm->mov(a1, s1);
3889257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    masm->bind(&find_ra);
3890257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
3891257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Adjust the value in ra to point to the correct return location, 2nd
3892257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // instruction past the real call into C code (the jalr(t9)), and push it.
3893257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // This is the return address of the exit frame.
38943ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    const int kNumInstructionsToJump = 5;
3895257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    masm->Addu(ra, ra, kNumInstructionsToJump * kPointerSize);
3896257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    masm->sw(ra, MemOperand(sp));  // This spot was reserved in EnterExitFrame.
38973ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    // Stack space reservation moved to the branch delay slot below.
3898257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Stack is still aligned.
3899257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
3900257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Call the C routine.
3901257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    masm->mov(t9, s2);  // Function pointer to t9 to conform to ABI for PIC.
3902257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    masm->jalr(t9);
39033ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    // Set up sp in the delay slot.
39043ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    masm->addiu(sp, sp, -kCArgsSlotsSize);
3905257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Make sure the stored 'ra' points to this position.
3906257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    ASSERT_EQ(kNumInstructionsToJump,
3907257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch              masm->InstructionsGeneratedSince(&find_ra));
3908257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
3909257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
3910257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  if (always_allocate) {
3911257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // It's okay to clobber a2 and a3 here. v0 & v1 contain result.
3912257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ li(a2, Operand(scope_depth));
3913257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ lw(a3, MemOperand(a2));
3914257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ Subu(a3, a3, Operand(1));
3915257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ sw(a3, MemOperand(a2));
3916257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
3917257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
3918257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Check for failure result.
3919257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label failure_returned;
3920257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  STATIC_ASSERT(((kFailureTag + 1) & kFailureTagMask) == 0);
3921257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ addiu(a2, v0, 1);
3922257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ andi(t0, a2, kFailureTagMask);
39233ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ Branch(USE_DELAY_SLOT, &failure_returned, eq, t0, Operand(zero_reg));
39243ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Restore stack (remove arg slots) in branch delay slot.
39253ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ addiu(sp, sp, kCArgsSlotsSize);
39263ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
3927257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
3928257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Exit C frame and return.
3929257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // v0:v1: result
3930257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // sp: stack pointer
3931257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // fp: frame pointer
39323ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ LeaveExitFrame(save_doubles_, s0, true);
3933257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
3934257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Check if we should retry or throw exception.
3935257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label retry;
3936257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&failure_returned);
3937257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  STATIC_ASSERT(Failure::RETRY_AFTER_GC == 0);
3938257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ andi(t0, v0, ((1 << kFailureTypeTagSize) - 1) << kFailureTagSize);
3939257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Branch(&retry, eq, t0, Operand(zero_reg));
3940257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
3941257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Special handling of out of memory exceptions.
3942257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Failure* out_of_memory = Failure::OutOfMemoryException();
39433ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ Branch(USE_DELAY_SLOT,
39443ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch            throw_out_of_memory_exception,
39453ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch            eq,
39463ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch            v0,
39473ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch            Operand(reinterpret_cast<int32_t>(out_of_memory)));
39483ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // If we throw the OOM exception, the value of a3 doesn't matter.
39493ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Any instruction can be in the delay slot that's not a jump.
3950257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
3951257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Retrieve the pending exception and clear the variable.
39523ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ LoadRoot(a3, Heap::kTheHoleValueRootIndex);
3953589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch  __ li(t0, Operand(ExternalReference(Isolate::kPendingExceptionAddress,
39543ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                                      isolate)));
3955257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ lw(v0, MemOperand(t0));
3956257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ sw(a3, MemOperand(t0));
3957257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
3958257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Special handling of termination exceptions which are uncatchable
3959257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // by javascript code.
39603ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ LoadRoot(t0, Heap::kTerminationExceptionRootIndex);
39613ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ Branch(throw_termination_exception, eq, v0, Operand(t0));
3962257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
3963257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Handle normal exception.
3964257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ jmp(throw_normal_exception);
3965257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
3966257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&retry);
3967257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Last failure (v0) will be moved to (a0) for parameter when retrying.
396844f0eee88ff00398ff7f715fab053374d808c90dSteve Block}
396944f0eee88ff00398ff7f715fab053374d808c90dSteve Block
397044f0eee88ff00398ff7f715fab053374d808c90dSteve Block
397144f0eee88ff00398ff7f715fab053374d808c90dSteve Blockvoid CEntryStub::Generate(MacroAssembler* masm) {
3972257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Called from JavaScript; parameters are on stack as if calling JS function
39733ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // s0: number of arguments including receiver
39743ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // s1: size of arguments excluding receiver
39753ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // s2: pointer to builtin function
3976257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // fp: frame pointer    (restored after C call)
3977257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // sp: stack pointer    (restored as callee's sp after C call)
3978257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // cp: current context  (C callee-saved)
3979257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
3980257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // NOTE: Invocations of builtins may return failure objects
3981257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // instead of a proper result. The builtin entry handles
3982257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // this by performing a garbage collection and retrying the
3983257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // builtin once.
3984257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
39853ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // NOTE: s0-s2 hold the arguments of this function instead of a0-a2.
39863ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // The reason for this is that these arguments would need to be saved anyway
39873ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // so it's faster to set them up directly.
39883ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // See MacroAssembler::PrepareCEntryArgs and PrepareCEntryFunction.
39893ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
3990257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Compute the argv pointer in a callee-saved register.
3991257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Addu(s1, sp, s1);
3992257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
3993257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Enter the exit frame that transitions from JavaScript to C++.
39943ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  FrameScope scope(masm, StackFrame::MANUAL);
3995257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ EnterExitFrame(save_doubles_);
3996257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
3997257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // s0: number of arguments (C callee-saved)
3998257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // s1: pointer to first argument (C callee-saved)
3999257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // s2: pointer to builtin function (C callee-saved)
4000257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
4001257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label throw_normal_exception;
4002257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label throw_termination_exception;
4003257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label throw_out_of_memory_exception;
4004257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
4005257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Call into the runtime system.
4006257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  GenerateCore(masm,
4007257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch               &throw_normal_exception,
4008257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch               &throw_termination_exception,
4009257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch               &throw_out_of_memory_exception,
4010257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch               false,
4011257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch               false);
4012257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
4013257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Do space-specific GC and retry runtime call.
4014257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  GenerateCore(masm,
4015257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch               &throw_normal_exception,
4016257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch               &throw_termination_exception,
4017257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch               &throw_out_of_memory_exception,
4018257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch               true,
4019257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch               false);
4020257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
4021257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Do full GC and retry runtime call one final time.
4022257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Failure* failure = Failure::InternalError();
4023257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ li(v0, Operand(reinterpret_cast<int32_t>(failure)));
4024257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  GenerateCore(masm,
4025257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch               &throw_normal_exception,
4026257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch               &throw_termination_exception,
4027257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch               &throw_out_of_memory_exception,
4028257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch               true,
4029257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch               true);
4030257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
4031257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&throw_out_of_memory_exception);
40323ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Set external caught exception to false.
40333ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  Isolate* isolate = masm->isolate();
40343ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  ExternalReference external_caught(Isolate::kExternalCaughtExceptionAddress,
40353ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                                    isolate);
40363ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ li(a0, Operand(false, RelocInfo::NONE));
40373ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ li(a2, Operand(external_caught));
40383ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ sw(a0, MemOperand(a2));
40393ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
40403ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Set pending exception and v0 to out of memory exception.
40413ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  Failure* out_of_memory = Failure::OutOfMemoryException();
40423ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ li(v0, Operand(reinterpret_cast<int32_t>(out_of_memory)));
40433ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ li(a2, Operand(ExternalReference(Isolate::kPendingExceptionAddress,
40443ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                                      isolate)));
40453ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ sw(v0, MemOperand(a2));
40463ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Fall through to the next label.
4047257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
4048257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&throw_termination_exception);
40493ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ ThrowUncatchable(v0);
4050257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
4051257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&throw_normal_exception);
40523ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ Throw(v0);
405344f0eee88ff00398ff7f715fab053374d808c90dSteve Block}
405444f0eee88ff00398ff7f715fab053374d808c90dSteve Block
405544f0eee88ff00398ff7f715fab053374d808c90dSteve Block
405644f0eee88ff00398ff7f715fab053374d808c90dSteve Blockvoid JSEntryStub::GenerateBody(MacroAssembler* masm, bool is_construct) {
40573ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  Label invoke, handler_entry, exit;
40583ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  Isolate* isolate = masm->isolate();
4059257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
4060257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Registers:
4061257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // a0: entry address
4062257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // a1: function
40633ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // a2: receiver
4064257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // a3: argc
4065257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  //
4066257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Stack:
4067257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // 4 args slots
4068257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // args
4069257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
4070257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Save callee saved registers on the stack.
407169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ MultiPush(kCalleeSaved | ra.bit());
4072257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
4073589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch  if (CpuFeatures::IsSupported(FPU)) {
4074589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch    CpuFeatures::Scope scope(FPU);
4075589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch    // Save callee-saved FPU registers.
4076589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch    __ MultiPushFPU(kCalleeSavedFPU);
40773ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    // Set up the reserved register for 0.0.
40783ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ Move(kDoubleRegZero, 0.0);
4079589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch  }
4080589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch
40813ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
4082257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Load argv in s0 register.
4083589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch  int offset_to_argv = (kNumCalleeSaved + 1) * kPointerSize;
4084589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch  if (CpuFeatures::IsSupported(FPU)) {
4085589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch    offset_to_argv += kNumCalleeSavedFPU * kDoubleSize;
4086589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch  }
4087589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch
40883ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ InitializeRootRegister();
4089589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch  __ lw(s0, MemOperand(sp, offset_to_argv + kCArgsSlotsSize));
4090257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
4091257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // We build an EntryFrame.
4092257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ li(t3, Operand(-1));  // Push a bad frame pointer to fail if it is used.
4093257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  int marker = is_construct ? StackFrame::ENTRY_CONSTRUCT : StackFrame::ENTRY;
4094257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ li(t2, Operand(Smi::FromInt(marker)));
4095257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ li(t1, Operand(Smi::FromInt(marker)));
4096589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch  __ li(t0, Operand(ExternalReference(Isolate::kCEntryFPAddress,
40973ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                                      isolate)));
4098257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ lw(t0, MemOperand(t0));
4099257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Push(t3, t2, t1, t0);
41003ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Set up frame pointer for the frame to be pushed.
4101257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ addiu(fp, sp, -EntryFrameConstants::kCallerFPOffset);
4102257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
4103257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Registers:
4104257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // a0: entry_address
4105257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // a1: function
41063ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // a2: receiver_pointer
4107257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // a3: argc
4108257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // s0: argv
4109257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  //
4110257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Stack:
4111257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // caller fp          |
4112257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // function slot      | entry frame
4113257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // context slot       |
4114257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // bad fp (0xff...f)  |
4115257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // callee saved registers + ra
4116257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // 4 args slots
4117257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // args
4118257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
41193fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // If this is the outermost JS call, set js_entry_sp value.
41203fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  Label non_outermost_js;
41213ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  ExternalReference js_entry_sp(Isolate::kJSEntrySPAddress, isolate);
41223fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ li(t1, Operand(ExternalReference(js_entry_sp)));
41233fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ lw(t2, MemOperand(t1));
41243fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ Branch(&non_outermost_js, ne, t2, Operand(zero_reg));
41253fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ sw(fp, MemOperand(t1));
41263fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ li(t0, Operand(Smi::FromInt(StackFrame::OUTERMOST_JSENTRY_FRAME)));
41273fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  Label cont;
41283fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ b(&cont);
41293fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ nop();   // Branch delay slot nop.
41303fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ bind(&non_outermost_js);
41313fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ li(t0, Operand(Smi::FromInt(StackFrame::INNER_JSENTRY_FRAME)));
41323fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ bind(&cont);
41333fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ push(t0);
4134257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
41353ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Jump to a faked try block that does the invoke, with a faked catch
41363ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // block that sets the pending exception.
41373ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ jmp(&invoke);
41383ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ bind(&handler_entry);
41393ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  handler_offset_ = handler_entry.pos();
41403ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Caught exception: Store result (exception) in the pending exception
41413ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // field in the JSEnv and return a failure sentinel.  Coming in here the
41423ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // fp will be invalid because the PushTryHandler below sets it to 0 to
41433ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // signal the existence of the JSEntry frame.
4144589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch  __ li(t0, Operand(ExternalReference(Isolate::kPendingExceptionAddress,
41453ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                                      isolate)));
4146257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ sw(v0, MemOperand(t0));  // We come back from 'invoke'. result is in v0.
4147257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ li(v0, Operand(reinterpret_cast<int32_t>(Failure::Exception())));
4148257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ b(&exit);  // b exposes branch delay slot.
4149257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ nop();   // Branch delay slot nop.
4150257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
41513ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Invoke: Link this frame into the handler chain.  There's only one
41523ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // handler block in this code object, so its index is 0.
4153257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&invoke);
41543ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ PushTryHandler(StackHandler::JS_ENTRY, 0);
4155257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // If an exception not caught by another handler occurs, this handler
4156257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // returns control to the code after the bal(&invoke) above, which
4157257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // restores all kCalleeSaved registers (including cp and fp) to their
4158257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // saved values before returning a failure to C.
4159257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
4160257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Clear any pending exceptions.
41613ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ LoadRoot(t1, Heap::kTheHoleValueRootIndex);
4162589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch  __ li(t0, Operand(ExternalReference(Isolate::kPendingExceptionAddress,
41633ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                                      isolate)));
4164257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ sw(t1, MemOperand(t0));
4165257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
4166257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Invoke the function by calling through JS entry trampoline builtin.
4167257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Notice that we cannot store a reference to the trampoline code directly in
4168257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // this stub, because runtime stubs are not traversed when doing GC.
4169257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
4170257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Registers:
4171257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // a0: entry_address
4172257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // a1: function
41733ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // a2: receiver_pointer
4174257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // a3: argc
4175257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // s0: argv
4176257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  //
4177257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Stack:
4178257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // handler frame
4179257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // entry frame
4180257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // callee saved registers + ra
4181257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // 4 args slots
4182257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // args
4183257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
4184257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  if (is_construct) {
4185257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    ExternalReference construct_entry(Builtins::kJSConstructEntryTrampoline,
41863ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                                      isolate);
4187257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ li(t0, Operand(construct_entry));
4188257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  } else {
4189257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    ExternalReference entry(Builtins::kJSEntryTrampoline, masm->isolate());
4190257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ li(t0, Operand(entry));
4191257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
4192257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ lw(t9, MemOperand(t0));  // Deref address.
4193257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
4194257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Call JSEntryTrampoline.
4195257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ addiu(t9, t9, Code::kHeaderSize - kHeapObjectTag);
4196257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Call(t9);
4197257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
4198257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Unlink this frame from the handler chain.
4199257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ PopTryHandler();
4200257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
4201257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&exit);  // v0 holds result
42023fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // Check if the current stack frame is marked as the outermost JS frame.
42033fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  Label non_outermost_js_2;
42043fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ pop(t1);
42053ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ Branch(&non_outermost_js_2,
42063ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch            ne,
42073ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch            t1,
42083fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch            Operand(Smi::FromInt(StackFrame::OUTERMOST_JSENTRY_FRAME)));
42093fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ li(t1, Operand(ExternalReference(js_entry_sp)));
42103fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ sw(zero_reg, MemOperand(t1));
42113fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ bind(&non_outermost_js_2);
4212257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
4213257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Restore the top frame descriptors from the stack.
4214257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ pop(t1);
4215589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch  __ li(t0, Operand(ExternalReference(Isolate::kCEntryFPAddress,
42163ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                                      isolate)));
4217257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ sw(t1, MemOperand(t0));
4218257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
4219257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Reset the stack to the callee saved registers.
4220257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ addiu(sp, sp, -EntryFrameConstants::kCallerFPOffset);
4221257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
4222589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch  if (CpuFeatures::IsSupported(FPU)) {
4223589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch    CpuFeatures::Scope scope(FPU);
4224589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch    // Restore callee-saved fpu registers.
4225589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch    __ MultiPopFPU(kCalleeSavedFPU);
4226589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch  }
4227589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch
4228257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Restore callee saved registers from the stack.
422969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ MultiPop(kCalleeSaved | ra.bit());
4230257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Return.
4231257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Jump(ra);
423244f0eee88ff00398ff7f715fab053374d808c90dSteve Block}
423344f0eee88ff00398ff7f715fab053374d808c90dSteve Block
423444f0eee88ff00398ff7f715fab053374d808c90dSteve Block
4235257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// Uses registers a0 to t0.
4236257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// Expected input (depending on whether args are in registers or on the stack):
4237257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// * object: a0 or at sp + 1 * kPointerSize.
4238257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// * function: a1 or at sp.
4239257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch//
42403ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch// An inlined call site may have been generated before calling this stub.
42413ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch// In this case the offset to the inline site to patch is passed on the stack,
42423ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch// in the safepoint slot for register t0.
424344f0eee88ff00398ff7f715fab053374d808c90dSteve Blockvoid InstanceofStub::Generate(MacroAssembler* masm) {
4244257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Call site inlining and patching implies arguments in registers.
4245257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  ASSERT(HasArgsInRegisters() || !HasCallSiteInlineCheck());
4246257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // ReturnTrueFalse is only implemented for inlined call sites.
4247257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  ASSERT(!ReturnTrueFalseObject() || HasCallSiteInlineCheck());
4248257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
4249257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Fixed register usage throughout the stub:
4250257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  const Register object = a0;  // Object (lhs).
4251257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Register map = a3;  // Map of the object.
4252257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  const Register function = a1;  // Function (rhs).
4253257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  const Register prototype = t0;  // Prototype of the function.
4254257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  const Register inline_site = t5;
4255257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  const Register scratch = a2;
4256257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
42573ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  const int32_t kDeltaToLoadBoolResult = 5 * kPointerSize;
42583ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
4259257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label slow, loop, is_instance, is_not_instance, not_js_object;
4260257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
4261257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  if (!HasArgsInRegisters()) {
4262257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ lw(object, MemOperand(sp, 1 * kPointerSize));
4263257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ lw(function, MemOperand(sp, 0));
4264257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
4265257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
4266257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Check that the left hand is a JS object and load map.
4267257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ JumpIfSmi(object, &not_js_object);
4268257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ IsObjectJSObjectType(object, map, scratch, &not_js_object);
4269257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
4270257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // If there is a call site cache don't look in the global cache, but do the
4271257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // real lookup and update the call site cache.
4272257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  if (!HasCallSiteInlineCheck()) {
4273257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Label miss;
42743ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ LoadRoot(at, Heap::kInstanceofCacheFunctionRootIndex);
42753ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ Branch(&miss, ne, function, Operand(at));
42763ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ LoadRoot(at, Heap::kInstanceofCacheMapRootIndex);
42773ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ Branch(&miss, ne, map, Operand(at));
4278257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ LoadRoot(v0, Heap::kInstanceofCacheAnswerRootIndex);
4279257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ DropAndRet(HasArgsInRegisters() ? 0 : 2);
4280257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
4281257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ bind(&miss);
4282257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
4283257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
4284257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Get the prototype of the function.
42853ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ TryGetFunctionPrototype(function, prototype, scratch, &slow, true);
4286257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
4287257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Check that the function prototype is a JS object.
4288257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ JumpIfSmi(prototype, &slow);
4289257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ IsObjectJSObjectType(prototype, scratch, scratch, &slow);
4290257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
4291257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Update the global instanceof or call site inlined cache with the current
4292257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // map and function. The cached answer will be set when it is known below.
4293257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  if (!HasCallSiteInlineCheck()) {
4294257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ StoreRoot(function, Heap::kInstanceofCacheFunctionRootIndex);
4295257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ StoreRoot(map, Heap::kInstanceofCacheMapRootIndex);
4296257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  } else {
42973ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    ASSERT(HasArgsInRegisters());
42983ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    // Patch the (relocated) inlined map check.
42993ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
43003ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    // The offset was stored in t0 safepoint slot.
43013ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    // (See LCodeGen::DoDeferredLInstanceOfKnownGlobal).
43023ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ LoadFromSafepointRegisterSlot(scratch, t0);
43033ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ Subu(inline_site, ra, scratch);
43043ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    // Get the map location in scratch and patch it.
43053ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ GetRelocatedValue(inline_site, scratch, v1);  // v1 used as scratch.
43063ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ sw(map, FieldMemOperand(scratch, JSGlobalPropertyCell::kValueOffset));
4307257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
4308257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
4309257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Register mapping: a3 is object map and t0 is function prototype.
4310257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Get prototype of object into a2.
4311257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ lw(scratch, FieldMemOperand(map, Map::kPrototypeOffset));
4312257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
4313257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // We don't need map any more. Use it as a scratch register.
4314257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Register scratch2 = map;
4315257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  map = no_reg;
4316257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
4317257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Loop through the prototype chain looking for the function prototype.
4318257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ LoadRoot(scratch2, Heap::kNullValueRootIndex);
4319257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&loop);
4320257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Branch(&is_instance, eq, scratch, Operand(prototype));
4321257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Branch(&is_not_instance, eq, scratch, Operand(scratch2));
4322257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ lw(scratch, FieldMemOperand(scratch, HeapObject::kMapOffset));
4323257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ lw(scratch, FieldMemOperand(scratch, Map::kPrototypeOffset));
4324257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Branch(&loop);
4325257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
4326257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&is_instance);
4327257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  ASSERT(Smi::FromInt(0) == 0);
4328257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  if (!HasCallSiteInlineCheck()) {
4329257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ mov(v0, zero_reg);
4330257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ StoreRoot(v0, Heap::kInstanceofCacheAnswerRootIndex);
4331257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  } else {
43323ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    // Patch the call site to return true.
43333ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ LoadRoot(v0, Heap::kTrueValueRootIndex);
43343ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ Addu(inline_site, inline_site, Operand(kDeltaToLoadBoolResult));
43353ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    // Get the boolean result location in scratch and patch it.
43363ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ PatchRelocatedValue(inline_site, scratch, v0);
43373ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
43383ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    if (!ReturnTrueFalseObject()) {
43393ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      ASSERT_EQ(Smi::FromInt(0), 0);
43403ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      __ mov(v0, zero_reg);
43413ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    }
4342257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
4343257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ DropAndRet(HasArgsInRegisters() ? 0 : 2);
4344257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
4345257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&is_not_instance);
4346257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  if (!HasCallSiteInlineCheck()) {
4347257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ li(v0, Operand(Smi::FromInt(1)));
4348257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ StoreRoot(v0, Heap::kInstanceofCacheAnswerRootIndex);
4349257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  } else {
43503ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    // Patch the call site to return false.
43513ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ LoadRoot(v0, Heap::kFalseValueRootIndex);
43523ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ Addu(inline_site, inline_site, Operand(kDeltaToLoadBoolResult));
43533ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    // Get the boolean result location in scratch and patch it.
43543ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ PatchRelocatedValue(inline_site, scratch, v0);
43553ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
43563ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    if (!ReturnTrueFalseObject()) {
43573ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      __ li(v0, Operand(Smi::FromInt(1)));
43583ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    }
4359257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
43603ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
4361257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ DropAndRet(HasArgsInRegisters() ? 0 : 2);
4362257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
4363257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label object_not_null, object_not_null_or_smi;
4364257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&not_js_object);
4365257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Before null, smi and string value checks, check that the rhs is a function
4366257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // as for a non-function rhs an exception needs to be thrown.
4367257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ JumpIfSmi(function, &slow);
4368257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ GetObjectType(function, scratch2, scratch);
4369257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Branch(&slow, ne, scratch, Operand(JS_FUNCTION_TYPE));
4370257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
4371257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Null is not instance of anything.
43723ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ Branch(&object_not_null,
43733ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch            ne,
43743ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch            scratch,
43753ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch            Operand(masm->isolate()->factory()->null_value()));
4376257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ li(v0, Operand(Smi::FromInt(1)));
4377257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ DropAndRet(HasArgsInRegisters() ? 0 : 2);
4378257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
4379257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&object_not_null);
4380257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Smi values are not instances of anything.
4381257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ JumpIfNotSmi(object, &object_not_null_or_smi);
4382257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ li(v0, Operand(Smi::FromInt(1)));
4383257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ DropAndRet(HasArgsInRegisters() ? 0 : 2);
4384257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
4385257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&object_not_null_or_smi);
4386257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // String values are not instances of anything.
4387257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ IsObjectJSStringType(object, scratch, &slow);
4388257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ li(v0, Operand(Smi::FromInt(1)));
4389257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ DropAndRet(HasArgsInRegisters() ? 0 : 2);
4390257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
4391257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Slow-case.  Tail call builtin.
4392257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&slow);
4393257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  if (!ReturnTrueFalseObject()) {
4394257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    if (HasArgsInRegisters()) {
4395257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ Push(a0, a1);
4396257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    }
4397257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION);
4398257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  } else {
43993ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    {
44003ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      FrameScope scope(masm, StackFrame::INTERNAL);
44013ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      __ Push(a0, a1);
44023ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      __ InvokeBuiltin(Builtins::INSTANCE_OF, CALL_FUNCTION);
44033ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    }
4404257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ mov(a0, v0);
4405257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ LoadRoot(v0, Heap::kTrueValueRootIndex);
4406257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ DropAndRet(HasArgsInRegisters() ? 0 : 2, eq, a0, Operand(zero_reg));
4407257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ LoadRoot(v0, Heap::kFalseValueRootIndex);
4408257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ DropAndRet(HasArgsInRegisters() ? 0 : 2);
4409257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
441044f0eee88ff00398ff7f715fab053374d808c90dSteve Block}
441144f0eee88ff00398ff7f715fab053374d808c90dSteve Block
441244f0eee88ff00398ff7f715fab053374d808c90dSteve Block
4413257744e915dfc84d6d07a6b2accf8402d9ffc708Ben MurdochRegister InstanceofStub::left() { return a0; }
4414257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
4415257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
4416257744e915dfc84d6d07a6b2accf8402d9ffc708Ben MurdochRegister InstanceofStub::right() { return a1; }
4417257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
4418257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
441944f0eee88ff00398ff7f715fab053374d808c90dSteve Blockvoid ArgumentsAccessStub::GenerateReadElement(MacroAssembler* masm) {
4420257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // The displacement is the offset of the last parameter (if any)
4421257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // relative to the frame pointer.
4422db1b4389239a7132c9cde0915dbd3f775dc1027aBen Murdoch  const int kDisplacement =
4423257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      StandardFrameConstants::kCallerSPOffset - kPointerSize;
4424257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
4425257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Check that the key is a smiGenerateReadElement.
4426257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label slow;
4427257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ JumpIfNotSmi(a1, &slow);
4428257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
4429257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Check if the calling frame is an arguments adaptor frame.
4430257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label adaptor;
4431257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ lw(a2, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
4432257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ lw(a3, MemOperand(a2, StandardFrameConstants::kContextOffset));
4433257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Branch(&adaptor,
4434257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch            eq,
4435257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch            a3,
4436257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch            Operand(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
4437257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
4438257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Check index (a1) against formal parameters count limit passed in
4439257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // through register a0. Use unsigned comparison to get negative
4440257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // check for free.
4441257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Branch(&slow, hs, a1, Operand(a0));
4442257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
4443257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Read the argument from the stack and return it.
4444257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ subu(a3, a0, a1);
4445257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ sll(t3, a3, kPointerSizeLog2 - kSmiTagSize);
4446257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Addu(a3, fp, Operand(t3));
4447257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ lw(v0, MemOperand(a3, kDisplacement));
4448257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Ret();
4449257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
4450257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Arguments adaptor case: Check index (a1) against actual arguments
4451257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // limit found in the arguments adaptor frame. Use unsigned
4452257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // comparison to get negative check for free.
4453257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&adaptor);
4454257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ lw(a0, MemOperand(a2, ArgumentsAdaptorFrameConstants::kLengthOffset));
4455257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Branch(&slow, Ugreater_equal, a1, Operand(a0));
4456257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
4457257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Read the argument from the adaptor frame and return it.
4458257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ subu(a3, a0, a1);
4459257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ sll(t3, a3, kPointerSizeLog2 - kSmiTagSize);
4460257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Addu(a3, a2, Operand(t3));
4461257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ lw(v0, MemOperand(a3, kDisplacement));
4462257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Ret();
4463257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
4464257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Slow-case: Handle non-smi or out-of-bounds access to arguments
4465257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // by calling the runtime system.
4466257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&slow);
4467257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ push(a1);
4468257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ TailCallRuntime(Runtime::kGetArgumentsProperty, 1, 1);
446944f0eee88ff00398ff7f715fab053374d808c90dSteve Block}
447044f0eee88ff00398ff7f715fab053374d808c90dSteve Block
447144f0eee88ff00398ff7f715fab053374d808c90dSteve Block
44723fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdochvoid ArgumentsAccessStub::GenerateNewNonStrictSlow(MacroAssembler* masm) {
4473257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // sp[0] : number of parameters
4474257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // sp[4] : receiver displacement
4475257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // sp[8] : function
44763fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // Check if the calling frame is an arguments adaptor frame.
44773fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  Label runtime;
44783fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ lw(a3, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
44793fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ lw(a2, MemOperand(a3, StandardFrameConstants::kContextOffset));
44803ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ Branch(&runtime,
44813ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch            ne,
44823ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch            a2,
44833ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch            Operand(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
44843fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
44853fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // Patch the arguments.length and the parameters pointer in the current frame.
44863fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ lw(a2, MemOperand(a3, ArgumentsAdaptorFrameConstants::kLengthOffset));
44873fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ sw(a2, MemOperand(sp, 0 * kPointerSize));
44883fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ sll(t3, a2, 1);
44893fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ Addu(a3, a3, Operand(t3));
44903fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ addiu(a3, a3, StandardFrameConstants::kCallerSPOffset);
44913fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ sw(a3, MemOperand(sp, 1 * kPointerSize));
44923fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
44933fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ bind(&runtime);
44943fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ TailCallRuntime(Runtime::kNewArgumentsFast, 3, 1);
44953fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch}
44963fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
44973fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
44983fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdochvoid ArgumentsAccessStub::GenerateNewNonStrictFast(MacroAssembler* masm) {
44993fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // Stack layout:
45003fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  //  sp[0] : number of parameters (tagged)
45013fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  //  sp[4] : address of receiver argument
45023fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  //  sp[8] : function
45033fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // Registers used over whole function:
45043fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  //  t2 : allocated object (tagged)
45053fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  //  t5 : mapped parameter count (tagged)
45063fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
45073fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ lw(a1, MemOperand(sp, 0 * kPointerSize));
45083fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // a1 = parameter count (tagged)
45093fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
45103fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // Check if the calling frame is an arguments adaptor frame.
45113fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  Label runtime;
45123fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  Label adaptor_frame, try_allocate;
45133fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ lw(a3, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
45143fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ lw(a2, MemOperand(a3, StandardFrameConstants::kContextOffset));
45153ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ Branch(&adaptor_frame,
45163ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch            eq,
45173ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch            a2,
45183fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch            Operand(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
45193fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
45203fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // No adaptor, parameter count = argument count.
45213fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ mov(a2, a1);
45223fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ b(&try_allocate);
45233fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ nop();   // Branch delay slot nop.
45243fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
45253fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // We have an adaptor frame. Patch the parameters pointer.
45263fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ bind(&adaptor_frame);
45273fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ lw(a2, MemOperand(a3, ArgumentsAdaptorFrameConstants::kLengthOffset));
45283fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ sll(t6, a2, 1);
45293fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ Addu(a3, a3, Operand(t6));
45303fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ Addu(a3, a3, Operand(StandardFrameConstants::kCallerSPOffset));
45313fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ sw(a3, MemOperand(sp, 1 * kPointerSize));
45323fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
45333fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // a1 = parameter count (tagged)
45343fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // a2 = argument count (tagged)
45353fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // Compute the mapped parameter count = min(a1, a2) in a1.
45363fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  Label skip_min;
45373fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ Branch(&skip_min, lt, a1, Operand(a2));
45383fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ mov(a1, a2);
45393fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ bind(&skip_min);
4540257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
45413fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ bind(&try_allocate);
45423fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
45433fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // Compute the sizes of backing store, parameter map, and arguments object.
45443fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // 1. Parameter map, has 2 extra words containing context and backing store.
45453fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  const int kParameterMapHeaderSize =
45463fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch      FixedArray::kHeaderSize + 2 * kPointerSize;
45473fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // If there are no mapped parameters, we do not need the parameter_map.
45483fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  Label param_map_size;
45493fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  ASSERT_EQ(0, Smi::FromInt(0));
45503fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ Branch(USE_DELAY_SLOT, &param_map_size, eq, a1, Operand(zero_reg));
45513fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ mov(t5, zero_reg);  // In delay slot: param map size = 0 when a1 == 0.
45523fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ sll(t5, a1, 1);
45533fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ addiu(t5, t5, kParameterMapHeaderSize);
45543fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ bind(&param_map_size);
45553fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
45563fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // 2. Backing store.
45573fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ sll(t6, a2, 1);
45583fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ Addu(t5, t5, Operand(t6));
45593fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ Addu(t5, t5, Operand(FixedArray::kHeaderSize));
45603fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
45613fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // 3. Arguments object.
45623fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ Addu(t5, t5, Operand(Heap::kArgumentsObjectSize));
45633fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
45643fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // Do the allocation of all three objects in one go.
45653fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ AllocateInNewSpace(t5, v0, a3, t0, &runtime, TAG_OBJECT);
45663fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
45673fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // v0 = address of new object(s) (tagged)
45683fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // a2 = argument count (tagged)
45693fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // Get the arguments boilerplate from the current (global) context into t0.
45703fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  const int kNormalOffset =
45713fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch      Context::SlotOffset(Context::ARGUMENTS_BOILERPLATE_INDEX);
45723fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  const int kAliasedOffset =
45733fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch      Context::SlotOffset(Context::ALIASED_ARGUMENTS_BOILERPLATE_INDEX);
45743fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
45753fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ lw(t0, MemOperand(cp, Context::SlotOffset(Context::GLOBAL_INDEX)));
45763fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ lw(t0, FieldMemOperand(t0, GlobalObject::kGlobalContextOffset));
45773fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  Label skip2_ne, skip2_eq;
45783fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ Branch(&skip2_ne, ne, a1, Operand(zero_reg));
45793fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ lw(t0, MemOperand(t0, kNormalOffset));
45803fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ bind(&skip2_ne);
45813fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
45823fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ Branch(&skip2_eq, eq, a1, Operand(zero_reg));
45833fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ lw(t0, MemOperand(t0, kAliasedOffset));
45843fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ bind(&skip2_eq);
45853fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
45863fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // v0 = address of new object (tagged)
45873fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // a1 = mapped parameter count (tagged)
45883fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // a2 = argument count (tagged)
45893fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // t0 = address of boilerplate object (tagged)
45903fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // Copy the JS object part.
45913fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  for (int i = 0; i < JSObject::kHeaderSize; i += kPointerSize) {
45923fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    __ lw(a3, FieldMemOperand(t0, i));
45933fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    __ sw(a3, FieldMemOperand(v0, i));
45943fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  }
45953fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
45963ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Set up the callee in-object property.
45973fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  STATIC_ASSERT(Heap::kArgumentsCalleeIndex == 1);
45983fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ lw(a3, MemOperand(sp, 2 * kPointerSize));
45993fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  const int kCalleeOffset = JSObject::kHeaderSize +
46003fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch      Heap::kArgumentsCalleeIndex * kPointerSize;
46013fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ sw(a3, FieldMemOperand(v0, kCalleeOffset));
46023fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
46033fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // Use the length (smi tagged) and set that as an in-object property too.
46043fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  STATIC_ASSERT(Heap::kArgumentsLengthIndex == 0);
46053fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  const int kLengthOffset = JSObject::kHeaderSize +
46063fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch      Heap::kArgumentsLengthIndex * kPointerSize;
46073fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ sw(a2, FieldMemOperand(v0, kLengthOffset));
46083fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
46093ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Set up the elements pointer in the allocated arguments object.
46103fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // If we allocated a parameter map, t0 will point there, otherwise
46113fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // it will point to the backing store.
46123fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ Addu(t0, v0, Operand(Heap::kArgumentsObjectSize));
46133fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ sw(t0, FieldMemOperand(v0, JSObject::kElementsOffset));
46143fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
46153fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // v0 = address of new object (tagged)
46163fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // a1 = mapped parameter count (tagged)
46173fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // a2 = argument count (tagged)
46183fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // t0 = address of parameter map or backing store (tagged)
46193fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // Initialize parameter map. If there are no mapped arguments, we're done.
46203fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  Label skip_parameter_map;
46213fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  Label skip3;
46223fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ Branch(&skip3, ne, a1, Operand(Smi::FromInt(0)));
46233fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // Move backing store address to a3, because it is
46243fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // expected there when filling in the unmapped arguments.
46253fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ mov(a3, t0);
46263fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ bind(&skip3);
46273fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
46283fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ Branch(&skip_parameter_map, eq, a1, Operand(Smi::FromInt(0)));
46293fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
46303fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ LoadRoot(t2, Heap::kNonStrictArgumentsElementsMapRootIndex);
46313fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ sw(t2, FieldMemOperand(t0, FixedArray::kMapOffset));
46323fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ Addu(t2, a1, Operand(Smi::FromInt(2)));
46333fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ sw(t2, FieldMemOperand(t0, FixedArray::kLengthOffset));
46343fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ sw(cp, FieldMemOperand(t0, FixedArray::kHeaderSize + 0 * kPointerSize));
46353fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ sll(t6, a1, 1);
46363fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ Addu(t2, t0, Operand(t6));
46373fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ Addu(t2, t2, Operand(kParameterMapHeaderSize));
46383fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ sw(t2, FieldMemOperand(t0, FixedArray::kHeaderSize + 1 * kPointerSize));
46393fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
46403fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // Copy the parameter slots and the holes in the arguments.
46413fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // We need to fill in mapped_parameter_count slots. They index the context,
46423fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // where parameters are stored in reverse order, at
46433fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  //   MIN_CONTEXT_SLOTS .. MIN_CONTEXT_SLOTS+parameter_count-1
46443fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // The mapped parameter thus need to get indices
46453fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  //   MIN_CONTEXT_SLOTS+parameter_count-1 ..
46463fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  //       MIN_CONTEXT_SLOTS+parameter_count-mapped_parameter_count
46473fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // We loop from right to left.
46483fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  Label parameters_loop, parameters_test;
46493fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ mov(t2, a1);
46503fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ lw(t5, MemOperand(sp, 0 * kPointerSize));
46513fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ Addu(t5, t5, Operand(Smi::FromInt(Context::MIN_CONTEXT_SLOTS)));
46523fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ Subu(t5, t5, Operand(a1));
46533fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ LoadRoot(t3, Heap::kTheHoleValueRootIndex);
46543fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ sll(t6, t2, 1);
46553fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ Addu(a3, t0, Operand(t6));
46563fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ Addu(a3, a3, Operand(kParameterMapHeaderSize));
46573fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
46583fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // t2 = loop variable (tagged)
46593fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // a1 = mapping index (tagged)
46603fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // a3 = address of backing store (tagged)
46613fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // t0 = address of parameter map (tagged)
46623fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // t1 = temporary scratch (a.o., for address calculation)
46633fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // t3 = the hole value
46643fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ jmp(&parameters_test);
46653fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
46663fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ bind(&parameters_loop);
46673fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ Subu(t2, t2, Operand(Smi::FromInt(1)));
46683fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ sll(t1, t2, 1);
46693fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ Addu(t1, t1, Operand(kParameterMapHeaderSize - kHeapObjectTag));
46703fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ Addu(t6, t0, t1);
46713fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ sw(t5, MemOperand(t6));
46723fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ Subu(t1, t1, Operand(kParameterMapHeaderSize - FixedArray::kHeaderSize));
46733fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ Addu(t6, a3, t1);
46743fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ sw(t3, MemOperand(t6));
46753fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ Addu(t5, t5, Operand(Smi::FromInt(1)));
46763fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ bind(&parameters_test);
46773fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ Branch(&parameters_loop, ne, t2, Operand(Smi::FromInt(0)));
46783fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
46793fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ bind(&skip_parameter_map);
46803fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // a2 = argument count (tagged)
46813fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // a3 = address of backing store (tagged)
46823fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // t1 = scratch
46833fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // Copy arguments header and remaining slots (if there are any).
46843fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ LoadRoot(t1, Heap::kFixedArrayMapRootIndex);
46853fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ sw(t1, FieldMemOperand(a3, FixedArray::kMapOffset));
46863fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ sw(a2, FieldMemOperand(a3, FixedArray::kLengthOffset));
46873fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
46883fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  Label arguments_loop, arguments_test;
46893fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ mov(t5, a1);
46903fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ lw(t0, MemOperand(sp, 1 * kPointerSize));
46913fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ sll(t6, t5, 1);
46923fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ Subu(t0, t0, Operand(t6));
46933fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ jmp(&arguments_test);
46943fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
46953fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ bind(&arguments_loop);
46963fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ Subu(t0, t0, Operand(kPointerSize));
46973fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ lw(t2, MemOperand(t0, 0));
46983fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ sll(t6, t5, 1);
46993fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ Addu(t1, a3, Operand(t6));
47003fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ sw(t2, FieldMemOperand(t1, FixedArray::kHeaderSize));
47013fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ Addu(t5, t5, Operand(Smi::FromInt(1)));
47023fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
47033fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ bind(&arguments_test);
47043fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ Branch(&arguments_loop, lt, t5, Operand(a2));
47053fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
47063fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // Return and remove the on-stack parameters.
47073ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ DropAndRet(3);
47083fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
47093fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // Do the runtime call to allocate the arguments object.
47103ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // a2 = argument count (tagged)
47113fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ bind(&runtime);
47123fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ sw(a2, MemOperand(sp, 0 * kPointerSize));  // Patch argument count.
47133fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ TailCallRuntime(Runtime::kNewArgumentsFast, 3, 1);
47143fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch}
47153fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
47163fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
47173fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdochvoid ArgumentsAccessStub::GenerateNewStrict(MacroAssembler* masm) {
47183fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // sp[0] : number of parameters
47193fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // sp[4] : receiver displacement
47203fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // sp[8] : function
4721257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Check if the calling frame is an arguments adaptor frame.
4722257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label adaptor_frame, try_allocate, runtime;
4723257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ lw(a2, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
4724257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ lw(a3, MemOperand(a2, StandardFrameConstants::kContextOffset));
4725257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Branch(&adaptor_frame,
4726257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch            eq,
4727257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch            a3,
4728257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch            Operand(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
4729257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
4730257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Get the length from the frame.
4731257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ lw(a1, MemOperand(sp, 0));
4732257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Branch(&try_allocate);
4733257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
4734257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Patch the arguments.length and the parameters pointer.
4735257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&adaptor_frame);
4736257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ lw(a1, MemOperand(a2, ArgumentsAdaptorFrameConstants::kLengthOffset));
4737257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ sw(a1, MemOperand(sp, 0));
4738257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ sll(at, a1, kPointerSizeLog2 - kSmiTagSize);
4739257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Addu(a3, a2, Operand(at));
4740257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
4741257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Addu(a3, a3, Operand(StandardFrameConstants::kCallerSPOffset));
4742257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ sw(a3, MemOperand(sp, 1 * kPointerSize));
4743257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
4744257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Try the new space allocation. Start out with computing the size
4745257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // of the arguments object and the elements array in words.
4746257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label add_arguments_object;
4747257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&try_allocate);
4748257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Branch(&add_arguments_object, eq, a1, Operand(zero_reg));
4749257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ srl(a1, a1, kSmiTagSize);
4750257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
4751257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Addu(a1, a1, Operand(FixedArray::kHeaderSize / kPointerSize));
4752257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&add_arguments_object);
47533fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ Addu(a1, a1, Operand(Heap::kArgumentsObjectSizeStrict / kPointerSize));
4754257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
4755257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Do the allocation of both objects in one go.
47563fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ AllocateInNewSpace(a1,
47573fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch                        v0,
47583fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch                        a2,
47593fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch                        a3,
47603fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch                        &runtime,
47613fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch                        static_cast<AllocationFlags>(TAG_OBJECT |
47623fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch                                                     SIZE_IN_WORDS));
4763257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
4764257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Get the arguments boilerplate from the current (global) context.
4765257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ lw(t0, MemOperand(cp, Context::SlotOffset(Context::GLOBAL_INDEX)));
4766257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ lw(t0, FieldMemOperand(t0, GlobalObject::kGlobalContextOffset));
47673fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ lw(t0, MemOperand(t0, Context::SlotOffset(
47683fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch      Context::STRICT_MODE_ARGUMENTS_BOILERPLATE_INDEX)));
4769257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
4770257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Copy the JS object part.
4771257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ CopyFields(v0, t0, a3.bit(), JSObject::kHeaderSize / kPointerSize);
4772257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
4773257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Get the length (smi tagged) and set that as an in-object property too.
4774257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  STATIC_ASSERT(Heap::kArgumentsLengthIndex == 0);
4775257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ lw(a1, MemOperand(sp, 0 * kPointerSize));
4776257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ sw(a1, FieldMemOperand(v0, JSObject::kHeaderSize +
47773fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch      Heap::kArgumentsLengthIndex * kPointerSize));
4778257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
4779257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label done;
4780257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Branch(&done, eq, a1, Operand(zero_reg));
4781257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
4782257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Get the parameters pointer from the stack.
4783257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ lw(a2, MemOperand(sp, 1 * kPointerSize));
4784257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
47853ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Set up the elements pointer in the allocated arguments object and
4786257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // initialize the header in the elements fixed array.
47873fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ Addu(t0, v0, Operand(Heap::kArgumentsObjectSizeStrict));
4788257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ sw(t0, FieldMemOperand(v0, JSObject::kElementsOffset));
4789257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ LoadRoot(a3, Heap::kFixedArrayMapRootIndex);
4790257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ sw(a3, FieldMemOperand(t0, FixedArray::kMapOffset));
4791257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ sw(a1, FieldMemOperand(t0, FixedArray::kLengthOffset));
47923fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // Untag the length for the loop.
47933fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ srl(a1, a1, kSmiTagSize);
4794257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
4795257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Copy the fixed array slots.
4796257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label loop;
47973ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Set up t0 to point to the first array slot.
4798257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Addu(t0, t0, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
4799257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&loop);
4800257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Pre-decrement a2 with kPointerSize on each iteration.
4801257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Pre-decrement in order to skip receiver.
4802257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Addu(a2, a2, Operand(-kPointerSize));
4803257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ lw(a3, MemOperand(a2));
4804257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Post-increment t0 with kPointerSize on each iteration.
4805257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ sw(a3, MemOperand(t0));
4806257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Addu(t0, t0, Operand(kPointerSize));
4807257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Subu(a1, a1, Operand(1));
4808257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Branch(&loop, ne, a1, Operand(zero_reg));
4809257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
4810257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Return and remove the on-stack parameters.
4811257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&done);
48123ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ DropAndRet(3);
4813257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
4814257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Do the runtime call to allocate the arguments object.
4815257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&runtime);
48163fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ TailCallRuntime(Runtime::kNewStrictArgumentsFast, 3, 1);
481744f0eee88ff00398ff7f715fab053374d808c90dSteve Block}
481844f0eee88ff00398ff7f715fab053374d808c90dSteve Block
481944f0eee88ff00398ff7f715fab053374d808c90dSteve Block
482044f0eee88ff00398ff7f715fab053374d808c90dSteve Blockvoid RegExpExecStub::Generate(MacroAssembler* masm) {
4821257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Just jump directly to runtime if native RegExp is not selected at compile
4822257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // time or if regexp entry in generated code is turned off runtime switch or
4823257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // at compilation.
4824257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch#ifdef V8_INTERPRETED_REGEXP
4825257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ TailCallRuntime(Runtime::kRegExpExec, 4, 1);
4826257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch#else  // V8_INTERPRETED_REGEXP
4827257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
4828257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Stack frame on entry.
4829257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  //  sp[0]: last_match_info (expected JSArray)
4830257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  //  sp[4]: previous index
4831257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  //  sp[8]: subject string
4832257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  //  sp[12]: JSRegExp object
4833257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
4834db1b4389239a7132c9cde0915dbd3f775dc1027aBen Murdoch  const int kLastMatchInfoOffset = 0 * kPointerSize;
4835db1b4389239a7132c9cde0915dbd3f775dc1027aBen Murdoch  const int kPreviousIndexOffset = 1 * kPointerSize;
4836db1b4389239a7132c9cde0915dbd3f775dc1027aBen Murdoch  const int kSubjectOffset = 2 * kPointerSize;
4837db1b4389239a7132c9cde0915dbd3f775dc1027aBen Murdoch  const int kJSRegExpOffset = 3 * kPointerSize;
4838257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
48393ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  Isolate* isolate = masm->isolate();
48403ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
4841257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label runtime, invoke_regexp;
4842257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
4843257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Allocation of registers for this function. These are in callee save
4844257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // registers and will be preserved by the call to the native RegExp code, as
4845257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // this code is called using the normal C calling convention. When calling
4846257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // directly from generated code the native RegExp code will not do a GC and
4847257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // therefore the content of these registers are safe to use after the call.
4848257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // MIPS - using s0..s2, since we are not using CEntry Stub.
4849257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Register subject = s0;
4850257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Register regexp_data = s1;
4851257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Register last_match_info_elements = s2;
4852257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
4853257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Ensure that a RegExp stack is allocated.
4854257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  ExternalReference address_of_regexp_stack_memory_address =
4855257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      ExternalReference::address_of_regexp_stack_memory_address(
48563ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch          isolate);
4857257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  ExternalReference address_of_regexp_stack_memory_size =
48583ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      ExternalReference::address_of_regexp_stack_memory_size(isolate);
4859257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ li(a0, Operand(address_of_regexp_stack_memory_size));
4860257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ lw(a0, MemOperand(a0, 0));
4861257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Branch(&runtime, eq, a0, Operand(zero_reg));
4862257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
4863257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Check that the first argument is a JSRegExp object.
4864257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ lw(a0, MemOperand(sp, kJSRegExpOffset));
4865257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  STATIC_ASSERT(kSmiTag == 0);
4866257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ JumpIfSmi(a0, &runtime);
4867257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ GetObjectType(a0, a1, a1);
4868257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Branch(&runtime, ne, a1, Operand(JS_REGEXP_TYPE));
4869257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
4870257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Check that the RegExp has been compiled (data contains a fixed array).
4871257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ lw(regexp_data, FieldMemOperand(a0, JSRegExp::kDataOffset));
4872257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  if (FLAG_debug_code) {
4873257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ And(t0, regexp_data, Operand(kSmiTagMask));
4874257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ Check(nz,
4875257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch             "Unexpected type for RegExp data, FixedArray expected",
4876257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch             t0,
4877257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch             Operand(zero_reg));
4878257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ GetObjectType(regexp_data, a0, a0);
4879257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ Check(eq,
4880257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch             "Unexpected type for RegExp data, FixedArray expected",
4881257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch             a0,
4882257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch             Operand(FIXED_ARRAY_TYPE));
4883257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
4884257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
4885257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // regexp_data: RegExp data (FixedArray)
4886257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Check the type of the RegExp. Only continue if type is JSRegExp::IRREGEXP.
4887257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ lw(a0, FieldMemOperand(regexp_data, JSRegExp::kDataTagOffset));
4888257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Branch(&runtime, ne, a0, Operand(Smi::FromInt(JSRegExp::IRREGEXP)));
4889257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
4890257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // regexp_data: RegExp data (FixedArray)
4891257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Check that the number of captures fit in the static offsets vector buffer.
4892257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ lw(a2,
4893257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch         FieldMemOperand(regexp_data, JSRegExp::kIrregexpCaptureCountOffset));
4894257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Calculate number of capture registers (number_of_captures + 1) * 2. This
4895257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // uses the asumption that smis are 2 * their untagged value.
4896257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  STATIC_ASSERT(kSmiTag == 0);
4897257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  STATIC_ASSERT(kSmiTagSize + kSmiShiftSize == 1);
4898257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Addu(a2, a2, Operand(2));  // a2 was a smi.
4899257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Check that the static offsets vector buffer is large enough.
4900257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Branch(&runtime, hi, a2, Operand(OffsetsVector::kStaticOffsetsVectorSize));
4901257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
4902257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // a2: Number of capture registers
4903257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // regexp_data: RegExp data (FixedArray)
4904257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Check that the second argument is a string.
4905257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ lw(subject, MemOperand(sp, kSubjectOffset));
4906257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ JumpIfSmi(subject, &runtime);
4907257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ GetObjectType(subject, a0, a0);
4908257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ And(a0, a0, Operand(kIsNotStringMask));
4909257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  STATIC_ASSERT(kStringTag == 0);
4910257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Branch(&runtime, ne, a0, Operand(zero_reg));
4911257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
4912257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Get the length of the string to r3.
4913257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ lw(a3, FieldMemOperand(subject, String::kLengthOffset));
4914257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
4915257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // a2: Number of capture registers
4916257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // a3: Length of subject string as a smi
4917257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // subject: Subject string
4918257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // regexp_data: RegExp data (FixedArray)
4919257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Check that the third argument is a positive smi less than the subject
4920257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // string length. A negative value will be greater (unsigned comparison).
4921257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ lw(a0, MemOperand(sp, kPreviousIndexOffset));
49223ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ JumpIfNotSmi(a0, &runtime);
4923257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Branch(&runtime, ls, a3, Operand(a0));
4924257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
4925257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // a2: Number of capture registers
4926257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // subject: Subject string
4927257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // regexp_data: RegExp data (FixedArray)
4928257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Check that the fourth object is a JSArray object.
4929257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ lw(a0, MemOperand(sp, kLastMatchInfoOffset));
4930257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ JumpIfSmi(a0, &runtime);
4931257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ GetObjectType(a0, a1, a1);
4932257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Branch(&runtime, ne, a1, Operand(JS_ARRAY_TYPE));
4933257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Check that the JSArray is in fast case.
4934257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ lw(last_match_info_elements,
4935257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch         FieldMemOperand(a0, JSArray::kElementsOffset));
4936257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ lw(a0, FieldMemOperand(last_match_info_elements, HeapObject::kMapOffset));
4937257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Branch(&runtime, ne, a0, Operand(
49383ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      isolate->factory()->fixed_array_map()));
4939257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Check that the last match info has space for the capture registers and the
4940257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // additional information.
4941257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ lw(a0,
4942257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch         FieldMemOperand(last_match_info_elements, FixedArray::kLengthOffset));
4943257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Addu(a2, a2, Operand(RegExpImpl::kLastMatchOverhead));
4944257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ sra(at, a0, kSmiTagSize);  // Untag length for comparison.
4945257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Branch(&runtime, gt, a2, Operand(at));
494669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch
494769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  // Reset offset for possibly sliced string.
494869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ mov(t0, zero_reg);
4949257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // subject: Subject string
4950257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // regexp_data: RegExp data (FixedArray)
4951257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Check the representation and encoding of the subject string.
4952257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label seq_string;
4953257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ lw(a0, FieldMemOperand(subject, HeapObject::kMapOffset));
4954257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ lbu(a0, FieldMemOperand(a0, Map::kInstanceTypeOffset));
49553ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // First check for flat string.  None of the following string type tests will
49563ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // succeed if subject is not a string or a short external string.
49573ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ And(a1,
49583ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch         a0,
49593ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch         Operand(kIsNotStringMask |
49603ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                 kStringRepresentationMask |
49613ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                 kShortExternalStringMask));
4962257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  STATIC_ASSERT((kStringTag | kSeqStringTag) == 0);
496369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ Branch(&seq_string, eq, a1, Operand(zero_reg));
4964257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
4965257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // subject: Subject string
4966257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // a0: instance type if Subject string
4967257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // regexp_data: RegExp data (FixedArray)
49683ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // a1: whether subject is a string and if yes, its string representation
496969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  // Check for flat cons string or sliced string.
4970257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // A flat cons string is a cons string where the second part is the empty
4971257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // string. In that case the subject string is just the first part of the cons
4972257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // string. Also in this case the first part of the cons string is known to be
4973257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // a sequential string or an external string.
497469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  // In the case of a sliced string its offset has to be taken into account.
49753ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  Label cons_string, external_string, check_encoding;
497669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  STATIC_ASSERT(kConsStringTag < kExternalStringTag);
497769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  STATIC_ASSERT(kSlicedStringTag > kExternalStringTag);
49783ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  STATIC_ASSERT(kIsNotStringMask > kExternalStringTag);
49793ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  STATIC_ASSERT(kShortExternalStringTag > kExternalStringTag);
498069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ Branch(&cons_string, lt, a1, Operand(kExternalStringTag));
49813ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ Branch(&external_string, eq, a1, Operand(kExternalStringTag));
49823ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
49833ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Catch non-string subject or short external string.
49843ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  STATIC_ASSERT(kNotStringTag != 0 && kShortExternalStringTag !=0);
49853ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ And(at, a1, Operand(kIsNotStringMask | kShortExternalStringMask));
49863ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ Branch(&runtime, ne, at, Operand(zero_reg));
498769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch
498869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  // String is sliced.
498969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ lw(t0, FieldMemOperand(subject, SlicedString::kOffsetOffset));
499069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ sra(t0, t0, kSmiTagSize);
499169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ lw(subject, FieldMemOperand(subject, SlicedString::kParentOffset));
499269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  // t5: offset of sliced string, smi-tagged.
499369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ jmp(&check_encoding);
499469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  // String is a cons string, check whether it is flat.
499569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ bind(&cons_string);
4996257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ lw(a0, FieldMemOperand(subject, ConsString::kSecondOffset));
4997257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ LoadRoot(a1, Heap::kEmptyStringRootIndex);
4998257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Branch(&runtime, ne, a0, Operand(a1));
4999257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ lw(subject, FieldMemOperand(subject, ConsString::kFirstOffset));
500069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  // Is first part of cons or parent of slice a flat string?
500169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ bind(&check_encoding);
5002257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ lw(a0, FieldMemOperand(subject, HeapObject::kMapOffset));
5003257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ lbu(a0, FieldMemOperand(a0, Map::kInstanceTypeOffset));
5004257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  STATIC_ASSERT(kSeqStringTag == 0);
5005257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ And(at, a0, Operand(kStringRepresentationMask));
50063ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ Branch(&external_string, ne, at, Operand(zero_reg));
5007257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5008257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&seq_string);
5009257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // subject: Subject string
5010257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // regexp_data: RegExp data (FixedArray)
5011257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // a0: Instance type of subject string
5012257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  STATIC_ASSERT(kStringEncodingMask == 4);
5013257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  STATIC_ASSERT(kAsciiStringTag == 4);
5014257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  STATIC_ASSERT(kTwoByteStringTag == 0);
5015257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Find the code object based on the assumptions above.
50163ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ And(a0, a0, Operand(kStringEncodingMask));  // Non-zero for ASCII.
5017257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ lw(t9, FieldMemOperand(regexp_data, JSRegExp::kDataAsciiCodeOffset));
50183ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ sra(a3, a0, 2);  // a3 is 1 for ASCII, 0 for UC16 (used below).
501969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ lw(t1, FieldMemOperand(regexp_data, JSRegExp::kDataUC16CodeOffset));
50203ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ Movz(t9, t1, a0);  // If UC16 (a0 is 0), replace t9 w/kDataUC16CodeOffset.
5021257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5022257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Check that the irregexp code has been generated for the actual string
50233fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // encoding. If it has, the field contains a code object otherwise it contains
50243fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // a smi (code flushing support).
50253fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ JumpIfSmi(t9, &runtime);
5026257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5027257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // a3: encoding of subject string (1 if ASCII, 0 if two_byte);
5028257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // t9: code
5029257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // subject: Subject string
5030257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // regexp_data: RegExp data (FixedArray)
5031257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Load used arguments before starting to push arguments for call to native
5032257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // RegExp code to avoid handling changing stack height.
5033257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ lw(a1, MemOperand(sp, kPreviousIndexOffset));
5034257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ sra(a1, a1, kSmiTagSize);  // Untag the Smi.
5035257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5036257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // a1: previous index
5037257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // a3: encoding of subject string (1 if ASCII, 0 if two_byte);
5038257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // t9: code
5039257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // subject: Subject string
5040257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // regexp_data: RegExp data (FixedArray)
5041257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // All checks done. Now push arguments for native regexp code.
50423ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ IncrementCounter(isolate->counters()->regexp_entry_native(),
5043257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                      1, a0, a2);
5044257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5045257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Isolates: note we add an additional parameter here (isolate pointer).
5046db1b4389239a7132c9cde0915dbd3f775dc1027aBen Murdoch  const int kRegExpExecuteArguments = 8;
5047db1b4389239a7132c9cde0915dbd3f775dc1027aBen Murdoch  const int kParameterRegisters = 4;
5048257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ EnterExitFrame(false, kRegExpExecuteArguments - kParameterRegisters);
5049257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5050257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Stack pointer now points to cell where return address is to be written.
5051257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Arguments are before that on the stack or in registers, meaning we
5052257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // treat the return address as argument 5. Thus every argument after that
5053257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // needs to be shifted back by 1. Since DirectCEntryStub will handle
5054257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // allocating space for the c argument slots, we don't need to calculate
5055257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // that into the argument positions on the stack. This is how the stack will
5056257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // look (sp meaning the value of sp at this moment):
5057257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // [sp + 4] - Argument 8
5058257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // [sp + 3] - Argument 7
5059257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // [sp + 2] - Argument 6
5060257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // [sp + 1] - Argument 5
5061257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // [sp + 0] - saved ra
5062257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5063257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Argument 8: Pass current isolate address.
5064257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // CFunctionArgumentOperand handles MIPS stack argument slots.
5065257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ li(a0, Operand(ExternalReference::isolate_address()));
5066257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ sw(a0, MemOperand(sp, 4 * kPointerSize));
5067257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5068257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Argument 7: Indicate that this is a direct call from JavaScript.
5069257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ li(a0, Operand(1));
5070257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ sw(a0, MemOperand(sp, 3 * kPointerSize));
5071257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5072257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Argument 6: Start (high end) of backtracking stack memory area.
5073257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ li(a0, Operand(address_of_regexp_stack_memory_address));
5074257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ lw(a0, MemOperand(a0, 0));
5075257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ li(a2, Operand(address_of_regexp_stack_memory_size));
5076257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ lw(a2, MemOperand(a2, 0));
5077257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ addu(a0, a0, a2);
5078257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ sw(a0, MemOperand(sp, 2 * kPointerSize));
5079257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5080257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Argument 5: static offsets vector buffer.
5081257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ li(a0, Operand(
50823ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch        ExternalReference::address_of_static_offsets_vector(isolate)));
5083257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ sw(a0, MemOperand(sp, 1 * kPointerSize));
5084257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5085257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // For arguments 4 and 3 get string length, calculate start of string data
5086257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // and calculate the shift of the index (0 for ASCII and 1 for two byte).
50873ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ Addu(t2, subject, Operand(SeqString::kHeaderSize - kHeapObjectTag));
5088257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Xor(a3, a3, Operand(1));  // 1 for 2-byte str, 0 for 1-byte.
508969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  // Load the length from the original subject string from the previous stack
509069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  // frame. Therefore we have to use fp, which points exactly to two pointer
509169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  // sizes below the previous sp. (Because creating a new stack frame pushes
509269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  // the previous fp onto the stack and moves up sp by 2 * kPointerSize.)
5093589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch  __ lw(subject, MemOperand(fp, kSubjectOffset + 2 * kPointerSize));
509469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  // If slice offset is not 0, load the length from the original sliced string.
509569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  // Argument 4, a3: End of string data
509669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  // Argument 3, a2: Start of string data
509769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  // Prepare start and end index of the input.
509869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ sllv(t1, t0, a3);
509969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ addu(t0, t2, t1);
5100257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ sllv(t1, a1, a3);
5101257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ addu(a2, t0, t1);
5102257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5103589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch  __ lw(t2, FieldMemOperand(subject, String::kLengthOffset));
510469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ sra(t2, t2, kSmiTagSize);
510569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ sllv(t1, t2, a3);
510669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ addu(a3, t0, t1);
5107257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Argument 2 (a1): Previous index.
5108257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Already there
5109257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5110257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Argument 1 (a0): Subject string.
5111589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch  __ mov(a0, subject);
5112257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5113257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Locate the code entry and call it.
5114257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Addu(t9, t9, Operand(Code::kHeaderSize - kHeapObjectTag));
5115257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  DirectCEntryStub stub;
5116257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  stub.GenerateCall(masm, t9);
5117257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5118257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ LeaveExitFrame(false, no_reg);
5119257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5120257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // v0: result
5121257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // subject: subject string (callee saved)
5122257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // regexp_data: RegExp data (callee saved)
5123257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // last_match_info_elements: Last match info elements (callee saved)
5124257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5125257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Check the result.
5126257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5127257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label success;
51283ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ Branch(&success, eq, v0, Operand(NativeRegExpMacroAssembler::SUCCESS));
5129257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label failure;
51303ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ Branch(&failure, eq, v0, Operand(NativeRegExpMacroAssembler::FAILURE));
5131257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // If not exception it can only be retry. Handle that in the runtime system.
51323ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ Branch(&runtime, ne, v0, Operand(NativeRegExpMacroAssembler::EXCEPTION));
5133257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Result must now be exception. If there is no pending exception already a
5134257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // stack overflow (on the backtrack stack) was detected in RegExp code but
5135257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // haven't created the exception yet. Handle that in the runtime system.
5136257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // TODO(592): Rerunning the RegExp to get the stack overflow exception.
51373ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ li(a1, Operand(isolate->factory()->the_hole_value()));
5138589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch  __ li(a2, Operand(ExternalReference(Isolate::kPendingExceptionAddress,
51393ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                                      isolate)));
5140257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ lw(v0, MemOperand(a2, 0));
5141589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch  __ Branch(&runtime, eq, v0, Operand(a1));
5142257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5143257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ sw(a1, MemOperand(a2, 0));  // Clear pending exception.
5144257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5145257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Check if the exception is a termination. If so, throw as uncatchable.
5146257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ LoadRoot(a0, Heap::kTerminationExceptionRootIndex);
5147257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label termination_exception;
5148589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch  __ Branch(&termination_exception, eq, v0, Operand(a0));
5149257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
51503ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ Throw(v0);
5151257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5152257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&termination_exception);
51533ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ ThrowUncatchable(v0);
5154257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5155257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&failure);
5156257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // For failure and exception return null.
51573ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ li(v0, Operand(isolate->factory()->null_value()));
51583ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ DropAndRet(4);
5159257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5160257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Process the result from the native regexp code.
5161257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&success);
5162257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ lw(a1,
5163257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch         FieldMemOperand(regexp_data, JSRegExp::kIrregexpCaptureCountOffset));
5164257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Calculate number of capture registers (number_of_captures + 1) * 2.
5165257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  STATIC_ASSERT(kSmiTag == 0);
5166257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  STATIC_ASSERT(kSmiTagSize + kSmiShiftSize == 1);
5167257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Addu(a1, a1, Operand(2));  // a1 was a smi.
5168257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5169257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // a1: number of capture registers
5170257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // subject: subject string
5171257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Store the capture count.
5172257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ sll(a2, a1, kSmiTagSize + kSmiShiftSize);  // To smi.
5173257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ sw(a2, FieldMemOperand(last_match_info_elements,
5174257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                             RegExpImpl::kLastCaptureCountOffset));
5175257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Store last subject and last input.
5176257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ sw(subject,
5177257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch         FieldMemOperand(last_match_info_elements,
5178257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                         RegExpImpl::kLastSubjectOffset));
51793ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ mov(a2, subject);
51803ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ RecordWriteField(last_match_info_elements,
51813ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                      RegExpImpl::kLastSubjectOffset,
51823ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                      a2,
51833ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                      t3,
51843ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                      kRAHasNotBeenSaved,
51853ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                      kDontSaveFPRegs);
5186257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ sw(subject,
5187257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch         FieldMemOperand(last_match_info_elements,
5188257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                         RegExpImpl::kLastInputOffset));
51893ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ RecordWriteField(last_match_info_elements,
51903ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                      RegExpImpl::kLastInputOffset,
51913ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                      subject,
51923ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                      t3,
51933ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                      kRAHasNotBeenSaved,
51943ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                      kDontSaveFPRegs);
5195257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5196257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Get the static offsets vector filled by the native regexp code.
5197257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  ExternalReference address_of_static_offsets_vector =
51983ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      ExternalReference::address_of_static_offsets_vector(isolate);
5199257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ li(a2, Operand(address_of_static_offsets_vector));
5200257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5201257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // a1: number of capture registers
5202257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // a2: offsets vector
5203257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label next_capture, done;
5204257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Capture register counter starts from number of capture registers and
5205257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // counts down until wrapping after zero.
5206257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Addu(a0,
5207257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch         last_match_info_elements,
5208257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch         Operand(RegExpImpl::kFirstCaptureOffset - kHeapObjectTag));
5209257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&next_capture);
5210257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Subu(a1, a1, Operand(1));
5211257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Branch(&done, lt, a1, Operand(zero_reg));
5212257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Read the value from the static offsets vector buffer.
5213257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ lw(a3, MemOperand(a2, 0));
5214257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ addiu(a2, a2, kPointerSize);
5215257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Store the smi value in the last match info.
5216257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ sll(a3, a3, kSmiTagSize);  // Convert to Smi.
5217257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ sw(a3, MemOperand(a0, 0));
5218257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Branch(&next_capture, USE_DELAY_SLOT);
52193ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ addiu(a0, a0, kPointerSize);  // In branch delay slot.
5220257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5221257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&done);
5222257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5223257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Return last match info.
5224257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ lw(v0, MemOperand(sp, kLastMatchInfoOffset));
52253ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ DropAndRet(4);
52263ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
52273ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // External string.  Short external strings have already been ruled out.
52283ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // a0: scratch
52293ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ bind(&external_string);
52303ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ lw(a0, FieldMemOperand(subject, HeapObject::kMapOffset));
52313ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ lbu(a0, FieldMemOperand(a0, Map::kInstanceTypeOffset));
52323ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  if (FLAG_debug_code) {
52333ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    // Assert that we do not have a cons or slice (indirect strings) here.
52343ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    // Sequential strings have already been ruled out.
52353ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ And(at, a0, Operand(kIsIndirectStringMask));
52363ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ Assert(eq,
52373ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch              "external string expected, but not found",
52383ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch              at,
52393ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch              Operand(zero_reg));
52403ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  }
52413ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ lw(subject,
52423ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch        FieldMemOperand(subject, ExternalString::kResourceDataOffset));
52433ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Move the pointer so that offset-wise, it looks like a sequential string.
52443ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqAsciiString::kHeaderSize);
52453ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ Subu(subject,
52463ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch          subject,
52473ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch          SeqTwoByteString::kHeaderSize - kHeapObjectTag);
52483ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ jmp(&seq_string);
5249592a9fc1d8ea420377a2e7efd0600e20b058be2bBen Murdoch
5250257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Do the runtime call to execute the regexp.
5251257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&runtime);
5252257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ TailCallRuntime(Runtime::kRegExpExec, 4, 1);
5253257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch#endif  // V8_INTERPRETED_REGEXP
525444f0eee88ff00398ff7f715fab053374d808c90dSteve Block}
525544f0eee88ff00398ff7f715fab053374d808c90dSteve Block
525644f0eee88ff00398ff7f715fab053374d808c90dSteve Block
525744f0eee88ff00398ff7f715fab053374d808c90dSteve Blockvoid RegExpConstructResultStub::Generate(MacroAssembler* masm) {
5258257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  const int kMaxInlineLength = 100;
5259257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label slowcase;
5260257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label done;
5261257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ lw(a1, MemOperand(sp, kPointerSize * 2));
5262257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  STATIC_ASSERT(kSmiTag == 0);
5263257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  STATIC_ASSERT(kSmiTagSize == 1);
5264257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ JumpIfNotSmi(a1, &slowcase);
5265257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Branch(&slowcase, hi, a1, Operand(Smi::FromInt(kMaxInlineLength)));
5266257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Smi-tagging is equivalent to multiplying by 2.
5267257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Allocate RegExpResult followed by FixedArray with size in ebx.
5268257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // JSArray:   [Map][empty properties][Elements][Length-smi][index][input]
5269257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Elements:  [Map][Length][..elements..]
5270257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Size of JSArray with two in-object properties and the header of a
5271257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // FixedArray.
5272257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  int objects_size =
5273257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      (JSRegExpResult::kSize + FixedArray::kHeaderSize) / kPointerSize;
5274257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ srl(t1, a1, kSmiTagSize + kSmiShiftSize);
5275257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Addu(a2, t1, Operand(objects_size));
5276257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ AllocateInNewSpace(
5277257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      a2,  // In: Size, in words.
5278257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      v0,  // Out: Start of allocation (tagged).
5279257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      a3,  // Scratch register.
5280257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      t0,  // Scratch register.
5281257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      &slowcase,
5282257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      static_cast<AllocationFlags>(TAG_OBJECT | SIZE_IN_WORDS));
5283257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // v0: Start of allocated area, object-tagged.
5284257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // a1: Number of elements in array, as smi.
5285257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // t1: Number of elements, untagged.
5286257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5287257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Set JSArray map to global.regexp_result_map().
5288257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Set empty properties FixedArray.
5289257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Set elements to point to FixedArray allocated right after the JSArray.
5290257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Interleave operations for better latency.
5291257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ lw(a2, ContextOperand(cp, Context::GLOBAL_INDEX));
5292257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Addu(a3, v0, Operand(JSRegExpResult::kSize));
5293257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ li(t0, Operand(masm->isolate()->factory()->empty_fixed_array()));
5294257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ lw(a2, FieldMemOperand(a2, GlobalObject::kGlobalContextOffset));
5295257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ sw(a3, FieldMemOperand(v0, JSObject::kElementsOffset));
5296257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ lw(a2, ContextOperand(a2, Context::REGEXP_RESULT_MAP_INDEX));
5297257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ sw(t0, FieldMemOperand(v0, JSObject::kPropertiesOffset));
5298257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ sw(a2, FieldMemOperand(v0, HeapObject::kMapOffset));
5299257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5300257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Set input, index and length fields from arguments.
5301257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ lw(a1, MemOperand(sp, kPointerSize * 0));
53023ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ lw(a2, MemOperand(sp, kPointerSize * 1));
53033ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ lw(t2, MemOperand(sp, kPointerSize * 2));
5304257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ sw(a1, FieldMemOperand(v0, JSRegExpResult::kInputOffset));
53053ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ sw(a2, FieldMemOperand(v0, JSRegExpResult::kIndexOffset));
53063ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ sw(t2, FieldMemOperand(v0, JSArray::kLengthOffset));
5307257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5308257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Fill out the elements FixedArray.
5309257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // v0: JSArray, tagged.
5310257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // a3: FixedArray, tagged.
5311257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // t1: Number of elements in array, untagged.
5312257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5313257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Set map.
5314257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ li(a2, Operand(masm->isolate()->factory()->fixed_array_map()));
5315257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ sw(a2, FieldMemOperand(a3, HeapObject::kMapOffset));
5316257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Set FixedArray length.
5317257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ sll(t2, t1, kSmiTagSize);
5318257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ sw(t2, FieldMemOperand(a3, FixedArray::kLengthOffset));
5319257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Fill contents of fixed-array with the-hole.
5320257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ li(a2, Operand(masm->isolate()->factory()->the_hole_value()));
5321257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Addu(a3, a3, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
5322257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Fill fixed array elements with hole.
5323257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // v0: JSArray, tagged.
5324257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // a2: the hole.
5325257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // a3: Start of elements in FixedArray.
5326257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // t1: Number of elements to fill.
5327257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label loop;
5328257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ sll(t1, t1, kPointerSizeLog2);  // Convert num elements to num bytes.
5329257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ addu(t1, t1, a3);  // Point past last element to store.
5330257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&loop);
5331257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Branch(&done, ge, a3, Operand(t1));  // Break when a3 past end of elem.
5332257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ sw(a2, MemOperand(a3));
5333257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Branch(&loop, USE_DELAY_SLOT);
5334257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ addiu(a3, a3, kPointerSize);  // In branch delay slot.
5335257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5336257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&done);
53373ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ DropAndRet(3);
5338257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5339257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&slowcase);
5340257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ TailCallRuntime(Runtime::kRegExpConstructResult, 3, 1);
534144f0eee88ff00398ff7f715fab053374d808c90dSteve Block}
534244f0eee88ff00398ff7f715fab053374d808c90dSteve Block
534344f0eee88ff00398ff7f715fab053374d808c90dSteve Block
53443ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochstatic void GenerateRecordCallTarget(MacroAssembler* masm) {
53453ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Cache the called function in a global property cell.  Cache states
53463ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // are uninitialized, monomorphic (indicated by a JSFunction), and
53473ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // megamorphic.
53483ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // a1 : the function to call
53493ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // a2 : cache cell for call target
53503ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  Label done;
53513ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
53523ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  ASSERT_EQ(*TypeFeedbackCells::MegamorphicSentinel(masm->isolate()),
53533ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch            masm->isolate()->heap()->undefined_value());
53543ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  ASSERT_EQ(*TypeFeedbackCells::UninitializedSentinel(masm->isolate()),
53553ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch            masm->isolate()->heap()->the_hole_value());
53563ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
53573ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Load the cache state into a3.
53583ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ lw(a3, FieldMemOperand(a2, JSGlobalPropertyCell::kValueOffset));
53593ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
53603ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // A monomorphic cache hit or an already megamorphic state: invoke the
53613ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // function without changing the state.
53623ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ Branch(&done, eq, a3, Operand(a1));
53633ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ LoadRoot(at, Heap::kUndefinedValueRootIndex);
53643ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ Branch(&done, eq, a3, Operand(at));
53653ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
53663ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // A monomorphic miss (i.e, here the cache is not uninitialized) goes
53673ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // megamorphic.
53683ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
53693ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
53703ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ Branch(USE_DELAY_SLOT, &done, eq, a3, Operand(at));
53713ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // An uninitialized cache is patched with the function.
53723ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Store a1 in the delay slot. This may or may not get overwritten depending
53733ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // on the result of the comparison.
53743ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ sw(a1, FieldMemOperand(a2, JSGlobalPropertyCell::kValueOffset));
53753ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // No need for a write barrier here - cells are rescanned.
53763ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
53773ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // MegamorphicSentinel is an immortal immovable object (undefined) so no
53783ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // write-barrier is needed.
53793ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ LoadRoot(at, Heap::kUndefinedValueRootIndex);
53803ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ sw(at, FieldMemOperand(a2, JSGlobalPropertyCell::kValueOffset));
53813ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
53823ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ bind(&done);
53833ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch}
53843ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
53853ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
538644f0eee88ff00398ff7f715fab053374d808c90dSteve Blockvoid CallFunctionStub::Generate(MacroAssembler* masm) {
53873ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // a1 : the function to call
53883ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // a2 : cache cell for call target
53893ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  Label slow, non_function;
5390257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5391257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // The receiver might implicitly be the global object. This is
5392257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // indicated by passing the hole as the receiver to the call
5393257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // function stub.
5394257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  if (ReceiverMightBeImplicit()) {
5395257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Label call;
5396257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Get the receiver from the stack.
5397257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // function, receiver [, arguments]
5398257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ lw(t0, MemOperand(sp, argc_ * kPointerSize));
5399257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Call as function is indicated with the hole.
5400257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
5401257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ Branch(&call, ne, t0, Operand(at));
5402257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Patch the receiver on the stack with the global receiver object.
54033ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ lw(a2, MemOperand(cp, Context::SlotOffset(Context::GLOBAL_INDEX)));
54043ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ lw(a2, FieldMemOperand(a2, GlobalObject::kGlobalReceiverOffset));
54053ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ sw(a2, MemOperand(sp, argc_ * kPointerSize));
5406257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ bind(&call);
5407257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
5408257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5409257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Check that the function is really a JavaScript function.
5410257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // a1: pushed function (to be verified)
54113ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ JumpIfSmi(a1, &non_function);
5412257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Get the map of the function object.
5413257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ GetObjectType(a1, a2, a2);
5414257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Branch(&slow, ne, a2, Operand(JS_FUNCTION_TYPE));
5415257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5416257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Fast-case: Invoke the function now.
5417257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // a1: pushed function
5418257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  ParameterCount actual(argc_);
5419257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5420257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  if (ReceiverMightBeImplicit()) {
5421257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Label call_as_function;
5422257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
5423257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ Branch(&call_as_function, eq, t0, Operand(at));
54243fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    __ InvokeFunction(a1,
54253fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch                      actual,
54263fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch                      JUMP_FUNCTION,
54273fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch                      NullCallWrapper(),
54283fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch                      CALL_AS_METHOD);
5429257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ bind(&call_as_function);
5430257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
5431257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ InvokeFunction(a1,
5432257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                    actual,
5433257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                    JUMP_FUNCTION,
5434257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                    NullCallWrapper(),
5435257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                    CALL_AS_FUNCTION);
5436257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5437257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Slow-case: Non-function called.
5438257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&slow);
54393ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Check for function proxy.
54403ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ Branch(&non_function, ne, a2, Operand(JS_FUNCTION_PROXY_TYPE));
54413ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ push(a1);  // Put proxy as additional argument.
54423ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ li(a0, Operand(argc_ + 1, RelocInfo::NONE));
54433ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ li(a2, Operand(0, RelocInfo::NONE));
54443ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ GetBuiltinEntry(a3, Builtins::CALL_FUNCTION_PROXY);
54453ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ SetCallKind(t1, CALL_AS_METHOD);
54463ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  {
54473ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    Handle<Code> adaptor =
54483ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      masm->isolate()->builtins()->ArgumentsAdaptorTrampoline();
54493ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ Jump(adaptor, RelocInfo::CODE_TARGET);
54503ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  }
54513ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
5452257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // CALL_NON_FUNCTION expects the non-function callee as receiver (instead
5453257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // of the original receiver from the call site).
54543ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ bind(&non_function);
5455257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ sw(a1, MemOperand(sp, argc_ * kPointerSize));
54563ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ li(a0, Operand(argc_));  // Set up the number of arguments.
5457257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ mov(a2, zero_reg);
5458257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ GetBuiltinEntry(a3, Builtins::CALL_NON_FUNCTION);
54593fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ SetCallKind(t1, CALL_AS_METHOD);
5460257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Jump(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
5461257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          RelocInfo::CODE_TARGET);
546244f0eee88ff00398ff7f715fab053374d808c90dSteve Block}
546344f0eee88ff00398ff7f715fab053374d808c90dSteve Block
546444f0eee88ff00398ff7f715fab053374d808c90dSteve Block
54653ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochvoid CallConstructStub::Generate(MacroAssembler* masm) {
54663ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // a0 : number of arguments
54673ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // a1 : the function to call
54683ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // a2 : cache cell for call target
54693ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  Label slow, non_function_call;
54703ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
54713ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Check that the function is not a smi.
54723ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ JumpIfSmi(a1, &non_function_call);
54733ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Check that the function is a JSFunction.
54743ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ GetObjectType(a1, a3, a3);
54753ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ Branch(&slow, ne, a3, Operand(JS_FUNCTION_TYPE));
54763ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
54773ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  if (RecordCallTarget()) {
54783ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    GenerateRecordCallTarget(masm);
54793ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  }
54803ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
54813ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Jump to the function-specific construct stub.
54823ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ lw(a2, FieldMemOperand(a1, JSFunction::kSharedFunctionInfoOffset));
54833ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ lw(a2, FieldMemOperand(a2, SharedFunctionInfo::kConstructStubOffset));
54843ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ Addu(at, a2, Operand(Code::kHeaderSize - kHeapObjectTag));
54853ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ Jump(at);
54863ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
54873ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // a0: number of arguments
54883ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // a1: called object
54893ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // a3: object type
54903ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  Label do_call;
54913ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ bind(&slow);
54923ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ Branch(&non_function_call, ne, a3, Operand(JS_FUNCTION_PROXY_TYPE));
54933ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ GetBuiltinEntry(a3, Builtins::CALL_FUNCTION_PROXY_AS_CONSTRUCTOR);
54943ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ jmp(&do_call);
54953ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
54963ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ bind(&non_function_call);
54973ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ GetBuiltinEntry(a3, Builtins::CALL_NON_FUNCTION_AS_CONSTRUCTOR);
54983ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ bind(&do_call);
54993ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Set expected number of arguments to zero (not changing r0).
55003ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ li(a2, Operand(0, RelocInfo::NONE));
55013ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ SetCallKind(t1, CALL_AS_METHOD);
55023ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ Jump(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
55033ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch          RelocInfo::CODE_TARGET);
55043ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch}
55053ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
55063ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
550744f0eee88ff00398ff7f715fab053374d808c90dSteve Block// Unfortunately you have to run without snapshots to see most of these
550844f0eee88ff00398ff7f715fab053374d808c90dSteve Block// names in the profile since most compare stubs end up in the snapshot.
55093fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdochvoid CompareStub::PrintName(StringStream* stream) {
5510257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  ASSERT((lhs_.is(a0) && rhs_.is(a1)) ||
5511257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch         (lhs_.is(a1) && rhs_.is(a0)));
5512257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  const char* cc_name;
5513257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  switch (cc_) {
5514257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case lt: cc_name = "LT"; break;
5515257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case gt: cc_name = "GT"; break;
5516257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case le: cc_name = "LE"; break;
5517257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case ge: cc_name = "GE"; break;
5518257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case eq: cc_name = "EQ"; break;
5519257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case ne: cc_name = "NE"; break;
5520257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    default: cc_name = "UnknownCondition"; break;
5521257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
55223fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  bool is_equality = cc_ == eq || cc_ == ne;
55233fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  stream->Add("CompareStub_%s", cc_name);
55243fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  stream->Add(lhs_.is(a0) ? "_a0" : "_a1");
55253fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  stream->Add(rhs_.is(a0) ? "_a0" : "_a1");
55263fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  if (strict_ && is_equality) stream->Add("_STRICT");
55273fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  if (never_nan_nan_ && is_equality) stream->Add("_NO_NAN");
55283fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  if (!include_number_compare_) stream->Add("_NO_NUMBER");
55293fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  if (!include_smi_compare_) stream->Add("_NO_SMI");
553044f0eee88ff00398ff7f715fab053374d808c90dSteve Block}
553144f0eee88ff00398ff7f715fab053374d808c90dSteve Block
553244f0eee88ff00398ff7f715fab053374d808c90dSteve Block
553344f0eee88ff00398ff7f715fab053374d808c90dSteve Blockint CompareStub::MinorKey() {
5534257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Encode the two parameters in a unique 16 bit value.
5535257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  ASSERT(static_cast<unsigned>(cc_) < (1 << 14));
5536257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  ASSERT((lhs_.is(a0) && rhs_.is(a1)) ||
5537257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch         (lhs_.is(a1) && rhs_.is(a0)));
5538257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  return ConditionField::encode(static_cast<unsigned>(cc_))
5539257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch         | RegisterField::encode(lhs_.is(a0))
5540257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch         | StrictField::encode(strict_)
5541257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch         | NeverNanNanField::encode(cc_ == eq ? never_nan_nan_ : false)
5542257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch         | IncludeSmiCompareField::encode(include_smi_compare_);
554344f0eee88ff00398ff7f715fab053374d808c90dSteve Block}
554444f0eee88ff00398ff7f715fab053374d808c90dSteve Block
554544f0eee88ff00398ff7f715fab053374d808c90dSteve Block
5546257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// StringCharCodeAtGenerator.
554744f0eee88ff00398ff7f715fab053374d808c90dSteve Blockvoid StringCharCodeAtGenerator::GenerateFast(MacroAssembler* masm) {
5548257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label flat_string;
5549257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label ascii_string;
5550257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label got_char_code;
555169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  Label sliced_string;
5552257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5553257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  ASSERT(!t0.is(index_));
5554257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  ASSERT(!t0.is(result_));
5555257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  ASSERT(!t0.is(object_));
5556257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5557257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // If the receiver is a smi trigger the non-string case.
5558257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ JumpIfSmi(object_, receiver_not_string_);
5559257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5560257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Fetch the instance type of the receiver into result register.
5561257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ lw(result_, FieldMemOperand(object_, HeapObject::kMapOffset));
5562257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ lbu(result_, FieldMemOperand(result_, Map::kInstanceTypeOffset));
5563257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // If the receiver is not a string trigger the non-string case.
5564257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ And(t0, result_, Operand(kIsNotStringMask));
5565257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Branch(receiver_not_string_, ne, t0, Operand(zero_reg));
5566257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5567257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // If the index is non-smi trigger the non-smi case.
5568257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ JumpIfNotSmi(index_, &index_not_smi_);
5569257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5570257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&got_smi_index_);
5571257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5572257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Check for index out of range.
5573257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ lw(t0, FieldMemOperand(object_, String::kLengthOffset));
55743ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ Branch(index_out_of_range_, ls, t0, Operand(index_));
557585b71799222b55eb5dd74ea26efe0c64ab655c8cBen Murdoch
55763ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ sra(index_, index_, kSmiTagSize);
557785b71799222b55eb5dd74ea26efe0c64ab655c8cBen Murdoch
55783ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  StringCharLoadGenerator::Generate(masm,
55793ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                                    object_,
55803ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                                    index_,
55813ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                                    result_,
55823ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                                    &call_runtime_);
558385b71799222b55eb5dd74ea26efe0c64ab655c8cBen Murdoch
5584257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ sll(result_, result_, kSmiTagSize);
5585257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&exit_);
558644f0eee88ff00398ff7f715fab053374d808c90dSteve Block}
558744f0eee88ff00398ff7f715fab053374d808c90dSteve Block
558844f0eee88ff00398ff7f715fab053374d808c90dSteve Block
558944f0eee88ff00398ff7f715fab053374d808c90dSteve Blockvoid StringCharCodeAtGenerator::GenerateSlow(
55903ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    MacroAssembler* masm,
55913ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    const RuntimeCallHelper& call_helper) {
5592257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Abort("Unexpected fallthrough to CharCodeAt slow case");
5593257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5594257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Index is not a smi.
5595257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&index_not_smi_);
5596257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // If index is a heap number, try converting it to an integer.
5597257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ CheckMap(index_,
55983ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch              result_,
5599257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch              Heap::kHeapNumberMapRootIndex,
5600257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch              index_not_number_,
5601257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch              DONT_DO_SMI_CHECK);
5602257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  call_helper.BeforeCall(masm);
5603257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Consumed by runtime conversion function:
56043ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ Push(object_, index_);
5605257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  if (index_flags_ == STRING_INDEX_IS_NUMBER) {
5606257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ CallRuntime(Runtime::kNumberToIntegerMapMinusZero, 1);
5607257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  } else {
5608257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    ASSERT(index_flags_ == STRING_INDEX_IS_ARRAY_INDEX);
5609257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // NumberToSmi discards numbers that are not exact integers.
5610257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ CallRuntime(Runtime::kNumberToSmi, 1);
5611257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
5612257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5613257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Save the conversion result before the pop instructions below
5614257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // have a chance to overwrite it.
5615257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
56163ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ Move(index_, v0);
5617257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ pop(object_);
5618257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Reload the instance type.
5619257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ lw(result_, FieldMemOperand(object_, HeapObject::kMapOffset));
5620257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ lbu(result_, FieldMemOperand(result_, Map::kInstanceTypeOffset));
5621257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  call_helper.AfterCall(masm);
5622257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // If index is still not a smi, it must be out of range.
56233ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ JumpIfNotSmi(index_, index_out_of_range_);
5624257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Otherwise, return to the fast path.
5625257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Branch(&got_smi_index_);
5626257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5627257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Call runtime. We get here when the receiver is a string and the
5628257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // index is a number, but the code of getting the actual character
5629257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // is too complex (e.g., when the string needs to be flattened).
5630257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&call_runtime_);
5631257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  call_helper.BeforeCall(masm);
56323ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ sll(index_, index_, kSmiTagSize);
5633257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Push(object_, index_);
5634257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ CallRuntime(Runtime::kStringCharCodeAt, 2);
5635257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5636257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Move(result_, v0);
5637257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5638257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  call_helper.AfterCall(masm);
5639257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ jmp(&exit_);
5640257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5641257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Abort("Unexpected fallthrough from CharCodeAt slow case");
564244f0eee88ff00398ff7f715fab053374d808c90dSteve Block}
564344f0eee88ff00398ff7f715fab053374d808c90dSteve Block
564444f0eee88ff00398ff7f715fab053374d808c90dSteve Block
564544f0eee88ff00398ff7f715fab053374d808c90dSteve Block// -------------------------------------------------------------------------
564644f0eee88ff00398ff7f715fab053374d808c90dSteve Block// StringCharFromCodeGenerator
564744f0eee88ff00398ff7f715fab053374d808c90dSteve Block
564844f0eee88ff00398ff7f715fab053374d808c90dSteve Blockvoid StringCharFromCodeGenerator::GenerateFast(MacroAssembler* masm) {
5649257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Fast case of Heap::LookupSingleCharacterStringFromCode.
5650257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5651257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  ASSERT(!t0.is(result_));
5652257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  ASSERT(!t0.is(code_));
5653257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5654257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  STATIC_ASSERT(kSmiTag == 0);
5655257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  STATIC_ASSERT(kSmiShiftSize == 0);
5656257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  ASSERT(IsPowerOf2(String::kMaxAsciiCharCode + 1));
5657257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ And(t0,
5658257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch         code_,
5659257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch         Operand(kSmiTagMask |
5660257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                 ((~String::kMaxAsciiCharCode) << kSmiTagSize)));
5661257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Branch(&slow_case_, ne, t0, Operand(zero_reg));
5662257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5663257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ LoadRoot(result_, Heap::kSingleCharacterStringCacheRootIndex);
5664257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // At this point code register contains smi tagged ASCII char code.
5665257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  STATIC_ASSERT(kSmiTag == 0);
5666257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ sll(t0, code_, kPointerSizeLog2 - kSmiTagSize);
5667257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Addu(result_, result_, t0);
5668257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ lw(result_, FieldMemOperand(result_, FixedArray::kHeaderSize));
5669257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ LoadRoot(t0, Heap::kUndefinedValueRootIndex);
5670257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Branch(&slow_case_, eq, result_, Operand(t0));
5671257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&exit_);
567244f0eee88ff00398ff7f715fab053374d808c90dSteve Block}
567344f0eee88ff00398ff7f715fab053374d808c90dSteve Block
567444f0eee88ff00398ff7f715fab053374d808c90dSteve Block
567544f0eee88ff00398ff7f715fab053374d808c90dSteve Blockvoid StringCharFromCodeGenerator::GenerateSlow(
56763ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    MacroAssembler* masm,
56773ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    const RuntimeCallHelper& call_helper) {
5678257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Abort("Unexpected fallthrough to CharFromCode slow case");
5679257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5680257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&slow_case_);
5681257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  call_helper.BeforeCall(masm);
5682257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ push(code_);
5683257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ CallRuntime(Runtime::kCharFromCode, 1);
5684257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Move(result_, v0);
5685257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5686257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  call_helper.AfterCall(masm);
5687257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Branch(&exit_);
5688257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5689257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Abort("Unexpected fallthrough from CharFromCode slow case");
569044f0eee88ff00398ff7f715fab053374d808c90dSteve Block}
569144f0eee88ff00398ff7f715fab053374d808c90dSteve Block
569244f0eee88ff00398ff7f715fab053374d808c90dSteve Block
569344f0eee88ff00398ff7f715fab053374d808c90dSteve Block// -------------------------------------------------------------------------
569444f0eee88ff00398ff7f715fab053374d808c90dSteve Block// StringCharAtGenerator
569544f0eee88ff00398ff7f715fab053374d808c90dSteve Block
569644f0eee88ff00398ff7f715fab053374d808c90dSteve Blockvoid StringCharAtGenerator::GenerateFast(MacroAssembler* masm) {
5697257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  char_code_at_generator_.GenerateFast(masm);
5698257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  char_from_code_generator_.GenerateFast(masm);
569944f0eee88ff00398ff7f715fab053374d808c90dSteve Block}
570044f0eee88ff00398ff7f715fab053374d808c90dSteve Block
570144f0eee88ff00398ff7f715fab053374d808c90dSteve Block
570244f0eee88ff00398ff7f715fab053374d808c90dSteve Blockvoid StringCharAtGenerator::GenerateSlow(
57033ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    MacroAssembler* masm,
57043ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    const RuntimeCallHelper& call_helper) {
5705257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  char_code_at_generator_.GenerateSlow(masm, call_helper);
5706257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  char_from_code_generator_.GenerateSlow(masm, call_helper);
570744f0eee88ff00398ff7f715fab053374d808c90dSteve Block}
570844f0eee88ff00398ff7f715fab053374d808c90dSteve Block
570944f0eee88ff00398ff7f715fab053374d808c90dSteve Block
571044f0eee88ff00398ff7f715fab053374d808c90dSteve Blockvoid StringHelper::GenerateCopyCharacters(MacroAssembler* masm,
571144f0eee88ff00398ff7f715fab053374d808c90dSteve Block                                          Register dest,
571244f0eee88ff00398ff7f715fab053374d808c90dSteve Block                                          Register src,
571344f0eee88ff00398ff7f715fab053374d808c90dSteve Block                                          Register count,
571444f0eee88ff00398ff7f715fab053374d808c90dSteve Block                                          Register scratch,
571544f0eee88ff00398ff7f715fab053374d808c90dSteve Block                                          bool ascii) {
5716257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label loop;
5717257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label done;
5718257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // This loop just copies one character at a time, as it is only used for
5719257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // very short strings.
5720257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  if (!ascii) {
5721257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ addu(count, count, count);
5722257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
5723257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Branch(&done, eq, count, Operand(zero_reg));
5724257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ addu(count, dest, count);  // Count now points to the last dest byte.
5725257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5726257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&loop);
5727257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ lbu(scratch, MemOperand(src));
5728257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ addiu(src, src, 1);
5729257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ sb(scratch, MemOperand(dest));
5730257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ addiu(dest, dest, 1);
5731257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Branch(&loop, lt, dest, Operand(count));
5732257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5733257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&done);
573444f0eee88ff00398ff7f715fab053374d808c90dSteve Block}
573544f0eee88ff00398ff7f715fab053374d808c90dSteve Block
573644f0eee88ff00398ff7f715fab053374d808c90dSteve Block
573744f0eee88ff00398ff7f715fab053374d808c90dSteve Blockenum CopyCharactersFlags {
573844f0eee88ff00398ff7f715fab053374d808c90dSteve Block  COPY_ASCII = 1,
573944f0eee88ff00398ff7f715fab053374d808c90dSteve Block  DEST_ALWAYS_ALIGNED = 2
574044f0eee88ff00398ff7f715fab053374d808c90dSteve Block};
574144f0eee88ff00398ff7f715fab053374d808c90dSteve Block
574244f0eee88ff00398ff7f715fab053374d808c90dSteve Block
574344f0eee88ff00398ff7f715fab053374d808c90dSteve Blockvoid StringHelper::GenerateCopyCharactersLong(MacroAssembler* masm,
574444f0eee88ff00398ff7f715fab053374d808c90dSteve Block                                              Register dest,
574544f0eee88ff00398ff7f715fab053374d808c90dSteve Block                                              Register src,
574644f0eee88ff00398ff7f715fab053374d808c90dSteve Block                                              Register count,
574744f0eee88ff00398ff7f715fab053374d808c90dSteve Block                                              Register scratch1,
574844f0eee88ff00398ff7f715fab053374d808c90dSteve Block                                              Register scratch2,
574944f0eee88ff00398ff7f715fab053374d808c90dSteve Block                                              Register scratch3,
575044f0eee88ff00398ff7f715fab053374d808c90dSteve Block                                              Register scratch4,
575144f0eee88ff00398ff7f715fab053374d808c90dSteve Block                                              Register scratch5,
575244f0eee88ff00398ff7f715fab053374d808c90dSteve Block                                              int flags) {
5753257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  bool ascii = (flags & COPY_ASCII) != 0;
5754257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  bool dest_always_aligned = (flags & DEST_ALWAYS_ALIGNED) != 0;
5755257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5756257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  if (dest_always_aligned && FLAG_debug_code) {
5757257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Check that destination is actually word aligned if the flag says
5758257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // that it is.
5759257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ And(scratch4, dest, Operand(kPointerAlignmentMask));
5760257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ Check(eq,
5761257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch             "Destination of copy not aligned.",
5762257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch             scratch4,
5763257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch             Operand(zero_reg));
5764257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
5765257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5766257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  const int kReadAlignment = 4;
5767257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  const int kReadAlignmentMask = kReadAlignment - 1;
5768257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Ensure that reading an entire aligned word containing the last character
5769257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // of a string will not read outside the allocated area (because we pad up
5770257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // to kObjectAlignment).
5771257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  STATIC_ASSERT(kObjectAlignment >= kReadAlignment);
5772257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Assumes word reads and writes are little endian.
5773257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Nothing to do for zero characters.
5774257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label done;
5775257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5776257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  if (!ascii) {
5777257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ addu(count, count, count);
5778257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
5779257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Branch(&done, eq, count, Operand(zero_reg));
5780257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5781257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label byte_loop;
5782257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Must copy at least eight bytes, otherwise just do it one byte at a time.
5783257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Subu(scratch1, count, Operand(8));
5784257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Addu(count, dest, Operand(count));
5785257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Register limit = count;  // Read until src equals this.
5786257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Branch(&byte_loop, lt, scratch1, Operand(zero_reg));
5787257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5788257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  if (!dest_always_aligned) {
5789257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Align dest by byte copying. Copies between zero and three bytes.
5790257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ And(scratch4, dest, Operand(kReadAlignmentMask));
5791257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Label dest_aligned;
5792257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ Branch(&dest_aligned, eq, scratch4, Operand(zero_reg));
5793257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Label aligned_loop;
5794257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ bind(&aligned_loop);
5795257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ lbu(scratch1, MemOperand(src));
5796257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ addiu(src, src, 1);
5797257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ sb(scratch1, MemOperand(dest));
5798257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ addiu(dest, dest, 1);
5799257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ addiu(scratch4, scratch4, 1);
5800257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ Branch(&aligned_loop, le, scratch4, Operand(kReadAlignmentMask));
5801257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ bind(&dest_aligned);
5802257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
5803257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5804257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label simple_loop;
5805257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5806257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ And(scratch4, src, Operand(kReadAlignmentMask));
5807257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Branch(&simple_loop, eq, scratch4, Operand(zero_reg));
5808257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5809257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Loop for src/dst that are not aligned the same way.
5810257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // This loop uses lwl and lwr instructions. These instructions
5811257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // depend on the endianness, and the implementation assumes little-endian.
5812257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  {
5813257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Label loop;
5814257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ bind(&loop);
5815257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ lwr(scratch1, MemOperand(src));
5816257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ Addu(src, src, Operand(kReadAlignment));
5817257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ lwl(scratch1, MemOperand(src, -1));
5818257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ sw(scratch1, MemOperand(dest));
5819257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ Addu(dest, dest, Operand(kReadAlignment));
5820257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ Subu(scratch2, limit, dest);
5821257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ Branch(&loop, ge, scratch2, Operand(kReadAlignment));
5822257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
5823257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5824257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Branch(&byte_loop);
5825257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5826257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Simple loop.
5827257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Copy words from src to dest, until less than four bytes left.
5828257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Both src and dest are word aligned.
5829257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&simple_loop);
5830257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  {
5831257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Label loop;
5832257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ bind(&loop);
5833257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ lw(scratch1, MemOperand(src));
5834257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ Addu(src, src, Operand(kReadAlignment));
5835257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ sw(scratch1, MemOperand(dest));
5836257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ Addu(dest, dest, Operand(kReadAlignment));
5837257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ Subu(scratch2, limit, dest);
5838257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ Branch(&loop, ge, scratch2, Operand(kReadAlignment));
5839257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
5840257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5841257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Copy bytes from src to dest until dest hits limit.
5842257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&byte_loop);
5843257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Test if dest has already reached the limit.
5844257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Branch(&done, ge, dest, Operand(limit));
5845257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ lbu(scratch1, MemOperand(src));
5846257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ addiu(src, src, 1);
5847257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ sb(scratch1, MemOperand(dest));
5848257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ addiu(dest, dest, 1);
5849257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Branch(&byte_loop);
5850257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5851257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&done);
585244f0eee88ff00398ff7f715fab053374d808c90dSteve Block}
585344f0eee88ff00398ff7f715fab053374d808c90dSteve Block
585444f0eee88ff00398ff7f715fab053374d808c90dSteve Block
585544f0eee88ff00398ff7f715fab053374d808c90dSteve Blockvoid StringHelper::GenerateTwoCharacterSymbolTableProbe(MacroAssembler* masm,
585644f0eee88ff00398ff7f715fab053374d808c90dSteve Block                                                        Register c1,
585744f0eee88ff00398ff7f715fab053374d808c90dSteve Block                                                        Register c2,
585844f0eee88ff00398ff7f715fab053374d808c90dSteve Block                                                        Register scratch1,
585944f0eee88ff00398ff7f715fab053374d808c90dSteve Block                                                        Register scratch2,
586044f0eee88ff00398ff7f715fab053374d808c90dSteve Block                                                        Register scratch3,
586144f0eee88ff00398ff7f715fab053374d808c90dSteve Block                                                        Register scratch4,
586244f0eee88ff00398ff7f715fab053374d808c90dSteve Block                                                        Register scratch5,
586344f0eee88ff00398ff7f715fab053374d808c90dSteve Block                                                        Label* not_found) {
5864257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Register scratch3 is the general scratch register in this function.
5865257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Register scratch = scratch3;
5866257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5867257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Make sure that both characters are not digits as such strings has a
5868257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // different hash algorithm. Don't try to look for these in the symbol table.
5869257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label not_array_index;
5870257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Subu(scratch, c1, Operand(static_cast<int>('0')));
5871257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Branch(&not_array_index,
5872257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch            Ugreater,
5873257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch            scratch,
5874257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch            Operand(static_cast<int>('9' - '0')));
5875257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Subu(scratch, c2, Operand(static_cast<int>('0')));
5876257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5877257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // If check failed combine both characters into single halfword.
5878257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // This is required by the contract of the method: code at the
5879257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // not_found branch expects this combination in c1 register.
5880257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label tmp;
5881257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ sll(scratch1, c2, kBitsPerByte);
5882257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Branch(&tmp, Ugreater, scratch, Operand(static_cast<int>('9' - '0')));
5883257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Or(c1, c1, scratch1);
5884257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&tmp);
58853ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ Branch(
58863ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      not_found, Uless_equal, scratch, Operand(static_cast<int>('9' - '0')));
5887257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5888257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&not_array_index);
5889257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Calculate the two character string hash.
5890257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Register hash = scratch1;
5891257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  StringHelper::GenerateHashInit(masm, hash, c1);
5892257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  StringHelper::GenerateHashAddCharacter(masm, hash, c2);
5893257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  StringHelper::GenerateHashGetHash(masm, hash);
5894257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5895257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Collect the two characters in a register.
5896257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Register chars = c1;
5897257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ sll(scratch, c2, kBitsPerByte);
5898257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Or(chars, chars, scratch);
5899257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5900257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // chars: two character string, char 1 in byte 0 and char 2 in byte 1.
5901257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // hash:  hash of two character string.
5902257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5903257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Load symbol table.
5904257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Load address of first element of the symbol table.
5905257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Register symbol_table = c2;
5906257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ LoadRoot(symbol_table, Heap::kSymbolTableRootIndex);
5907257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5908257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Register undefined = scratch4;
5909257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ LoadRoot(undefined, Heap::kUndefinedValueRootIndex);
5910257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5911257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Calculate capacity mask from the symbol table capacity.
5912257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Register mask = scratch2;
5913257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ lw(mask, FieldMemOperand(symbol_table, SymbolTable::kCapacityOffset));
5914257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ sra(mask, mask, 1);
5915257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Addu(mask, mask, -1);
5916257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5917257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Calculate untagged address of the first element of the symbol table.
5918257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Register first_symbol_table_element = symbol_table;
5919257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Addu(first_symbol_table_element, symbol_table,
5920257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch         Operand(SymbolTable::kElementsStartOffset - kHeapObjectTag));
5921257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5922257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Registers.
5923257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // chars: two character string, char 1 in byte 0 and char 2 in byte 1.
5924257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // hash:  hash of two character string
5925257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // mask:  capacity mask
5926257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // first_symbol_table_element: address of the first element of
5927257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  //                             the symbol table
5928257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // undefined: the undefined object
5929257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // scratch: -
5930257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5931257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Perform a number of probes in the symbol table.
5932db1b4389239a7132c9cde0915dbd3f775dc1027aBen Murdoch  const int kProbes = 4;
5933257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label found_in_symbol_table;
5934257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label next_probe[kProbes];
5935257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Register candidate = scratch5;  // Scratch register contains candidate.
5936257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  for (int i = 0; i < kProbes; i++) {
5937257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Calculate entry in symbol table.
5938257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    if (i > 0) {
5939257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ Addu(candidate, hash, Operand(SymbolTable::GetProbeOffset(i)));
5940257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    } else {
5941257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ mov(candidate, hash);
5942257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    }
5943257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5944257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ And(candidate, candidate, Operand(mask));
5945257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5946257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Load the entry from the symble table.
5947257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    STATIC_ASSERT(SymbolTable::kEntrySize == 1);
5948257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ sll(scratch, candidate, kPointerSizeLog2);
5949257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ Addu(scratch, scratch, first_symbol_table_element);
5950257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ lw(candidate, MemOperand(scratch));
5951257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5952257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // If entry is undefined no string with this hash can be found.
5953257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Label is_string;
5954257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ GetObjectType(candidate, scratch, scratch);
5955257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ Branch(&is_string, ne, scratch, Operand(ODDBALL_TYPE));
5956257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5957257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ Branch(not_found, eq, undefined, Operand(candidate));
59583ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    // Must be the hole (deleted entry).
5959257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    if (FLAG_debug_code) {
59603ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      __ LoadRoot(scratch, Heap::kTheHoleValueRootIndex);
59613ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      __ Assert(eq, "oddball in symbol table is not undefined or the hole",
5962257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          scratch, Operand(candidate));
5963257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    }
5964257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ jmp(&next_probe[i]);
5965257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5966257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ bind(&is_string);
5967257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5968257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Check that the candidate is a non-external ASCII string.  The instance
5969257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // type is still in the scratch register from the CompareObjectType
5970257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // operation.
5971257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ JumpIfInstanceTypeIsNotSequentialAscii(scratch, scratch, &next_probe[i]);
5972257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5973257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // If length is not 2 the string is not a candidate.
5974257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ lw(scratch, FieldMemOperand(candidate, String::kLengthOffset));
5975257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ Branch(&next_probe[i], ne, scratch, Operand(Smi::FromInt(2)));
5976257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5977257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Check if the two characters match.
5978257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Assumes that word load is little endian.
5979257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ lhu(scratch, FieldMemOperand(candidate, SeqAsciiString::kHeaderSize));
5980257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ Branch(&found_in_symbol_table, eq, chars, Operand(scratch));
5981257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ bind(&next_probe[i]);
5982257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
5983257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5984257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // No matching 2 character string found by probing.
5985257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ jmp(not_found);
5986257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5987257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Scratch register contains result when we fall through to here.
5988257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Register result = candidate;
5989257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&found_in_symbol_table);
5990257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ mov(v0, result);
599144f0eee88ff00398ff7f715fab053374d808c90dSteve Block}
599244f0eee88ff00398ff7f715fab053374d808c90dSteve Block
599344f0eee88ff00398ff7f715fab053374d808c90dSteve Block
599444f0eee88ff00398ff7f715fab053374d808c90dSteve Blockvoid StringHelper::GenerateHashInit(MacroAssembler* masm,
5995c7cc028aaeedbbfa11c11d0b7b243b3d9e837ed9Ben Murdoch                                    Register hash,
5996c7cc028aaeedbbfa11c11d0b7b243b3d9e837ed9Ben Murdoch                                    Register character) {
5997c7cc028aaeedbbfa11c11d0b7b243b3d9e837ed9Ben Murdoch  // hash = seed + character + ((seed + character) << 10);
5998c7cc028aaeedbbfa11c11d0b7b243b3d9e837ed9Ben Murdoch  __ LoadRoot(hash, Heap::kHashSeedRootIndex);
5999c7cc028aaeedbbfa11c11d0b7b243b3d9e837ed9Ben Murdoch  // Untag smi seed and add the character.
6000c7cc028aaeedbbfa11c11d0b7b243b3d9e837ed9Ben Murdoch  __ SmiUntag(hash);
6001257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ addu(hash, hash, character);
6002c7cc028aaeedbbfa11c11d0b7b243b3d9e837ed9Ben Murdoch  __ sll(at, hash, 10);
6003c7cc028aaeedbbfa11c11d0b7b243b3d9e837ed9Ben Murdoch  __ addu(hash, hash, at);
6004257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // hash ^= hash >> 6;
60053ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ srl(at, hash, 6);
6006257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ xor_(hash, hash, at);
600744f0eee88ff00398ff7f715fab053374d808c90dSteve Block}
600844f0eee88ff00398ff7f715fab053374d808c90dSteve Block
600944f0eee88ff00398ff7f715fab053374d808c90dSteve Block
601044f0eee88ff00398ff7f715fab053374d808c90dSteve Blockvoid StringHelper::GenerateHashAddCharacter(MacroAssembler* masm,
6011c7cc028aaeedbbfa11c11d0b7b243b3d9e837ed9Ben Murdoch                                            Register hash,
6012c7cc028aaeedbbfa11c11d0b7b243b3d9e837ed9Ben Murdoch                                            Register character) {
6013257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // hash += character;
6014257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ addu(hash, hash, character);
6015257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // hash += hash << 10;
6016257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ sll(at, hash, 10);
6017257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ addu(hash, hash, at);
6018257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // hash ^= hash >> 6;
60193ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ srl(at, hash, 6);
6020257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ xor_(hash, hash, at);
602144f0eee88ff00398ff7f715fab053374d808c90dSteve Block}
602244f0eee88ff00398ff7f715fab053374d808c90dSteve Block
602344f0eee88ff00398ff7f715fab053374d808c90dSteve Block
602444f0eee88ff00398ff7f715fab053374d808c90dSteve Blockvoid StringHelper::GenerateHashGetHash(MacroAssembler* masm,
6025c7cc028aaeedbbfa11c11d0b7b243b3d9e837ed9Ben Murdoch                                       Register hash) {
6026257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // hash += hash << 3;
6027257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ sll(at, hash, 3);
6028257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ addu(hash, hash, at);
6029257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // hash ^= hash >> 11;
60303ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ srl(at, hash, 11);
6031257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ xor_(hash, hash, at);
6032257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // hash += hash << 15;
6033257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ sll(at, hash, 15);
6034257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ addu(hash, hash, at);
6035257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
60363ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ li(at, Operand(String::kHashBitMask));
60373ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ and_(hash, hash, at);
60383ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
6039257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // if (hash == 0) hash = 27;
60403ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ ori(at, zero_reg, StringHasher::kZeroHash);
60413ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ Movz(hash, at, hash);
604244f0eee88ff00398ff7f715fab053374d808c90dSteve Block}
604344f0eee88ff00398ff7f715fab053374d808c90dSteve Block
604444f0eee88ff00398ff7f715fab053374d808c90dSteve Block
604544f0eee88ff00398ff7f715fab053374d808c90dSteve Blockvoid SubStringStub::Generate(MacroAssembler* masm) {
60463ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  Label runtime;
6047257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Stack frame on entry.
6048257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  //  ra: return address
6049257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  //  sp[0]: to
6050257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  //  sp[4]: from
6051257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  //  sp[8]: string
6052257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6053257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // This stub is called from the native-call %_SubString(...), so
6054257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // nothing can be assumed about the arguments. It is tested that:
6055257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  //  "string" is a sequential string,
6056257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  //  both "from" and "to" are smis, and
6057257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  //  0 <= from <= to <= string.length.
6058257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // If any of these assumptions fail, we call the runtime system.
6059257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6060db1b4389239a7132c9cde0915dbd3f775dc1027aBen Murdoch  const int kToOffset = 0 * kPointerSize;
6061db1b4389239a7132c9cde0915dbd3f775dc1027aBen Murdoch  const int kFromOffset = 1 * kPointerSize;
6062db1b4389239a7132c9cde0915dbd3f775dc1027aBen Murdoch  const int kStringOffset = 2 * kPointerSize;
6063257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
60643ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ lw(a2, MemOperand(sp, kToOffset));
60653ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ lw(a3, MemOperand(sp, kFromOffset));
6066257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  STATIC_ASSERT(kFromOffset == kToOffset + 4);
6067257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  STATIC_ASSERT(kSmiTag == 0);
6068257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  STATIC_ASSERT(kSmiTagSize + kSmiShiftSize == 1);
6069257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
60703ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Utilize delay slots. SmiUntag doesn't emit a jump, everything else is
60713ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // safe in this case.
60723ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ UntagAndJumpIfNotSmi(a2, a2, &runtime);
60733ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ UntagAndJumpIfNotSmi(a3, a3, &runtime);
60743ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Both a2 and a3 are untagged integers.
607585b71799222b55eb5dd74ea26efe0c64ab655c8cBen Murdoch
60763ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ Branch(&runtime, lt, a3, Operand(zero_reg));  // From < 0.
607785b71799222b55eb5dd74ea26efe0c64ab655c8cBen Murdoch
60783ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ Branch(&runtime, gt, a3, Operand(a2));  // Fail if from > to.
60793ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ Subu(a2, a2, a3);
6080257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
60813ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Make sure first argument is a string.
6082589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch  __ lw(v0, MemOperand(sp, kStringOffset));
60833ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ JumpIfSmi(v0, &runtime);
6084589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch  __ lw(a1, FieldMemOperand(v0, HeapObject::kMapOffset));
6085257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ lbu(a1, FieldMemOperand(a1, Map::kInstanceTypeOffset));
60863ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ And(t0, a1, Operand(kIsNotStringMask));
6087257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
60883ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ Branch(&runtime, ne, t0, Operand(zero_reg));
6089257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6090589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch  // Short-cut for the case of trivial substring.
6091589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch  Label return_v0;
6092589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch  // v0: original string
6093589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch  // a2: result string length
6094589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch  __ lw(t0, FieldMemOperand(v0, String::kLengthOffset));
6095589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch  __ sra(t0, t0, 1);
6096589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch  __ Branch(&return_v0, eq, a2, Operand(t0));
6097589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch
609885b71799222b55eb5dd74ea26efe0c64ab655c8cBen Murdoch
609985b71799222b55eb5dd74ea26efe0c64ab655c8cBen Murdoch  Label result_longer_than_two;
61003ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Check for special case of two character ASCII string, in which case
61013ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // we do a lookup in the symbol table first.
61023ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ li(t0, 2);
61033ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ Branch(&result_longer_than_two, gt, a2, Operand(t0));
61043ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ Branch(&runtime, lt, a2, Operand(t0));
61053ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
61063ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ JumpIfInstanceTypeIsNotSequentialAscii(a1, a1, &runtime);
610785b71799222b55eb5dd74ea26efe0c64ab655c8cBen Murdoch
6108257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Get the two characters forming the sub string.
6109589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch  __ Addu(v0, v0, Operand(a3));
6110589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch  __ lbu(a3, FieldMemOperand(v0, SeqAsciiString::kHeaderSize));
6111589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch  __ lbu(t0, FieldMemOperand(v0, SeqAsciiString::kHeaderSize + 1));
6112257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6113257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Try to lookup two character string in symbol table.
6114257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label make_two_character_string;
6115257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  StringHelper::GenerateTwoCharacterSymbolTableProbe(
6116257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      masm, a3, t0, a1, t1, t2, t3, t4, &make_two_character_string);
6117589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch  __ jmp(&return_v0);
6118257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6119257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // a2: result string length.
6120257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // a3: two characters combined into halfword in little endian byte order.
6121257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&make_two_character_string);
61223ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ AllocateAsciiString(v0, a2, t0, t1, t4, &runtime);
6123257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ sh(a3, FieldMemOperand(v0, SeqAsciiString::kHeaderSize));
6124589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch  __ jmp(&return_v0);
6125257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6126257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&result_longer_than_two);
6127257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
61283ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Deal with different string types: update the index if necessary
61293ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // and put the underlying string into t1.
61303ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // v0: original string
61313ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // a1: instance type
61323ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // a2: length
61333ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // a3: from index (untagged)
61343ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  Label underlying_unpacked, sliced_string, seq_or_external_string;
61353ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // If the string is not indirect, it can only be sequential or external.
61363ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  STATIC_ASSERT(kIsIndirectStringMask == (kSlicedStringTag & kConsStringTag));
61373ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  STATIC_ASSERT(kIsIndirectStringMask != 0);
61383ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ And(t0, a1, Operand(kIsIndirectStringMask));
61393ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ Branch(USE_DELAY_SLOT, &seq_or_external_string, eq, t0, Operand(zero_reg));
61403ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // t0 is used as a scratch register and can be overwritten in either case.
61413ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ And(t0, a1, Operand(kSlicedNotConsMask));
61423ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ Branch(&sliced_string, ne, t0, Operand(zero_reg));
61433ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Cons string.  Check whether it is flat, then fetch first part.
61443ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ lw(t1, FieldMemOperand(v0, ConsString::kSecondOffset));
61453ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ LoadRoot(t0, Heap::kEmptyStringRootIndex);
61463ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ Branch(&runtime, ne, t1, Operand(t0));
61473ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ lw(t1, FieldMemOperand(v0, ConsString::kFirstOffset));
61483ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Update instance type.
61493ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ lw(a1, FieldMemOperand(t1, HeapObject::kMapOffset));
61503ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ lbu(a1, FieldMemOperand(a1, Map::kInstanceTypeOffset));
61513ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ jmp(&underlying_unpacked);
61523ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
61533ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ bind(&sliced_string);
61543ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Sliced string.  Fetch parent and correct start index by offset.
61553ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ lw(t1, FieldMemOperand(v0, SlicedString::kParentOffset));
61563ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ lw(t0, FieldMemOperand(v0, SlicedString::kOffsetOffset));
61573ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ sra(t0, t0, 1);  // Add offset to index.
61583ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ Addu(a3, a3, t0);
61593ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Update instance type.
61603ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ lw(a1, FieldMemOperand(t1, HeapObject::kMapOffset));
61613ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ lbu(a1, FieldMemOperand(a1, Map::kInstanceTypeOffset));
61623ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ jmp(&underlying_unpacked);
6163c7cc028aaeedbbfa11c11d0b7b243b3d9e837ed9Ben Murdoch
61643ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ bind(&seq_or_external_string);
61653ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Sequential or external string.  Just move string to the expected register.
61663ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ mov(t1, v0);
61673ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
61683ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ bind(&underlying_unpacked);
61693ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
61703ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  if (FLAG_string_slices) {
61713ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    Label copy_routine;
61723ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    // t1: underlying subject string
61733ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    // a1: instance type of underlying subject string
61743ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    // a2: length
61753ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    // a3: adjusted start index (untagged)
61763ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    // Short slice.  Copy instead of slicing.
61773ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ Branch(&copy_routine, lt, a2, Operand(SlicedString::kMinLength));
61783ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    // Allocate new sliced string.  At this point we do not reload the instance
61793ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    // type including the string encoding because we simply rely on the info
61803ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    // provided by the original string.  It does not matter if the original
61813ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    // string's encoding is wrong because we always have to recheck encoding of
61823ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    // the newly created string's parent anyways due to externalized strings.
61833ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    Label two_byte_slice, set_slice_header;
61843ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    STATIC_ASSERT((kStringEncodingMask & kAsciiStringTag) != 0);
61853ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0);
61863ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ And(t0, a1, Operand(kStringEncodingMask));
61873ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ Branch(&two_byte_slice, eq, t0, Operand(zero_reg));
61883ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ AllocateAsciiSlicedString(v0, a2, t2, t3, &runtime);
61893ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ jmp(&set_slice_header);
61903ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ bind(&two_byte_slice);
61913ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ AllocateTwoByteSlicedString(v0, a2, t2, t3, &runtime);
61923ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ bind(&set_slice_header);
61933ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ sll(a3, a3, 1);
61943ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ sw(t1, FieldMemOperand(v0, SlicedString::kParentOffset));
61953ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ sw(a3, FieldMemOperand(v0, SlicedString::kOffsetOffset));
61963ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ jmp(&return_v0);
61973ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
61983ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ bind(&copy_routine);
61993ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  }
62003ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
62013ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // t1: underlying subject string
62023ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // a1: instance type of underlying subject string
62033ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // a2: length
62043ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // a3: adjusted start index (untagged)
62053ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  Label two_byte_sequential, sequential_string, allocate_result;
62063ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  STATIC_ASSERT(kExternalStringTag != 0);
62073ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  STATIC_ASSERT(kSeqStringTag == 0);
62083ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ And(t0, a1, Operand(kExternalStringTag));
62093ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ Branch(&sequential_string, eq, t0, Operand(zero_reg));
62103ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
62113ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Handle external string.
62123ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Rule out short external strings.
62133ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  STATIC_CHECK(kShortExternalStringTag != 0);
62143ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ And(t0, a1, Operand(kShortExternalStringTag));
62153ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ Branch(&runtime, ne, t0, Operand(zero_reg));
62163ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ lw(t1, FieldMemOperand(t1, ExternalString::kResourceDataOffset));
62173ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // t1 already points to the first character of underlying string.
62183ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ jmp(&allocate_result);
62193ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
62203ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ bind(&sequential_string);
62213ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Locate first character of underlying subject string.
62223ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqAsciiString::kHeaderSize);
62233ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ Addu(t1, t1, Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag));
62243ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
62253ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ bind(&allocate_result);
62263ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Sequential acii string.  Allocate the result.
62273ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  STATIC_ASSERT((kAsciiStringTag & kStringEncodingMask) != 0);
62283ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ And(t0, a1, Operand(kStringEncodingMask));
62293ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ Branch(&two_byte_sequential, eq, t0, Operand(zero_reg));
62303ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
62313ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Allocate and copy the resulting ASCII string.
62323ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ AllocateAsciiString(v0, a2, t0, t2, t3, &runtime);
62333ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
62343ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Locate first character of substring to copy.
62353ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ Addu(t1, t1, a3);
6236257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6237257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Locate first character of result.
6238257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Addu(a1, v0, Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag));
6239257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6240589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch  // v0: result string
6241589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch  // a1: first character of result string
6242589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch  // a2: result string length
6243589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch  // t1: first character of substring to copy
6244257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  STATIC_ASSERT((SeqAsciiString::kHeaderSize & kObjectAlignmentMask) == 0);
6245257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  StringHelper::GenerateCopyCharactersLong(
6246257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      masm, a1, t1, a2, a3, t0, t2, t3, t4, COPY_ASCII | DEST_ALWAYS_ALIGNED);
6247589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch  __ jmp(&return_v0);
6248257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
62493ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Allocate and copy the resulting two-byte string.
62503ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ bind(&two_byte_sequential);
62513ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ AllocateTwoByteString(v0, a2, t0, t2, t3, &runtime);
625285b71799222b55eb5dd74ea26efe0c64ab655c8cBen Murdoch
62533ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Locate first character of substring to copy.
62543ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  STATIC_ASSERT(kSmiTagSize == 1 && kSmiTag == 0);
62553ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ sll(t0, a3, 1);
62563ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ Addu(t1, t1, t0);
6257257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Locate first character of result.
6258257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Addu(a1, v0, Operand(SeqTwoByteString::kHeaderSize - kHeapObjectTag));
6259589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch
6260257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // v0: result string.
6261257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // a1: first character of result.
6262257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // a2: result length.
6263589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch  // t1: first character of substring to copy.
6264257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  STATIC_ASSERT((SeqTwoByteString::kHeaderSize & kObjectAlignmentMask) == 0);
6265257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  StringHelper::GenerateCopyCharactersLong(
6266257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      masm, a1, t1, a2, a3, t0, t2, t3, t4, DEST_ALWAYS_ALIGNED);
6267589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch
6268589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch  __ bind(&return_v0);
62693ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  Counters* counters = masm->isolate()->counters();
6270257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ IncrementCounter(counters->sub_string_native(), 1, a3, t0);
62713ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ DropAndRet(3);
6272257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6273257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Just jump to runtime to create the sub string.
62743ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ bind(&runtime);
6275257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ TailCallRuntime(Runtime::kSubString, 3, 1);
6276257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch}
6277257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6278257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6279257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid StringCompareStub::GenerateFlatAsciiStringEquals(MacroAssembler* masm,
6280257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                                      Register left,
6281257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                                      Register right,
6282257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                                      Register scratch1,
6283257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                                      Register scratch2,
6284257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                                      Register scratch3) {
6285257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Register length = scratch1;
6286257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6287257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Compare lengths.
6288257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label strings_not_equal, check_zero_length;
6289257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ lw(length, FieldMemOperand(left, String::kLengthOffset));
6290257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ lw(scratch2, FieldMemOperand(right, String::kLengthOffset));
6291257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Branch(&check_zero_length, eq, length, Operand(scratch2));
6292257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&strings_not_equal);
6293257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ li(v0, Operand(Smi::FromInt(NOT_EQUAL)));
6294257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Ret();
6295257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6296257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Check if the length is zero.
6297257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label compare_chars;
6298257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&check_zero_length);
6299257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  STATIC_ASSERT(kSmiTag == 0);
6300257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Branch(&compare_chars, ne, length, Operand(zero_reg));
6301257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ li(v0, Operand(Smi::FromInt(EQUAL)));
6302257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Ret();
6303257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6304257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Compare characters.
6305257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&compare_chars);
6306257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6307257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  GenerateAsciiCharsCompareLoop(masm,
6308257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                left, right, length, scratch2, scratch3, v0,
6309257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                &strings_not_equal);
6310257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6311257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Characters are equal.
6312257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ li(v0, Operand(Smi::FromInt(EQUAL)));
6313257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Ret();
631444f0eee88ff00398ff7f715fab053374d808c90dSteve Block}
631544f0eee88ff00398ff7f715fab053374d808c90dSteve Block
631644f0eee88ff00398ff7f715fab053374d808c90dSteve Block
631744f0eee88ff00398ff7f715fab053374d808c90dSteve Blockvoid StringCompareStub::GenerateCompareFlatAsciiStrings(MacroAssembler* masm,
631844f0eee88ff00398ff7f715fab053374d808c90dSteve Block                                                        Register left,
6319257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                                        Register right,
632044f0eee88ff00398ff7f715fab053374d808c90dSteve Block                                                        Register scratch1,
632144f0eee88ff00398ff7f715fab053374d808c90dSteve Block                                                        Register scratch2,
632244f0eee88ff00398ff7f715fab053374d808c90dSteve Block                                                        Register scratch3,
632344f0eee88ff00398ff7f715fab053374d808c90dSteve Block                                                        Register scratch4) {
6324257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label result_not_equal, compare_lengths;
6325257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Find minimum length and length difference.
6326257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ lw(scratch1, FieldMemOperand(left, String::kLengthOffset));
6327257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ lw(scratch2, FieldMemOperand(right, String::kLengthOffset));
6328257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Subu(scratch3, scratch1, Operand(scratch2));
6329257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Register length_delta = scratch3;
6330257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ slt(scratch4, scratch2, scratch1);
63313ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ Movn(scratch1, scratch2, scratch4);
6332257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Register min_length = scratch1;
6333257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  STATIC_ASSERT(kSmiTag == 0);
6334257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Branch(&compare_lengths, eq, min_length, Operand(zero_reg));
6335257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6336257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Compare loop.
6337257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  GenerateAsciiCharsCompareLoop(masm,
6338257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                left, right, min_length, scratch2, scratch4, v0,
6339257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                &result_not_equal);
6340257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6341257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Compare lengths - strings up to min-length are equal.
6342257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&compare_lengths);
6343257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  ASSERT(Smi::FromInt(EQUAL) == static_cast<Smi*>(0));
6344257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Use length_delta as result if it's zero.
6345257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ mov(scratch2, length_delta);
6346257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ mov(scratch4, zero_reg);
6347257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ mov(v0, zero_reg);
6348257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6349257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&result_not_equal);
6350257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Conditionally update the result based either on length_delta or
6351257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // the last comparion performed in the loop above.
6352257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label ret;
6353257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Branch(&ret, eq, scratch2, Operand(scratch4));
6354257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ li(v0, Operand(Smi::FromInt(GREATER)));
6355257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Branch(&ret, gt, scratch2, Operand(scratch4));
6356257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ li(v0, Operand(Smi::FromInt(LESS)));
6357257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&ret);
6358257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Ret();
6359257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch}
6360257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6361257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6362257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid StringCompareStub::GenerateAsciiCharsCompareLoop(
6363257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    MacroAssembler* masm,
6364257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Register left,
6365257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Register right,
6366257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Register length,
6367257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Register scratch1,
6368257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Register scratch2,
6369257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Register scratch3,
6370257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Label* chars_not_equal) {
6371257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Change index to run from -length to -1 by adding length to string
6372257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // start. This means that loop ends when index reaches zero, which
6373257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // doesn't need an additional compare.
6374257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ SmiUntag(length);
6375257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Addu(scratch1, length,
6376257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag));
6377257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Addu(left, left, Operand(scratch1));
6378257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Addu(right, right, Operand(scratch1));
6379257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Subu(length, zero_reg, length);
6380257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Register index = length;  // index = -length;
6381257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6382257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6383257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Compare loop.
6384257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label loop;
6385257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&loop);
6386257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Addu(scratch3, left, index);
6387257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ lbu(scratch1, MemOperand(scratch3));
6388257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Addu(scratch3, right, index);
6389257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ lbu(scratch2, MemOperand(scratch3));
6390257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Branch(chars_not_equal, ne, scratch1, Operand(scratch2));
6391257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Addu(index, index, 1);
6392257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Branch(&loop, ne, index, Operand(zero_reg));
639344f0eee88ff00398ff7f715fab053374d808c90dSteve Block}
639444f0eee88ff00398ff7f715fab053374d808c90dSteve Block
639544f0eee88ff00398ff7f715fab053374d808c90dSteve Block
639644f0eee88ff00398ff7f715fab053374d808c90dSteve Blockvoid StringCompareStub::Generate(MacroAssembler* masm) {
6397257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label runtime;
6398257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6399257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Counters* counters = masm->isolate()->counters();
6400257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6401257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Stack frame on entry.
6402257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  //  sp[0]: right string
6403257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  //  sp[4]: left string
6404257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ lw(a1, MemOperand(sp, 1 * kPointerSize));  // Left.
6405257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ lw(a0, MemOperand(sp, 0 * kPointerSize));  // Right.
6406257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6407257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label not_same;
6408257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Branch(&not_same, ne, a0, Operand(a1));
6409257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  STATIC_ASSERT(EQUAL == 0);
6410257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  STATIC_ASSERT(kSmiTag == 0);
6411257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ li(v0, Operand(Smi::FromInt(EQUAL)));
6412257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ IncrementCounter(counters->string_compare_native(), 1, a1, a2);
64133ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ DropAndRet(2);
6414257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6415257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&not_same);
6416257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6417257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Check that both objects are sequential ASCII strings.
6418257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ JumpIfNotBothSequentialAsciiStrings(a1, a0, a2, a3, &runtime);
6419257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6420257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Compare flat ASCII strings natively. Remove arguments from stack first.
6421257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ IncrementCounter(counters->string_compare_native(), 1, a2, a3);
6422257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Addu(sp, sp, Operand(2 * kPointerSize));
6423257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  GenerateCompareFlatAsciiStrings(masm, a1, a0, a2, a3, t0, t1);
6424257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6425257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&runtime);
6426257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ TailCallRuntime(Runtime::kStringCompare, 2, 1);
642744f0eee88ff00398ff7f715fab053374d808c90dSteve Block}
642844f0eee88ff00398ff7f715fab053374d808c90dSteve Block
642944f0eee88ff00398ff7f715fab053374d808c90dSteve Block
643044f0eee88ff00398ff7f715fab053374d808c90dSteve Blockvoid StringAddStub::Generate(MacroAssembler* masm) {
64313ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  Label call_runtime, call_builtin;
6432257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Builtins::JavaScript builtin_id = Builtins::ADD;
6433257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6434257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Counters* counters = masm->isolate()->counters();
6435257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6436257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Stack on entry:
6437257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // sp[0]: second argument (right).
6438257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // sp[4]: first argument (left).
6439257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6440257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Load the two arguments.
6441257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ lw(a0, MemOperand(sp, 1 * kPointerSize));  // First argument.
6442257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ lw(a1, MemOperand(sp, 0 * kPointerSize));  // Second argument.
6443257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6444257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Make sure that both arguments are strings if not known in advance.
6445257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  if (flags_ == NO_STRING_ADD_FLAGS) {
64463ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ JumpIfEitherSmi(a0, a1, &call_runtime);
6447257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Load instance types.
6448257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ lw(t0, FieldMemOperand(a0, HeapObject::kMapOffset));
6449257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ lw(t1, FieldMemOperand(a1, HeapObject::kMapOffset));
6450257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ lbu(t0, FieldMemOperand(t0, Map::kInstanceTypeOffset));
6451257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ lbu(t1, FieldMemOperand(t1, Map::kInstanceTypeOffset));
6452257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    STATIC_ASSERT(kStringTag == 0);
6453257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // If either is not a string, go to runtime.
6454257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ Or(t4, t0, Operand(t1));
6455257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ And(t4, t4, Operand(kIsNotStringMask));
64563ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ Branch(&call_runtime, ne, t4, Operand(zero_reg));
6457257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  } else {
6458257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Here at least one of the arguments is definitely a string.
6459257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // We convert the one that is not known to be a string.
6460257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    if ((flags_ & NO_STRING_CHECK_LEFT_IN_STUB) == 0) {
6461257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      ASSERT((flags_ & NO_STRING_CHECK_RIGHT_IN_STUB) != 0);
6462257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      GenerateConvertArgument(
6463257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          masm, 1 * kPointerSize, a0, a2, a3, t0, t1, &call_builtin);
6464257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      builtin_id = Builtins::STRING_ADD_RIGHT;
6465257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    } else if ((flags_ & NO_STRING_CHECK_RIGHT_IN_STUB) == 0) {
6466257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      ASSERT((flags_ & NO_STRING_CHECK_LEFT_IN_STUB) != 0);
6467257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      GenerateConvertArgument(
6468257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          masm, 0 * kPointerSize, a1, a2, a3, t0, t1, &call_builtin);
6469257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      builtin_id = Builtins::STRING_ADD_LEFT;
6470257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    }
6471257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
6472257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6473257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Both arguments are strings.
6474257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // a0: first string
6475257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // a1: second string
6476257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // t0: first string instance type (if flags_ == NO_STRING_ADD_FLAGS)
6477257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // t1: second string instance type (if flags_ == NO_STRING_ADD_FLAGS)
6478257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  {
6479257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Label strings_not_empty;
6480257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Check if either of the strings are empty. In that case return the other.
6481257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // These tests use zero-length check on string-length whch is an Smi.
6482257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Assert that Smi::FromInt(0) is really 0.
6483257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    STATIC_ASSERT(kSmiTag == 0);
6484257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    ASSERT(Smi::FromInt(0) == 0);
6485257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ lw(a2, FieldMemOperand(a0, String::kLengthOffset));
6486257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ lw(a3, FieldMemOperand(a1, String::kLengthOffset));
6487257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ mov(v0, a0);       // Assume we'll return first string (from a0).
64883ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ Movz(v0, a1, a2);  // If first is empty, return second (from a1).
6489257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ slt(t4, zero_reg, a2);   // if (a2 > 0) t4 = 1.
6490257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ slt(t5, zero_reg, a3);   // if (a3 > 0) t5 = 1.
6491257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ and_(t4, t4, t5);        // Branch if both strings were non-empty.
6492257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ Branch(&strings_not_empty, ne, t4, Operand(zero_reg));
6493257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6494257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ IncrementCounter(counters->string_add_native(), 1, a2, a3);
64953ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ DropAndRet(2);
6496257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6497257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ bind(&strings_not_empty);
6498257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
6499257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6500257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Untag both string-lengths.
6501257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ sra(a2, a2, kSmiTagSize);
6502257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ sra(a3, a3, kSmiTagSize);
6503257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6504257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Both strings are non-empty.
6505257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // a0: first string
6506257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // a1: second string
6507257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // a2: length of first string
6508257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // a3: length of second string
6509257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // t0: first string instance type (if flags_ == NO_STRING_ADD_FLAGS)
6510257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // t1: second string instance type (if flags_ == NO_STRING_ADD_FLAGS)
6511257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Look at the length of the result of adding the two strings.
6512257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label string_add_flat_result, longer_than_two;
6513257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Adding two lengths can't overflow.
6514257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  STATIC_ASSERT(String::kMaxLength < String::kMaxLength * 2);
6515257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Addu(t2, a2, Operand(a3));
6516257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Use the symbol table when adding two one character strings, as it
6517257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // helps later optimizations to return a symbol here.
6518257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Branch(&longer_than_two, ne, t2, Operand(2));
6519257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6520257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Check that both strings are non-external ASCII strings.
6521257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  if (flags_ != NO_STRING_ADD_FLAGS) {
6522257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ lw(t0, FieldMemOperand(a0, HeapObject::kMapOffset));
6523257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ lw(t1, FieldMemOperand(a1, HeapObject::kMapOffset));
6524257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ lbu(t0, FieldMemOperand(t0, Map::kInstanceTypeOffset));
6525257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ lbu(t1, FieldMemOperand(t1, Map::kInstanceTypeOffset));
6526257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
6527257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ JumpIfBothInstanceTypesAreNotSequentialAscii(t0, t1, t2, t3,
65283ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                                                 &call_runtime);
6529257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6530257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Get the two characters forming the sub string.
6531257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ lbu(a2, FieldMemOperand(a0, SeqAsciiString::kHeaderSize));
6532257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ lbu(a3, FieldMemOperand(a1, SeqAsciiString::kHeaderSize));
6533257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6534257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Try to lookup two character string in symbol table. If it is not found
6535257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // just allocate a new one.
6536257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label make_two_character_string;
6537257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  StringHelper::GenerateTwoCharacterSymbolTableProbe(
65383ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      masm, a2, a3, t2, t3, t0, t1, t5, &make_two_character_string);
6539257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ IncrementCounter(counters->string_add_native(), 1, a2, a3);
65403ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ DropAndRet(2);
6541257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6542257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&make_two_character_string);
6543257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Resulting string has length 2 and first chars of two strings
6544257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // are combined into single halfword in a2 register.
6545257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // So we can fill resulting string without two loops by a single
6546257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // halfword store instruction (which assumes that processor is
6547257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // in a little endian mode).
6548257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ li(t2, Operand(2));
65493ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ AllocateAsciiString(v0, t2, t0, t1, t5, &call_runtime);
6550257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ sh(a2, FieldMemOperand(v0, SeqAsciiString::kHeaderSize));
6551257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ IncrementCounter(counters->string_add_native(), 1, a2, a3);
65523ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ DropAndRet(2);
6553257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6554257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&longer_than_two);
6555257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Check if resulting string will be flat.
65563ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ Branch(&string_add_flat_result, lt, t2, Operand(ConsString::kMinLength));
6557257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Handle exceptionally long strings in the runtime system.
6558257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  STATIC_ASSERT((String::kMaxLength & 0x80000000) == 0);
6559257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  ASSERT(IsPowerOf2(String::kMaxLength + 1));
6560257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // kMaxLength + 1 is representable as shifted literal, kMaxLength is not.
65613ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ Branch(&call_runtime, hs, t2, Operand(String::kMaxLength + 1));
6562257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6563257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // If result is not supposed to be flat, allocate a cons string object.
6564257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // If both strings are ASCII the result is an ASCII cons string.
6565257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  if (flags_ != NO_STRING_ADD_FLAGS) {
6566257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ lw(t0, FieldMemOperand(a0, HeapObject::kMapOffset));
6567257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ lw(t1, FieldMemOperand(a1, HeapObject::kMapOffset));
6568257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ lbu(t0, FieldMemOperand(t0, Map::kInstanceTypeOffset));
6569257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ lbu(t1, FieldMemOperand(t1, Map::kInstanceTypeOffset));
6570257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
6571257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label non_ascii, allocated, ascii_data;
6572257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  STATIC_ASSERT(kTwoByteStringTag == 0);
65733ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Branch to non_ascii if either string-encoding field is zero (non-ASCII).
6574257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ And(t4, t0, Operand(t1));
6575257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ And(t4, t4, Operand(kStringEncodingMask));
6576257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Branch(&non_ascii, eq, t4, Operand(zero_reg));
6577257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6578257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Allocate an ASCII cons string.
6579257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&ascii_data);
65803ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ AllocateAsciiConsString(v0, t2, t0, t1, &call_runtime);
6581257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&allocated);
6582257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Fill the fields of the cons string.
65833ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ sw(a0, FieldMemOperand(v0, ConsString::kFirstOffset));
65843ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ sw(a1, FieldMemOperand(v0, ConsString::kSecondOffset));
6585257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ IncrementCounter(counters->string_add_native(), 1, a2, a3);
65863ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ DropAndRet(2);
6587257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6588257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&non_ascii);
6589257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // At least one of the strings is two-byte. Check whether it happens
6590257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // to contain only ASCII characters.
6591257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // t0: first instance type.
6592257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // t1: second instance type.
6593257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Branch to if _both_ instances have kAsciiDataHintMask set.
6594257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ And(at, t0, Operand(kAsciiDataHintMask));
6595257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ and_(at, at, t1);
6596257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Branch(&ascii_data, ne, at, Operand(zero_reg));
6597257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6598257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ xor_(t0, t0, t1);
6599257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  STATIC_ASSERT(kAsciiStringTag != 0 && kAsciiDataHintTag != 0);
6600257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ And(t0, t0, Operand(kAsciiStringTag | kAsciiDataHintTag));
6601257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Branch(&ascii_data, eq, t0, Operand(kAsciiStringTag | kAsciiDataHintTag));
6602257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6603257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Allocate a two byte cons string.
66043ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ AllocateTwoByteConsString(v0, t2, t0, t1, &call_runtime);
6605257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Branch(&allocated);
6606257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
66073ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // We cannot encounter sliced strings or cons strings here since:
66083ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  STATIC_ASSERT(SlicedString::kMinLength >= ConsString::kMinLength);
66093ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Handle creating a flat result from either external or sequential strings.
66103ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Locate the first characters' locations.
6611257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // a0: first string
6612257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // a1: second string
6613257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // a2: length of first string
6614257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // a3: length of second string
6615257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // t0: first string instance type (if flags_ == NO_STRING_ADD_FLAGS)
6616257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // t1: second string instance type (if flags_ == NO_STRING_ADD_FLAGS)
6617257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // t2: sum of lengths.
66183ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  Label first_prepared, second_prepared;
6619257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&string_add_flat_result);
6620257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  if (flags_ != NO_STRING_ADD_FLAGS) {
6621257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ lw(t0, FieldMemOperand(a0, HeapObject::kMapOffset));
6622257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ lw(t1, FieldMemOperand(a1, HeapObject::kMapOffset));
6623257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ lbu(t0, FieldMemOperand(t0, Map::kInstanceTypeOffset));
6624257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ lbu(t1, FieldMemOperand(t1, Map::kInstanceTypeOffset));
6625257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
66263ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Check whether both strings have same encoding
66273ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ Xor(t3, t0, Operand(t1));
66283ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ And(t3, t3, Operand(kStringEncodingMask));
66293ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ Branch(&call_runtime, ne, t3, Operand(zero_reg));
66303ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
6631257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  STATIC_ASSERT(kSeqStringTag == 0);
66323ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ And(t4, t0, Operand(kStringRepresentationMask));
6633c7cc028aaeedbbfa11c11d0b7b243b3d9e837ed9Ben Murdoch
66343ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  STATIC_ASSERT(SeqAsciiString::kHeaderSize == SeqTwoByteString::kHeaderSize);
66353ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  Label skip_first_add;
66363ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ Branch(&skip_first_add, ne, t4, Operand(zero_reg));
66373ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ Branch(USE_DELAY_SLOT, &first_prepared);
66383ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ addiu(t3, a0, SeqAsciiString::kHeaderSize - kHeapObjectTag);
66393ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ bind(&skip_first_add);
66403ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // External string: rule out short external string and load string resource.
66413ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  STATIC_ASSERT(kShortExternalStringTag != 0);
66423ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ And(t4, t0, Operand(kShortExternalStringMask));
66433ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ Branch(&call_runtime, ne, t4, Operand(zero_reg));
66443ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ lw(t3, FieldMemOperand(a0, ExternalString::kResourceDataOffset));
66453ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ bind(&first_prepared);
66463ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
66473ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  STATIC_ASSERT(kSeqStringTag == 0);
66483ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ And(t4, t1, Operand(kStringRepresentationMask));
66493ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  STATIC_ASSERT(SeqAsciiString::kHeaderSize == SeqTwoByteString::kHeaderSize);
66503ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  Label skip_second_add;
66513ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ Branch(&skip_second_add, ne, t4, Operand(zero_reg));
66523ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ Branch(USE_DELAY_SLOT, &second_prepared);
66533ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ addiu(a1, a1, SeqAsciiString::kHeaderSize - kHeapObjectTag);
66543ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ bind(&skip_second_add);
66553ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // External string: rule out short external string and load string resource.
66563ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  STATIC_ASSERT(kShortExternalStringTag != 0);
66573ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ And(t4, t1, Operand(kShortExternalStringMask));
66583ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ Branch(&call_runtime, ne, t4, Operand(zero_reg));
66593ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ lw(a1, FieldMemOperand(a1, ExternalString::kResourceDataOffset));
66603ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ bind(&second_prepared);
66613ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
66623ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  Label non_ascii_string_add_flat_result;
66633ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // t3: first character of first string
66643ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // a1: first character of second string
6665257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // a2: length of first string
6666257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // a3: length of second string
6667257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // t2: sum of lengths.
66683ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Both strings have the same encoding.
66693ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  STATIC_ASSERT(kTwoByteStringTag == 0);
66703ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ And(t4, t1, Operand(kStringEncodingMask));
66713ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ Branch(&non_ascii_string_add_flat_result, eq, t4, Operand(zero_reg));
66723ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
66733ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ AllocateAsciiString(v0, t2, t0, t1, t5, &call_runtime);
66743ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ Addu(t2, v0, Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag));
66753ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // v0: result string.
66763ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // t3: first character of first string.
66773ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // a1: first character of second string
6678257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // a2: length of first string.
6679257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // a3: length of second string.
6680257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // t2: first character of result.
6681257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
66823ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  StringHelper::GenerateCopyCharacters(masm, t2, t3, a2, t0, true);
6683257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // t2: next character of result.
6684257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  StringHelper::GenerateCopyCharacters(masm, t2, a1, a3, t0, true);
6685257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ IncrementCounter(counters->string_add_native(), 1, a2, a3);
66863ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ DropAndRet(2);
6687257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6688257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&non_ascii_string_add_flat_result);
66893ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ AllocateTwoByteString(v0, t2, t0, t1, t5, &call_runtime);
66903ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ Addu(t2, v0, Operand(SeqTwoByteString::kHeaderSize - kHeapObjectTag));
66913ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // v0: result string.
66923ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // t3: first character of first string.
66933ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // a1: first character of second string.
6694257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // a2: length of first string.
6695257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // a3: length of second string.
6696257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // t2: first character of result.
66973ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  StringHelper::GenerateCopyCharacters(masm, t2, t3, a2, t0, false);
66983ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // t2: next character of result.
6699257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  StringHelper::GenerateCopyCharacters(masm, t2, a1, a3, t0, false);
6700257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6701257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ IncrementCounter(counters->string_add_native(), 1, a2, a3);
67023ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ DropAndRet(2);
6703257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6704257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Just jump to runtime to add the two strings.
67053ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ bind(&call_runtime);
6706257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ TailCallRuntime(Runtime::kStringAdd, 2, 1);
6707257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6708257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  if (call_builtin.is_linked()) {
6709257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ bind(&call_builtin);
6710257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ InvokeBuiltin(builtin_id, JUMP_FUNCTION);
6711257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
6712257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch}
6713257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6714257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6715257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid StringAddStub::GenerateConvertArgument(MacroAssembler* masm,
6716257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                            int stack_offset,
6717257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                            Register arg,
6718257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                            Register scratch1,
6719257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                            Register scratch2,
6720257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                            Register scratch3,
6721257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                            Register scratch4,
6722257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                            Label* slow) {
6723257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // First check if the argument is already a string.
6724257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label not_string, done;
6725257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ JumpIfSmi(arg, &not_string);
6726257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ GetObjectType(arg, scratch1, scratch1);
6727257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Branch(&done, lt, scratch1, Operand(FIRST_NONSTRING_TYPE));
6728257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6729257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Check the number to string cache.
6730257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label not_cached;
6731257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&not_string);
6732257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Puts the cached result into scratch1.
6733257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  NumberToStringStub::GenerateLookupNumberStringCache(masm,
6734257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                                      arg,
6735257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                                      scratch1,
6736257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                                      scratch2,
6737257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                                      scratch3,
6738257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                                      scratch4,
6739257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                                      false,
6740257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                                      &not_cached);
6741257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ mov(arg, scratch1);
6742257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ sw(arg, MemOperand(sp, stack_offset));
6743257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ jmp(&done);
6744257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6745257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Check if the argument is a safe string wrapper.
6746257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&not_cached);
6747257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ JumpIfSmi(arg, slow);
6748257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ GetObjectType(arg, scratch1, scratch2);  // map -> scratch1.
6749257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Branch(slow, ne, scratch2, Operand(JS_VALUE_TYPE));
6750257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ lbu(scratch2, FieldMemOperand(scratch1, Map::kBitField2Offset));
6751257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ li(scratch4, 1 << Map::kStringWrapperSafeForDefaultValueOf);
6752257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ And(scratch2, scratch2, scratch4);
6753257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Branch(slow, ne, scratch2, Operand(scratch4));
6754257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ lw(arg, FieldMemOperand(arg, JSValue::kValueOffset));
6755257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ sw(arg, MemOperand(sp, stack_offset));
6756257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6757257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&done);
675844f0eee88ff00398ff7f715fab053374d808c90dSteve Block}
675944f0eee88ff00398ff7f715fab053374d808c90dSteve Block
676044f0eee88ff00398ff7f715fab053374d808c90dSteve Block
676144f0eee88ff00398ff7f715fab053374d808c90dSteve Blockvoid ICCompareStub::GenerateSmis(MacroAssembler* masm) {
6762257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  ASSERT(state_ == CompareIC::SMIS);
6763257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label miss;
6764257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Or(a2, a1, a0);
6765257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ JumpIfNotSmi(a2, &miss);
6766257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6767257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  if (GetCondition() == eq) {
6768257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // For equality we do not care about the sign of the result.
6769257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ Subu(v0, a0, a1);
6770257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  } else {
6771257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Untag before subtracting to avoid handling overflow.
6772257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ SmiUntag(a1);
6773257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ SmiUntag(a0);
6774257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ Subu(v0, a1, a0);
6775257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
6776257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Ret();
6777257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6778257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&miss);
6779257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  GenerateMiss(masm);
678044f0eee88ff00398ff7f715fab053374d808c90dSteve Block}
678144f0eee88ff00398ff7f715fab053374d808c90dSteve Block
678244f0eee88ff00398ff7f715fab053374d808c90dSteve Block
678344f0eee88ff00398ff7f715fab053374d808c90dSteve Blockvoid ICCompareStub::GenerateHeapNumbers(MacroAssembler* masm) {
6784257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  ASSERT(state_ == CompareIC::HEAP_NUMBERS);
6785257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6786257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label generic_stub;
67873ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  Label unordered, maybe_undefined1, maybe_undefined2;
6788257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label miss;
6789257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ And(a2, a1, Operand(a0));
6790257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ JumpIfSmi(a2, &generic_stub);
6791257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6792257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ GetObjectType(a0, a2, a2);
67933ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ Branch(&maybe_undefined1, ne, a2, Operand(HEAP_NUMBER_TYPE));
6794257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ GetObjectType(a1, a2, a2);
67953ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ Branch(&maybe_undefined2, ne, a2, Operand(HEAP_NUMBER_TYPE));
6796257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6797257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Inlining the double comparison and falling back to the general compare
6798257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // stub if NaN is involved or FPU is unsupported.
6799257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  if (CpuFeatures::IsSupported(FPU)) {
6800257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    CpuFeatures::Scope scope(FPU);
6801257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6802257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Load left and right operand.
6803257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ Subu(a2, a1, Operand(kHeapObjectTag));
6804257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ ldc1(f0, MemOperand(a2, HeapNumber::kValueOffset));
6805257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ Subu(a2, a0, Operand(kHeapObjectTag));
6806257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ ldc1(f2, MemOperand(a2, HeapNumber::kValueOffset));
6807257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
68083ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    // Return a result of -1, 0, or 1, or use CompareStub for NaNs.
68093ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    Label fpu_eq, fpu_lt;
68103ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    // Test if equal, and also handle the unordered/NaN case.
68113ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ BranchF(&fpu_eq, &unordered, eq, f0, f2);
6812257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
68133ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    // Test if less (unordered case is already handled).
68143ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ BranchF(&fpu_lt, NULL, lt, f0, f2);
681585b71799222b55eb5dd74ea26efe0c64ab655c8cBen Murdoch
68163ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    // Otherwise it's greater, so just fall thru, and return.
68173ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ li(v0, Operand(GREATER));
68183ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ Ret();
6819257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6820257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ bind(&fpu_eq);
68215d4cdbf7a67d3662fa0bee4efdb7edd8daec9b0bBen Murdoch    __ li(v0, Operand(EQUAL));
68225d4cdbf7a67d3662fa0bee4efdb7edd8daec9b0bBen Murdoch    __ Ret();
6823257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6824257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ bind(&fpu_lt);
68255d4cdbf7a67d3662fa0bee4efdb7edd8daec9b0bBen Murdoch    __ li(v0, Operand(LESS));
68265d4cdbf7a67d3662fa0bee4efdb7edd8daec9b0bBen Murdoch    __ Ret();
682785b71799222b55eb5dd74ea26efe0c64ab655c8cBen Murdoch  }
68285d4cdbf7a67d3662fa0bee4efdb7edd8daec9b0bBen Murdoch
68293ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ bind(&unordered);
68303ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
6831257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  CompareStub stub(GetCondition(), strict(), NO_COMPARE_FLAGS, a1, a0);
6832257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&generic_stub);
6833257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Jump(stub.GetCode(), RelocInfo::CODE_TARGET);
6834257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
68353ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ bind(&maybe_undefined1);
68363ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  if (Token::IsOrderedRelationalCompareOp(op_)) {
68373ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ LoadRoot(at, Heap::kUndefinedValueRootIndex);
68383ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ Branch(&miss, ne, a0, Operand(at));
68393ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ GetObjectType(a1, a2, a2);
68403ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ Branch(&maybe_undefined2, ne, a2, Operand(HEAP_NUMBER_TYPE));
68413ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ jmp(&unordered);
68423ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  }
68433ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
68443ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ bind(&maybe_undefined2);
68453ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  if (Token::IsOrderedRelationalCompareOp(op_)) {
68463ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ LoadRoot(at, Heap::kUndefinedValueRootIndex);
68473ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ Branch(&unordered, eq, a1, Operand(at));
68483ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  }
68493ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
6850257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&miss);
6851257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  GenerateMiss(masm);
6852257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch}
6853257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6854257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6855257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid ICCompareStub::GenerateSymbols(MacroAssembler* masm) {
6856257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  ASSERT(state_ == CompareIC::SYMBOLS);
6857257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label miss;
6858257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6859257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Registers containing left and right operands respectively.
6860257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Register left = a1;
6861257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Register right = a0;
6862257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Register tmp1 = a2;
6863257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Register tmp2 = a3;
6864257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6865257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Check that both operands are heap objects.
6866257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ JumpIfEitherSmi(left, right, &miss);
6867257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6868257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Check that both operands are symbols.
6869257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ lw(tmp1, FieldMemOperand(left, HeapObject::kMapOffset));
6870257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ lw(tmp2, FieldMemOperand(right, HeapObject::kMapOffset));
6871257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ lbu(tmp1, FieldMemOperand(tmp1, Map::kInstanceTypeOffset));
6872257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ lbu(tmp2, FieldMemOperand(tmp2, Map::kInstanceTypeOffset));
6873257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  STATIC_ASSERT(kSymbolTag != 0);
6874257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ And(tmp1, tmp1, Operand(tmp2));
6875257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ And(tmp1, tmp1, kIsSymbolMask);
6876257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Branch(&miss, eq, tmp1, Operand(zero_reg));
6877257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Make sure a0 is non-zero. At this point input operands are
6878257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // guaranteed to be non-zero.
6879257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  ASSERT(right.is(a0));
6880257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  STATIC_ASSERT(EQUAL == 0);
6881257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  STATIC_ASSERT(kSmiTag == 0);
6882257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ mov(v0, right);
6883257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Symbols are compared by identity.
6884257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Ret(ne, left, Operand(right));
6885257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ li(v0, Operand(Smi::FromInt(EQUAL)));
6886257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Ret();
6887257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6888257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&miss);
6889257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  GenerateMiss(masm);
6890257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch}
6891257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6892257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6893257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid ICCompareStub::GenerateStrings(MacroAssembler* masm) {
6894257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  ASSERT(state_ == CompareIC::STRINGS);
6895257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label miss;
6896257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
68973ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  bool equality = Token::IsEqualityOp(op_);
68983ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
6899257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Registers containing left and right operands respectively.
6900257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Register left = a1;
6901257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Register right = a0;
6902257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Register tmp1 = a2;
6903257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Register tmp2 = a3;
6904257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Register tmp3 = t0;
6905257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Register tmp4 = t1;
6906257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Register tmp5 = t2;
6907257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6908257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Check that both operands are heap objects.
6909257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ JumpIfEitherSmi(left, right, &miss);
6910257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6911257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Check that both operands are strings. This leaves the instance
6912257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // types loaded in tmp1 and tmp2.
6913257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ lw(tmp1, FieldMemOperand(left, HeapObject::kMapOffset));
6914257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ lw(tmp2, FieldMemOperand(right, HeapObject::kMapOffset));
6915257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ lbu(tmp1, FieldMemOperand(tmp1, Map::kInstanceTypeOffset));
6916257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ lbu(tmp2, FieldMemOperand(tmp2, Map::kInstanceTypeOffset));
6917257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  STATIC_ASSERT(kNotStringTag != 0);
6918257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Or(tmp3, tmp1, tmp2);
6919257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ And(tmp5, tmp3, Operand(kIsNotStringMask));
6920257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Branch(&miss, ne, tmp5, Operand(zero_reg));
6921257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6922257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Fast check for identical strings.
6923257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label left_ne_right;
6924257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  STATIC_ASSERT(EQUAL == 0);
6925257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  STATIC_ASSERT(kSmiTag == 0);
69263ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ Branch(&left_ne_right, ne, left, Operand(right));
69273ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ Ret(USE_DELAY_SLOT);
6928257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ mov(v0, zero_reg);  // In the delay slot.
6929257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&left_ne_right);
6930257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6931257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Handle not identical strings.
6932257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6933257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Check that both strings are symbols. If they are, we're done
6934257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // because we already know they are not identical.
69353ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  if (equality) {
69363ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    ASSERT(GetCondition() == eq);
69373ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    STATIC_ASSERT(kSymbolTag != 0);
69383ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ And(tmp3, tmp1, Operand(tmp2));
69393ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ And(tmp5, tmp3, Operand(kIsSymbolMask));
69403ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    Label is_symbol;
69413ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ Branch(&is_symbol, eq, tmp5, Operand(zero_reg));
69423ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    // Make sure a0 is non-zero. At this point input operands are
69433ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    // guaranteed to be non-zero.
69443ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    ASSERT(right.is(a0));
69453ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ Ret(USE_DELAY_SLOT);
69463ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ mov(v0, a0);  // In the delay slot.
69473ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ bind(&is_symbol);
69483ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  }
6949257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6950257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Check that both strings are sequential ASCII.
6951257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label runtime;
69523ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ JumpIfBothInstanceTypesAreNotSequentialAscii(
69533ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      tmp1, tmp2, tmp3, tmp4, &runtime);
6954257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6955257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Compare flat ASCII strings. Returns when done.
69563ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  if (equality) {
69573ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    StringCompareStub::GenerateFlatAsciiStringEquals(
69583ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch        masm, left, right, tmp1, tmp2, tmp3);
69593ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  } else {
69603ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    StringCompareStub::GenerateCompareFlatAsciiStrings(
69613ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch        masm, left, right, tmp1, tmp2, tmp3, tmp4);
69623ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  }
6963257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6964257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Handle more complex cases in runtime.
6965257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&runtime);
6966257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Push(left, right);
69673ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  if (equality) {
69683ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ TailCallRuntime(Runtime::kStringEquals, 2, 1);
69693ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  } else {
69703ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ TailCallRuntime(Runtime::kStringCompare, 2, 1);
69713ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  }
6972257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6973257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&miss);
6974257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  GenerateMiss(masm);
697544f0eee88ff00398ff7f715fab053374d808c90dSteve Block}
697644f0eee88ff00398ff7f715fab053374d808c90dSteve Block
697744f0eee88ff00398ff7f715fab053374d808c90dSteve Block
697844f0eee88ff00398ff7f715fab053374d808c90dSteve Blockvoid ICCompareStub::GenerateObjects(MacroAssembler* masm) {
6979257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  ASSERT(state_ == CompareIC::OBJECTS);
6980257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label miss;
6981257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ And(a2, a1, Operand(a0));
6982257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ JumpIfSmi(a2, &miss);
6983257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6984257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ GetObjectType(a0, a2, a2);
6985257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Branch(&miss, ne, a2, Operand(JS_OBJECT_TYPE));
6986257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ GetObjectType(a1, a2, a2);
6987257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Branch(&miss, ne, a2, Operand(JS_OBJECT_TYPE));
6988257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6989257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  ASSERT(GetCondition() == eq);
69903ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ Ret(USE_DELAY_SLOT);
69913ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ subu(v0, a0, a1);
6992257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6993257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&miss);
6994257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  GenerateMiss(masm);
699544f0eee88ff00398ff7f715fab053374d808c90dSteve Block}
699644f0eee88ff00398ff7f715fab053374d808c90dSteve Block
699744f0eee88ff00398ff7f715fab053374d808c90dSteve Block
69983ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochvoid ICCompareStub::GenerateKnownObjects(MacroAssembler* masm) {
69993ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  Label miss;
70003ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ And(a2, a1, a0);
70013ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ JumpIfSmi(a2, &miss);
70023ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ lw(a2, FieldMemOperand(a0, HeapObject::kMapOffset));
70033ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ lw(a3, FieldMemOperand(a1, HeapObject::kMapOffset));
70043ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ Branch(&miss, ne, a2, Operand(known_map_));
70053ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ Branch(&miss, ne, a3, Operand(known_map_));
700685b71799222b55eb5dd74ea26efe0c64ab655c8cBen Murdoch
70073ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ Ret(USE_DELAY_SLOT);
70083ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ subu(v0, a0, a1);
70093ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
70103ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ bind(&miss);
70113ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  GenerateMiss(masm);
70123ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch}
70133ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
70143ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochvoid ICCompareStub::GenerateMiss(MacroAssembler* masm) {
70153ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  {
70163ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    // Call the runtime system in a fresh internal frame.
70173ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    ExternalReference miss =
70183ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch        ExternalReference(IC_Utility(IC::kCompareIC_Miss), masm->isolate());
70193ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    FrameScope scope(masm, StackFrame::INTERNAL);
70203ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ Push(a1, a0);
70213ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ push(ra);
70223ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ Push(a1, a0);
70233ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ li(t0, Operand(Smi::FromInt(op_)));
70243ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ addiu(sp, sp, -kPointerSize);
70253ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ CallExternalReference(miss, 3, USE_DELAY_SLOT);
70263ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ sw(t0, MemOperand(sp));  // In the delay slot.
70273ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    // Compute the entry point of the rewritten stub.
70283ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ Addu(a2, v0, Operand(Code::kHeaderSize - kHeapObjectTag));
70293ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    // Restore registers.
70303ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ Pop(a1, a0, ra);
70313ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  }
7032257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Jump(a2);
703344f0eee88ff00398ff7f715fab053374d808c90dSteve Block}
703444f0eee88ff00398ff7f715fab053374d808c90dSteve Block
70353fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
7036257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid DirectCEntryStub::Generate(MacroAssembler* masm) {
7037257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // No need to pop or drop anything, LeaveExitFrame will restore the old
7038257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // stack, thus dropping the allocated space for the return value.
7039257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // The saved ra is after the reserved stack space for the 4 args.
7040257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ lw(t9, MemOperand(sp, kCArgsSlotsSize));
7041257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
70423ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  if (FLAG_debug_code && FLAG_enable_slow_asserts) {
7043257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // In case of an error the return address may point to a memory area
7044257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // filled with kZapValue by the GC.
7045257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Dereference the address and check for this.
7046257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ lw(t0, MemOperand(t9));
7047257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ Assert(ne, "Received invalid return address.", t0,
7048257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        Operand(reinterpret_cast<uint32_t>(kZapValue)));
7049257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
7050257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Jump(t9);
7051257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch}
705244f0eee88ff00398ff7f715fab053374d808c90dSteve Block
7053257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
7054257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid DirectCEntryStub::GenerateCall(MacroAssembler* masm,
7055257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                    ExternalReference function) {
7056257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ li(t9, Operand(function));
7057257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  this->GenerateCall(masm, t9);
7058257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch}
7059257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
70603fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
7061257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid DirectCEntryStub::GenerateCall(MacroAssembler* masm,
7062257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                    Register target) {
7063257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Move(t9, target);
7064257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ AssertStackIsAligned();
7065257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Allocate space for arg slots.
7066257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Subu(sp, sp, kCArgsSlotsSize);
7067257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
7068257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Block the trampoline pool through the whole function to make sure the
7069257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // number of generated instructions is constant.
7070257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Assembler::BlockTrampolinePoolScope block_trampoline_pool(masm);
7071257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
7072257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // We need to get the current 'pc' value, which is not available on MIPS.
7073257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label find_ra;
7074257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  masm->bal(&find_ra);  // ra = pc + 8.
7075257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  masm->nop();  // Branch delay slot nop.
7076257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  masm->bind(&find_ra);
7077257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
7078257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  const int kNumInstructionsToJump = 6;
7079257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  masm->addiu(ra, ra, kNumInstructionsToJump * kPointerSize);
7080257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Push return address (accessible to GC through exit frame pc).
7081257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // This spot for ra was reserved in EnterExitFrame.
7082257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  masm->sw(ra, MemOperand(sp, kCArgsSlotsSize));
70833ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  masm->li(ra,
70843ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch           Operand(reinterpret_cast<intptr_t>(GetCode().location()),
70853ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                   RelocInfo::CODE_TARGET),
70863ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch           CONSTANT_SIZE);
7087257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Call the function.
7088257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  masm->Jump(t9);
7089257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Make sure the stored 'ra' points to this position.
7090257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  ASSERT_EQ(kNumInstructionsToJump, masm->InstructionsGeneratedSince(&find_ra));
7091257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch}
7092257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
7093257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
70943ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochvoid StringDictionaryLookupStub::GenerateNegativeLookup(MacroAssembler* masm,
70953ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                                                        Label* miss,
70963ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                                                        Label* done,
70973ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                                                        Register receiver,
70983ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                                                        Register properties,
70993ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                                                        Handle<String> name,
71003ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                                                        Register scratch0) {
71013ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // If names of slots in range from 1 to kProbes - 1 for the hash value are
7102257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // not equal to the name and kProbes-th slot is not used (its name is the
7103257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // undefined value), it guarantees the hash table doesn't contain the
7104257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // property. It's true even if some slots represent deleted properties
71053ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // (their names are the hole value).
7106257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  for (int i = 0; i < kInlinedProbes; i++) {
7107257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // scratch0 points to properties hash.
7108257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Compute the masked index: (hash + i + i * i) & mask.
7109257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Register index = scratch0;
7110257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Capacity is smi 2^n.
7111257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ lw(index, FieldMemOperand(properties, kCapacityOffset));
7112257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ Subu(index, index, Operand(1));
7113257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ And(index, index, Operand(
71143ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch        Smi::FromInt(name->Hash() + StringDictionary::GetProbeOffset(i))));
7115257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
7116257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Scale the index by multiplying by the entry size.
7117257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    ASSERT(StringDictionary::kEntrySize == 3);
71183ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ sll(at, index, 1);
7119257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ Addu(index, index, at);
7120257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
7121257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Register entity_name = scratch0;
7122257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Having undefined at this place means the name is not contained.
7123257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    ASSERT_EQ(kSmiTagSize, 1);
7124257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Register tmp = properties;
7125257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ sll(scratch0, index, 1);
7126257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ Addu(tmp, properties, scratch0);
7127257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ lw(entity_name, FieldMemOperand(tmp, kElementsStartOffset));
7128257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
7129257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    ASSERT(!tmp.is(entity_name));
7130257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ LoadRoot(tmp, Heap::kUndefinedValueRootIndex);
7131257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ Branch(done, eq, entity_name, Operand(tmp));
7132257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
7133257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    if (i != kInlinedProbes - 1) {
71343ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      // Load the hole ready for use below:
71353ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      __ LoadRoot(tmp, Heap::kTheHoleValueRootIndex);
71363ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
7137257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // Stop if found the property.
7138257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ Branch(miss, eq, entity_name, Operand(Handle<String>(name)));
7139257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
71403ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      Label the_hole;
71413ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      __ Branch(&the_hole, eq, entity_name, Operand(tmp));
71423ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
7143257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // Check if the entry name is not a symbol.
7144257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ lw(entity_name, FieldMemOperand(entity_name, HeapObject::kMapOffset));
7145257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ lbu(entity_name,
7146257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch             FieldMemOperand(entity_name, Map::kInstanceTypeOffset));
7147257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ And(scratch0, entity_name, Operand(kIsSymbolMask));
7148257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ Branch(miss, eq, scratch0, Operand(zero_reg));
7149257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
71503ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      __ bind(&the_hole);
71513ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
7152257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // Restore the properties.
7153257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ lw(properties,
7154257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch            FieldMemOperand(receiver, JSObject::kPropertiesOffset));
7155257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    }
7156257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
7157257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
7158257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  const int spill_mask =
7159257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      (ra.bit() | t2.bit() | t1.bit() | t0.bit() | a3.bit() |
71603ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch       a2.bit() | a1.bit() | a0.bit() | v0.bit());
7161257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
7162257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ MultiPush(spill_mask);
7163257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ lw(a0, FieldMemOperand(receiver, JSObject::kPropertiesOffset));
7164257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ li(a1, Operand(Handle<String>(name)));
7165257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  StringDictionaryLookupStub stub(NEGATIVE_LOOKUP);
71663ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ CallStub(&stub);
71673ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ mov(at, v0);
7168257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ MultiPop(spill_mask);
7169257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
71703ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ Branch(done, eq, at, Operand(zero_reg));
71713ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ Branch(miss, ne, at, Operand(zero_reg));
7172257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch}
7173257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
7174257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
7175257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// Probe the string dictionary in the |elements| register. Jump to the
7176257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// |done| label if a property with the given name is found. Jump to
7177257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// the |miss| label otherwise.
7178257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// If lookup was successful |scratch2| will be equal to elements + 4 * index.
7179257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid StringDictionaryLookupStub::GeneratePositiveLookup(MacroAssembler* masm,
7180257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                                        Label* miss,
7181257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                                        Label* done,
7182257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                                        Register elements,
7183257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                                        Register name,
7184257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                                        Register scratch1,
7185257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                                        Register scratch2) {
71863ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  ASSERT(!elements.is(scratch1));
71873ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  ASSERT(!elements.is(scratch2));
71883ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  ASSERT(!name.is(scratch1));
71893ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  ASSERT(!name.is(scratch2));
71903ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
7191257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Assert that name contains a string.
7192257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  if (FLAG_debug_code) __ AbortIfNotString(name);
7193257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
7194257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Compute the capacity mask.
7195257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ lw(scratch1, FieldMemOperand(elements, kCapacityOffset));
7196257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ sra(scratch1, scratch1, kSmiTagSize);  // convert smi to int
7197257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Subu(scratch1, scratch1, Operand(1));
7198257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
7199257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Generate an unrolled loop that performs a few probes before
7200257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // giving up. Measurements done on Gmail indicate that 2 probes
7201257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // cover ~93% of loads from dictionaries.
7202257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  for (int i = 0; i < kInlinedProbes; i++) {
7203257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Compute the masked index: (hash + i + i * i) & mask.
7204257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ lw(scratch2, FieldMemOperand(name, String::kHashFieldOffset));
7205257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    if (i > 0) {
7206257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // Add the probe offset (i + i * i) left shifted to avoid right shifting
7207257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // the hash in a separate instruction. The value hash + i + i * i is right
7208257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // shifted in the following and instruction.
7209257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      ASSERT(StringDictionary::GetProbeOffset(i) <
7210257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch             1 << (32 - String::kHashFieldOffset));
7211257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ Addu(scratch2, scratch2, Operand(
7212257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch           StringDictionary::GetProbeOffset(i) << String::kHashShift));
7213257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    }
7214257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ srl(scratch2, scratch2, String::kHashShift);
7215257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ And(scratch2, scratch1, scratch2);
7216257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
7217257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Scale the index by multiplying by the element size.
7218257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    ASSERT(StringDictionary::kEntrySize == 3);
7219257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // scratch2 = scratch2 * 3.
7220257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
72213ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ sll(at, scratch2, 1);
7222257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ Addu(scratch2, scratch2, at);
7223257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
7224257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Check if the key is identical to the name.
7225257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ sll(at, scratch2, 2);
7226257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ Addu(scratch2, elements, at);
7227257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ lw(at, FieldMemOperand(scratch2, kElementsStartOffset));
7228257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ Branch(done, eq, name, Operand(at));
7229257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
7230257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
7231257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  const int spill_mask =
7232257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      (ra.bit() | t2.bit() | t1.bit() | t0.bit() |
72333ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch       a3.bit() | a2.bit() | a1.bit() | a0.bit() | v0.bit()) &
7234257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      ~(scratch1.bit() | scratch2.bit());
7235257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
7236257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ MultiPush(spill_mask);
72373ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  if (name.is(a0)) {
72383ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    ASSERT(!elements.is(a1));
72393ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ Move(a1, name);
72403ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ Move(a0, elements);
72413ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  } else {
72423ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ Move(a0, elements);
72433ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ Move(a1, name);
72443ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  }
7245257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  StringDictionaryLookupStub stub(POSITIVE_LOOKUP);
7246257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ CallStub(&stub);
7247257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ mov(scratch2, a2);
72483ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ mov(at, v0);
7249257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ MultiPop(spill_mask);
7250257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
72513ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ Branch(done, ne, at, Operand(zero_reg));
72523ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ Branch(miss, eq, at, Operand(zero_reg));
7253257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch}
7254257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
7255257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
7256257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid StringDictionaryLookupStub::Generate(MacroAssembler* masm) {
72573ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // This stub overrides SometimesSetsUpAFrame() to return false.  That means
72583ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // we cannot call anything that could cause a GC from this stub.
7259257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Registers:
7260257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  //  result: StringDictionary to probe
7261257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  //  a1: key
7262257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  //  : StringDictionary to probe.
7263257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  //  index_: will hold an index of entry if lookup is successful.
7264257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  //          might alias with result_.
7265257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Returns:
7266257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  //  result_ is zero if lookup failed, non zero otherwise.
7267257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
7268257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Register result = v0;
7269257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Register dictionary = a0;
7270257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Register key = a1;
7271257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Register index = a2;
7272257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Register mask = a3;
7273257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Register hash = t0;
7274257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Register undefined = t1;
7275257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Register entry_key = t2;
7276257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
7277257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label in_dictionary, maybe_in_dictionary, not_in_dictionary;
7278257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
7279257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ lw(mask, FieldMemOperand(dictionary, kCapacityOffset));
7280257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ sra(mask, mask, kSmiTagSize);
7281257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Subu(mask, mask, Operand(1));
7282257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
7283257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ lw(hash, FieldMemOperand(key, String::kHashFieldOffset));
7284257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
7285257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ LoadRoot(undefined, Heap::kUndefinedValueRootIndex);
7286257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
7287257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  for (int i = kInlinedProbes; i < kTotalProbes; i++) {
7288257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Compute the masked index: (hash + i + i * i) & mask.
7289257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Capacity is smi 2^n.
7290257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    if (i > 0) {
7291257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // Add the probe offset (i + i * i) left shifted to avoid right shifting
7292257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // the hash in a separate instruction. The value hash + i + i * i is right
7293257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // shifted in the following and instruction.
7294257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      ASSERT(StringDictionary::GetProbeOffset(i) <
7295257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch             1 << (32 - String::kHashFieldOffset));
7296257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ Addu(index, hash, Operand(
7297257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch           StringDictionary::GetProbeOffset(i) << String::kHashShift));
7298257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    } else {
7299257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ mov(index, hash);
7300257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    }
7301257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ srl(index, index, String::kHashShift);
7302257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ And(index, mask, index);
7303257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
7304257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Scale the index by multiplying by the entry size.
7305257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    ASSERT(StringDictionary::kEntrySize == 3);
7306257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // index *= 3.
7307257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ mov(at, index);
7308257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ sll(index, index, 1);
7309257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ Addu(index, index, at);
7310257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
7311257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
7312257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    ASSERT_EQ(kSmiTagSize, 1);
7313257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ sll(index, index, 2);
7314257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ Addu(index, index, dictionary);
7315257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ lw(entry_key, FieldMemOperand(index, kElementsStartOffset));
7316257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
7317257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Having undefined at this place means the name is not contained.
7318257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ Branch(&not_in_dictionary, eq, entry_key, Operand(undefined));
7319257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
7320257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Stop if found the property.
7321257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ Branch(&in_dictionary, eq, entry_key, Operand(key));
7322257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
7323257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    if (i != kTotalProbes - 1 && mode_ == NEGATIVE_LOOKUP) {
7324257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // Check if the entry name is not a symbol.
7325257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ lw(entry_key, FieldMemOperand(entry_key, HeapObject::kMapOffset));
7326257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ lbu(entry_key,
7327257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch             FieldMemOperand(entry_key, Map::kInstanceTypeOffset));
7328257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ And(result, entry_key, Operand(kIsSymbolMask));
7329257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ Branch(&maybe_in_dictionary, eq, result, Operand(zero_reg));
7330257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    }
7331257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
7332257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
7333257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&maybe_in_dictionary);
7334257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // If we are doing negative lookup then probing failure should be
7335257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // treated as a lookup success. For positive lookup probing failure
7336257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // should be treated as lookup failure.
7337257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  if (mode_ == POSITIVE_LOOKUP) {
73383ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ Ret(USE_DELAY_SLOT);
7339257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ mov(result, zero_reg);
7340257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
7341257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
7342257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&in_dictionary);
73433ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ Ret(USE_DELAY_SLOT);
7344257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ li(result, 1);
7345257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
7346257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&not_in_dictionary);
73473ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ Ret(USE_DELAY_SLOT);
7348257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ mov(result, zero_reg);
73493ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch}
73503ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
73513ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
73523ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochstruct AheadOfTimeWriteBarrierStubList {
73533ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  Register object, value, address;
73543ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  RememberedSetAction action;
73553ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch};
73563ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
7357db1b4389239a7132c9cde0915dbd3f775dc1027aBen Murdoch#define REG(Name) { kRegister_ ## Name ## _Code }
73583ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
7359db1b4389239a7132c9cde0915dbd3f775dc1027aBen Murdochstatic const AheadOfTimeWriteBarrierStubList kAheadOfTime[] = {
73603ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Used in RegExpExecStub.
7361db1b4389239a7132c9cde0915dbd3f775dc1027aBen Murdoch  { REG(s2), REG(s0), REG(t3), EMIT_REMEMBERED_SET },
7362db1b4389239a7132c9cde0915dbd3f775dc1027aBen Murdoch  { REG(s2), REG(a2), REG(t3), EMIT_REMEMBERED_SET },
73633ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Used in CompileArrayPushCall.
73643ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Also used in StoreIC::GenerateNormal via GenerateDictionaryStore.
73653ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Also used in KeyedStoreIC::GenerateGeneric.
7366db1b4389239a7132c9cde0915dbd3f775dc1027aBen Murdoch  { REG(a3), REG(t0), REG(t1), EMIT_REMEMBERED_SET },
73673ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Used in CompileStoreGlobal.
7368db1b4389239a7132c9cde0915dbd3f775dc1027aBen Murdoch  { REG(t0), REG(a1), REG(a2), OMIT_REMEMBERED_SET },
73693ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Used in StoreStubCompiler::CompileStoreField via GenerateStoreField.
7370db1b4389239a7132c9cde0915dbd3f775dc1027aBen Murdoch  { REG(a1), REG(a2), REG(a3), EMIT_REMEMBERED_SET },
7371db1b4389239a7132c9cde0915dbd3f775dc1027aBen Murdoch  { REG(a3), REG(a2), REG(a1), EMIT_REMEMBERED_SET },
73723ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Used in KeyedStoreStubCompiler::CompileStoreField via GenerateStoreField.
7373db1b4389239a7132c9cde0915dbd3f775dc1027aBen Murdoch  { REG(a2), REG(a1), REG(a3), EMIT_REMEMBERED_SET },
7374db1b4389239a7132c9cde0915dbd3f775dc1027aBen Murdoch  { REG(a3), REG(a1), REG(a2), EMIT_REMEMBERED_SET },
73753ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // KeyedStoreStubCompiler::GenerateStoreFastElement.
7376db1b4389239a7132c9cde0915dbd3f775dc1027aBen Murdoch  { REG(a3), REG(a2), REG(t0), EMIT_REMEMBERED_SET },
7377db1b4389239a7132c9cde0915dbd3f775dc1027aBen Murdoch  { REG(a2), REG(a3), REG(t0), EMIT_REMEMBERED_SET },
73783ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // ElementsTransitionGenerator::GenerateSmiOnlyToObject
73793ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // and ElementsTransitionGenerator::GenerateSmiOnlyToDouble
73803ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // and ElementsTransitionGenerator::GenerateDoubleToObject
7381db1b4389239a7132c9cde0915dbd3f775dc1027aBen Murdoch  { REG(a2), REG(a3), REG(t5), EMIT_REMEMBERED_SET },
7382db1b4389239a7132c9cde0915dbd3f775dc1027aBen Murdoch  { REG(a2), REG(a3), REG(t5), OMIT_REMEMBERED_SET },
73833ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // ElementsTransitionGenerator::GenerateDoubleToObject
7384db1b4389239a7132c9cde0915dbd3f775dc1027aBen Murdoch  { REG(t2), REG(a2), REG(a0), EMIT_REMEMBERED_SET },
7385db1b4389239a7132c9cde0915dbd3f775dc1027aBen Murdoch  { REG(a2), REG(t2), REG(t5), EMIT_REMEMBERED_SET },
73863ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // StoreArrayLiteralElementStub::Generate
7387db1b4389239a7132c9cde0915dbd3f775dc1027aBen Murdoch  { REG(t1), REG(a0), REG(t2), EMIT_REMEMBERED_SET },
73883ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Null termination.
7389db1b4389239a7132c9cde0915dbd3f775dc1027aBen Murdoch  { REG(no_reg), REG(no_reg), REG(no_reg), EMIT_REMEMBERED_SET}
73903ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch};
73913ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
7392db1b4389239a7132c9cde0915dbd3f775dc1027aBen Murdoch#undef REG
7393db1b4389239a7132c9cde0915dbd3f775dc1027aBen Murdoch
73943ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
73953ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochbool RecordWriteStub::IsPregenerated() {
7396db1b4389239a7132c9cde0915dbd3f775dc1027aBen Murdoch  for (const AheadOfTimeWriteBarrierStubList* entry = kAheadOfTime;
73973ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch       !entry->object.is(no_reg);
73983ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch       entry++) {
73993ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    if (object_.is(entry->object) &&
74003ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch        value_.is(entry->value) &&
74013ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch        address_.is(entry->address) &&
74023ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch        remembered_set_action_ == entry->action &&
74033ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch        save_fp_regs_mode_ == kDontSaveFPRegs) {
74043ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      return true;
74053ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    }
74063ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  }
74073ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  return false;
74083ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch}
74093ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
74103ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
74113ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochbool StoreBufferOverflowStub::IsPregenerated() {
74123ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  return save_doubles_ == kDontSaveFPRegs || ISOLATE->fp_stubs_generated();
74133ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch}
74143ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
74153ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
74163ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochvoid StoreBufferOverflowStub::GenerateFixedRegStubsAheadOfTime() {
74173ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  StoreBufferOverflowStub stub1(kDontSaveFPRegs);
74183ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  stub1.GetCode()->set_is_pregenerated(true);
74193ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch}
74203ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
74213ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
74223ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochvoid RecordWriteStub::GenerateFixedRegStubsAheadOfTime() {
7423db1b4389239a7132c9cde0915dbd3f775dc1027aBen Murdoch  for (const AheadOfTimeWriteBarrierStubList* entry = kAheadOfTime;
74243ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch       !entry->object.is(no_reg);
74253ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch       entry++) {
74263ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    RecordWriteStub stub(entry->object,
74273ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                         entry->value,
74283ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                         entry->address,
74293ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                         entry->action,
74303ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                         kDontSaveFPRegs);
74313ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    stub.GetCode()->set_is_pregenerated(true);
74323ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  }
74333ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch}
74343ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
74353ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
74363ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch// Takes the input in 3 registers: address_ value_ and object_.  A pointer to
74373ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch// the value has just been written into the object, now this stub makes sure
74383ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch// we keep the GC informed.  The word in the object where the value has been
74393ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch// written is in the address register.
74403ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochvoid RecordWriteStub::Generate(MacroAssembler* masm) {
74413ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  Label skip_to_incremental_noncompacting;
74423ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  Label skip_to_incremental_compacting;
74433ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
74443ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // The first two branch+nop instructions are generated with labels so as to
74453ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // get the offset fixed up correctly by the bind(Label*) call.  We patch it
74463ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // back and forth between a "bne zero_reg, zero_reg, ..." (a nop in this
74473ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // position) and the "beq zero_reg, zero_reg, ..." when we start and stop
74483ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // incremental heap marking.
74493ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // See RecordWriteStub::Patch for details.
74503ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ beq(zero_reg, zero_reg, &skip_to_incremental_noncompacting);
74513ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ nop();
74523ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ beq(zero_reg, zero_reg, &skip_to_incremental_compacting);
74533ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ nop();
74543ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
74553ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  if (remembered_set_action_ == EMIT_REMEMBERED_SET) {
74563ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ RememberedSetHelper(object_,
74573ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                           address_,
74583ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                           value_,
74593ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                           save_fp_regs_mode_,
74603ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                           MacroAssembler::kReturnAtEnd);
74613ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  }
74623ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ Ret();
74633ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
74643ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ bind(&skip_to_incremental_noncompacting);
74653ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  GenerateIncremental(masm, INCREMENTAL);
74663ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
74673ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ bind(&skip_to_incremental_compacting);
74683ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  GenerateIncremental(masm, INCREMENTAL_COMPACTION);
74693ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
74703ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Initial mode of the stub is expected to be STORE_BUFFER_ONLY.
74713ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Will be checked in IncrementalMarking::ActivateGeneratedStub.
74723ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
74733ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  PatchBranchIntoNop(masm, 0);
74743ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  PatchBranchIntoNop(masm, 2 * Assembler::kInstrSize);
74753ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch}
74763ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
74773ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
74783ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochvoid RecordWriteStub::GenerateIncremental(MacroAssembler* masm, Mode mode) {
74793ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  regs_.Save(masm);
74803ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
74813ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  if (remembered_set_action_ == EMIT_REMEMBERED_SET) {
74823ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    Label dont_need_remembered_set;
74833ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
74843ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ lw(regs_.scratch0(), MemOperand(regs_.address(), 0));
74853ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ JumpIfNotInNewSpace(regs_.scratch0(),  // Value.
74863ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                           regs_.scratch0(),
74873ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                           &dont_need_remembered_set);
74883ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
74893ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ CheckPageFlag(regs_.object(),
74903ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                     regs_.scratch0(),
74913ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                     1 << MemoryChunk::SCAN_ON_SCAVENGE,
74923ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                     ne,
74933ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                     &dont_need_remembered_set);
74943ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
74953ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    // First notify the incremental marker if necessary, then update the
74963ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    // remembered set.
74973ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    CheckNeedsToInformIncrementalMarker(
74983ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch        masm, kUpdateRememberedSetOnNoNeedToInformIncrementalMarker, mode);
74993ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    InformIncrementalMarker(masm, mode);
75003ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    regs_.Restore(masm);
75013ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ RememberedSetHelper(object_,
75023ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                           address_,
75033ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                           value_,
75043ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                           save_fp_regs_mode_,
75053ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                           MacroAssembler::kReturnAtEnd);
75063ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
75073ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ bind(&dont_need_remembered_set);
75083ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  }
75093ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
75103ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  CheckNeedsToInformIncrementalMarker(
75113ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      masm, kReturnOnNoNeedToInformIncrementalMarker, mode);
75123ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  InformIncrementalMarker(masm, mode);
75133ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  regs_.Restore(masm);
7514592a9fc1d8ea420377a2e7efd0600e20b058be2bBen Murdoch  __ Ret();
7515592a9fc1d8ea420377a2e7efd0600e20b058be2bBen Murdoch}
7516592a9fc1d8ea420377a2e7efd0600e20b058be2bBen Murdoch
7517592a9fc1d8ea420377a2e7efd0600e20b058be2bBen Murdoch
75183ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochvoid RecordWriteStub::InformIncrementalMarker(MacroAssembler* masm, Mode mode) {
75193ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  regs_.SaveCallerSaveRegisters(masm, save_fp_regs_mode_);
75203ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  int argument_count = 3;
75213ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ PrepareCallCFunction(argument_count, regs_.scratch0());
75223ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  Register address =
75233ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      a0.is(regs_.address()) ? regs_.scratch0() : regs_.address();
75243ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  ASSERT(!address.is(regs_.object()));
75253ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  ASSERT(!address.is(a0));
75263ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ Move(address, regs_.address());
75273ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ Move(a0, regs_.object());
75283ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  if (mode == INCREMENTAL_COMPACTION) {
75293ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ Move(a1, address);
75303ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  } else {
75313ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    ASSERT(mode == INCREMENTAL);
75323ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ lw(a1, MemOperand(address, 0));
75333ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  }
75343ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ li(a2, Operand(ExternalReference::isolate_address()));
75353ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
75363ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  AllowExternalCallThatCantCauseGC scope(masm);
75373ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  if (mode == INCREMENTAL_COMPACTION) {
75383ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ CallCFunction(
75393ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch        ExternalReference::incremental_evacuation_record_write_function(
75403ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch            masm->isolate()),
75413ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch        argument_count);
75423ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  } else {
75433ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    ASSERT(mode == INCREMENTAL);
75443ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ CallCFunction(
75453ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch        ExternalReference::incremental_marking_record_write_function(
75463ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch            masm->isolate()),
75473ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch        argument_count);
75483ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  }
75493ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  regs_.RestoreCallerSaveRegisters(masm, save_fp_regs_mode_);
75503ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch}
75513ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
75523ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
75533ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochvoid RecordWriteStub::CheckNeedsToInformIncrementalMarker(
75543ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    MacroAssembler* masm,
75553ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    OnNoNeedToInformIncrementalMarker on_no_need,
75563ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    Mode mode) {
75573ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  Label on_black;
75583ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  Label need_incremental;
75593ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  Label need_incremental_pop_scratch;
75603ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
75613ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Let's look at the color of the object:  If it is not black we don't have
75623ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // to inform the incremental marker.
75633ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ JumpIfBlack(regs_.object(), regs_.scratch0(), regs_.scratch1(), &on_black);
75643ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
75653ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  regs_.Restore(masm);
75663ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  if (on_no_need == kUpdateRememberedSetOnNoNeedToInformIncrementalMarker) {
75673ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ RememberedSetHelper(object_,
75683ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                           address_,
75693ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                           value_,
75703ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                           save_fp_regs_mode_,
75713ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                           MacroAssembler::kReturnAtEnd);
75723ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  } else {
75733ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ Ret();
75743ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  }
75753ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
75763ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ bind(&on_black);
75773ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
75783ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Get the value from the slot.
75793ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ lw(regs_.scratch0(), MemOperand(regs_.address(), 0));
75803ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
75813ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  if (mode == INCREMENTAL_COMPACTION) {
75823ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    Label ensure_not_white;
75833ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
75843ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ CheckPageFlag(regs_.scratch0(),  // Contains value.
75853ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                     regs_.scratch1(),  // Scratch.
75863ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                     MemoryChunk::kEvacuationCandidateMask,
75873ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                     eq,
75883ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                     &ensure_not_white);
75893ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
75903ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ CheckPageFlag(regs_.object(),
75913ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                     regs_.scratch1(),  // Scratch.
75923ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                     MemoryChunk::kSkipEvacuationSlotsRecordingMask,
75933ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                     eq,
75943ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                     &need_incremental);
75953ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
75963ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ bind(&ensure_not_white);
75973ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  }
75983ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
75993ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // We need extra registers for this, so we push the object and the address
76003ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // register temporarily.
76013ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ Push(regs_.object(), regs_.address());
76023ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ EnsureNotWhite(regs_.scratch0(),  // The value.
76033ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                    regs_.scratch1(),  // Scratch.
76043ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                    regs_.object(),  // Scratch.
76053ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                    regs_.address(),  // Scratch.
76063ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                    &need_incremental_pop_scratch);
76073ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ Pop(regs_.object(), regs_.address());
76083ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
76093ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  regs_.Restore(masm);
76103ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  if (on_no_need == kUpdateRememberedSetOnNoNeedToInformIncrementalMarker) {
76113ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ RememberedSetHelper(object_,
76123ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                           address_,
76133ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                           value_,
76143ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                           save_fp_regs_mode_,
76153ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                           MacroAssembler::kReturnAtEnd);
76163ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  } else {
76173ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ Ret();
76183ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  }
76193ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
76203ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ bind(&need_incremental_pop_scratch);
76213ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ Pop(regs_.object(), regs_.address());
76223ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
76233ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ bind(&need_incremental);
76243ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
76253ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Fall through when we need to inform the incremental marker.
76263ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch}
76273ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
76283ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
76293ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochvoid StoreArrayLiteralElementStub::Generate(MacroAssembler* masm) {
76303ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // ----------- S t a t e -------------
76313ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  //  -- a0    : element value to store
76323ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  //  -- a1    : array literal
76333ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  //  -- a2    : map of array literal
76343ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  //  -- a3    : element index as smi
76353ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  //  -- t0    : array literal index in function as smi
76363ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // -----------------------------------
76373ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
76383ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  Label element_done;
76393ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  Label double_elements;
76403ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  Label smi_element;
76413ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  Label slow_elements;
76423ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  Label fast_elements;
76433ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
76443ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ CheckFastElements(a2, t1, &double_elements);
76453ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // FAST_SMI_ONLY_ELEMENTS or FAST_ELEMENTS
76463ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ JumpIfSmi(a0, &smi_element);
76473ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ CheckFastSmiOnlyElements(a2, t1, &fast_elements);
76483ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
76493ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Store into the array literal requires a elements transition. Call into
76503ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // the runtime.
76513ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ bind(&slow_elements);
76523ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // call.
76533ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ Push(a1, a3, a0);
76543ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ lw(t1, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
76553ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ lw(t1, FieldMemOperand(t1, JSFunction::kLiteralsOffset));
76563ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ Push(t1, t0);
76573ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ TailCallRuntime(Runtime::kStoreArrayLiteralElement, 5, 1);
76583ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
76593ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Array literal has ElementsKind of FAST_ELEMENTS and value is an object.
76603ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ bind(&fast_elements);
76613ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ lw(t1, FieldMemOperand(a1, JSObject::kElementsOffset));
76623ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ sll(t2, a3, kPointerSizeLog2 - kSmiTagSize);
76633ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ Addu(t2, t1, t2);
76643ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ Addu(t2, t2, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
76653ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ sw(a0, MemOperand(t2, 0));
76663ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Update the write barrier for the array store.
76673ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ RecordWrite(t1, t2, a0, kRAHasNotBeenSaved, kDontSaveFPRegs,
76683ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                 EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
76693ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ Ret(USE_DELAY_SLOT);
76703ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ mov(v0, a0);
76713ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
76723ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Array literal has ElementsKind of FAST_SMI_ONLY_ELEMENTS or
76733ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // FAST_ELEMENTS, and value is Smi.
76743ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ bind(&smi_element);
76753ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ lw(t1, FieldMemOperand(a1, JSObject::kElementsOffset));
76763ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ sll(t2, a3, kPointerSizeLog2 - kSmiTagSize);
76773ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ Addu(t2, t1, t2);
76783ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ sw(a0, FieldMemOperand(t2, FixedArray::kHeaderSize));
76793ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ Ret(USE_DELAY_SLOT);
76803ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ mov(v0, a0);
76813ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
76823ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Array literal has ElementsKind of FAST_DOUBLE_ELEMENTS.
76833ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ bind(&double_elements);
76843ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ lw(t1, FieldMemOperand(a1, JSObject::kElementsOffset));
76853ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ StoreNumberToDoubleElements(a0, a3, a1, t1, t2, t3, t5, a2,
76863ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                                 &slow_elements);
76873ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ Ret(USE_DELAY_SLOT);
76883ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ mov(v0, a0);
76893ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch}
76903ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
76913ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
769244f0eee88ff00398ff7f715fab053374d808c90dSteve Block#undef __
769344f0eee88ff00398ff7f715fab053374d808c90dSteve Block
769444f0eee88ff00398ff7f715fab053374d808c90dSteve Block} }  // namespace v8::internal
769544f0eee88ff00398ff7f715fab053374d808c90dSteve Block
769644f0eee88ff00398ff7f715fab053374d808c90dSteve Block#endif  // V8_TARGET_ARCH_MIPS
7697