13ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch// Copyright 2012 the V8 project authors. All rights reserved.
280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// Redistribution and use in source and binary forms, with or without
380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// modification, are permitted provided that the following conditions are
480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// met:
580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen//
680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen//     * Redistributions of source code must retain the above copyright
780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen//       notice, this list of conditions and the following disclaimer.
880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen//     * Redistributions in binary form must reproduce the above
980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen//       copyright notice, this list of conditions and the following
1080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen//       disclaimer in the documentation and/or other materials provided
1180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen//       with the distribution.
1280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen//     * Neither the name of Google Inc. nor the names of its
1380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen//       contributors may be used to endorse or promote products derived
1480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen//       from this software without specific prior written permission.
1580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen//
1680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
1780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
1880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
1980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
2080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
2180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
2280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
2680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
2880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#include "v8.h"
2980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
3080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#if defined(V8_TARGET_ARCH_IA32)
3180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
3280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#include "bootstrapper.h"
33257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch#include "code-stubs.h"
3444f0eee88ff00398ff7f715fab053374d808c90dSteve Block#include "isolate.h"
35257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch#include "jsregexp.h"
3680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#include "regexp-macro-assembler.h"
373ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch#include "stub-cache.h"
383ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch#include "codegen.h"
3980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
4080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsennamespace v8 {
4180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsennamespace internal {
4280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
4380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#define __ ACCESS_MASM(masm)
441e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
451e0659c275bb392c045087af4f6b0d7565cb3d77Steve Blockvoid ToNumberStub::Generate(MacroAssembler* masm) {
461e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  // The ToNumber stub takes one argument in eax.
47257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label check_heap_number, call_builtin;
483fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ JumpIfNotSmi(eax, &check_heap_number, Label::kNear);
491e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  __ ret(0);
501e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
511e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  __ bind(&check_heap_number);
521e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset));
5344f0eee88ff00398ff7f715fab053374d808c90dSteve Block  Factory* factory = masm->isolate()->factory();
543ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ cmp(ebx, Immediate(factory->heap_number_map()));
55257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(not_equal, &call_builtin, Label::kNear);
561e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  __ ret(0);
571e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
581e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  __ bind(&call_builtin);
591e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  __ pop(ecx);  // Pop return address.
601e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  __ push(eax);
611e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  __ push(ecx);  // Push return address.
621e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  __ InvokeBuiltin(Builtins::TO_NUMBER, JUMP_FUNCTION);
631e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block}
641e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
651e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
6680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid FastNewClosureStub::Generate(MacroAssembler* masm) {
6780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Create a new closure from the given function info in new
6880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // space. Set the context to the current context in esi.
6980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label gc;
7080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ AllocateInNewSpace(JSFunction::kSize, eax, ebx, ecx, &gc, TAG_OBJECT);
7180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
7280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Get the function info from the stack.
7380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(edx, Operand(esp, 1 * kPointerSize));
7480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
753ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  int map_index = (language_mode_ == CLASSIC_MODE)
763ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      ? Context::FUNCTION_MAP_INDEX
773ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      : Context::STRICT_MODE_FUNCTION_MAP_INDEX;
7844f0eee88ff00398ff7f715fab053374d808c90dSteve Block
7980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Compute the function map in the current global context and set that
8080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // as the map of the allocated object.
8180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(ecx, Operand(esi, Context::SlotOffset(Context::GLOBAL_INDEX)));
8280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(ecx, FieldOperand(ecx, GlobalObject::kGlobalContextOffset));
8344f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ mov(ecx, Operand(ecx, Context::SlotOffset(map_index)));
8480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(FieldOperand(eax, JSObject::kMapOffset), ecx);
8580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
8680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Initialize the rest of the function. We don't have to update the
8780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // write barrier because the allocated object is in new space.
8844f0eee88ff00398ff7f715fab053374d808c90dSteve Block  Factory* factory = masm->isolate()->factory();
8944f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ mov(ebx, Immediate(factory->empty_fixed_array()));
9080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(FieldOperand(eax, JSObject::kPropertiesOffset), ebx);
9180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(FieldOperand(eax, JSObject::kElementsOffset), ebx);
9280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(FieldOperand(eax, JSFunction::kPrototypeOrInitialMapOffset),
9344f0eee88ff00398ff7f715fab053374d808c90dSteve Block         Immediate(factory->the_hole_value()));
9480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(FieldOperand(eax, JSFunction::kSharedFunctionInfoOffset), edx);
9580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(FieldOperand(eax, JSFunction::kContextOffset), esi);
9680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(FieldOperand(eax, JSFunction::kLiteralsOffset), ebx);
97b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ mov(FieldOperand(eax, JSFunction::kNextFunctionLinkOffset),
9844f0eee88ff00398ff7f715fab053374d808c90dSteve Block         Immediate(factory->undefined_value()));
9980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
10080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Initialize the code pointer in the function to be the one
10180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // found in the shared function info object.
10280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(edx, FieldOperand(edx, SharedFunctionInfo::kCodeOffset));
10380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ lea(edx, FieldOperand(edx, Code::kHeaderSize));
10480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(FieldOperand(eax, JSFunction::kCodeEntryOffset), edx);
10580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
10680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Return and remove the on-stack parameter.
10780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ ret(1 * kPointerSize);
10880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
10980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Create a new closure through the slower runtime call.
11080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&gc);
11180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ pop(ecx);  // Temporarily remove return address.
11280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ pop(edx);
11380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ push(esi);
11480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ push(edx);
11544f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ push(Immediate(factory->false_value()));
11680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ push(ecx);  // Restore return address.
1178a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  __ TailCallRuntime(Runtime::kNewClosure, 3, 1);
11880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
11980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
12080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
12180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid FastNewContextStub::Generate(MacroAssembler* masm) {
12280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Try to allocate the context in new space.
12380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label gc;
12480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  int length = slots_ + Context::MIN_CONTEXT_SLOTS;
12580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ AllocateInNewSpace((length * kPointerSize) + FixedArray::kHeaderSize,
12680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                        eax, ebx, ecx, &gc, TAG_OBJECT);
12780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
12880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Get the function from the stack.
12980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(ecx, Operand(esp, 1 * kPointerSize));
13080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
1313ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Set up the object header.
13244f0eee88ff00398ff7f715fab053374d808c90dSteve Block  Factory* factory = masm->isolate()->factory();
1333fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ mov(FieldOperand(eax, HeapObject::kMapOffset),
1343fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch         factory->function_context_map());
13580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(FieldOperand(eax, Context::kLengthOffset),
13680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen         Immediate(Smi::FromInt(length)));
13780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
1383ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Set up the fixed slots.
1399fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ Set(ebx, Immediate(0));  // Set to NULL.
14080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(Operand(eax, Context::SlotOffset(Context::CLOSURE_INDEX)), ecx);
1413fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ mov(Operand(eax, Context::SlotOffset(Context::PREVIOUS_INDEX)), esi);
14280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(Operand(eax, Context::SlotOffset(Context::EXTENSION_INDEX)), ebx);
14380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
1443fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // Copy the global object from the previous context.
1453fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ mov(ebx, Operand(esi, Context::SlotOffset(Context::GLOBAL_INDEX)));
14680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(Operand(eax, Context::SlotOffset(Context::GLOBAL_INDEX)), ebx);
14780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
14880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Initialize the rest of the slots to undefined.
14944f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ mov(ebx, factory->undefined_value());
15080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  for (int i = Context::MIN_CONTEXT_SLOTS; i < length; i++) {
15180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ mov(Operand(eax, Context::SlotOffset(i)), ebx);
15280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
15380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
15480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Return and remove the on-stack parameter.
1553ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ mov(esi, eax);
15680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ ret(1 * kPointerSize);
15780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
15880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Need to collect. Call into runtime system.
15980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&gc);
1603fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ TailCallRuntime(Runtime::kNewFunctionContext, 1, 1);
16180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
16280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
16380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
1643ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochvoid FastNewBlockContextStub::Generate(MacroAssembler* masm) {
1653ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Stack layout on entry:
1663ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  //
1673ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // [esp + (1 * kPointerSize)]: function
1683ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // [esp + (2 * kPointerSize)]: serialized scope info
1693ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
1703ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Try to allocate the context in new space.
1713ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  Label gc;
1723ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  int length = slots_ + Context::MIN_CONTEXT_SLOTS;
1733ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ AllocateInNewSpace(FixedArray::SizeFor(length),
1743ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                        eax, ebx, ecx, &gc, TAG_OBJECT);
1753ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
1763ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Get the function or sentinel from the stack.
1773ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ mov(ecx, Operand(esp, 1 * kPointerSize));
1783ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
1793ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Get the serialized scope info from the stack.
1803ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ mov(ebx, Operand(esp, 2 * kPointerSize));
1813ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
1823ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Set up the object header.
1833ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  Factory* factory = masm->isolate()->factory();
1843ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ mov(FieldOperand(eax, HeapObject::kMapOffset),
1853ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch         factory->block_context_map());
1863ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ mov(FieldOperand(eax, Context::kLengthOffset),
1873ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch         Immediate(Smi::FromInt(length)));
1883ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
1893ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // If this block context is nested in the global context we get a smi
1903ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // sentinel instead of a function. The block context should get the
1913ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // canonical empty function of the global context as its closure which
1923ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // we still have to look up.
1933ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  Label after_sentinel;
1943ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ JumpIfNotSmi(ecx, &after_sentinel, Label::kNear);
1953ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  if (FLAG_debug_code) {
1963ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    const char* message = "Expected 0 as a Smi sentinel";
1973ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ cmp(ecx, 0);
1983ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ Assert(equal, message);
1993ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  }
2003ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ mov(ecx, GlobalObjectOperand());
2013ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ mov(ecx, FieldOperand(ecx, GlobalObject::kGlobalContextOffset));
2023ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ mov(ecx, ContextOperand(ecx, Context::CLOSURE_INDEX));
2033ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ bind(&after_sentinel);
2043ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
2053ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Set up the fixed slots.
2063ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ mov(ContextOperand(eax, Context::CLOSURE_INDEX), ecx);
2073ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ mov(ContextOperand(eax, Context::PREVIOUS_INDEX), esi);
2083ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ mov(ContextOperand(eax, Context::EXTENSION_INDEX), ebx);
2093ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
2103ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Copy the global object from the previous context.
2113ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ mov(ebx, ContextOperand(esi, Context::GLOBAL_INDEX));
2123ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ mov(ContextOperand(eax, Context::GLOBAL_INDEX), ebx);
2133ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
2143ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Initialize the rest of the slots to the hole value.
2153ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  if (slots_ == 1) {
2163ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ mov(ContextOperand(eax, Context::MIN_CONTEXT_SLOTS),
2173ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch           factory->the_hole_value());
2183ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  } else {
2193ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ mov(ebx, factory->the_hole_value());
2203ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    for (int i = 0; i < slots_; i++) {
2213ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      __ mov(ContextOperand(eax, i + Context::MIN_CONTEXT_SLOTS), ebx);
2223ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    }
2233ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  }
2243ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
2253ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Return and remove the on-stack parameters.
2263ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ mov(esi, eax);
2273ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ ret(2 * kPointerSize);
2283ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
2293ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Need to collect. Call into runtime system.
2303ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ bind(&gc);
2313ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ TailCallRuntime(Runtime::kPushBlockContext, 2, 1);
2323ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch}
2333ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
2343ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
2353ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochstatic void GenerateFastCloneShallowArrayCommon(
2363ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    MacroAssembler* masm,
2373ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    int length,
2383ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    FastCloneShallowArrayStub::Mode mode,
2393ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    Label* fail) {
2403ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Registers on entry:
2413ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  //
2423ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // ecx: boilerplate literal array.
2433ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  ASSERT(mode != FastCloneShallowArrayStub::CLONE_ANY_ELEMENTS);
2443ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
2453ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // All sizes here are multiples of kPointerSize.
2463ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  int elements_size = 0;
2473ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  if (length > 0) {
2483ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    elements_size = mode == FastCloneShallowArrayStub::CLONE_DOUBLE_ELEMENTS
2493ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch        ? FixedDoubleArray::SizeFor(length)
2503ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch        : FixedArray::SizeFor(length);
2513ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  }
2523ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  int size = JSArray::kSize + elements_size;
2533ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
2543ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Allocate both the JS array and the elements array in one big
2553ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // allocation. This avoids multiple limit checks.
2563ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ AllocateInNewSpace(size, eax, ebx, edx, fail, TAG_OBJECT);
2573ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
2583ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Copy the JS array part.
2593ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  for (int i = 0; i < JSArray::kSize; i += kPointerSize) {
2603ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    if ((i != JSArray::kElementsOffset) || (length == 0)) {
2613ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      __ mov(ebx, FieldOperand(ecx, i));
2623ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      __ mov(FieldOperand(eax, i), ebx);
2633ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    }
2643ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  }
2653ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
2663ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  if (length > 0) {
2673ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    // Get hold of the elements array of the boilerplate and setup the
2683ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    // elements pointer in the resulting object.
2693ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ mov(ecx, FieldOperand(ecx, JSArray::kElementsOffset));
2703ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ lea(edx, Operand(eax, JSArray::kSize));
2713ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ mov(FieldOperand(eax, JSArray::kElementsOffset), edx);
2723ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
2733ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    // Copy the elements array.
2743ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    if (mode == FastCloneShallowArrayStub::CLONE_ELEMENTS) {
2753ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      for (int i = 0; i < elements_size; i += kPointerSize) {
2763ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch        __ mov(ebx, FieldOperand(ecx, i));
2773ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch        __ mov(FieldOperand(edx, i), ebx);
2783ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      }
2793ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    } else {
2803ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      ASSERT(mode == FastCloneShallowArrayStub::CLONE_DOUBLE_ELEMENTS);
2813ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      int i;
2823ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      for (i = 0; i < FixedDoubleArray::kHeaderSize; i += kPointerSize) {
2833ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch        __ mov(ebx, FieldOperand(ecx, i));
2843ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch        __ mov(FieldOperand(edx, i), ebx);
2853ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      }
2863ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      while (i < elements_size) {
2873ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch        __ fld_d(FieldOperand(ecx, i));
2883ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch        __ fstp_d(FieldOperand(edx, i));
2893ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch        i += kDoubleSize;
2903ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      }
2913ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      ASSERT(i == elements_size);
2923ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    }
2933ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  }
2943ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch}
2953ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
2963ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
29780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid FastCloneShallowArrayStub::Generate(MacroAssembler* masm) {
29880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Stack layout on entry:
29980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  //
30080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // [esp + kPointerSize]: constant elements.
30180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // [esp + (2 * kPointerSize)]: literal index.
30280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // [esp + (3 * kPointerSize)]: literals array.
30380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
30480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Load boilerplate object into ecx and check if we need to create a
30580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // boilerplate.
30680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(ecx, Operand(esp, 3 * kPointerSize));
30780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(eax, Operand(esp, 2 * kPointerSize));
30880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  STATIC_ASSERT(kPointerSize == 4);
30980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  STATIC_ASSERT(kSmiTagSize == 1);
31080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  STATIC_ASSERT(kSmiTag == 0);
31180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(ecx, FieldOperand(ecx, eax, times_half_pointer_size,
31280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                           FixedArray::kHeaderSize));
31344f0eee88ff00398ff7f715fab053374d808c90dSteve Block  Factory* factory = masm->isolate()->factory();
31444f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ cmp(ecx, factory->undefined_value());
3153ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  Label slow_case;
31680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(equal, &slow_case);
31780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
3183ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  FastCloneShallowArrayStub::Mode mode = mode_;
3193ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // ecx is boilerplate object.
3203ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  if (mode == CLONE_ANY_ELEMENTS) {
3213ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    Label double_elements, check_fast_elements;
3223ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ mov(ebx, FieldOperand(ecx, JSArray::kElementsOffset));
3233ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ CheckMap(ebx, factory->fixed_cow_array_map(),
3243ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                &check_fast_elements, DONT_DO_SMI_CHECK);
3253ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    GenerateFastCloneShallowArrayCommon(masm, 0,
3263ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                                        COPY_ON_WRITE_ELEMENTS, &slow_case);
3273ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ ret(3 * kPointerSize);
3283ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
3293ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ bind(&check_fast_elements);
3303ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ CheckMap(ebx, factory->fixed_array_map(),
3313ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                &double_elements, DONT_DO_SMI_CHECK);
3323ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    GenerateFastCloneShallowArrayCommon(masm, length_,
3333ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                                        CLONE_ELEMENTS, &slow_case);
3343ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ ret(3 * kPointerSize);
3353ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
3363ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ bind(&double_elements);
3373ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    mode = CLONE_DOUBLE_ELEMENTS;
3383ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    // Fall through to generate the code to handle double elements.
3393ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  }
3403ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
34180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  if (FLAG_debug_code) {
34280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    const char* message;
34380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    Handle<Map> expected_map;
3443ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    if (mode == CLONE_ELEMENTS) {
34580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      message = "Expected (writable) fixed array";
34644f0eee88ff00398ff7f715fab053374d808c90dSteve Block      expected_map = factory->fixed_array_map();
3473ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    } else if (mode == CLONE_DOUBLE_ELEMENTS) {
3483ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      message = "Expected (writable) fixed double array";
3493ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      expected_map = factory->fixed_double_array_map();
35080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    } else {
3513ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      ASSERT(mode == COPY_ON_WRITE_ELEMENTS);
35280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      message = "Expected copy-on-write fixed array";
35344f0eee88ff00398ff7f715fab053374d808c90dSteve Block      expected_map = factory->fixed_cow_array_map();
35480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    }
35580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ push(ecx);
35680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ mov(ecx, FieldOperand(ecx, JSArray::kElementsOffset));
35780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ cmp(FieldOperand(ecx, HeapObject::kMapOffset), expected_map);
35880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ Assert(equal, message);
35980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ pop(ecx);
36080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
36180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
3623ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  GenerateFastCloneShallowArrayCommon(masm, length_, mode, &slow_case);
3633ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Return and remove the on-stack parameters.
3643ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ ret(3 * kPointerSize);
365592a9fc1d8ea420377a2e7efd0600e20b058be2bBen Murdoch
3663ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ bind(&slow_case);
3673ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ TailCallRuntime(Runtime::kCreateArrayLiteralShallow, 3, 1);
3683ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch}
369592a9fc1d8ea420377a2e7efd0600e20b058be2bBen Murdoch
370592a9fc1d8ea420377a2e7efd0600e20b058be2bBen Murdoch
3713ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochvoid FastCloneShallowObjectStub::Generate(MacroAssembler* masm) {
3723ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Stack layout on entry:
3733ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  //
3743ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // [esp + kPointerSize]: object literal flags.
3753ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // [esp + (2 * kPointerSize)]: constant properties.
3763ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // [esp + (3 * kPointerSize)]: literal index.
3773ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // [esp + (4 * kPointerSize)]: literals array.
3783ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
3793ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Load boilerplate object into ecx and check if we need to create a
3803ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // boilerplate.
3813ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  Label slow_case;
3823ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ mov(ecx, Operand(esp, 4 * kPointerSize));
3833ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ mov(eax, Operand(esp, 3 * kPointerSize));
3843ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  STATIC_ASSERT(kPointerSize == 4);
3853ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  STATIC_ASSERT(kSmiTagSize == 1);
3863ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  STATIC_ASSERT(kSmiTag == 0);
3873ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ mov(ecx, FieldOperand(ecx, eax, times_half_pointer_size,
3883ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                           FixedArray::kHeaderSize));
3893ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  Factory* factory = masm->isolate()->factory();
3903ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ cmp(ecx, factory->undefined_value());
3913ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ j(equal, &slow_case);
3923ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
3933ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Check that the boilerplate contains only fast properties and we can
3943ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // statically determine the instance size.
3953ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  int size = JSObject::kHeaderSize + length_ * kPointerSize;
3963ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ mov(eax, FieldOperand(ecx, HeapObject::kMapOffset));
3973ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ movzx_b(eax, FieldOperand(eax, Map::kInstanceSizeOffset));
3983ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ cmp(eax, Immediate(size >> kPointerSizeLog2));
3993ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ j(not_equal, &slow_case);
4003ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
4013ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Allocate the JS object and copy header together with all in-object
4023ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // properties from the boilerplate.
4033ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ AllocateInNewSpace(size, eax, ebx, edx, &slow_case, TAG_OBJECT);
4043ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  for (int i = 0; i < size; i += kPointerSize) {
4053ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ mov(ebx, FieldOperand(ecx, i));
4063ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ mov(FieldOperand(eax, i), ebx);
40780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
40880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
40980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Return and remove the on-stack parameters.
4103ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ ret(4 * kPointerSize);
41180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
41280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&slow_case);
4133ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ TailCallRuntime(Runtime::kCreateObjectLiteralShallow, 4, 1);
41480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
41580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
41680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
41769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch// The stub expects its argument on the stack and returns its result in tos_:
41869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch// zero for false, and a non-zero value for true.
41980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid ToBooleanStub::Generate(MacroAssembler* masm) {
4203ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // This stub overrides SometimesSetsUpAFrame() to return false.  That means
4213ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // we cannot call anything that could cause a GC from this stub.
42269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  Label patch;
423257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Factory* factory = masm->isolate()->factory();
42469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  const Register argument = eax;
4253fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  const Register map = edx;
4263fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
42769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  if (!types_.IsEmpty()) {
42869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    __ mov(argument, Operand(esp, 1 * kPointerSize));
42969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  }
430257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
431257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // undefined -> false
43269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  CheckOddball(masm, UNDEFINED, Heap::kUndefinedValueRootIndex, false);
433257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
434257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Boolean -> its value
43569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  CheckOddball(masm, BOOLEAN, Heap::kFalseValueRootIndex, false);
43669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  CheckOddball(masm, BOOLEAN, Heap::kTrueValueRootIndex, true);
43780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
4383fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // 'null' -> false.
43969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  CheckOddball(masm, NULL_TYPE, Heap::kNullValueRootIndex, false);
44080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
44169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  if (types_.Contains(SMI)) {
44269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    // Smis: 0 -> false, all other -> true
44369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    Label not_smi;
44469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    __ JumpIfNotSmi(argument, &not_smi, Label::kNear);
44569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    // argument contains the correct return value already.
44669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    if (!tos_.is(argument)) {
44769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch      __ mov(tos_, argument);
44869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    }
44969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    __ ret(1 * kPointerSize);
45069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    __ bind(&not_smi);
45169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  } else if (types_.NeedsMap()) {
45269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    // If we need a map later and have a Smi -> patch.
45369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    __ JumpIfSmi(argument, &patch, Label::kNear);
45469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  }
45580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
45669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  if (types_.NeedsMap()) {
45769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    __ mov(map, FieldOperand(argument, HeapObject::kMapOffset));
45869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch
45969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    if (types_.CanBeUndetectable()) {
46069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch      __ test_b(FieldOperand(map, Map::kBitFieldOffset),
46169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch                1 << Map::kIsUndetectable);
46269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch      // Undetectable -> false.
46369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch      Label not_undetectable;
46469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch      __ j(zero, &not_undetectable, Label::kNear);
46569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch      __ Set(tos_, Immediate(0));
46669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch      __ ret(1 * kPointerSize);
46769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch      __ bind(&not_undetectable);
46869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    }
46969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  }
47080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
47169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  if (types_.Contains(SPEC_OBJECT)) {
47269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    // spec object -> true.
47369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    Label not_js_object;
47469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    __ CmpInstanceType(map, FIRST_SPEC_OBJECT_TYPE);
47569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    __ j(below, &not_js_object, Label::kNear);
47669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    // argument contains the correct return value already.
47769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    if (!tos_.is(argument)) {
47869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch      __ Set(tos_, Immediate(1));
47969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    }
48069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    __ ret(1 * kPointerSize);
48169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    __ bind(&not_js_object);
48269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  }
48380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
48469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  if (types_.Contains(STRING)) {
48569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    // String value -> false iff empty.
48669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    Label not_string;
48769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    __ CmpInstanceType(map, FIRST_NONSTRING_TYPE);
48869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    __ j(above_equal, &not_string, Label::kNear);
48969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    __ mov(tos_, FieldOperand(argument, String::kLengthOffset));
49069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    __ ret(1 * kPointerSize);  // the string length is OK as the return value
49169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    __ bind(&not_string);
49269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  }
49380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
49469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  if (types_.Contains(HEAP_NUMBER)) {
49569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    // heap number -> false iff +0, -0, or NaN.
49669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    Label not_heap_number, false_result;
49769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    __ cmp(map, factory->heap_number_map());
49869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    __ j(not_equal, &not_heap_number, Label::kNear);
49969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    __ fldz();
50069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    __ fld_d(FieldOperand(argument, HeapNumber::kValueOffset));
50169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    __ FCmp();
50269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    __ j(zero, &false_result, Label::kNear);
50369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    // argument contains the correct return value already.
50469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    if (!tos_.is(argument)) {
50569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch      __ Set(tos_, Immediate(1));
50669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    }
50769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    __ ret(1 * kPointerSize);
50869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    __ bind(&false_result);
50969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    __ Set(tos_, Immediate(0));
51069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    __ ret(1 * kPointerSize);
51169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    __ bind(&not_heap_number);
51269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  }
51369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch
51469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ bind(&patch);
51569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  GenerateTypeTransition(masm);
51669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch}
51769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch
51869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch
5193ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochvoid StoreBufferOverflowStub::Generate(MacroAssembler* masm) {
5203ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // We don't allow a GC during a store buffer overflow so there is no need to
5213ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // store the registers in any particular way, but we do have to store and
5223ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // restore them.
5233ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ pushad();
5243ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  if (save_doubles_ == kSaveFPRegs) {
5253ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    CpuFeatures::Scope scope(SSE2);
5263ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ sub(esp, Immediate(kDoubleSize * XMMRegister::kNumRegisters));
5273ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    for (int i = 0; i < XMMRegister::kNumRegisters; i++) {
5283ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      XMMRegister reg = XMMRegister::from_code(i);
5293ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      __ movdbl(Operand(esp, i * kDoubleSize), reg);
5303ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    }
5313ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  }
5323ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  const int argument_count = 1;
5333ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
5343ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  AllowExternalCallThatCantCauseGC scope(masm);
5353ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ PrepareCallCFunction(argument_count, ecx);
5363ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ mov(Operand(esp, 0 * kPointerSize),
5373ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch         Immediate(ExternalReference::isolate_address()));
5383ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ CallCFunction(
5393ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      ExternalReference::store_buffer_overflow_function(masm->isolate()),
5403ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      argument_count);
5413ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  if (save_doubles_ == kSaveFPRegs) {
5423ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    CpuFeatures::Scope scope(SSE2);
5433ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    for (int i = 0; i < XMMRegister::kNumRegisters; i++) {
5443ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      XMMRegister reg = XMMRegister::from_code(i);
5453ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      __ movdbl(reg, Operand(esp, i * kDoubleSize));
5463ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    }
5473ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ add(esp, Immediate(kDoubleSize * XMMRegister::kNumRegisters));
5483ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  }
5493ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ popad();
5503ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ ret(0);
5513ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch}
5523ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
5533ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
55469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdochvoid ToBooleanStub::CheckOddball(MacroAssembler* masm,
55569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch                                 Type type,
55669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch                                 Heap::RootListIndex value,
55769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch                                 bool result) {
55869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  const Register argument = eax;
55969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  if (types_.Contains(type)) {
56069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    // If we see an expected oddball, return its ToBoolean value tos_.
56169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    Label different_value;
56269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    __ CompareRoot(argument, value);
56369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    __ j(not_equal, &different_value, Label::kNear);
56469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    if (!result) {
56569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch      // If we have to return zero, there is no way around clearing tos_.
56669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch      __ Set(tos_, Immediate(0));
56769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    } else if (!tos_.is(argument)) {
56869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch      // If we have to return non-zero, we can re-use the argument if it is the
56969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch      // same register as the result, because we never see Smi-zero here.
57069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch      __ Set(tos_, Immediate(1));
57169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    }
57269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    __ ret(1 * kPointerSize);
57369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    __ bind(&different_value);
57469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  }
57569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch}
57669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch
57769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch
57869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdochvoid ToBooleanStub::GenerateTypeTransition(MacroAssembler* masm) {
57969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ pop(ecx);  // Get return address, operand is now on top of stack.
58069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ push(Immediate(Smi::FromInt(tos_.code())));
58169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ push(Immediate(Smi::FromInt(types_.ToByte())));
58269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ push(ecx);  // Push return address.
58369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  // Patch the caller to an appropriate specialized stub and return the
58469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  // operation result to the caller of the stub.
58569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ TailCallExternalReference(
58669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch      ExternalReference(IC_Utility(IC::kToBoolean_Patch), masm->isolate()),
58769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch      3,
58869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch      1);
58980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
59080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
59180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
5928b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdochclass FloatingPointHelper : public AllStatic {
5938b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch public:
5948b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  enum ArgLocation {
5958b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch    ARGS_ON_STACK,
5968b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch    ARGS_IN_REGISTERS
5978b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  };
59880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
5998b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  // Code pattern for loading a floating point value. Input value must
6008b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  // be either a smi or a heap number object (fp value). Requirements:
6018b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  // operand in register number. Returns operand as floating point number
6028b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  // on FPU stack.
6038b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  static void LoadFloatOperand(MacroAssembler* masm, Register number);
60480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
6058b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  // Code pattern for loading floating point values. Input values must
6068b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  // be either smi or heap number objects (fp values). Requirements:
6078b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  // operand_1 on TOS+1 or in edx, operand_2 on TOS+2 or in eax.
6088b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  // Returns operands as floating point numbers on FPU stack.
6098b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  static void LoadFloatOperands(MacroAssembler* masm,
6108b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch                                Register scratch,
6118b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch                                ArgLocation arg_location = ARGS_ON_STACK);
61280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
6138b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  // Similar to LoadFloatOperand but assumes that both operands are smis.
6148b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  // Expects operands in edx, eax.
6158b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  static void LoadFloatSmis(MacroAssembler* masm, Register scratch);
616b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
6178b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  // Test if operands are smi or number objects (fp). Requirements:
6188b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  // operand_1 in eax, operand_2 in edx; falls through on float
6198b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  // operands, jumps to the non_float label otherwise.
6208b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  static void CheckFloatOperands(MacroAssembler* masm,
6218b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch                                 Label* non_float,
6228b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch                                 Register scratch);
623b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
6248b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  // Checks that the two floating point numbers on top of the FPU stack
6258b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  // have int32 values.
6268b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  static void CheckFloatOperandsAreInt32(MacroAssembler* masm,
6278b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch                                         Label* non_int32);
628b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
6298b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  // Takes the operands in edx and eax and loads them as integers in eax
6308b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  // and ecx.
6318b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  static void LoadUnknownsAsIntegers(MacroAssembler* masm,
6328b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch                                     bool use_sse3,
6338b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch                                     Label* operand_conversion_failure);
634b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
6358b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  // Must only be called after LoadUnknownsAsIntegers.  Assumes that the
6368b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  // operands are pushed on the stack, and that their conversions to int32
6378b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  // are in eax and ecx.  Checks that the original numbers were in the int32
6388b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  // range.
6398b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  static void CheckLoadedIntegersWereInt32(MacroAssembler* masm,
6408b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch                                           bool use_sse3,
6418b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch                                           Label* not_int32);
642b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
6438b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  // Assumes that operands are smis or heap numbers and loads them
6448b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  // into xmm0 and xmm1. Operands are in edx and eax.
6458b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  // Leaves operands unchanged.
6468b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  static void LoadSSE2Operands(MacroAssembler* masm);
647b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
6488b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  // Test if operands are numbers (smi or HeapNumber objects), and load
6498b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  // them into xmm0 and xmm1 if they are.  Jump to label not_numbers if
6508b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  // either operand is not a number.  Operands are in edx and eax.
6518b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  // Leaves operands unchanged.
6528b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  static void LoadSSE2Operands(MacroAssembler* masm, Label* not_numbers);
653b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
6548b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  // Similar to LoadSSE2Operands but assumes that both operands are smis.
6558b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  // Expects operands in edx, eax.
6568b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  static void LoadSSE2Smis(MacroAssembler* masm, Register scratch);
657b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
658257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Checks that the two floating point numbers loaded into xmm0 and xmm1
659257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // have int32 values.
660257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  static void CheckSSE2OperandsAreInt32(MacroAssembler* masm,
661257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                        Label* non_int32,
662257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                        Register scratch);
663257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch};
664257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
665257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
666257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// Get the integer part of a heap number.  Surprisingly, all this bit twiddling
667257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// is faster than using the built-in instructions on floating point registers.
668257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// Trashes edi and ebx.  Dest is ecx.  Source cannot be ecx or one of the
669257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// trashed registers.
670257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochstatic void IntegerConvert(MacroAssembler* masm,
671257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                           Register source,
672257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                           bool use_sse3,
673257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                           Label* conversion_failure) {
674257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  ASSERT(!source.is(ecx) && !source.is(edi) && !source.is(ebx));
675257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label done, right_exponent, normal_exponent;
676257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Register scratch = ebx;
677257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Register scratch2 = edi;
678257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Get exponent word.
679257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ mov(scratch, FieldOperand(source, HeapNumber::kExponentOffset));
680257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Get exponent alone in scratch2.
681257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ mov(scratch2, scratch);
682257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ and_(scratch2, HeapNumber::kExponentMask);
683257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  if (use_sse3) {
684257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    CpuFeatures::Scope scope(SSE3);
685257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Check whether the exponent is too big for a 64 bit signed integer.
686257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    static const uint32_t kTooBigExponent =
687257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        (HeapNumber::kExponentBias + 63) << HeapNumber::kExponentShift;
6883ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ cmp(scratch2, Immediate(kTooBigExponent));
689257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ j(greater_equal, conversion_failure);
690257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Load x87 register with heap number.
691257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ fld_d(FieldOperand(source, HeapNumber::kValueOffset));
692257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Reserve space for 64 bit answer.
6933ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ sub(esp, Immediate(sizeof(uint64_t)));  // Nolint.
694257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Do conversion, which cannot fail because we checked the exponent.
695257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ fisttp_d(Operand(esp, 0));
696257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ mov(ecx, Operand(esp, 0));  // Load low word of answer into ecx.
6973ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ add(esp, Immediate(sizeof(uint64_t)));  // Nolint.
698257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  } else {
699257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Load ecx with zero.  We use this either for the final shift or
700257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // for the answer.
7013ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ xor_(ecx, ecx);
702257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Check whether the exponent matches a 32 bit signed int that cannot be
703257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // represented by a Smi.  A non-smi 32 bit integer is 1.xxx * 2^30 so the
704257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // exponent is 30 (biased).  This is the exponent that we are fastest at and
705257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // also the highest exponent we can handle here.
706257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    const uint32_t non_smi_exponent =
707257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        (HeapNumber::kExponentBias + 30) << HeapNumber::kExponentShift;
7083ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ cmp(scratch2, Immediate(non_smi_exponent));
709257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // If we have a match of the int32-but-not-Smi exponent then skip some
710257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // logic.
71169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    __ j(equal, &right_exponent, Label::kNear);
712257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // If the exponent is higher than that then go to slow case.  This catches
713257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // numbers that don't fit in a signed int32, infinities and NaNs.
71469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    __ j(less, &normal_exponent, Label::kNear);
715257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
716257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    {
717257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // Handle a big exponent.  The only reason we have this code is that the
718257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // >>> operator has a tendency to generate numbers with an exponent of 31.
719257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      const uint32_t big_non_smi_exponent =
720257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          (HeapNumber::kExponentBias + 31) << HeapNumber::kExponentShift;
7213ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      __ cmp(scratch2, Immediate(big_non_smi_exponent));
722257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ j(not_equal, conversion_failure);
723257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // We have the big exponent, typically from >>>.  This means the number is
724257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // in the range 2^31 to 2^32 - 1.  Get the top bits of the mantissa.
725257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ mov(scratch2, scratch);
726257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ and_(scratch2, HeapNumber::kMantissaMask);
727257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // Put back the implicit 1.
728257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ or_(scratch2, 1 << HeapNumber::kExponentShift);
729257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // Shift up the mantissa bits to take up the space the exponent used to
730257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // take. We just orred in the implicit bit so that took care of one and
731257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // we want to use the full unsigned range so we subtract 1 bit from the
732257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // shift distance.
733257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      const int big_shift_distance = HeapNumber::kNonMantissaBitsInTopWord - 1;
734257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ shl(scratch2, big_shift_distance);
735257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // Get the second half of the double.
736257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ mov(ecx, FieldOperand(source, HeapNumber::kMantissaOffset));
737257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // Shift down 21 bits to get the most significant 11 bits or the low
738257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // mantissa word.
739257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ shr(ecx, 32 - big_shift_distance);
7403ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      __ or_(ecx, scratch2);
741257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // We have the answer in ecx, but we may need to negate it.
7423ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      __ test(scratch, scratch);
74369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch      __ j(positive, &done, Label::kNear);
744257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ neg(ecx);
74569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch      __ jmp(&done, Label::kNear);
746257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    }
747257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
748257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ bind(&normal_exponent);
749257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Exponent word in scratch, exponent part of exponent word in scratch2.
750257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Zero in ecx.
751257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // We know the exponent is smaller than 30 (biased).  If it is less than
7523ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    // 0 (biased) then the number is smaller in magnitude than 1.0 * 2^0, i.e.
753257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // it rounds to zero.
754257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    const uint32_t zero_exponent =
755257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        (HeapNumber::kExponentBias + 0) << HeapNumber::kExponentShift;
7563ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ sub(scratch2, Immediate(zero_exponent));
757257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // ecx already has a Smi zero.
75869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    __ j(less, &done, Label::kNear);
759257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
760257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // We have a shifted exponent between 0 and 30 in scratch2.
761257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ shr(scratch2, HeapNumber::kExponentShift);
762257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ mov(ecx, Immediate(30));
7633ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ sub(ecx, scratch2);
764257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
765257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ bind(&right_exponent);
766257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Here ecx is the shift, scratch is the exponent word.
767257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Get the top bits of the mantissa.
768257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ and_(scratch, HeapNumber::kMantissaMask);
769257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Put back the implicit 1.
770257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ or_(scratch, 1 << HeapNumber::kExponentShift);
771257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Shift up the mantissa bits to take up the space the exponent used to
772257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // take. We have kExponentShift + 1 significant bits int he low end of the
773257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // word.  Shift them to the top bits.
774257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    const int shift_distance = HeapNumber::kNonMantissaBitsInTopWord - 2;
775257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ shl(scratch, shift_distance);
776257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Get the second half of the double. For some exponents we don't
777257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // actually need this because the bits get shifted out again, but
778257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // it's probably slower to test than just to do it.
779257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ mov(scratch2, FieldOperand(source, HeapNumber::kMantissaOffset));
780257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Shift down 22 bits to get the most significant 10 bits or the low
781257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // mantissa word.
782257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ shr(scratch2, 32 - shift_distance);
7833ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ or_(scratch2, scratch);
784257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Move down according to the exponent.
785257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ shr_cl(scratch2);
786257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Now the unsigned answer is in scratch2.  We need to move it to ecx and
787257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // we may need to fix the sign.
788257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Label negative;
7893ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ xor_(ecx, ecx);
790257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ cmp(ecx, FieldOperand(source, HeapNumber::kExponentOffset));
791257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ j(greater, &negative, Label::kNear);
792257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ mov(ecx, scratch2);
793257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ jmp(&done, Label::kNear);
794257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ bind(&negative);
7953ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ sub(ecx, scratch2);
796257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ bind(&done);
797257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
798257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch}
799257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
800257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
8013fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdochvoid UnaryOpStub::PrintName(StringStream* stream) {
802257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  const char* op_name = Token::Name(op_);
803257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  const char* overwrite_name = NULL;  // Make g++ happy.
804257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  switch (mode_) {
805257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case UNARY_NO_OVERWRITE: overwrite_name = "Alloc"; break;
806257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case UNARY_OVERWRITE: overwrite_name = "Overwrite"; break;
807257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
8083fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  stream->Add("UnaryOpStub_%s_%s_%s",
8093fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch              op_name,
8103fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch              overwrite_name,
8113fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch              UnaryOpIC::GetName(operand_type_));
812257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch}
813257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
814257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
815257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// TODO(svenpanne): Use virtual functions instead of switch.
816257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::Generate(MacroAssembler* masm) {
817257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  switch (operand_type_) {
818257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case UnaryOpIC::UNINITIALIZED:
819257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      GenerateTypeTransition(masm);
820257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      break;
821257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case UnaryOpIC::SMI:
822257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      GenerateSmiStub(masm);
823257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      break;
824257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case UnaryOpIC::HEAP_NUMBER:
825257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      GenerateHeapNumberStub(masm);
826257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      break;
827257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case UnaryOpIC::GENERIC:
828257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      GenerateGenericStub(masm);
829257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      break;
830257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
831257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch}
832257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
833257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
834257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::GenerateTypeTransition(MacroAssembler* masm) {
835257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ pop(ecx);  // Save return address.
8363fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
8373fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ push(eax);  // the operand
838257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ push(Immediate(Smi::FromInt(op_)));
8393fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ push(Immediate(Smi::FromInt(mode_)));
840257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ push(Immediate(Smi::FromInt(operand_type_)));
841257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
842257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ push(ecx);  // Push return address.
843257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
844257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Patch the caller to an appropriate specialized stub and return the
845257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // operation result to the caller of the stub.
846257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ TailCallExternalReference(
8473fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch      ExternalReference(IC_Utility(IC::kUnaryOp_Patch), masm->isolate()), 4, 1);
848257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch}
849257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
850257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
851257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// TODO(svenpanne): Use virtual functions instead of switch.
852257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::GenerateSmiStub(MacroAssembler* masm) {
853257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  switch (op_) {
854257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case Token::SUB:
855257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      GenerateSmiStubSub(masm);
856257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      break;
857257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case Token::BIT_NOT:
858257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      GenerateSmiStubBitNot(masm);
859257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      break;
860257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    default:
861257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      UNREACHABLE();
862257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
863257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch}
864257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
865257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
866257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::GenerateSmiStubSub(MacroAssembler* masm) {
867257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label non_smi, undo, slow;
868257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  GenerateSmiCodeSub(masm, &non_smi, &undo, &slow,
869257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                     Label::kNear, Label::kNear, Label::kNear);
870257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&undo);
871257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  GenerateSmiCodeUndo(masm);
872257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&non_smi);
873257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&slow);
874257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  GenerateTypeTransition(masm);
875257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch}
876257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
877257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
878257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::GenerateSmiStubBitNot(MacroAssembler* masm) {
879257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label non_smi;
880257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  GenerateSmiCodeBitNot(masm, &non_smi);
881257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&non_smi);
882257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  GenerateTypeTransition(masm);
883257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch}
884257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
885257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
886257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::GenerateSmiCodeSub(MacroAssembler* masm,
887257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                     Label* non_smi,
888257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                     Label* undo,
889257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                     Label* slow,
890257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                     Label::Distance non_smi_near,
891257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                     Label::Distance undo_near,
892257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                     Label::Distance slow_near) {
893257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Check whether the value is a smi.
8943fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ JumpIfNotSmi(eax, non_smi, non_smi_near);
895257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
896257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // We can't handle -0 with smis, so use a type transition for that case.
8973ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ test(eax, eax);
898257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(zero, slow, slow_near);
899257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
900257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Try optimistic subtraction '0 - value', saving operand in eax for undo.
9013ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ mov(edx, eax);
902257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Set(eax, Immediate(0));
9033ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ sub(eax, edx);
904257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(overflow, undo, undo_near);
905257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ ret(0);
906257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch}
907257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
908257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
909257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::GenerateSmiCodeBitNot(
910257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    MacroAssembler* masm,
911257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Label* non_smi,
912257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Label::Distance non_smi_near) {
913257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Check whether the value is a smi.
9143fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ JumpIfNotSmi(eax, non_smi, non_smi_near);
915257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
916257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Flip bits and revert inverted smi-tag.
917257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ not_(eax);
918257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ and_(eax, ~kSmiTagMask);
919257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ ret(0);
920257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch}
921257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
922257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
923257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::GenerateSmiCodeUndo(MacroAssembler* masm) {
9243ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ mov(eax, edx);
925257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch}
926257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
927257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
928257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// TODO(svenpanne): Use virtual functions instead of switch.
929257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::GenerateHeapNumberStub(MacroAssembler* masm) {
930257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  switch (op_) {
931257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case Token::SUB:
932257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      GenerateHeapNumberStubSub(masm);
933257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      break;
934257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case Token::BIT_NOT:
935257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      GenerateHeapNumberStubBitNot(masm);
936257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      break;
937257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    default:
938257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      UNREACHABLE();
939257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
940257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch}
941257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
942257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
943257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::GenerateHeapNumberStubSub(MacroAssembler* masm) {
944257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label non_smi, undo, slow, call_builtin;
945257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  GenerateSmiCodeSub(masm, &non_smi, &undo, &call_builtin, Label::kNear);
946257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&non_smi);
947257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  GenerateHeapNumberCodeSub(masm, &slow);
948257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&undo);
949257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  GenerateSmiCodeUndo(masm);
950257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&slow);
951257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  GenerateTypeTransition(masm);
952257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&call_builtin);
953257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  GenerateGenericCodeFallback(masm);
954257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch}
955257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
956257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
957257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::GenerateHeapNumberStubBitNot(
958257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    MacroAssembler* masm) {
959257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label non_smi, slow;
960257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  GenerateSmiCodeBitNot(masm, &non_smi, Label::kNear);
961257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&non_smi);
962257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  GenerateHeapNumberCodeBitNot(masm, &slow);
963257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&slow);
964257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  GenerateTypeTransition(masm);
965257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch}
966257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
967257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
968257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::GenerateHeapNumberCodeSub(MacroAssembler* masm,
969257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                            Label* slow) {
970257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ mov(edx, FieldOperand(eax, HeapObject::kMapOffset));
971257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ cmp(edx, masm->isolate()->factory()->heap_number_map());
972257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(not_equal, slow);
973257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
974257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  if (mode_ == UNARY_OVERWRITE) {
975257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ xor_(FieldOperand(eax, HeapNumber::kExponentOffset),
976257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch            Immediate(HeapNumber::kSignMask));  // Flip sign.
977257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  } else {
9783ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ mov(edx, eax);
979257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // edx: operand
980257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
981257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Label slow_allocate_heapnumber, heapnumber_allocated;
982257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ AllocateHeapNumber(eax, ebx, ecx, &slow_allocate_heapnumber);
98369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    __ jmp(&heapnumber_allocated, Label::kNear);
984257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
985257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ bind(&slow_allocate_heapnumber);
9863ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    {
9873ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      FrameScope scope(masm, StackFrame::INTERNAL);
9883ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      __ push(edx);
9893ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      __ CallRuntime(Runtime::kNumberAlloc, 0);
9903ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      __ pop(edx);
9913ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    }
992257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
993257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ bind(&heapnumber_allocated);
994257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // eax: allocated 'empty' number
995257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ mov(ecx, FieldOperand(edx, HeapNumber::kExponentOffset));
996257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ xor_(ecx, HeapNumber::kSignMask);  // Flip sign.
997257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ mov(FieldOperand(eax, HeapNumber::kExponentOffset), ecx);
998257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ mov(ecx, FieldOperand(edx, HeapNumber::kMantissaOffset));
999257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ mov(FieldOperand(eax, HeapNumber::kMantissaOffset), ecx);
1000257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
1001257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ ret(0);
1002257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch}
1003257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1004257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1005257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::GenerateHeapNumberCodeBitNot(MacroAssembler* masm,
1006257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                               Label* slow) {
1007257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ mov(edx, FieldOperand(eax, HeapObject::kMapOffset));
1008257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ cmp(edx, masm->isolate()->factory()->heap_number_map());
1009257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(not_equal, slow);
1010257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1011257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Convert the heap number in eax to an untagged integer in ecx.
1012257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  IntegerConvert(masm, eax, CpuFeatures::IsSupported(SSE3), slow);
1013257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1014257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Do the bitwise operation and check if the result fits in a smi.
1015257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label try_float;
1016257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ not_(ecx);
1017257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ cmp(ecx, 0xc0000000);
1018257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(sign, &try_float, Label::kNear);
1019257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1020257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Tag the result as a smi and we're done.
1021257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  STATIC_ASSERT(kSmiTagSize == 1);
1022257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ lea(eax, Operand(ecx, times_2, kSmiTag));
1023257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ ret(0);
1024257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1025257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Try to store the result in a heap number.
1026257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&try_float);
1027257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  if (mode_ == UNARY_NO_OVERWRITE) {
1028257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Label slow_allocate_heapnumber, heapnumber_allocated;
1029257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ mov(ebx, eax);
1030257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ AllocateHeapNumber(eax, edx, edi, &slow_allocate_heapnumber);
1031257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ jmp(&heapnumber_allocated);
1032257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1033257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ bind(&slow_allocate_heapnumber);
10343ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    {
10353ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      FrameScope scope(masm, StackFrame::INTERNAL);
10363ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      // Push the original HeapNumber on the stack. The integer value can't
10373ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      // be stored since it's untagged and not in the smi range (so we can't
10383ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      // smi-tag it). We'll recalculate the value after the GC instead.
10393ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      __ push(ebx);
10403ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      __ CallRuntime(Runtime::kNumberAlloc, 0);
10413ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      // New HeapNumber is in eax.
10423ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      __ pop(edx);
10433ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    }
1044257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // IntegerConvert uses ebx and edi as scratch registers.
1045257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // This conversion won't go slow-case.
1046257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    IntegerConvert(masm, edx, CpuFeatures::IsSupported(SSE3), slow);
1047257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ not_(ecx);
1048257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1049257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ bind(&heapnumber_allocated);
1050257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
1051257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  if (CpuFeatures::IsSupported(SSE2)) {
1052257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    CpuFeatures::Scope use_sse2(SSE2);
10533ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ cvtsi2sd(xmm0, ecx);
1054257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0);
1055257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  } else {
1056257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ push(ecx);
1057257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ fild_s(Operand(esp, 0));
1058257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ pop(ecx);
1059257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset));
1060257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
1061257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ ret(0);
1062257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch}
1063257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1064257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1065257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// TODO(svenpanne): Use virtual functions instead of switch.
1066257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::GenerateGenericStub(MacroAssembler* masm) {
1067257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  switch (op_) {
1068257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case Token::SUB:
1069257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      GenerateGenericStubSub(masm);
1070257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      break;
1071257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case Token::BIT_NOT:
1072257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      GenerateGenericStubBitNot(masm);
1073257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      break;
1074257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    default:
1075257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      UNREACHABLE();
1076257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
1077257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch}
1078257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1079257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1080257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::GenerateGenericStubSub(MacroAssembler* masm)  {
1081257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label non_smi, undo, slow;
1082257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  GenerateSmiCodeSub(masm, &non_smi, &undo, &slow, Label::kNear);
1083257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&non_smi);
1084257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  GenerateHeapNumberCodeSub(masm, &slow);
1085257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&undo);
1086257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  GenerateSmiCodeUndo(masm);
1087257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&slow);
1088257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  GenerateGenericCodeFallback(masm);
1089257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch}
1090257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1091257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1092257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::GenerateGenericStubBitNot(MacroAssembler* masm) {
1093257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label non_smi, slow;
1094257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  GenerateSmiCodeBitNot(masm, &non_smi, Label::kNear);
1095257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&non_smi);
1096257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  GenerateHeapNumberCodeBitNot(masm, &slow);
1097257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&slow);
1098257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  GenerateGenericCodeFallback(masm);
1099257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch}
1100257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1101257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1102257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::GenerateGenericCodeFallback(MacroAssembler* masm) {
1103257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Handle the slow case by jumping to the corresponding JavaScript builtin.
1104257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ pop(ecx);  // pop return address.
1105257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ push(eax);
1106257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ push(ecx);  // push return address
1107257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  switch (op_) {
1108257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case Token::SUB:
1109257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ InvokeBuiltin(Builtins::UNARY_MINUS, JUMP_FUNCTION);
1110257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      break;
1111257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case Token::BIT_NOT:
1112257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ InvokeBuiltin(Builtins::BIT_NOT, JUMP_FUNCTION);
1113257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      break;
1114257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    default:
1115257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      UNREACHABLE();
1116257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
1117257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch}
1118b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1119b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1120257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid BinaryOpStub::GenerateTypeTransition(MacroAssembler* masm) {
1121b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ pop(ecx);  // Save return address.
1122b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ push(edx);
1123b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ push(eax);
1124b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Left and right arguments are now on top.
1125b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Push this stub's key. Although the operation and the type info are
1126b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // encoded into the key, the encoding is opaque, so push them too.
1127b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ push(Immediate(Smi::FromInt(MinorKey())));
1128b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ push(Immediate(Smi::FromInt(op_)));
1129b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ push(Immediate(Smi::FromInt(operands_type_)));
1130b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1131b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ push(ecx);  // Push return address.
1132b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1133b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Patch the caller to an appropriate specialized stub and return the
1134b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // operation result to the caller of the stub.
1135b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ TailCallExternalReference(
1136257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      ExternalReference(IC_Utility(IC::kBinaryOp_Patch),
113744f0eee88ff00398ff7f715fab053374d808c90dSteve Block                        masm->isolate()),
1138b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      5,
1139b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      1);
1140b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch}
1141b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1142b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1143b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch// Prepare for a type transition runtime call when the args are already on
1144b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch// the stack, under the return address.
1145257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid BinaryOpStub::GenerateTypeTransitionWithSavedArgs(MacroAssembler* masm) {
1146b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ pop(ecx);  // Save return address.
1147b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Left and right arguments are already on top of the stack.
1148b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Push this stub's key. Although the operation and the type info are
1149b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // encoded into the key, the encoding is opaque, so push them too.
1150b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ push(Immediate(Smi::FromInt(MinorKey())));
1151b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ push(Immediate(Smi::FromInt(op_)));
1152b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ push(Immediate(Smi::FromInt(operands_type_)));
1153b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1154b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ push(ecx);  // Push return address.
1155b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1156b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Patch the caller to an appropriate specialized stub and return the
1157b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // operation result to the caller of the stub.
1158b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ TailCallExternalReference(
1159257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      ExternalReference(IC_Utility(IC::kBinaryOp_Patch),
116044f0eee88ff00398ff7f715fab053374d808c90dSteve Block                        masm->isolate()),
1161b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      5,
1162b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      1);
1163b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch}
1164b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1165b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1166257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid BinaryOpStub::Generate(MacroAssembler* masm) {
11673ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Explicitly allow generation of nested stubs. It is safe here because
11683ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // generation code does not use any raw pointers.
11693ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  AllowStubCallsScope allow_stub_calls(masm, true);
11703ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
1171b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  switch (operands_type_) {
1172257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case BinaryOpIC::UNINITIALIZED:
1173b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      GenerateTypeTransition(masm);
1174b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1175257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case BinaryOpIC::SMI:
1176b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      GenerateSmiStub(masm);
1177b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1178257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case BinaryOpIC::INT32:
1179b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      GenerateInt32Stub(masm);
1180b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1181257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case BinaryOpIC::HEAP_NUMBER:
1182b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      GenerateHeapNumberStub(masm);
1183b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1184257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case BinaryOpIC::ODDBALL:
118544f0eee88ff00398ff7f715fab053374d808c90dSteve Block      GenerateOddballStub(masm);
118644f0eee88ff00398ff7f715fab053374d808c90dSteve Block      break;
1187257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case BinaryOpIC::BOTH_STRING:
1188257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      GenerateBothStringStub(masm);
1189257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      break;
1190257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case BinaryOpIC::STRING:
1191b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      GenerateStringStub(masm);
1192b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1193257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case BinaryOpIC::GENERIC:
1194b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      GenerateGeneric(masm);
1195b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1196b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    default:
1197b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      UNREACHABLE();
1198b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  }
1199b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch}
1200b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1201b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
12023fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdochvoid BinaryOpStub::PrintName(StringStream* stream) {
1203b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  const char* op_name = Token::Name(op_);
1204b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  const char* overwrite_name;
1205b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  switch (mode_) {
1206b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case NO_OVERWRITE: overwrite_name = "Alloc"; break;
1207b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case OVERWRITE_RIGHT: overwrite_name = "OverwriteRight"; break;
1208b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case OVERWRITE_LEFT: overwrite_name = "OverwriteLeft"; break;
1209b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    default: overwrite_name = "UnknownOverwrite"; break;
1210b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  }
12113fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  stream->Add("BinaryOpStub_%s_%s_%s",
12123fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch              op_name,
12133fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch              overwrite_name,
12143fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch              BinaryOpIC::GetName(operands_type_));
1215b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch}
1216b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1217b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1218257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid BinaryOpStub::GenerateSmiCode(
1219257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    MacroAssembler* masm,
1220b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    Label* slow,
1221b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    SmiCodeGenerateHeapNumberResults allow_heapnumber_results) {
1222b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // 1. Move arguments into edx, eax except for DIV and MOD, which need the
1223b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // dividend in eax and edx free for the division.  Use eax, ebx for those.
1224b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  Comment load_comment(masm, "-- Load arguments");
1225b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  Register left = edx;
1226b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  Register right = eax;
1227b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  if (op_ == Token::DIV || op_ == Token::MOD) {
1228b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    left = eax;
1229b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    right = ebx;
1230b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ mov(ebx, eax);
1231b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ mov(eax, edx);
1232b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  }
1233b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1234b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1235b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // 2. Prepare the smi check of both operands by oring them together.
1236b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  Comment smi_check_comment(masm, "-- Smi check arguments");
1237b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  Label not_smis;
1238b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  Register combined = ecx;
1239b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  ASSERT(!left.is(combined) && !right.is(combined));
1240b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  switch (op_) {
1241b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::BIT_OR:
1242b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // Perform the operation into eax and smi check the result.  Preserve
1243b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // eax in case the result is not a smi.
1244b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      ASSERT(!left.is(ecx) && !right.is(ecx));
1245b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ mov(ecx, right);
12463ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      __ or_(right, left);  // Bitwise or is commutative.
1247b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      combined = right;
1248b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1249b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1250b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::BIT_XOR:
1251b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::BIT_AND:
1252b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::ADD:
1253b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::SUB:
1254b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::MUL:
1255b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::DIV:
1256b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::MOD:
1257b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ mov(combined, right);
12583ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      __ or_(combined, left);
1259b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1260b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1261b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::SHL:
1262b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::SAR:
1263b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::SHR:
1264b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // Move the right operand into ecx for the shift operation, use eax
1265b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // for the smi check register.
1266b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      ASSERT(!left.is(ecx) && !right.is(ecx));
1267b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ mov(ecx, right);
12683ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      __ or_(right, left);
1269b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      combined = right;
1270b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1271b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1272b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    default:
1273b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1274b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  }
1275b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1276b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // 3. Perform the smi check of the operands.
1277b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  STATIC_ASSERT(kSmiTag == 0);  // Adjust zero check if not the case.
12783fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ JumpIfNotSmi(combined, &not_smis);
1279b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1280b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // 4. Operands are both smis, perform the operation leaving the result in
1281b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // eax and check the result if necessary.
1282b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  Comment perform_smi(masm, "-- Perform smi operation");
1283b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  Label use_fp_on_smis;
1284b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  switch (op_) {
1285b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::BIT_OR:
1286b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // Nothing to do.
1287b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1288b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1289b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::BIT_XOR:
1290b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      ASSERT(right.is(eax));
12913ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      __ xor_(right, left);  // Bitwise xor is commutative.
1292b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1293b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1294b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::BIT_AND:
1295b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      ASSERT(right.is(eax));
12963ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      __ and_(right, left);  // Bitwise and is commutative.
1297b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1298b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1299b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::SHL:
1300b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // Remove tags from operands (but keep sign).
1301b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ SmiUntag(left);
1302b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ SmiUntag(ecx);
1303b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // Perform the operation.
1304b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ shl_cl(left);
1305b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // Check that the *signed* result fits in a smi.
1306b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ cmp(left, 0xc0000000);
1307257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ j(sign, &use_fp_on_smis);
1308b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // Tag the result and store it in register eax.
1309b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ SmiTag(left);
1310b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ mov(eax, left);
1311b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1312b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1313b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::SAR:
1314b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // Remove tags from operands (but keep sign).
1315b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ SmiUntag(left);
1316b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ SmiUntag(ecx);
1317b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // Perform the operation.
1318b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ sar_cl(left);
1319b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // Tag the result and store it in register eax.
1320b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ SmiTag(left);
1321b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ mov(eax, left);
1322b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1323b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1324b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::SHR:
1325b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // Remove tags from operands (but keep sign).
1326b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ SmiUntag(left);
1327b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ SmiUntag(ecx);
1328b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // Perform the operation.
1329b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ shr_cl(left);
1330b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // Check that the *unsigned* result fits in a smi.
1331b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // Neither of the two high-order bits can be set:
1332b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // - 0x80000000: high bit would be lost when smi tagging.
1333b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // - 0x40000000: this number would convert to negative when
1334b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // Smi tagging these two cases can only happen with shifts
1335b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // by 0 or 1 when handed a valid smi.
1336b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ test(left, Immediate(0xc0000000));
1337257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ j(not_zero, &use_fp_on_smis);
1338b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // Tag the result and store it in register eax.
1339b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ SmiTag(left);
1340b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ mov(eax, left);
1341b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1342b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1343b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::ADD:
1344b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      ASSERT(right.is(eax));
13453ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      __ add(right, left);  // Addition is commutative.
1346257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ j(overflow, &use_fp_on_smis);
1347b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1348b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1349b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::SUB:
13503ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      __ sub(left, right);
1351257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ j(overflow, &use_fp_on_smis);
1352b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ mov(eax, left);
1353b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1354b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1355b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::MUL:
1356b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // If the smi tag is 0 we can just leave the tag on one operand.
1357b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      STATIC_ASSERT(kSmiTag == 0);  // Adjust code below if not the case.
1358b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // We can't revert the multiplication if the result is not a smi
1359b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // so save the right operand.
1360b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ mov(ebx, right);
1361b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // Remove tag from one of the operands (but keep sign).
1362b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ SmiUntag(right);
1363b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // Do multiplication.
13643ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      __ imul(right, left);  // Multiplication is commutative.
1365257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ j(overflow, &use_fp_on_smis);
1366b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // Check for negative zero result.  Use combined = left | right.
1367b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ NegativeZeroTest(right, combined, &use_fp_on_smis);
1368b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1369b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1370b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::DIV:
1371b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // We can't revert the division if the result is not a smi so
1372b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // save the left operand.
1373b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ mov(edi, left);
1374b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // Check for 0 divisor.
13753ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      __ test(right, right);
1376257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ j(zero, &use_fp_on_smis);
1377b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // Sign extend left into edx:eax.
1378b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      ASSERT(left.is(eax));
1379b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ cdq();
1380b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // Divide edx:eax by right.
1381b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ idiv(right);
1382b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // Check for the corner case of dividing the most negative smi by
1383b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // -1. We cannot use the overflow flag, since it is not set by idiv
1384b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // instruction.
1385b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize == 1);
1386b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ cmp(eax, 0x40000000);
1387b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ j(equal, &use_fp_on_smis);
1388b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // Check for negative zero result.  Use combined = left | right.
1389b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ NegativeZeroTest(eax, combined, &use_fp_on_smis);
1390b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // Check that the remainder is zero.
13913ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      __ test(edx, edx);
1392b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ j(not_zero, &use_fp_on_smis);
1393b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // Tag the result and store it in register eax.
1394b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ SmiTag(eax);
1395b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1396b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1397b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::MOD:
1398b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // Check for 0 divisor.
13993ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      __ test(right, right);
1400257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ j(zero, &not_smis);
1401b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1402b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // Sign extend left into edx:eax.
1403b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      ASSERT(left.is(eax));
1404b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ cdq();
1405b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // Divide edx:eax by right.
1406b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ idiv(right);
1407b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // Check for negative zero result.  Use combined = left | right.
1408b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ NegativeZeroTest(edx, combined, slow);
1409b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // Move remainder to register eax.
1410b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ mov(eax, edx);
1411b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1412b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1413b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    default:
1414b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      UNREACHABLE();
1415b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  }
1416b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1417b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // 5. Emit return of result in eax.  Some operations have registers pushed.
1418b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  switch (op_) {
1419b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::ADD:
1420b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::SUB:
1421b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::MUL:
1422b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::DIV:
1423b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ ret(0);
1424b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1425b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::MOD:
1426b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::BIT_OR:
1427b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::BIT_AND:
1428b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::BIT_XOR:
1429b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::SAR:
1430b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::SHL:
1431b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::SHR:
1432b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ ret(2 * kPointerSize);
1433b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1434b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    default:
1435b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      UNREACHABLE();
1436b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  }
1437b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1438b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // 6. For some operations emit inline code to perform floating point
1439b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // operations on known smis (e.g., if the result of the operation
1440b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // overflowed the smi range).
1441b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  if (allow_heapnumber_results == NO_HEAPNUMBER_RESULTS) {
1442b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ bind(&use_fp_on_smis);
1443b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    switch (op_) {
1444b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // Undo the effects of some operations, and some register moves.
1445b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      case Token::SHL:
1446b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        // The arguments are saved on the stack, and only used from there.
1447b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        break;
1448b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      case Token::ADD:
1449b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        // Revert right = right + left.
14503ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch        __ sub(right, left);
1451b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        break;
1452b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      case Token::SUB:
1453b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        // Revert left = left - right.
14543ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch        __ add(left, right);
1455b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        break;
1456b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      case Token::MUL:
1457b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        // Right was clobbered but a copy is in ebx.
1458b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        __ mov(right, ebx);
1459b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        break;
1460b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      case Token::DIV:
1461b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        // Left was clobbered but a copy is in edi.  Right is in ebx for
1462b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        // division.  They should be in eax, ebx for jump to not_smi.
1463b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        __ mov(eax, edi);
1464b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        break;
1465b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      default:
1466b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        // No other operators jump to use_fp_on_smis.
1467b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        break;
1468b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    }
1469b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ jmp(&not_smis);
1470b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  } else {
1471b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    ASSERT(allow_heapnumber_results == ALLOW_HEAPNUMBER_RESULTS);
1472b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    switch (op_) {
1473257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      case Token::SHL:
1474257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      case Token::SHR: {
1475b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        Comment perform_float(masm, "-- Perform float operation on smis");
1476b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        __ bind(&use_fp_on_smis);
1477b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        // Result we want is in left == edx, so we can put the allocated heap
1478b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        // number in eax.
1479b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        __ AllocateHeapNumber(eax, ecx, ebx, slow);
1480b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        // Store the result in the HeapNumber and return.
1481257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        // It's OK to overwrite the arguments on the stack because we
1482257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        // are about to return.
1483257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        if (op_ == Token::SHR) {
1484b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          __ mov(Operand(esp, 1 * kPointerSize), left);
1485257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          __ mov(Operand(esp, 2 * kPointerSize), Immediate(0));
1486257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          __ fild_d(Operand(esp, 1 * kPointerSize));
1487b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset));
1488257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        } else {
1489257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          ASSERT_EQ(Token::SHL, op_);
1490257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          if (CpuFeatures::IsSupported(SSE2)) {
1491257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch            CpuFeatures::Scope use_sse2(SSE2);
14923ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch            __ cvtsi2sd(xmm0, left);
1493257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch            __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0);
1494257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          } else {
1495257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch            __ mov(Operand(esp, 1 * kPointerSize), left);
1496257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch            __ fild_s(Operand(esp, 1 * kPointerSize));
1497257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch            __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset));
1498257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          }
1499b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        }
1500257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        __ ret(2 * kPointerSize);
1501257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        break;
1502b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      }
1503b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1504b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      case Token::ADD:
1505b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      case Token::SUB:
1506b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      case Token::MUL:
1507b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      case Token::DIV: {
1508b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        Comment perform_float(masm, "-- Perform float operation on smis");
1509b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        __ bind(&use_fp_on_smis);
1510b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        // Restore arguments to edx, eax.
1511b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        switch (op_) {
1512b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          case Token::ADD:
1513b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            // Revert right = right + left.
15143ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch            __ sub(right, left);
1515b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            break;
1516b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          case Token::SUB:
1517b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            // Revert left = left - right.
15183ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch            __ add(left, right);
1519b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            break;
1520b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          case Token::MUL:
1521b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            // Right was clobbered but a copy is in ebx.
1522b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            __ mov(right, ebx);
1523b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            break;
1524b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          case Token::DIV:
1525b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            // Left was clobbered but a copy is in edi.  Right is in ebx for
1526b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            // division.
1527b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            __ mov(edx, edi);
1528b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            __ mov(eax, right);
1529b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            break;
1530b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          default: UNREACHABLE();
1531b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            break;
1532b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        }
1533b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        __ AllocateHeapNumber(ecx, ebx, no_reg, slow);
15348b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch        if (CpuFeatures::IsSupported(SSE2)) {
1535b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          CpuFeatures::Scope use_sse2(SSE2);
1536b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          FloatingPointHelper::LoadSSE2Smis(masm, ebx);
1537b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          switch (op_) {
1538b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            case Token::ADD: __ addsd(xmm0, xmm1); break;
1539b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            case Token::SUB: __ subsd(xmm0, xmm1); break;
1540b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            case Token::MUL: __ mulsd(xmm0, xmm1); break;
1541b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            case Token::DIV: __ divsd(xmm0, xmm1); break;
1542b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            default: UNREACHABLE();
1543b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          }
1544b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          __ movdbl(FieldOperand(ecx, HeapNumber::kValueOffset), xmm0);
1545b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        } else {  // SSE2 not available, use FPU.
1546b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          FloatingPointHelper::LoadFloatSmis(masm, ebx);
1547b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          switch (op_) {
1548b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            case Token::ADD: __ faddp(1); break;
1549b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            case Token::SUB: __ fsubp(1); break;
1550b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            case Token::MUL: __ fmulp(1); break;
1551b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            case Token::DIV: __ fdivp(1); break;
1552b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            default: UNREACHABLE();
1553b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          }
1554b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          __ fstp_d(FieldOperand(ecx, HeapNumber::kValueOffset));
1555b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        }
1556b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        __ mov(eax, ecx);
1557b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        __ ret(0);
1558b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        break;
1559b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      }
1560b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1561b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      default:
1562b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        break;
1563b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    }
1564b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  }
1565b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1566b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // 7. Non-smi operands, fall out to the non-smi code with the operands in
1567b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // edx and eax.
1568b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  Comment done_comment(masm, "-- Enter non-smi code");
1569b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ bind(&not_smis);
1570b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  switch (op_) {
1571b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::BIT_OR:
1572b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::SHL:
1573b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::SAR:
1574b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::SHR:
1575b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // Right operand is saved in ecx and eax was destroyed by the smi
1576b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // check.
1577b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ mov(eax, ecx);
1578b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1579b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1580b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::DIV:
1581b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::MOD:
1582b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // Operands are in eax, ebx at this point.
1583b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ mov(edx, eax);
1584b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ mov(eax, ebx);
1585b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1586b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1587b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    default:
1588b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1589b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  }
1590b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch}
1591b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1592b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1593257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid BinaryOpStub::GenerateSmiStub(MacroAssembler* masm) {
1594b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  Label call_runtime;
1595b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1596b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  switch (op_) {
1597b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::ADD:
1598b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::SUB:
1599b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::MUL:
1600b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::DIV:
1601b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1602b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::MOD:
1603b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::BIT_OR:
1604b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::BIT_AND:
1605b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::BIT_XOR:
1606b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::SAR:
1607b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::SHL:
1608b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::SHR:
1609b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      GenerateRegisterArgsPush(masm);
1610b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1611b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    default:
1612b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      UNREACHABLE();
1613b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  }
1614b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1615257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  if (result_type_ == BinaryOpIC::UNINITIALIZED ||
1616257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      result_type_ == BinaryOpIC::SMI) {
1617b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    GenerateSmiCode(masm, &call_runtime, NO_HEAPNUMBER_RESULTS);
1618b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  } else {
1619b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    GenerateSmiCode(masm, &call_runtime, ALLOW_HEAPNUMBER_RESULTS);
1620b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  }
1621b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ bind(&call_runtime);
1622b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  switch (op_) {
1623b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::ADD:
1624b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::SUB:
1625b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::MUL:
1626b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::DIV:
1627b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      GenerateTypeTransition(masm);
1628b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1629b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::MOD:
1630b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::BIT_OR:
1631b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::BIT_AND:
1632b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::BIT_XOR:
1633b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::SAR:
1634b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::SHL:
1635b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::SHR:
1636b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      GenerateTypeTransitionWithSavedArgs(masm);
1637b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1638b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    default:
1639b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      UNREACHABLE();
1640b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  }
1641b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch}
1642b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1643b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1644257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid BinaryOpStub::GenerateStringStub(MacroAssembler* masm) {
1645257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  ASSERT(operands_type_ == BinaryOpIC::STRING);
1646b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  ASSERT(op_ == Token::ADD);
16471e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  // Try to add arguments as strings, otherwise, transition to the generic
1648257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // BinaryOpIC type.
16491e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  GenerateAddStrings(masm);
1650b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  GenerateTypeTransition(masm);
1651b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch}
1652b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1653b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1654257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid BinaryOpStub::GenerateBothStringStub(MacroAssembler* masm) {
1655257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label call_runtime;
1656257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  ASSERT(operands_type_ == BinaryOpIC::BOTH_STRING);
1657257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  ASSERT(op_ == Token::ADD);
1658257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // If both arguments are strings, call the string add stub.
1659257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Otherwise, do a transition.
1660257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1661257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Registers containing left and right operands respectively.
1662257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Register left = edx;
1663257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Register right = eax;
1664257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1665257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Test if left operand is a string.
166669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ JumpIfSmi(left, &call_runtime, Label::kNear);
1667257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ CmpObjectType(left, FIRST_NONSTRING_TYPE, ecx);
166869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ j(above_equal, &call_runtime, Label::kNear);
1669257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1670257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Test if right operand is a string.
167169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ JumpIfSmi(right, &call_runtime, Label::kNear);
1672257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ CmpObjectType(right, FIRST_NONSTRING_TYPE, ecx);
167369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ j(above_equal, &call_runtime, Label::kNear);
1674257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1675257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  StringAddStub string_add_stub(NO_STRING_CHECK_IN_STUB);
1676257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  GenerateRegisterArgsPush(masm);
1677257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ TailCallStub(&string_add_stub);
1678257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1679257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&call_runtime);
1680257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  GenerateTypeTransition(masm);
1681257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch}
1682257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1683257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1684257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid BinaryOpStub::GenerateInt32Stub(MacroAssembler* masm) {
1685b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  Label call_runtime;
1686257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  ASSERT(operands_type_ == BinaryOpIC::INT32);
1687b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1688b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Floating point case.
1689b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  switch (op_) {
1690b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::ADD:
1691b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::SUB:
1692b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::MUL:
1693b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::DIV: {
1694b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      Label not_floats;
1695b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      Label not_int32;
16968b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch      if (CpuFeatures::IsSupported(SSE2)) {
1697b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        CpuFeatures::Scope use_sse2(SSE2);
1698b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        FloatingPointHelper::LoadSSE2Operands(masm, &not_floats);
1699b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        FloatingPointHelper::CheckSSE2OperandsAreInt32(masm, &not_int32, ecx);
1700b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        switch (op_) {
1701b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          case Token::ADD: __ addsd(xmm0, xmm1); break;
1702b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          case Token::SUB: __ subsd(xmm0, xmm1); break;
1703b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          case Token::MUL: __ mulsd(xmm0, xmm1); break;
1704b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          case Token::DIV: __ divsd(xmm0, xmm1); break;
1705b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          default: UNREACHABLE();
1706b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        }
1707b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        // Check result type if it is currently Int32.
1708257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        if (result_type_ <= BinaryOpIC::INT32) {
1709b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          __ cvttsd2si(ecx, Operand(xmm0));
17103ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch          __ cvtsi2sd(xmm2, ecx);
1711b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          __ ucomisd(xmm0, xmm2);
1712b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          __ j(not_zero, &not_int32);
1713b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          __ j(carry, &not_int32);
1714b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        }
1715b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        GenerateHeapResultAllocation(masm, &call_runtime);
1716b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0);
1717b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        __ ret(0);
1718b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      } else {  // SSE2 not available, use FPU.
1719b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        FloatingPointHelper::CheckFloatOperands(masm, &not_floats, ebx);
1720b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        FloatingPointHelper::LoadFloatOperands(
1721b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            masm,
1722b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            ecx,
1723b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            FloatingPointHelper::ARGS_IN_REGISTERS);
1724b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        FloatingPointHelper::CheckFloatOperandsAreInt32(masm, &not_int32);
1725b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        switch (op_) {
1726b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          case Token::ADD: __ faddp(1); break;
1727b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          case Token::SUB: __ fsubp(1); break;
1728b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          case Token::MUL: __ fmulp(1); break;
1729b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          case Token::DIV: __ fdivp(1); break;
1730b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          default: UNREACHABLE();
1731b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        }
1732b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        Label after_alloc_failure;
1733b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        GenerateHeapResultAllocation(masm, &after_alloc_failure);
1734b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset));
1735b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        __ ret(0);
1736b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        __ bind(&after_alloc_failure);
1737b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        __ ffree();
1738b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        __ jmp(&call_runtime);
1739b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      }
1740b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1741b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ bind(&not_floats);
1742b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ bind(&not_int32);
1743b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      GenerateTypeTransition(masm);
1744b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1745b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    }
1746b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1747b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::MOD: {
1748b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // For MOD we go directly to runtime in the non-smi case.
1749b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1750b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    }
1751b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::BIT_OR:
1752b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::BIT_AND:
1753b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::BIT_XOR:
1754b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::SAR:
1755b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::SHL:
1756b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::SHR: {
1757b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      GenerateRegisterArgsPush(masm);
1758b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      Label not_floats;
1759b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      Label not_int32;
1760b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      Label non_smi_result;
1761b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      /*  {
1762b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        CpuFeatures::Scope use_sse2(SSE2);
1763b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        FloatingPointHelper::LoadSSE2Operands(masm, &not_floats);
1764b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        FloatingPointHelper::CheckSSE2OperandsAreInt32(masm, &not_int32, ecx);
1765b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        }*/
1766b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      FloatingPointHelper::LoadUnknownsAsIntegers(masm,
1767b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                                                  use_sse3_,
1768b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                                                  &not_floats);
1769b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      FloatingPointHelper::CheckLoadedIntegersWereInt32(masm, use_sse3_,
1770b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                                                        &not_int32);
1771b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      switch (op_) {
17723ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch        case Token::BIT_OR:  __ or_(eax, ecx); break;
17733ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch        case Token::BIT_AND: __ and_(eax, ecx); break;
17743ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch        case Token::BIT_XOR: __ xor_(eax, ecx); break;
1775b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        case Token::SAR: __ sar_cl(eax); break;
1776b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        case Token::SHL: __ shl_cl(eax); break;
1777b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        case Token::SHR: __ shr_cl(eax); break;
1778b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        default: UNREACHABLE();
1779b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      }
1780b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      if (op_ == Token::SHR) {
1781b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        // Check if result is non-negative and fits in a smi.
1782b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        __ test(eax, Immediate(0xc0000000));
1783b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        __ j(not_zero, &call_runtime);
1784b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      } else {
1785b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        // Check if result fits in a smi.
1786b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        __ cmp(eax, 0xc0000000);
178769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch        __ j(negative, &non_smi_result, Label::kNear);
1788b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      }
1789b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // Tag smi result and return.
1790b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ SmiTag(eax);
1791b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ ret(2 * kPointerSize);  // Drop two pushed arguments from the stack.
1792b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1793b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // All ops except SHR return a signed int32 that we load in
1794b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // a HeapNumber.
1795b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      if (op_ != Token::SHR) {
1796b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        __ bind(&non_smi_result);
1797b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        // Allocate a heap number if needed.
17983ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch        __ mov(ebx, eax);  // ebx: result
1799257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        Label skip_allocation;
1800b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        switch (mode_) {
1801b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          case OVERWRITE_LEFT:
1802b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          case OVERWRITE_RIGHT:
1803b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            // If the operand was an object, we skip the
1804b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            // allocation of a heap number.
1805b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            __ mov(eax, Operand(esp, mode_ == OVERWRITE_RIGHT ?
1806b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                                1 * kPointerSize : 2 * kPointerSize));
18073fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch            __ JumpIfNotSmi(eax, &skip_allocation, Label::kNear);
1808b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            // Fall through!
1809b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          case NO_OVERWRITE:
1810b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            __ AllocateHeapNumber(eax, ecx, edx, &call_runtime);
1811b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            __ bind(&skip_allocation);
1812b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            break;
1813b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          default: UNREACHABLE();
1814b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        }
1815b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        // Store the result in the HeapNumber and return.
18168b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch        if (CpuFeatures::IsSupported(SSE2)) {
1817b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          CpuFeatures::Scope use_sse2(SSE2);
18183ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch          __ cvtsi2sd(xmm0, ebx);
1819b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0);
1820b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        } else {
1821b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          __ mov(Operand(esp, 1 * kPointerSize), ebx);
1822b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          __ fild_s(Operand(esp, 1 * kPointerSize));
1823b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset));
1824b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        }
1825b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        __ ret(2 * kPointerSize);  // Drop two pushed arguments from the stack.
1826b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      }
1827b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1828b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ bind(&not_floats);
1829b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ bind(&not_int32);
1830b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      GenerateTypeTransitionWithSavedArgs(masm);
1831b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1832b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    }
1833b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    default: UNREACHABLE(); break;
1834b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  }
1835b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1836b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // If an allocation fails, or SHR or MOD hit a hard case,
1837b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // use the runtime system to get the correct result.
1838b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ bind(&call_runtime);
1839b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1840b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  switch (op_) {
1841b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::ADD:
1842b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      GenerateRegisterArgsPush(masm);
1843b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ InvokeBuiltin(Builtins::ADD, JUMP_FUNCTION);
1844b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1845b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::SUB:
1846b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      GenerateRegisterArgsPush(masm);
1847b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ InvokeBuiltin(Builtins::SUB, JUMP_FUNCTION);
1848b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1849b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::MUL:
1850b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      GenerateRegisterArgsPush(masm);
1851b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ InvokeBuiltin(Builtins::MUL, JUMP_FUNCTION);
1852b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1853b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::DIV:
1854b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      GenerateRegisterArgsPush(masm);
1855b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ InvokeBuiltin(Builtins::DIV, JUMP_FUNCTION);
1856b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1857b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::MOD:
1858b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      GenerateRegisterArgsPush(masm);
1859b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ InvokeBuiltin(Builtins::MOD, JUMP_FUNCTION);
1860b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1861b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::BIT_OR:
1862b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ InvokeBuiltin(Builtins::BIT_OR, JUMP_FUNCTION);
1863b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1864b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::BIT_AND:
1865b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ InvokeBuiltin(Builtins::BIT_AND, JUMP_FUNCTION);
1866b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1867b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::BIT_XOR:
1868b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ InvokeBuiltin(Builtins::BIT_XOR, JUMP_FUNCTION);
1869b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1870b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::SAR:
1871b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ InvokeBuiltin(Builtins::SAR, JUMP_FUNCTION);
1872b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1873b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::SHL:
1874b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ InvokeBuiltin(Builtins::SHL, JUMP_FUNCTION);
1875b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1876b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::SHR:
1877b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ InvokeBuiltin(Builtins::SHR, JUMP_FUNCTION);
1878b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1879b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    default:
1880b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      UNREACHABLE();
1881b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  }
1882b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch}
1883b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1884b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1885257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid BinaryOpStub::GenerateOddballStub(MacroAssembler* masm) {
188644f0eee88ff00398ff7f715fab053374d808c90dSteve Block  if (op_ == Token::ADD) {
188744f0eee88ff00398ff7f715fab053374d808c90dSteve Block    // Handle string addition here, because it is the only operation
188844f0eee88ff00398ff7f715fab053374d808c90dSteve Block    // that does not do a ToNumber conversion on the operands.
188944f0eee88ff00398ff7f715fab053374d808c90dSteve Block    GenerateAddStrings(masm);
189044f0eee88ff00398ff7f715fab053374d808c90dSteve Block  }
189144f0eee88ff00398ff7f715fab053374d808c90dSteve Block
1892257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Factory* factory = masm->isolate()->factory();
1893257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
189444f0eee88ff00398ff7f715fab053374d808c90dSteve Block  // Convert odd ball arguments to numbers.
1895257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label check, done;
1896257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ cmp(edx, factory->undefined_value());
1897257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(not_equal, &check, Label::kNear);
189844f0eee88ff00398ff7f715fab053374d808c90dSteve Block  if (Token::IsBitOp(op_)) {
18993ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ xor_(edx, edx);
190044f0eee88ff00398ff7f715fab053374d808c90dSteve Block  } else {
1901257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ mov(edx, Immediate(factory->nan_value()));
190244f0eee88ff00398ff7f715fab053374d808c90dSteve Block  }
1903257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ jmp(&done, Label::kNear);
190444f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ bind(&check);
1905257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ cmp(eax, factory->undefined_value());
1906257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(not_equal, &done, Label::kNear);
190744f0eee88ff00398ff7f715fab053374d808c90dSteve Block  if (Token::IsBitOp(op_)) {
19083ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ xor_(eax, eax);
190944f0eee88ff00398ff7f715fab053374d808c90dSteve Block  } else {
1910257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ mov(eax, Immediate(factory->nan_value()));
191144f0eee88ff00398ff7f715fab053374d808c90dSteve Block  }
191244f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ bind(&done);
191344f0eee88ff00398ff7f715fab053374d808c90dSteve Block
191444f0eee88ff00398ff7f715fab053374d808c90dSteve Block  GenerateHeapNumberStub(masm);
191544f0eee88ff00398ff7f715fab053374d808c90dSteve Block}
191644f0eee88ff00398ff7f715fab053374d808c90dSteve Block
191744f0eee88ff00398ff7f715fab053374d808c90dSteve Block
1918257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid BinaryOpStub::GenerateHeapNumberStub(MacroAssembler* masm) {
1919b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  Label call_runtime;
1920b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1921b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Floating point case.
1922b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  switch (op_) {
1923b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::ADD:
1924b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::SUB:
1925b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::MUL:
1926b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::DIV: {
1927b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      Label not_floats;
19288b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch      if (CpuFeatures::IsSupported(SSE2)) {
1929b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        CpuFeatures::Scope use_sse2(SSE2);
1930b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        FloatingPointHelper::LoadSSE2Operands(masm, &not_floats);
1931b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1932b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        switch (op_) {
1933b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          case Token::ADD: __ addsd(xmm0, xmm1); break;
1934b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          case Token::SUB: __ subsd(xmm0, xmm1); break;
1935b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          case Token::MUL: __ mulsd(xmm0, xmm1); break;
1936b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          case Token::DIV: __ divsd(xmm0, xmm1); break;
1937b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          default: UNREACHABLE();
1938b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        }
1939b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        GenerateHeapResultAllocation(masm, &call_runtime);
1940b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0);
1941b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        __ ret(0);
1942b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      } else {  // SSE2 not available, use FPU.
1943b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        FloatingPointHelper::CheckFloatOperands(masm, &not_floats, ebx);
1944b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        FloatingPointHelper::LoadFloatOperands(
1945b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            masm,
1946b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            ecx,
1947b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            FloatingPointHelper::ARGS_IN_REGISTERS);
1948b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        switch (op_) {
1949b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          case Token::ADD: __ faddp(1); break;
1950b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          case Token::SUB: __ fsubp(1); break;
1951b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          case Token::MUL: __ fmulp(1); break;
1952b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          case Token::DIV: __ fdivp(1); break;
1953b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          default: UNREACHABLE();
1954b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        }
1955b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        Label after_alloc_failure;
1956b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        GenerateHeapResultAllocation(masm, &after_alloc_failure);
1957b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset));
1958b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        __ ret(0);
1959b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        __ bind(&after_alloc_failure);
1960b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        __ ffree();
1961b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        __ jmp(&call_runtime);
1962b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      }
1963b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1964b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ bind(&not_floats);
1965b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      GenerateTypeTransition(masm);
1966b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1967b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    }
1968b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1969b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::MOD: {
1970b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // For MOD we go directly to runtime in the non-smi case.
1971b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1972b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    }
1973b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::BIT_OR:
1974b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::BIT_AND:
1975b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::BIT_XOR:
1976b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::SAR:
1977b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::SHL:
1978b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::SHR: {
1979b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      GenerateRegisterArgsPush(masm);
1980b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      Label not_floats;
1981b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      Label non_smi_result;
1982b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      FloatingPointHelper::LoadUnknownsAsIntegers(masm,
1983b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                                                  use_sse3_,
1984b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                                                  &not_floats);
1985b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      switch (op_) {
19863ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch        case Token::BIT_OR:  __ or_(eax, ecx); break;
19873ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch        case Token::BIT_AND: __ and_(eax, ecx); break;
19883ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch        case Token::BIT_XOR: __ xor_(eax, ecx); break;
1989b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        case Token::SAR: __ sar_cl(eax); break;
1990b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        case Token::SHL: __ shl_cl(eax); break;
1991b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        case Token::SHR: __ shr_cl(eax); break;
1992b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        default: UNREACHABLE();
1993b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      }
1994b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      if (op_ == Token::SHR) {
1995b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        // Check if result is non-negative and fits in a smi.
1996b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        __ test(eax, Immediate(0xc0000000));
1997b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        __ j(not_zero, &call_runtime);
1998b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      } else {
1999b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        // Check if result fits in a smi.
2000b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        __ cmp(eax, 0xc0000000);
200169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch        __ j(negative, &non_smi_result, Label::kNear);
2002b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      }
2003b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // Tag smi result and return.
2004b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ SmiTag(eax);
2005b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ ret(2 * kPointerSize);  // Drop two pushed arguments from the stack.
2006b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
2007b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // All ops except SHR return a signed int32 that we load in
2008b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // a HeapNumber.
2009b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      if (op_ != Token::SHR) {
2010b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        __ bind(&non_smi_result);
2011b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        // Allocate a heap number if needed.
20123ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch        __ mov(ebx, eax);  // ebx: result
2013257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        Label skip_allocation;
2014b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        switch (mode_) {
2015b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          case OVERWRITE_LEFT:
2016b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          case OVERWRITE_RIGHT:
2017b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            // If the operand was an object, we skip the
2018b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            // allocation of a heap number.
2019b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            __ mov(eax, Operand(esp, mode_ == OVERWRITE_RIGHT ?
2020b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                                1 * kPointerSize : 2 * kPointerSize));
20213fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch            __ JumpIfNotSmi(eax, &skip_allocation, Label::kNear);
2022b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            // Fall through!
2023b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          case NO_OVERWRITE:
2024b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            __ AllocateHeapNumber(eax, ecx, edx, &call_runtime);
2025b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            __ bind(&skip_allocation);
2026b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            break;
2027b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          default: UNREACHABLE();
2028b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        }
2029b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        // Store the result in the HeapNumber and return.
20308b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch        if (CpuFeatures::IsSupported(SSE2)) {
2031b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          CpuFeatures::Scope use_sse2(SSE2);
20323ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch          __ cvtsi2sd(xmm0, ebx);
2033b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0);
2034b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        } else {
2035b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          __ mov(Operand(esp, 1 * kPointerSize), ebx);
2036b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          __ fild_s(Operand(esp, 1 * kPointerSize));
2037b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset));
2038b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        }
2039b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        __ ret(2 * kPointerSize);  // Drop two pushed arguments from the stack.
2040b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      }
2041b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
2042b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ bind(&not_floats);
2043b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      GenerateTypeTransitionWithSavedArgs(masm);
2044b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
2045b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    }
2046b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    default: UNREACHABLE(); break;
2047b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  }
2048b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
2049b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // If an allocation fails, or SHR or MOD hit a hard case,
2050b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // use the runtime system to get the correct result.
2051b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ bind(&call_runtime);
2052b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
2053b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  switch (op_) {
2054b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::ADD:
2055b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      GenerateRegisterArgsPush(masm);
2056b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ InvokeBuiltin(Builtins::ADD, JUMP_FUNCTION);
2057b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
2058b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::SUB:
2059b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      GenerateRegisterArgsPush(masm);
2060b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ InvokeBuiltin(Builtins::SUB, JUMP_FUNCTION);
2061b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
2062b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::MUL:
2063b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      GenerateRegisterArgsPush(masm);
2064b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ InvokeBuiltin(Builtins::MUL, JUMP_FUNCTION);
2065b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
2066b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::DIV:
2067b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      GenerateRegisterArgsPush(masm);
2068b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ InvokeBuiltin(Builtins::DIV, JUMP_FUNCTION);
2069b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
2070b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::MOD:
2071b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      GenerateRegisterArgsPush(masm);
2072b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ InvokeBuiltin(Builtins::MOD, JUMP_FUNCTION);
2073b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
2074b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::BIT_OR:
2075b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ InvokeBuiltin(Builtins::BIT_OR, JUMP_FUNCTION);
2076b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
2077b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::BIT_AND:
2078b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ InvokeBuiltin(Builtins::BIT_AND, JUMP_FUNCTION);
2079b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
2080b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::BIT_XOR:
2081b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ InvokeBuiltin(Builtins::BIT_XOR, JUMP_FUNCTION);
2082b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
2083b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::SAR:
2084b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ InvokeBuiltin(Builtins::SAR, JUMP_FUNCTION);
2085b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
2086b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::SHL:
2087b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ InvokeBuiltin(Builtins::SHL, JUMP_FUNCTION);
2088b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
2089b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::SHR:
2090b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ InvokeBuiltin(Builtins::SHR, JUMP_FUNCTION);
2091b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
2092b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    default:
2093b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      UNREACHABLE();
2094b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  }
2095b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch}
2096b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
2097b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
2098257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid BinaryOpStub::GenerateGeneric(MacroAssembler* masm) {
2099b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  Label call_runtime;
2100b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
210144f0eee88ff00398ff7f715fab053374d808c90dSteve Block  Counters* counters = masm->isolate()->counters();
210244f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ IncrementCounter(counters->generic_binary_stub_calls(), 1);
2103b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
2104b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  switch (op_) {
2105b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::ADD:
2106b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::SUB:
2107b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::MUL:
2108b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::DIV:
2109b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
2110b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::MOD:
2111b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::BIT_OR:
2112b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::BIT_AND:
2113b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::BIT_XOR:
2114b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::SAR:
2115b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::SHL:
2116b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::SHR:
2117b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      GenerateRegisterArgsPush(masm);
2118b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
2119b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    default:
2120b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      UNREACHABLE();
2121b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  }
2122b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
2123b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  GenerateSmiCode(masm, &call_runtime, ALLOW_HEAPNUMBER_RESULTS);
2124b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
2125b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Floating point case.
2126b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  switch (op_) {
2127b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::ADD:
2128b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::SUB:
2129b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::MUL:
2130b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::DIV: {
2131b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      Label not_floats;
21328b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch      if (CpuFeatures::IsSupported(SSE2)) {
2133b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        CpuFeatures::Scope use_sse2(SSE2);
2134b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        FloatingPointHelper::LoadSSE2Operands(masm, &not_floats);
2135b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
2136b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        switch (op_) {
2137b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          case Token::ADD: __ addsd(xmm0, xmm1); break;
2138b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          case Token::SUB: __ subsd(xmm0, xmm1); break;
2139b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          case Token::MUL: __ mulsd(xmm0, xmm1); break;
2140b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          case Token::DIV: __ divsd(xmm0, xmm1); break;
2141b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          default: UNREACHABLE();
2142b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        }
2143b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        GenerateHeapResultAllocation(masm, &call_runtime);
2144b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0);
2145b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        __ ret(0);
2146b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      } else {  // SSE2 not available, use FPU.
2147b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        FloatingPointHelper::CheckFloatOperands(masm, &not_floats, ebx);
2148b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        FloatingPointHelper::LoadFloatOperands(
2149b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            masm,
2150b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            ecx,
2151b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            FloatingPointHelper::ARGS_IN_REGISTERS);
2152b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        switch (op_) {
2153b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          case Token::ADD: __ faddp(1); break;
2154b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          case Token::SUB: __ fsubp(1); break;
2155b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          case Token::MUL: __ fmulp(1); break;
2156b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          case Token::DIV: __ fdivp(1); break;
2157b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          default: UNREACHABLE();
2158b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        }
2159b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        Label after_alloc_failure;
2160b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        GenerateHeapResultAllocation(masm, &after_alloc_failure);
2161b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset));
2162b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        __ ret(0);
2163b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        __ bind(&after_alloc_failure);
2164b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          __ ffree();
2165b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          __ jmp(&call_runtime);
2166b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      }
2167b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        __ bind(&not_floats);
2168b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        break;
2169b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      }
2170b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::MOD: {
2171b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // For MOD we go directly to runtime in the non-smi case.
2172b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
2173b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    }
2174b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::BIT_OR:
2175b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::BIT_AND:
2176b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      case Token::BIT_XOR:
2177b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::SAR:
2178b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::SHL:
2179b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::SHR: {
2180b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      Label non_smi_result;
2181b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      FloatingPointHelper::LoadUnknownsAsIntegers(masm,
2182b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                                                  use_sse3_,
2183b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                                                  &call_runtime);
2184b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      switch (op_) {
21853ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch        case Token::BIT_OR:  __ or_(eax, ecx); break;
21863ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch        case Token::BIT_AND: __ and_(eax, ecx); break;
21873ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch        case Token::BIT_XOR: __ xor_(eax, ecx); break;
2188b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        case Token::SAR: __ sar_cl(eax); break;
2189b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        case Token::SHL: __ shl_cl(eax); break;
2190b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        case Token::SHR: __ shr_cl(eax); break;
2191b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        default: UNREACHABLE();
2192b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      }
2193b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      if (op_ == Token::SHR) {
2194b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        // Check if result is non-negative and fits in a smi.
2195b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        __ test(eax, Immediate(0xc0000000));
2196b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        __ j(not_zero, &call_runtime);
2197b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      } else {
2198b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        // Check if result fits in a smi.
2199b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        __ cmp(eax, 0xc0000000);
220069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch        __ j(negative, &non_smi_result, Label::kNear);
2201b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      }
2202b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // Tag smi result and return.
2203b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ SmiTag(eax);
2204b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ ret(2 * kPointerSize);  // Drop the arguments from the stack.
2205b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
2206b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // All ops except SHR return a signed int32 that we load in
2207b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // a HeapNumber.
2208b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      if (op_ != Token::SHR) {
2209b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        __ bind(&non_smi_result);
2210b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        // Allocate a heap number if needed.
22113ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch        __ mov(ebx, eax);  // ebx: result
2212257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        Label skip_allocation;
2213b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        switch (mode_) {
2214b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          case OVERWRITE_LEFT:
2215b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          case OVERWRITE_RIGHT:
2216b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            // If the operand was an object, we skip the
2217b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch              // allocation of a heap number.
2218b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            __ mov(eax, Operand(esp, mode_ == OVERWRITE_RIGHT ?
2219b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                                1 * kPointerSize : 2 * kPointerSize));
22203fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch            __ JumpIfNotSmi(eax, &skip_allocation, Label::kNear);
2221b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            // Fall through!
2222b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          case NO_OVERWRITE:
2223b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            __ AllocateHeapNumber(eax, ecx, edx, &call_runtime);
2224b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            __ bind(&skip_allocation);
2225b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            break;
2226b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          default: UNREACHABLE();
2227b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        }
2228b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        // Store the result in the HeapNumber and return.
22298b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch        if (CpuFeatures::IsSupported(SSE2)) {
2230b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          CpuFeatures::Scope use_sse2(SSE2);
22313ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch          __ cvtsi2sd(xmm0, ebx);
2232b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0);
2233b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        } else {
2234b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          __ mov(Operand(esp, 1 * kPointerSize), ebx);
2235b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          __ fild_s(Operand(esp, 1 * kPointerSize));
2236b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset));
2237b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        }
2238b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        __ ret(2 * kPointerSize);
2239b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      }
2240b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
2241b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    }
2242b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    default: UNREACHABLE(); break;
2243b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  }
2244b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
2245b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // If all else fails, use the runtime system to get the correct
2246b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // result.
2247b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ bind(&call_runtime);
2248b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  switch (op_) {
2249b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::ADD: {
22501e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      GenerateAddStrings(masm);
2251b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      GenerateRegisterArgsPush(masm);
2252b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ InvokeBuiltin(Builtins::ADD, JUMP_FUNCTION);
2253b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
2254b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    }
2255b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::SUB:
2256b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      GenerateRegisterArgsPush(masm);
2257b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ InvokeBuiltin(Builtins::SUB, JUMP_FUNCTION);
2258b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
2259b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::MUL:
2260b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      GenerateRegisterArgsPush(masm);
2261b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ InvokeBuiltin(Builtins::MUL, JUMP_FUNCTION);
2262b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
2263b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::DIV:
2264b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      GenerateRegisterArgsPush(masm);
2265b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ InvokeBuiltin(Builtins::DIV, JUMP_FUNCTION);
2266b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
2267b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::MOD:
2268b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ InvokeBuiltin(Builtins::MOD, JUMP_FUNCTION);
2269b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
2270b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::BIT_OR:
2271b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ InvokeBuiltin(Builtins::BIT_OR, JUMP_FUNCTION);
2272b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
2273b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::BIT_AND:
2274b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ InvokeBuiltin(Builtins::BIT_AND, JUMP_FUNCTION);
2275b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
2276b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::BIT_XOR:
2277b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ InvokeBuiltin(Builtins::BIT_XOR, JUMP_FUNCTION);
2278b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
2279b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::SAR:
2280b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ InvokeBuiltin(Builtins::SAR, JUMP_FUNCTION);
2281b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
2282b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::SHL:
2283b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ InvokeBuiltin(Builtins::SHL, JUMP_FUNCTION);
2284b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
2285b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::SHR:
2286b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ InvokeBuiltin(Builtins::SHR, JUMP_FUNCTION);
2287b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
2288b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    default:
2289b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      UNREACHABLE();
2290b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  }
2291b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch}
2292b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
2293b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
2294257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid BinaryOpStub::GenerateAddStrings(MacroAssembler* masm) {
2295e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  ASSERT(op_ == Token::ADD);
2296257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label left_not_string, call_runtime;
22971e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
22981e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  // Registers containing left and right operands respectively.
22991e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  Register left = edx;
23001e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  Register right = eax;
23011e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
23021e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  // Test if left operand is a string.
23033fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ JumpIfSmi(left, &left_not_string, Label::kNear);
23041e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  __ CmpObjectType(left, FIRST_NONSTRING_TYPE, ecx);
2305257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(above_equal, &left_not_string, Label::kNear);
23061e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
23071e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  StringAddStub string_add_left_stub(NO_STRING_CHECK_LEFT_IN_STUB);
23081e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  GenerateRegisterArgsPush(masm);
23091e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  __ TailCallStub(&string_add_left_stub);
23101e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
23111e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  // Left operand is not a string, test right.
23121e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  __ bind(&left_not_string);
23133fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ JumpIfSmi(right, &call_runtime, Label::kNear);
23141e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  __ CmpObjectType(right, FIRST_NONSTRING_TYPE, ecx);
2315257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(above_equal, &call_runtime, Label::kNear);
23161e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
23171e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  StringAddStub string_add_right_stub(NO_STRING_CHECK_RIGHT_IN_STUB);
23181e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  GenerateRegisterArgsPush(masm);
23191e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  __ TailCallStub(&string_add_right_stub);
23201e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
23211e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  // Neither argument is a string.
23221e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  __ bind(&call_runtime);
23231e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block}
23241e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
23251e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
2326257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid BinaryOpStub::GenerateHeapResultAllocation(
2327b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    MacroAssembler* masm,
2328b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    Label* alloc_failure) {
2329b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  Label skip_allocation;
2330b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  OverwriteMode mode = mode_;
2331b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  switch (mode) {
2332b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case OVERWRITE_LEFT: {
2333b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // If the argument in edx is already an object, we skip the
2334b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // allocation of a heap number.
23353fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch      __ JumpIfNotSmi(edx, &skip_allocation, Label::kNear);
2336b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // Allocate a heap number for the result. Keep eax and edx intact
2337b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // for the possible runtime call.
2338b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ AllocateHeapNumber(ebx, ecx, no_reg, alloc_failure);
2339b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // Now edx can be overwritten losing one of the arguments as we are
2340b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // now done and will not need it any more.
23413ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      __ mov(edx, ebx);
2342b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ bind(&skip_allocation);
2343b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // Use object in edx as a result holder
23443ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      __ mov(eax, edx);
2345b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
2346b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    }
2347b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case OVERWRITE_RIGHT:
2348b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // If the argument in eax is already an object, we skip the
2349b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // allocation of a heap number.
23503fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch      __ JumpIfNotSmi(eax, &skip_allocation, Label::kNear);
2351b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // Fall through!
2352b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case NO_OVERWRITE:
2353b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // Allocate a heap number for the result. Keep eax and edx intact
2354b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // for the possible runtime call.
2355b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ AllocateHeapNumber(ebx, ecx, no_reg, alloc_failure);
2356b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // Now eax can be overwritten losing one of the arguments as we are
2357b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // now done and will not need it any more.
2358b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ mov(eax, ebx);
2359b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ bind(&skip_allocation);
2360b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
2361b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    default: UNREACHABLE();
2362b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  }
2363b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch}
2364b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
2365b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
2366257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid BinaryOpStub::GenerateRegisterArgsPush(MacroAssembler* masm) {
236780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ pop(ecx);
2368b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ push(edx);
2369b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ push(eax);
237080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ push(ecx);
237180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
237280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
237380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
237480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid TranscendentalCacheStub::Generate(MacroAssembler* masm) {
2375b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // TAGGED case:
2376b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  //   Input:
2377b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  //     esp[4]: tagged number input argument (should be number).
2378b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  //     esp[0]: return address.
2379b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  //   Output:
2380b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  //     eax: tagged double result.
2381b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // UNTAGGED case:
2382b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  //   Input::
2383b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  //     esp[0]: return address.
2384b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  //     xmm1: untagged double input argument
2385b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  //   Output:
2386b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  //     xmm1: untagged double result.
2387b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
238880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label runtime_call;
238980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label runtime_call_clear_stack;
2390b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  Label skip_cache;
2391b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  const bool tagged = (argument_type_ == TAGGED);
2392b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  if (tagged) {
2393b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    // Test that eax is a number.
2394257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Label input_not_smi;
2395257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Label loaded;
2396b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ mov(eax, Operand(esp, kPointerSize));
23973fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    __ JumpIfNotSmi(eax, &input_not_smi, Label::kNear);
2398b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    // Input is a smi. Untag and load it onto the FPU stack.
2399b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    // Then load the low and high words of the double into ebx, edx.
2400b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    STATIC_ASSERT(kSmiTagSize == 1);
2401b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ sar(eax, 1);
24023ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ sub(esp, Immediate(2 * kPointerSize));
2403b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ mov(Operand(esp, 0), eax);
2404b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ fild_s(Operand(esp, 0));
2405b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ fst_d(Operand(esp, 0));
2406b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ pop(edx);
2407b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ pop(ebx);
2408257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ jmp(&loaded, Label::kNear);
2409b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ bind(&input_not_smi);
2410b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    // Check if input is a HeapNumber.
2411b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset));
241244f0eee88ff00398ff7f715fab053374d808c90dSteve Block    Factory* factory = masm->isolate()->factory();
24133ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ cmp(ebx, Immediate(factory->heap_number_map()));
2414b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ j(not_equal, &runtime_call);
2415b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    // Input is a HeapNumber. Push it on the FPU stack and load its
2416b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    // low and high words into ebx, edx.
2417b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ fld_d(FieldOperand(eax, HeapNumber::kValueOffset));
2418b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ mov(edx, FieldOperand(eax, HeapNumber::kExponentOffset));
2419b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ mov(ebx, FieldOperand(eax, HeapNumber::kMantissaOffset));
2420b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
2421b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ bind(&loaded);
2422b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  } else {  // UNTAGGED.
24238b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch    if (CpuFeatures::IsSupported(SSE4_1)) {
2424b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      CpuFeatures::Scope sse4_scope(SSE4_1);
24253ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      __ pextrd(edx, xmm1, 0x1);  // copy xmm1[63..32] to edx.
2426b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    } else {
2427b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ pshufd(xmm0, xmm1, 0x1);
24283ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      __ movd(edx, xmm0);
2429b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    }
24303ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ movd(ebx, xmm1);
2431b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  }
243280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
2433b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // ST[0] or xmm1  == double value
243480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // ebx = low 32 bits of double value
243580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // edx = high 32 bits of double value
243680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Compute hash (the shifts are arithmetic):
243780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  //   h = (low ^ high); h ^= h >> 16; h ^= h >> 8; h = h & (cacheSize - 1);
243880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(ecx, ebx);
24393ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ xor_(ecx, edx);
244080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(eax, ecx);
244180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ sar(eax, 16);
24423ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ xor_(ecx, eax);
244380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(eax, ecx);
244480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ sar(eax, 8);
24453ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ xor_(ecx, eax);
244644f0eee88ff00398ff7f715fab053374d808c90dSteve Block  ASSERT(IsPowerOf2(TranscendentalCache::SubCache::kCacheSize));
24473ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ and_(ecx,
244844f0eee88ff00398ff7f715fab053374d808c90dSteve Block          Immediate(TranscendentalCache::SubCache::kCacheSize - 1));
244980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
2450b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // ST[0] or xmm1 == double value.
245180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // ebx = low 32 bits of double value.
245280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // edx = high 32 bits of double value.
245380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // ecx = TranscendentalCache::hash(double value).
245444f0eee88ff00398ff7f715fab053374d808c90dSteve Block  ExternalReference cache_array =
245544f0eee88ff00398ff7f715fab053374d808c90dSteve Block      ExternalReference::transcendental_cache_array_address(masm->isolate());
245644f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ mov(eax, Immediate(cache_array));
245744f0eee88ff00398ff7f715fab053374d808c90dSteve Block  int cache_array_index =
245844f0eee88ff00398ff7f715fab053374d808c90dSteve Block      type_ * sizeof(masm->isolate()->transcendental_cache()->caches_[0]);
245944f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ mov(eax, Operand(eax, cache_array_index));
246080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Eax points to the cache for the type type_.
246180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // If NULL, the cache hasn't been initialized yet, so go through runtime.
24623ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ test(eax, eax);
246380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(zero, &runtime_call_clear_stack);
246480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#ifdef DEBUG
246580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check that the layout of cache elements match expectations.
246644f0eee88ff00398ff7f715fab053374d808c90dSteve Block  { TranscendentalCache::SubCache::Element test_elem[2];
246780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    char* elem_start = reinterpret_cast<char*>(&test_elem[0]);
246880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    char* elem2_start = reinterpret_cast<char*>(&test_elem[1]);
246980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    char* elem_in0  = reinterpret_cast<char*>(&(test_elem[0].in[0]));
247080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    char* elem_in1  = reinterpret_cast<char*>(&(test_elem[0].in[1]));
247180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    char* elem_out = reinterpret_cast<char*>(&(test_elem[0].output));
247280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    CHECK_EQ(12, elem2_start - elem_start);  // Two uint_32's and a pointer.
247380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    CHECK_EQ(0, elem_in0 - elem_start);
247480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    CHECK_EQ(kIntSize, elem_in1 - elem_start);
247580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    CHECK_EQ(2 * kIntSize, elem_out - elem_start);
247680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
247780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#endif
247880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Find the address of the ecx'th entry in the cache, i.e., &eax[ecx*12].
247980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ lea(ecx, Operand(ecx, ecx, times_2, 0));
248080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ lea(ecx, Operand(eax, ecx, times_4, 0));
248180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check if cache matches: Double value is stored in uint32_t[2] array.
2482257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label cache_miss;
248380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cmp(ebx, Operand(ecx, 0));
2484257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(not_equal, &cache_miss, Label::kNear);
248580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cmp(edx, Operand(ecx, kIntSize));
2486257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(not_equal, &cache_miss, Label::kNear);
248780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Cache hit!
24883ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  Counters* counters = masm->isolate()->counters();
24893ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ IncrementCounter(counters->transcendental_cache_hit(), 1);
249080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(eax, Operand(ecx, 2 * kIntSize));
2491b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  if (tagged) {
2492b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ fstp(0);
2493b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ ret(kPointerSize);
2494b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  } else {  // UNTAGGED.
2495b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ movdbl(xmm1, FieldOperand(eax, HeapNumber::kValueOffset));
2496b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ Ret();
2497b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  }
249880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
249980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&cache_miss);
25003ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ IncrementCounter(counters->transcendental_cache_miss(), 1);
250180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Update cache with new value.
250280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // We are short on registers, so use no_reg as scratch.
250380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // This gives slightly larger code.
2504b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  if (tagged) {
2505b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ AllocateHeapNumber(eax, edi, no_reg, &runtime_call_clear_stack);
2506b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  } else {  // UNTAGGED.
2507b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ AllocateHeapNumber(eax, edi, no_reg, &skip_cache);
25083ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ sub(esp, Immediate(kDoubleSize));
2509b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ movdbl(Operand(esp, 0), xmm1);
2510b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ fld_d(Operand(esp, 0));
25113ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ add(esp, Immediate(kDoubleSize));
2512b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  }
25133ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  GenerateOperation(masm, type_);
251480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(Operand(ecx, 0), ebx);
251580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(Operand(ecx, kIntSize), edx);
251680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(Operand(ecx, 2 * kIntSize), eax);
251780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset));
2518b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  if (tagged) {
2519b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ ret(kPointerSize);
2520b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  } else {  // UNTAGGED.
2521b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ movdbl(xmm1, FieldOperand(eax, HeapNumber::kValueOffset));
2522b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ Ret();
2523b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
2524b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    // Skip cache and return answer directly, only in untagged case.
2525b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ bind(&skip_cache);
25263ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ sub(esp, Immediate(kDoubleSize));
2527b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ movdbl(Operand(esp, 0), xmm1);
2528b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ fld_d(Operand(esp, 0));
25293ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    GenerateOperation(masm, type_);
2530b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ fstp_d(Operand(esp, 0));
2531b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ movdbl(xmm1, Operand(esp, 0));
25323ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ add(esp, Immediate(kDoubleSize));
2533b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    // We return the value in xmm1 without adding it to the cache, but
2534b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    // we cause a scavenging GC so that future allocations will succeed.
25353ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    {
25363ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      FrameScope scope(masm, StackFrame::INTERNAL);
25373ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      // Allocate an unused object bigger than a HeapNumber.
25383ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      __ push(Immediate(Smi::FromInt(2 * kDoubleSize)));
25393ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      __ CallRuntimeSaveDoubles(Runtime::kAllocateInNewSpace);
25403ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    }
2541b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ Ret();
2542b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  }
254380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
2544b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Call runtime, doing whatever allocation and cleanup is necessary.
2545b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  if (tagged) {
2546b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ bind(&runtime_call_clear_stack);
2547b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ fstp(0);
2548b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ bind(&runtime_call);
254944f0eee88ff00398ff7f715fab053374d808c90dSteve Block    ExternalReference runtime =
255044f0eee88ff00398ff7f715fab053374d808c90dSteve Block        ExternalReference(RuntimeFunction(), masm->isolate());
255144f0eee88ff00398ff7f715fab053374d808c90dSteve Block    __ TailCallExternalReference(runtime, 1, 1);
2552b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  } else {  // UNTAGGED.
2553b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ bind(&runtime_call_clear_stack);
2554b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ bind(&runtime_call);
2555b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ AllocateHeapNumber(eax, edi, no_reg, &skip_cache);
2556b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm1);
25573ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    {
25583ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      FrameScope scope(masm, StackFrame::INTERNAL);
25593ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      __ push(eax);
25603ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      __ CallRuntime(RuntimeFunction(), 1);
25613ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    }
2562b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ movdbl(xmm1, FieldOperand(eax, HeapNumber::kValueOffset));
2563b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ Ret();
2564b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  }
256580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
256680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
256780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
256880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian MonsenRuntime::FunctionId TranscendentalCacheStub::RuntimeFunction() {
256980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  switch (type_) {
257080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    case TranscendentalCache::SIN: return Runtime::kMath_sin;
257180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    case TranscendentalCache::COS: return Runtime::kMath_cos;
25723ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    case TranscendentalCache::TAN: return Runtime::kMath_tan;
2573b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case TranscendentalCache::LOG: return Runtime::kMath_log;
257480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    default:
257580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      UNIMPLEMENTED();
257680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      return Runtime::kAbort;
257780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
257880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
257980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
258080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
25813ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochvoid TranscendentalCacheStub::GenerateOperation(
25823ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    MacroAssembler* masm, TranscendentalCache::Type type) {
258380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Only free register is edi.
2584b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Input value is on FP stack, and also in ebx/edx.
2585b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Input value is possibly in xmm1.
2586b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Address of result (a newly allocated HeapNumber) may be in eax.
25873ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  if (type == TranscendentalCache::SIN ||
25883ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      type == TranscendentalCache::COS ||
25893ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      type == TranscendentalCache::TAN) {
2590b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    // Both fsin and fcos require arguments in the range +/-2^63 and
2591b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    // return NaN for infinities and NaN. They can share all code except
2592b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    // the actual fsin/fcos operation.
2593257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Label in_range, done;
2594b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    // If argument is outside the range -2^63..2^63, fsin/cos doesn't
2595b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    // work. We must reduce it to the appropriate range.
2596b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ mov(edi, edx);
25973ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ and_(edi, Immediate(0x7ff00000));  // Exponent only.
2598b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    int supported_exponent_limit =
2599b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        (63 + HeapNumber::kExponentBias) << HeapNumber::kExponentShift;
26003ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ cmp(edi, Immediate(supported_exponent_limit));
2601257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ j(below, &in_range, Label::kNear);
2602b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    // Check for infinity and NaN. Both return NaN for sin.
26033ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ cmp(edi, Immediate(0x7ff00000));
2604257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Label non_nan_result;
2605257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ j(not_equal, &non_nan_result, Label::kNear);
2606b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    // Input is +/-Infinity or NaN. Result is NaN.
2607b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ fstp(0);
2608b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    // NaN is represented by 0x7ff8000000000000.
2609b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ push(Immediate(0x7ff80000));
2610b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ push(Immediate(0));
2611b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ fld_d(Operand(esp, 0));
26123ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ add(esp, Immediate(2 * kPointerSize));
2613257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ jmp(&done, Label::kNear);
261480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
2615257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ bind(&non_nan_result);
261680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
2617257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Use fpmod to restrict argument to the range +/-2*PI.
2618257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ mov(edi, eax);  // Save eax before using fnstsw_ax.
2619257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ fldpi();
2620257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ fadd(0);
2621257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ fld(1);
2622257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // FPU Stack: input, 2*pi, input.
2623257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    {
2624257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      Label no_exceptions;
2625257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ fwait();
2626257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ fnstsw_ax();
2627257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // Clear if Illegal Operand or Zero Division exceptions are set.
26283ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      __ test(eax, Immediate(5));
2629257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ j(zero, &no_exceptions, Label::kNear);
2630257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ fnclex();
2631257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ bind(&no_exceptions);
2632257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    }
263380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
2634257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Compute st(0) % st(1)
2635257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    {
2636257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      Label partial_remainder_loop;
2637257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ bind(&partial_remainder_loop);
2638257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ fprem1();
2639257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ fwait();
2640257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ fnstsw_ax();
26413ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      __ test(eax, Immediate(0x400 /* C2 */));
2642257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // If C2 is set, computation only has partial result. Loop to
2643257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // continue computation.
2644257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ j(not_zero, &partial_remainder_loop);
2645257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    }
2646257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // FPU Stack: input, 2*pi, input % 2*pi
2647257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ fstp(2);
2648257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ fstp(0);
2649257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ mov(eax, edi);  // Restore eax (allocated HeapNumber pointer).
265080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
2651257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // FPU Stack: input % 2*pi
2652257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ bind(&in_range);
26533ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    switch (type) {
2654257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      case TranscendentalCache::SIN:
2655257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        __ fsin();
2656257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        break;
2657257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      case TranscendentalCache::COS:
2658257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        __ fcos();
2659257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        break;
26603ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      case TranscendentalCache::TAN:
26613ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch        // FPTAN calculates tangent onto st(0) and pushes 1.0 onto the
26623ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch        // FP register stack.
26633ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch        __ fptan();
26643ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch        __ fstp(0);  // Pop FP register stack.
26653ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch        break;
2666257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      default:
2667257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        UNREACHABLE();
266880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    }
2669257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ bind(&done);
2670257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  } else {
26713ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    ASSERT(type == TranscendentalCache::LOG);
2672257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ fldln2();
2673257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ fxch();
2674257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ fyl2x();
267580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
267680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
267780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
267880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
267980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// Input: edx, eax are the left and right objects of a bit op.
268080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// Output: eax, ecx are left and right integers for a bit op.
268180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid FloatingPointHelper::LoadUnknownsAsIntegers(MacroAssembler* masm,
268280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                                 bool use_sse3,
268380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                                 Label* conversion_failure) {
268480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check float operands.
268580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label arg1_is_object, check_undefined_arg1;
268680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label arg2_is_object, check_undefined_arg2;
268780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label load_arg2, done;
268880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
268980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Test if arg1 is a Smi.
269069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ JumpIfNotSmi(edx, &arg1_is_object, Label::kNear);
269180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
269280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiUntag(edx);
269380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ jmp(&load_arg2);
269480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
269580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // If the argument is undefined it converts to zero (ECMA-262, section 9.5).
269680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&check_undefined_arg1);
269744f0eee88ff00398ff7f715fab053374d808c90dSteve Block  Factory* factory = masm->isolate()->factory();
269844f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ cmp(edx, factory->undefined_value());
269980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(not_equal, conversion_failure);
270080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(edx, Immediate(0));
270180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ jmp(&load_arg2);
270280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
270380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&arg1_is_object);
270480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(ebx, FieldOperand(edx, HeapObject::kMapOffset));
270544f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ cmp(ebx, factory->heap_number_map());
270680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(not_equal, &check_undefined_arg1);
270780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
270880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Get the untagged integer version of the edx heap number in ecx.
2709257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  IntegerConvert(masm, edx, use_sse3, conversion_failure);
271080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(edx, ecx);
271180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
271280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Here edx has the untagged integer, eax has a Smi or a heap number.
271380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&load_arg2);
271480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
271580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Test if arg2 is a Smi.
271669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ JumpIfNotSmi(eax, &arg2_is_object, Label::kNear);
271780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
271880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiUntag(eax);
271980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(ecx, eax);
272080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ jmp(&done);
272180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
272280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // If the argument is undefined it converts to zero (ECMA-262, section 9.5).
272380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&check_undefined_arg2);
272444f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ cmp(eax, factory->undefined_value());
272580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(not_equal, conversion_failure);
272680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(ecx, Immediate(0));
272780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ jmp(&done);
272880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
272980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&arg2_is_object);
273080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset));
273144f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ cmp(ebx, factory->heap_number_map());
273280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(not_equal, &check_undefined_arg2);
273380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
273480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Get the untagged integer version of the eax heap number in ecx.
2735257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  IntegerConvert(masm, eax, use_sse3, conversion_failure);
273680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&done);
273780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(eax, edx);
273880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
273980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
274080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
2741b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdochvoid FloatingPointHelper::CheckLoadedIntegersWereInt32(MacroAssembler* masm,
2742b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                                                       bool use_sse3,
2743b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                                                       Label* not_int32) {
2744b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  return;
2745b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch}
2746b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
2747b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
274880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid FloatingPointHelper::LoadFloatOperand(MacroAssembler* masm,
274980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                           Register number) {
2750257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label load_smi, done;
275180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
27523fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ JumpIfSmi(number, &load_smi, Label::kNear);
275380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ fld_d(FieldOperand(number, HeapNumber::kValueOffset));
2754257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ jmp(&done, Label::kNear);
275580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
275680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&load_smi);
275780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiUntag(number);
275880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ push(number);
275980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ fild_s(Operand(esp, 0));
276080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ pop(number);
276180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
276280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&done);
276380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
276480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
276580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
276680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid FloatingPointHelper::LoadSSE2Operands(MacroAssembler* masm) {
2767257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label load_smi_edx, load_eax, load_smi_eax, done;
276880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Load operand in edx into xmm0.
27693fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ JumpIfSmi(edx, &load_smi_edx, Label::kNear);
277080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movdbl(xmm0, FieldOperand(edx, HeapNumber::kValueOffset));
277180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
277280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&load_eax);
277380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Load operand in eax into xmm1.
27743fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ JumpIfSmi(eax, &load_smi_eax, Label::kNear);
277580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movdbl(xmm1, FieldOperand(eax, HeapNumber::kValueOffset));
2776257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ jmp(&done, Label::kNear);
277780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
277880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&load_smi_edx);
277980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiUntag(edx);  // Untag smi before converting to float.
27803ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ cvtsi2sd(xmm0, edx);
278180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiTag(edx);  // Retag smi for heap number overwriting test.
278280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ jmp(&load_eax);
278380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
278480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&load_smi_eax);
278580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiUntag(eax);  // Untag smi before converting to float.
27863ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ cvtsi2sd(xmm1, eax);
278780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiTag(eax);  // Retag smi for heap number overwriting test.
278880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
278980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&done);
279080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
279180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
279280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
279380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid FloatingPointHelper::LoadSSE2Operands(MacroAssembler* masm,
279480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                           Label* not_numbers) {
2795257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label load_smi_edx, load_eax, load_smi_eax, load_float_eax, done;
279680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Load operand in edx into xmm0, or branch to not_numbers.
27973fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ JumpIfSmi(edx, &load_smi_edx, Label::kNear);
279844f0eee88ff00398ff7f715fab053374d808c90dSteve Block  Factory* factory = masm->isolate()->factory();
279944f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ cmp(FieldOperand(edx, HeapObject::kMapOffset), factory->heap_number_map());
280080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(not_equal, not_numbers);  // Argument in edx is not a number.
280180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movdbl(xmm0, FieldOperand(edx, HeapNumber::kValueOffset));
280280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&load_eax);
280380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Load operand in eax into xmm1, or branch to not_numbers.
28043fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ JumpIfSmi(eax, &load_smi_eax, Label::kNear);
280544f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ cmp(FieldOperand(eax, HeapObject::kMapOffset), factory->heap_number_map());
2806257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(equal, &load_float_eax, Label::kNear);
280780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ jmp(not_numbers);  // Argument in eax is not a number.
280880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&load_smi_edx);
280980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiUntag(edx);  // Untag smi before converting to float.
28103ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ cvtsi2sd(xmm0, edx);
281180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiTag(edx);  // Retag smi for heap number overwriting test.
281280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ jmp(&load_eax);
281380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&load_smi_eax);
281480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiUntag(eax);  // Untag smi before converting to float.
28153ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ cvtsi2sd(xmm1, eax);
281680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiTag(eax);  // Retag smi for heap number overwriting test.
2817257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ jmp(&done, Label::kNear);
281880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&load_float_eax);
281980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movdbl(xmm1, FieldOperand(eax, HeapNumber::kValueOffset));
282080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&done);
282180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
282280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
282380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
282480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid FloatingPointHelper::LoadSSE2Smis(MacroAssembler* masm,
282580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                       Register scratch) {
282680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  const Register left = edx;
282780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  const Register right = eax;
282880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(scratch, left);
282980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  ASSERT(!scratch.is(right));  // We're about to clobber scratch.
283080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiUntag(scratch);
28313ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ cvtsi2sd(xmm0, scratch);
283280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
283380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(scratch, right);
283480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiUntag(scratch);
28353ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ cvtsi2sd(xmm1, scratch);
283680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
283780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
283880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
2839b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdochvoid FloatingPointHelper::CheckSSE2OperandsAreInt32(MacroAssembler* masm,
2840b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                                                    Label* non_int32,
2841b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                                                    Register scratch) {
2842b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ cvttsd2si(scratch, Operand(xmm0));
28433ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ cvtsi2sd(xmm2, scratch);
2844b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ ucomisd(xmm0, xmm2);
2845b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ j(not_zero, non_int32);
2846b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ j(carry, non_int32);
2847b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ cvttsd2si(scratch, Operand(xmm1));
28483ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ cvtsi2sd(xmm2, scratch);
2849b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ ucomisd(xmm1, xmm2);
2850b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ j(not_zero, non_int32);
2851b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ j(carry, non_int32);
2852b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch}
2853b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
2854b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
285580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid FloatingPointHelper::LoadFloatOperands(MacroAssembler* masm,
285680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                            Register scratch,
285780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                            ArgLocation arg_location) {
2858257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label load_smi_1, load_smi_2, done_load_1, done;
285980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  if (arg_location == ARGS_IN_REGISTERS) {
286080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ mov(scratch, edx);
286180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  } else {
286280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ mov(scratch, Operand(esp, 2 * kPointerSize));
286380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
28643fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ JumpIfSmi(scratch, &load_smi_1, Label::kNear);
286580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ fld_d(FieldOperand(scratch, HeapNumber::kValueOffset));
286680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&done_load_1);
286780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
286880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  if (arg_location == ARGS_IN_REGISTERS) {
286980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ mov(scratch, eax);
287080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  } else {
287180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ mov(scratch, Operand(esp, 1 * kPointerSize));
287280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
28733fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ JumpIfSmi(scratch, &load_smi_2, Label::kNear);
287480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ fld_d(FieldOperand(scratch, HeapNumber::kValueOffset));
2875257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ jmp(&done, Label::kNear);
287680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
287780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&load_smi_1);
287880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiUntag(scratch);
287980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ push(scratch);
288080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ fild_s(Operand(esp, 0));
288180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ pop(scratch);
288280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ jmp(&done_load_1);
288380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
288480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&load_smi_2);
288580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiUntag(scratch);
288680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ push(scratch);
288780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ fild_s(Operand(esp, 0));
288880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ pop(scratch);
288980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
289080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&done);
289180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
289280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
289380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
289480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid FloatingPointHelper::LoadFloatSmis(MacroAssembler* masm,
289580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                        Register scratch) {
289680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  const Register left = edx;
289780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  const Register right = eax;
289880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(scratch, left);
289980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  ASSERT(!scratch.is(right));  // We're about to clobber scratch.
290080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiUntag(scratch);
290180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ push(scratch);
290280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ fild_s(Operand(esp, 0));
290380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
290480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(scratch, right);
290580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiUntag(scratch);
290680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(Operand(esp, 0), scratch);
290780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ fild_s(Operand(esp, 0));
290880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ pop(scratch);
290980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
291080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
291180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
291280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid FloatingPointHelper::CheckFloatOperands(MacroAssembler* masm,
291380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                             Label* non_float,
291480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                             Register scratch) {
2915257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label test_other, done;
291680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Test if both operands are floats or smi -> scratch=k_is_float;
291780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Otherwise scratch = k_not_float.
29183fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ JumpIfSmi(edx, &test_other, Label::kNear);
291980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(scratch, FieldOperand(edx, HeapObject::kMapOffset));
292044f0eee88ff00398ff7f715fab053374d808c90dSteve Block  Factory* factory = masm->isolate()->factory();
292144f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ cmp(scratch, factory->heap_number_map());
292280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(not_equal, non_float);  // argument in edx is not a number -> NaN
292380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
292480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&test_other);
29253fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ JumpIfSmi(eax, &done, Label::kNear);
292680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(scratch, FieldOperand(eax, HeapObject::kMapOffset));
292744f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ cmp(scratch, factory->heap_number_map());
292880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(not_equal, non_float);  // argument in eax is not a number -> NaN
292980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
293080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Fall-through: Both operands are numbers.
293180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&done);
293280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
293380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
293480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
2935b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdochvoid FloatingPointHelper::CheckFloatOperandsAreInt32(MacroAssembler* masm,
2936b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                                                     Label* non_int32) {
2937b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  return;
2938b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch}
2939b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
2940b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
2941b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdochvoid MathPowStub::Generate(MacroAssembler* masm) {
2942b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  CpuFeatures::Scope use_sse2(SSE2);
294344f0eee88ff00398ff7f715fab053374d808c90dSteve Block  Factory* factory = masm->isolate()->factory();
29443ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  const Register exponent = eax;
29453ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  const Register base = edx;
29463ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  const Register scratch = ecx;
29473ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  const XMMRegister double_result = xmm3;
29483ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  const XMMRegister double_base = xmm2;
29493ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  const XMMRegister double_exponent = xmm1;
29503ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  const XMMRegister double_scratch = xmm4;
29513ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
29523ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  Label call_runtime, done, exponent_not_smi, int_exponent;
29533ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
29543ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Save 1 in double_result - we need this several times later on.
29553ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ mov(scratch, Immediate(1));
29563ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ cvtsi2sd(double_result, scratch);
29573ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
29583ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  if (exponent_type_ == ON_STACK) {
29593ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    Label base_is_smi, unpack_exponent;
29603ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    // The exponent and base are supplied as arguments on the stack.
29613ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    // This can only happen if the stub is called from non-optimized code.
29623ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    // Load input parameters from stack.
29633ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ mov(base, Operand(esp, 2 * kPointerSize));
29643ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ mov(exponent, Operand(esp, 1 * kPointerSize));
29653ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
29663ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ JumpIfSmi(base, &base_is_smi, Label::kNear);
29673ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ cmp(FieldOperand(base, HeapObject::kMapOffset),
29683ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch           factory->heap_number_map());
29693ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ j(not_equal, &call_runtime);
29703ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
29713ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ movdbl(double_base, FieldOperand(base, HeapNumber::kValueOffset));
29723ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ jmp(&unpack_exponent, Label::kNear);
29733ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
29743ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ bind(&base_is_smi);
29753ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ SmiUntag(base);
29763ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ cvtsi2sd(double_base, base);
29773ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
29783ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ bind(&unpack_exponent);
29793ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ JumpIfNotSmi(exponent, &exponent_not_smi, Label::kNear);
29803ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ SmiUntag(exponent);
29813ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ jmp(&int_exponent);
29823ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
29833ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ bind(&exponent_not_smi);
29843ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ cmp(FieldOperand(exponent, HeapObject::kMapOffset),
29853ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch           factory->heap_number_map());
29863ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ j(not_equal, &call_runtime);
29873ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ movdbl(double_exponent,
29883ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch              FieldOperand(exponent, HeapNumber::kValueOffset));
29893ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  } else if (exponent_type_ == TAGGED) {
29903ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ JumpIfNotSmi(exponent, &exponent_not_smi, Label::kNear);
29913ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ SmiUntag(exponent);
29923ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ jmp(&int_exponent);
29933ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
29943ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ bind(&exponent_not_smi);
29953ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ movdbl(double_exponent,
29963ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch              FieldOperand(exponent, HeapNumber::kValueOffset));
29973ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  }
2998b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
29993ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  if (exponent_type_ != INTEGER) {
30003ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    Label fast_power;
30013ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    // Detect integer exponents stored as double.
30023ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ cvttsd2si(exponent, Operand(double_exponent));
30033ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    // Skip to runtime if possibly NaN (indicated by the indefinite integer).
30043ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ cmp(exponent, Immediate(0x80000000u));
30053ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ j(equal, &call_runtime);
30063ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ cvtsi2sd(double_scratch, exponent);
30073ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    // Already ruled out NaNs for exponent.
30083ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ ucomisd(double_exponent, double_scratch);
30093ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ j(equal, &int_exponent);
30103ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
30113ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    if (exponent_type_ == ON_STACK) {
30123ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      // Detect square root case.  Crankshaft detects constant +/-0.5 at
30133ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      // compile time and uses DoMathPowHalf instead.  We then skip this check
30143ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      // for non-constant cases of +/-0.5 as these hardly occur.
30153ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      Label continue_sqrt, continue_rsqrt, not_plus_half;
30163ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      // Test for 0.5.
30173ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      // Load double_scratch with 0.5.
30183ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      __ mov(scratch, Immediate(0x3F000000u));
30193ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      __ movd(double_scratch, scratch);
30203ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      __ cvtss2sd(double_scratch, double_scratch);
30213ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      // Already ruled out NaNs for exponent.
30223ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      __ ucomisd(double_scratch, double_exponent);
30233ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      __ j(not_equal, &not_plus_half, Label::kNear);
30243ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
30253ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      // Calculates square root of base.  Check for the special case of
30263ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      // Math.pow(-Infinity, 0.5) == Infinity (ECMA spec, 15.8.2.13).
30273ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      // According to IEEE-754, single-precision -Infinity has the highest
30283ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      // 9 bits set and the lowest 23 bits cleared.
30293ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      __ mov(scratch, 0xFF800000u);
30303ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      __ movd(double_scratch, scratch);
30313ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      __ cvtss2sd(double_scratch, double_scratch);
30323ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      __ ucomisd(double_base, double_scratch);
30333ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      // Comparing -Infinity with NaN results in "unordered", which sets the
30343ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      // zero flag as if both were equal.  However, it also sets the carry flag.
30353ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      __ j(not_equal, &continue_sqrt, Label::kNear);
30363ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      __ j(carry, &continue_sqrt, Label::kNear);
30373ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
30383ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      // Set result to Infinity in the special case.
30393ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      __ xorps(double_result, double_result);
30403ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      __ subsd(double_result, double_scratch);
30413ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      __ jmp(&done);
30423ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
30433ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      __ bind(&continue_sqrt);
30443ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      // sqrtsd returns -0 when input is -0.  ECMA spec requires +0.
30453ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      __ xorps(double_scratch, double_scratch);
30463ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      __ addsd(double_scratch, double_base);  // Convert -0 to +0.
30473ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      __ sqrtsd(double_result, double_scratch);
30483ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      __ jmp(&done);
30493ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
30503ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      // Test for -0.5.
30513ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      __ bind(&not_plus_half);
30523ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      // Load double_exponent with -0.5 by substracting 1.
30533ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      __ subsd(double_scratch, double_result);
30543ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      // Already ruled out NaNs for exponent.
30553ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      __ ucomisd(double_scratch, double_exponent);
30563ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      __ j(not_equal, &fast_power, Label::kNear);
30573ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
30583ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      // Calculates reciprocal of square root of base.  Check for the special
30593ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      // case of Math.pow(-Infinity, -0.5) == 0 (ECMA spec, 15.8.2.13).
30603ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      // According to IEEE-754, single-precision -Infinity has the highest
30613ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      // 9 bits set and the lowest 23 bits cleared.
30623ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      __ mov(scratch, 0xFF800000u);
30633ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      __ movd(double_scratch, scratch);
30643ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      __ cvtss2sd(double_scratch, double_scratch);
30653ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      __ ucomisd(double_base, double_scratch);
30663ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      // Comparing -Infinity with NaN results in "unordered", which sets the
30673ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      // zero flag as if both were equal.  However, it also sets the carry flag.
30683ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      __ j(not_equal, &continue_rsqrt, Label::kNear);
30693ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      __ j(carry, &continue_rsqrt, Label::kNear);
30703ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
30713ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      // Set result to 0 in the special case.
30723ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      __ xorps(double_result, double_result);
30733ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      __ jmp(&done);
30743ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
30753ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      __ bind(&continue_rsqrt);
30763ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      // sqrtsd returns -0 when input is -0.  ECMA spec requires +0.
30773ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      __ xorps(double_exponent, double_exponent);
30783ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      __ addsd(double_exponent, double_base);  // Convert -0 to +0.
30793ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      __ sqrtsd(double_exponent, double_exponent);
30803ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      __ divsd(double_result, double_exponent);
30813ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      __ jmp(&done);
30823ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    }
3083b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
30843ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    // Using FPU instructions to calculate power.
30853ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    Label fast_power_failed;
30863ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ bind(&fast_power);
30873ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ fnclex();  // Clear flags to catch exceptions later.
30883ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    // Transfer (B)ase and (E)xponent onto the FPU register stack.
30893ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ sub(esp, Immediate(kDoubleSize));
30903ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ movdbl(Operand(esp, 0), double_exponent);
30913ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ fld_d(Operand(esp, 0));  // E
30923ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ movdbl(Operand(esp, 0), double_base);
30933ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ fld_d(Operand(esp, 0));  // B, E
30943ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
30953ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    // Exponent is in st(1) and base is in st(0)
30963ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    // B ^ E = (2^(E * log2(B)) - 1) + 1 = (2^X - 1) + 1 for X = E * log2(B)
30973ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    // FYL2X calculates st(1) * log2(st(0))
30983ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ fyl2x();    // X
30993ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ fld(0);     // X, X
31003ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ frndint();  // rnd(X), X
31013ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ fsub(1);    // rnd(X), X-rnd(X)
31023ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ fxch(1);    // X - rnd(X), rnd(X)
31033ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    // F2XM1 calculates 2^st(0) - 1 for -1 < st(0) < 1
31043ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ f2xm1();    // 2^(X-rnd(X)) - 1, rnd(X)
31053ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ fld1();     // 1, 2^(X-rnd(X)) - 1, rnd(X)
31063ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ faddp(1);   // 1, 2^(X-rnd(X)), rnd(X)
31073ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    // FSCALE calculates st(0) * 2^st(1)
31083ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ fscale();   // 2^X, rnd(X)
31093ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ fstp(1);
31103ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    // Bail out to runtime in case of exceptions in the status word.
31113ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ fnstsw_ax();
31123ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ test_b(eax, 0x5F);  // We check for all but precision exception.
31133ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ j(not_zero, &fast_power_failed, Label::kNear);
31143ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ fstp_d(Operand(esp, 0));
31153ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ movdbl(double_result, Operand(esp, 0));
31163ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ add(esp, Immediate(kDoubleSize));
31173ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ jmp(&done);
31183ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
31193ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ bind(&fast_power_failed);
31203ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ fninit();
31213ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ add(esp, Immediate(kDoubleSize));
31223ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ jmp(&call_runtime);
31233ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  }
3124c7cc028aaeedbbfa11c11d0b7b243b3d9e837ed9Ben Murdoch
31253ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Calculate power with integer exponent.
31263ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ bind(&int_exponent);
31273ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  const XMMRegister double_scratch2 = double_exponent;
31283ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ mov(scratch, exponent);  // Back up exponent.
31293ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ movsd(double_scratch, double_base);  // Back up base.
31303ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ movsd(double_scratch2, double_result);  // Load double_exponent with 1.
3131b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
3132b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Get absolute value of exponent.
31333ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  Label no_neg, while_true, no_multiply;
31343ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ test(scratch, scratch);
31353ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ j(positive, &no_neg, Label::kNear);
31363ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ neg(scratch);
3137b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ bind(&no_neg);
3138b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
3139b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ bind(&while_true);
31403ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ shr(scratch, 1);
3141257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(not_carry, &no_multiply, Label::kNear);
31423ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ mulsd(double_result, double_scratch);
3143b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ bind(&no_multiply);
3144b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
31453ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ mulsd(double_scratch, double_scratch);
31463ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ j(not_zero, &while_true);
3147b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
31483ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // scratch has the original value of the exponent - if the exponent is
31493ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // negative, return 1/result.
31503ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ test(exponent, exponent);
31513ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ j(positive, &done);
31523ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ divsd(double_scratch2, double_result);
31533ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ movsd(double_result, double_scratch2);
31543ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Test whether result is zero.  Bail out to check for subnormal result.
31553ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Due to subnormals, x^-y == (1/x)^y does not hold in all cases.
31563ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ xorps(double_scratch2, double_scratch2);
31573ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ ucomisd(double_scratch2, double_result);  // Result cannot be NaN.
31583ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // double_exponent aliased as double_scratch2 has already been overwritten
31593ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // and may not have contained the exponent value in the first place when the
31603ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // exponent is a smi.  We reset it with exponent value before bailing out.
31613ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ j(not_equal, &done);
31623ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ cvtsi2sd(double_exponent, exponent);
31633ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
31643ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Returning or bailing out.
31653ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  Counters* counters = masm->isolate()->counters();
31663ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  if (exponent_type_ == ON_STACK) {
31673ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    // The arguments are still on the stack.
31683ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ bind(&call_runtime);
31693ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ TailCallRuntime(Runtime::kMath_pow_cfunction, 2, 1);
3170b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
31713ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    // The stub is called from non-optimized code, which expects the result
31723ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    // as heap number in exponent.
31733ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ bind(&done);
31743ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ AllocateHeapNumber(eax, scratch, base, &call_runtime);
31753ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), double_result);
31763ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ IncrementCounter(counters->math_pow(), 1);
31773ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ ret(2 * kPointerSize);
31783ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  } else {
31793ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ bind(&call_runtime);
31803ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    {
31813ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      AllowExternalCallThatCantCauseGC scope(masm);
31823ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      __ PrepareCallCFunction(4, scratch);
31833ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      __ movdbl(Operand(esp, 0 * kDoubleSize), double_base);
31843ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      __ movdbl(Operand(esp, 1 * kDoubleSize), double_exponent);
31853ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      __ CallCFunction(
31863ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch          ExternalReference::power_double_double_function(masm->isolate()), 4);
31873ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    }
31883ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    // Return value is in st(0) on ia32.
31893ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    // Store it into the (fixed) result register.
31903ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ sub(esp, Immediate(kDoubleSize));
31913ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ fstp_d(Operand(esp, 0));
31923ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ movdbl(double_result, Operand(esp, 0));
31933ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ add(esp, Immediate(kDoubleSize));
319485b71799222b55eb5dd74ea26efe0c64ab655c8cBen Murdoch
31953ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ bind(&done);
31963ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ IncrementCounter(counters->math_pow(), 1);
31973ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ ret(0);
31983ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  }
3199b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch}
3200b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
3201b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
320280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid ArgumentsAccessStub::GenerateReadElement(MacroAssembler* masm) {
320380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // The key is in edx and the parameter count is in eax.
320480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
320580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // The displacement is used for skipping the frame pointer on the
320680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // stack. It is the offset of the last parameter (if any) relative
320780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // to the frame pointer.
320880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  static const int kDisplacement = 1 * kPointerSize;
320980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
321080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check that the key is a smi.
321180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label slow;
321269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ JumpIfNotSmi(edx, &slow, Label::kNear);
321380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
321480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check if the calling frame is an arguments adaptor frame.
3215257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label adaptor;
321680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(ebx, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
321780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(ecx, Operand(ebx, StandardFrameConstants::kContextOffset));
32183ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ cmp(ecx, Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
3219257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(equal, &adaptor, Label::kNear);
322080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
322180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check index against formal parameters count limit passed in
322280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // through register eax. Use unsigned comparison to get negative
322380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // check for free.
32243ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ cmp(edx, eax);
322569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ j(above_equal, &slow, Label::kNear);
322680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
322780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Read the argument from the stack and return it.
322880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  STATIC_ASSERT(kSmiTagSize == 1);
322980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  STATIC_ASSERT(kSmiTag == 0);  // Shifting code depends on these.
323080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ lea(ebx, Operand(ebp, eax, times_2, 0));
323180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ neg(edx);
323280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(eax, Operand(ebx, edx, times_2, kDisplacement));
323380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ ret(0);
323480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
323580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Arguments adaptor case: Check index against actual arguments
323680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // limit found in the arguments adaptor frame. Use unsigned
323780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // comparison to get negative check for free.
323880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&adaptor);
323980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(ecx, Operand(ebx, ArgumentsAdaptorFrameConstants::kLengthOffset));
32403ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ cmp(edx, ecx);
324169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ j(above_equal, &slow, Label::kNear);
324280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
324380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Read the argument from the stack and return it.
324480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  STATIC_ASSERT(kSmiTagSize == 1);
324580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  STATIC_ASSERT(kSmiTag == 0);  // Shifting code depends on these.
324680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ lea(ebx, Operand(ebx, ecx, times_2, 0));
324780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ neg(edx);
324880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(eax, Operand(ebx, edx, times_2, kDisplacement));
324980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ ret(0);
325080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
325180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Slow-case: Handle non-smi or out-of-bounds access to arguments
325280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // by calling the runtime system.
325380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&slow);
325480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ pop(ebx);  // Return address.
325580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ push(edx);
325680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ push(ebx);
325780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ TailCallRuntime(Runtime::kGetArgumentsProperty, 1, 1);
325880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
325980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
326080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
32613fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdochvoid ArgumentsAccessStub::GenerateNewNonStrictSlow(MacroAssembler* masm) {
326280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // esp[0] : return address
326380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // esp[4] : number of parameters
326480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // esp[8] : receiver displacement
32653fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // esp[12] : function
32663fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
32673fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // Check if the calling frame is an arguments adaptor frame.
32683fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  Label runtime;
32693fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ mov(edx, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
32703fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ mov(ecx, Operand(edx, StandardFrameConstants::kContextOffset));
32713ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ cmp(ecx, Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
32723fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ j(not_equal, &runtime, Label::kNear);
32733fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
32743fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // Patch the arguments.length and the parameters pointer.
32753fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ mov(ecx, Operand(edx, ArgumentsAdaptorFrameConstants::kLengthOffset));
32763fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ mov(Operand(esp, 1 * kPointerSize), ecx);
32773fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ lea(edx, Operand(edx, ecx, times_2,
32783fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch              StandardFrameConstants::kCallerSPOffset));
32793fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ mov(Operand(esp, 2 * kPointerSize), edx);
32803fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
32813fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ bind(&runtime);
32823fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ TailCallRuntime(Runtime::kNewArgumentsFast, 3, 1);
32833fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch}
32843fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
32853fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
32863fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdochvoid ArgumentsAccessStub::GenerateNewNonStrictFast(MacroAssembler* masm) {
32873fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // esp[0] : return address
32883fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // esp[4] : number of parameters (tagged)
32893fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // esp[8] : receiver displacement
32903fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // esp[12] : function
32913fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
32923fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // ebx = parameter count (tagged)
32933fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ mov(ebx, Operand(esp, 1 * kPointerSize));
32943fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
32953fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // Check if the calling frame is an arguments adaptor frame.
32963fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // TODO(rossberg): Factor out some of the bits that are shared with the other
32973fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // Generate* functions.
32983fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  Label runtime;
32993fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  Label adaptor_frame, try_allocate;
33003fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ mov(edx, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
33013fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ mov(ecx, Operand(edx, StandardFrameConstants::kContextOffset));
33023ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ cmp(ecx, Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
33033fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ j(equal, &adaptor_frame, Label::kNear);
33043fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
33053fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // No adaptor, parameter count = argument count.
33063fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ mov(ecx, ebx);
33073fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ jmp(&try_allocate, Label::kNear);
33083fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
33093fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // We have an adaptor frame. Patch the parameters pointer.
33103fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ bind(&adaptor_frame);
33113fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ mov(ecx, Operand(edx, ArgumentsAdaptorFrameConstants::kLengthOffset));
33123fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ lea(edx, Operand(edx, ecx, times_2,
33133fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch                      StandardFrameConstants::kCallerSPOffset));
33143fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ mov(Operand(esp, 2 * kPointerSize), edx);
33153fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
33163fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // ebx = parameter count (tagged)
33173fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // ecx = argument count (tagged)
33183fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // esp[4] = parameter count (tagged)
33193fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // esp[8] = address of receiver argument
33203fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // Compute the mapped parameter count = min(ebx, ecx) in ebx.
33213ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ cmp(ebx, ecx);
33223fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ j(less_equal, &try_allocate, Label::kNear);
33233fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ mov(ebx, ecx);
33243fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
33253fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ bind(&try_allocate);
33263fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
33273fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // Save mapped parameter count.
33283fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ push(ebx);
33293fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
33303fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // Compute the sizes of backing store, parameter map, and arguments object.
33313fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // 1. Parameter map, has 2 extra words containing context and backing store.
33323fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  const int kParameterMapHeaderSize =
33333fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch      FixedArray::kHeaderSize + 2 * kPointerSize;
33343fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  Label no_parameter_map;
33353ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ test(ebx, ebx);
33363fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ j(zero, &no_parameter_map, Label::kNear);
33373fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ lea(ebx, Operand(ebx, times_2, kParameterMapHeaderSize));
33383fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ bind(&no_parameter_map);
33393fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
33403fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // 2. Backing store.
33413fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ lea(ebx, Operand(ebx, ecx, times_2, FixedArray::kHeaderSize));
33423fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
33433fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // 3. Arguments object.
33443ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ add(ebx, Immediate(Heap::kArgumentsObjectSize));
33453fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
33463fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // Do the allocation of all three objects in one go.
33473fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ AllocateInNewSpace(ebx, eax, edx, edi, &runtime, TAG_OBJECT);
33483fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
33493fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // eax = address of new object(s) (tagged)
33503fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // ecx = argument count (tagged)
33513fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // esp[0] = mapped parameter count (tagged)
33523fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // esp[8] = parameter count (tagged)
33533fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // esp[12] = address of receiver argument
33543fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // Get the arguments boilerplate from the current (global) context into edi.
33553fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  Label has_mapped_parameters, copy;
33563fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ mov(edi, Operand(esi, Context::SlotOffset(Context::GLOBAL_INDEX)));
33573fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ mov(edi, FieldOperand(edi, GlobalObject::kGlobalContextOffset));
33583fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ mov(ebx, Operand(esp, 0 * kPointerSize));
33593ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ test(ebx, ebx);
33603fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ j(not_zero, &has_mapped_parameters, Label::kNear);
33613fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ mov(edi, Operand(edi,
33623fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch         Context::SlotOffset(Context::ARGUMENTS_BOILERPLATE_INDEX)));
33633fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ jmp(&copy, Label::kNear);
33643fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
33653fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ bind(&has_mapped_parameters);
33663fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ mov(edi, Operand(edi,
33673fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch            Context::SlotOffset(Context::ALIASED_ARGUMENTS_BOILERPLATE_INDEX)));
33683fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ bind(&copy);
33693fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
33703fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // eax = address of new object (tagged)
33713fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // ebx = mapped parameter count (tagged)
33723fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // ecx = argument count (tagged)
33733fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // edi = address of boilerplate object (tagged)
33743fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // esp[0] = mapped parameter count (tagged)
33753fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // esp[8] = parameter count (tagged)
33763fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // esp[12] = address of receiver argument
33773fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // Copy the JS object part.
33783fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  for (int i = 0; i < JSObject::kHeaderSize; i += kPointerSize) {
33793fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    __ mov(edx, FieldOperand(edi, i));
33803fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    __ mov(FieldOperand(eax, i), edx);
33813fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  }
33823fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
33833ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Set up the callee in-object property.
33843fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  STATIC_ASSERT(Heap::kArgumentsCalleeIndex == 1);
33853fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ mov(edx, Operand(esp, 4 * kPointerSize));
33863fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ mov(FieldOperand(eax, JSObject::kHeaderSize +
33873fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch                      Heap::kArgumentsCalleeIndex * kPointerSize),
33883fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch         edx);
33893fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
33903fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // Use the length (smi tagged) and set that as an in-object property too.
33913fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  STATIC_ASSERT(Heap::kArgumentsLengthIndex == 0);
33923fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ mov(FieldOperand(eax, JSObject::kHeaderSize +
33933fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch                      Heap::kArgumentsLengthIndex * kPointerSize),
33943fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch         ecx);
33953fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
33963ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Set up the elements pointer in the allocated arguments object.
33973fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // If we allocated a parameter map, edi will point there, otherwise to the
33983fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // backing store.
33993fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ lea(edi, Operand(eax, Heap::kArgumentsObjectSize));
34003fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ mov(FieldOperand(eax, JSObject::kElementsOffset), edi);
34013fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
34023fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // eax = address of new object (tagged)
34033fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // ebx = mapped parameter count (tagged)
34043fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // ecx = argument count (tagged)
34053fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // edi = address of parameter map or backing store (tagged)
34063fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // esp[0] = mapped parameter count (tagged)
34073fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // esp[8] = parameter count (tagged)
34083fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // esp[12] = address of receiver argument
34093fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // Free a register.
34103fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ push(eax);
34113fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
34123fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // Initialize parameter map. If there are no mapped arguments, we're done.
34133fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  Label skip_parameter_map;
34143ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ test(ebx, ebx);
34153fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ j(zero, &skip_parameter_map);
341680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
34173fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ mov(FieldOperand(edi, FixedArray::kMapOffset),
34183fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch         Immediate(FACTORY->non_strict_arguments_elements_map()));
34193fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ lea(eax, Operand(ebx, reinterpret_cast<intptr_t>(Smi::FromInt(2))));
34203fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ mov(FieldOperand(edi, FixedArray::kLengthOffset), eax);
34213fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ mov(FieldOperand(edi, FixedArray::kHeaderSize + 0 * kPointerSize), esi);
34223fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ lea(eax, Operand(edi, ebx, times_2, kParameterMapHeaderSize));
34233fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ mov(FieldOperand(edi, FixedArray::kHeaderSize + 1 * kPointerSize), eax);
34243fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
34253fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // Copy the parameter slots and the holes in the arguments.
34263fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // We need to fill in mapped_parameter_count slots. They index the context,
34273fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // where parameters are stored in reverse order, at
34283fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  //   MIN_CONTEXT_SLOTS .. MIN_CONTEXT_SLOTS+parameter_count-1
34293fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // The mapped parameter thus need to get indices
34303fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  //   MIN_CONTEXT_SLOTS+parameter_count-1 ..
34313fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  //       MIN_CONTEXT_SLOTS+parameter_count-mapped_parameter_count
34323fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // We loop from right to left.
34333fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  Label parameters_loop, parameters_test;
34343fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ push(ecx);
34353fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ mov(eax, Operand(esp, 2 * kPointerSize));
34363fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ mov(ebx, Immediate(Smi::FromInt(Context::MIN_CONTEXT_SLOTS)));
34373fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ add(ebx, Operand(esp, 4 * kPointerSize));
34383ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ sub(ebx, eax);
34393fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ mov(ecx, FACTORY->the_hole_value());
34403fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ mov(edx, edi);
34413fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ lea(edi, Operand(edi, eax, times_2, kParameterMapHeaderSize));
34423fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // eax = loop variable (tagged)
34433fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // ebx = mapping index (tagged)
34443fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // ecx = the hole value
34453fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // edx = address of parameter map (tagged)
34463fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // edi = address of backing store (tagged)
34473fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // esp[0] = argument count (tagged)
34483fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // esp[4] = address of new object (tagged)
34493fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // esp[8] = mapped parameter count (tagged)
34503fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // esp[16] = parameter count (tagged)
34513fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // esp[20] = address of receiver argument
34523fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ jmp(&parameters_test, Label::kNear);
34533fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
34543fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ bind(&parameters_loop);
34553ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ sub(eax, Immediate(Smi::FromInt(1)));
34563fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ mov(FieldOperand(edx, eax, times_2, kParameterMapHeaderSize), ebx);
34573fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ mov(FieldOperand(edi, eax, times_2, FixedArray::kHeaderSize), ecx);
34583ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ add(ebx, Immediate(Smi::FromInt(1)));
34593fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ bind(&parameters_test);
34603ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ test(eax, eax);
34613fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ j(not_zero, &parameters_loop, Label::kNear);
34623fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ pop(ecx);
34633fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
34643fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ bind(&skip_parameter_map);
34653fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
34663fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // ecx = argument count (tagged)
34673fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // edi = address of backing store (tagged)
34683fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // esp[0] = address of new object (tagged)
34693fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // esp[4] = mapped parameter count (tagged)
34703fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // esp[12] = parameter count (tagged)
34713fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // esp[16] = address of receiver argument
34723fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // Copy arguments header and remaining slots (if there are any).
34733fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ mov(FieldOperand(edi, FixedArray::kMapOffset),
34743fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch         Immediate(FACTORY->fixed_array_map()));
34753fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ mov(FieldOperand(edi, FixedArray::kLengthOffset), ecx);
34763fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
34773fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  Label arguments_loop, arguments_test;
34783fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ mov(ebx, Operand(esp, 1 * kPointerSize));
34793fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ mov(edx, Operand(esp, 4 * kPointerSize));
34803ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ sub(edx, ebx);  // Is there a smarter way to do negative scaling?
34813ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ sub(edx, ebx);
34823fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ jmp(&arguments_test, Label::kNear);
34833fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
34843fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ bind(&arguments_loop);
34853ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ sub(edx, Immediate(kPointerSize));
34863fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ mov(eax, Operand(edx, 0));
34873fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ mov(FieldOperand(edi, ebx, times_2, FixedArray::kHeaderSize), eax);
34883ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ add(ebx, Immediate(Smi::FromInt(1)));
34893fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
34903fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ bind(&arguments_test);
34913ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ cmp(ebx, ecx);
34923fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ j(less, &arguments_loop, Label::kNear);
34933fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
34943fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // Restore.
34953fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ pop(eax);  // Address of arguments object.
34963fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ pop(ebx);  // Parameter count.
34973fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
34983fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // Return and remove the on-stack parameters.
34993fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ ret(3 * kPointerSize);
35003fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
35013fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // Do the runtime call to allocate the arguments object.
35023fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ bind(&runtime);
35033fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ pop(eax);  // Remove saved parameter count.
35043fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ mov(Operand(esp, 1 * kPointerSize), ecx);  // Patch argument count.
35053fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ TailCallRuntime(Runtime::kNewStrictArgumentsFast, 3, 1);
35063fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch}
35073fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
35083fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
35093fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdochvoid ArgumentsAccessStub::GenerateNewStrict(MacroAssembler* masm) {
35103fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // esp[0] : return address
35113fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // esp[4] : number of parameters
35123fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // esp[8] : receiver displacement
35133fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // esp[12] : function
351480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
351580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check if the calling frame is an arguments adaptor frame.
351680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label adaptor_frame, try_allocate, runtime;
351780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(edx, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
351880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(ecx, Operand(edx, StandardFrameConstants::kContextOffset));
35193ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ cmp(ecx, Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
352069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ j(equal, &adaptor_frame, Label::kNear);
352180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
352280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Get the length from the frame.
352380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(ecx, Operand(esp, 1 * kPointerSize));
352469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ jmp(&try_allocate, Label::kNear);
352580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
352680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Patch the arguments.length and the parameters pointer.
352780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&adaptor_frame);
352880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(ecx, Operand(edx, ArgumentsAdaptorFrameConstants::kLengthOffset));
352980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(Operand(esp, 1 * kPointerSize), ecx);
35303fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ lea(edx, Operand(edx, ecx, times_2,
35313fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch                      StandardFrameConstants::kCallerSPOffset));
353280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(Operand(esp, 2 * kPointerSize), edx);
353380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
353480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Try the new space allocation. Start out with computing the size of
353580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // the arguments object and the elements array.
3536257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label add_arguments_object;
353780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&try_allocate);
35383ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ test(ecx, ecx);
3539257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(zero, &add_arguments_object, Label::kNear);
354080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ lea(ecx, Operand(ecx, times_2, FixedArray::kHeaderSize));
354180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&add_arguments_object);
35423ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ add(ecx, Immediate(Heap::kArgumentsObjectSizeStrict));
354380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
354480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Do the allocation of both objects in one go.
354580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ AllocateInNewSpace(ecx, eax, edx, ebx, &runtime, TAG_OBJECT);
354680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
354780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Get the arguments boilerplate from the current (global) context.
354880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(edi, Operand(esi, Context::SlotOffset(Context::GLOBAL_INDEX)));
354980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(edi, FieldOperand(edi, GlobalObject::kGlobalContextOffset));
35503fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  const int offset =
35513fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch      Context::SlotOffset(Context::STRICT_MODE_ARGUMENTS_BOILERPLATE_INDEX);
35523fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ mov(edi, Operand(edi, offset));
355380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
355480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Copy the JS object part.
355580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  for (int i = 0; i < JSObject::kHeaderSize; i += kPointerSize) {
355680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ mov(ebx, FieldOperand(edi, i));
355780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ mov(FieldOperand(eax, i), ebx);
355880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
355980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
356080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Get the length (smi tagged) and set that as an in-object property too.
356144f0eee88ff00398ff7f715fab053374d808c90dSteve Block  STATIC_ASSERT(Heap::kArgumentsLengthIndex == 0);
356280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(ecx, Operand(esp, 1 * kPointerSize));
356344f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ mov(FieldOperand(eax, JSObject::kHeaderSize +
35643fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch                      Heap::kArgumentsLengthIndex * kPointerSize),
356544f0eee88ff00398ff7f715fab053374d808c90dSteve Block         ecx);
356680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
356780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // If there are no actual arguments, we're done.
356880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label done;
35693ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ test(ecx, ecx);
357069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ j(zero, &done, Label::kNear);
357180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
357280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Get the parameters pointer from the stack.
357380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(edx, Operand(esp, 2 * kPointerSize));
357480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
35753ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Set up the elements pointer in the allocated arguments object and
357680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // initialize the header in the elements fixed array.
35773fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ lea(edi, Operand(eax, Heap::kArgumentsObjectSizeStrict));
357880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(FieldOperand(eax, JSObject::kElementsOffset), edi);
357980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(FieldOperand(edi, FixedArray::kMapOffset),
35803fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch         Immediate(FACTORY->fixed_array_map()));
358144f0eee88ff00398ff7f715fab053374d808c90dSteve Block
358280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(FieldOperand(edi, FixedArray::kLengthOffset), ecx);
358380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Untag the length for the loop below.
358480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiUntag(ecx);
358580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
358680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Copy the fixed array slots.
3587257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label loop;
358880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&loop);
358980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(ebx, Operand(edx, -1 * kPointerSize));  // Skip receiver.
359080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(FieldOperand(edi, FixedArray::kHeaderSize), ebx);
35913ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ add(edi, Immediate(kPointerSize));
35923ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ sub(edx, Immediate(kPointerSize));
359380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ dec(ecx);
359480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(not_zero, &loop);
359580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
359680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Return and remove the on-stack parameters.
359780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&done);
359880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ ret(3 * kPointerSize);
359980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
360080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Do the runtime call to allocate the arguments object.
360180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&runtime);
36023fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ TailCallRuntime(Runtime::kNewStrictArgumentsFast, 3, 1);
360380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
360480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
360580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
360680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid RegExpExecStub::Generate(MacroAssembler* masm) {
360780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Just jump directly to runtime if native RegExp is not selected at compile
360880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // time or if regexp entry in generated code is turned off runtime switch or
360980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // at compilation.
361080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#ifdef V8_INTERPRETED_REGEXP
361180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ TailCallRuntime(Runtime::kRegExpExec, 4, 1);
361280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#else  // V8_INTERPRETED_REGEXP
361380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
361480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Stack frame on entry.
361580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  //  esp[0]: return address
361680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  //  esp[4]: last_match_info (expected JSArray)
361780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  //  esp[8]: previous index
361880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  //  esp[12]: subject string
361980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  //  esp[16]: JSRegExp object
362080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
362180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  static const int kLastMatchInfoOffset = 1 * kPointerSize;
362280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  static const int kPreviousIndexOffset = 2 * kPointerSize;
362380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  static const int kSubjectOffset = 3 * kPointerSize;
362480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  static const int kJSRegExpOffset = 4 * kPointerSize;
362580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
362680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label runtime, invoke_regexp;
362780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
362880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Ensure that a RegExp stack is allocated.
362980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  ExternalReference address_of_regexp_stack_memory_address =
363044f0eee88ff00398ff7f715fab053374d808c90dSteve Block      ExternalReference::address_of_regexp_stack_memory_address(
363144f0eee88ff00398ff7f715fab053374d808c90dSteve Block          masm->isolate());
363280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  ExternalReference address_of_regexp_stack_memory_size =
363344f0eee88ff00398ff7f715fab053374d808c90dSteve Block      ExternalReference::address_of_regexp_stack_memory_size(masm->isolate());
363480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(ebx, Operand::StaticVariable(address_of_regexp_stack_memory_size));
36353ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ test(ebx, ebx);
3636257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(zero, &runtime);
363780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
363880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check that the first argument is a JSRegExp object.
363980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(eax, Operand(esp, kJSRegExpOffset));
364080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  STATIC_ASSERT(kSmiTag == 0);
36413fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ JumpIfSmi(eax, &runtime);
364280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ CmpObjectType(eax, JS_REGEXP_TYPE, ecx);
364380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(not_equal, &runtime);
364480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check that the RegExp has been compiled (data contains a fixed array).
364580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(ecx, FieldOperand(eax, JSRegExp::kDataOffset));
364680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  if (FLAG_debug_code) {
364780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ test(ecx, Immediate(kSmiTagMask));
364880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ Check(not_zero, "Unexpected type for RegExp data, FixedArray expected");
364980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ CmpObjectType(ecx, FIXED_ARRAY_TYPE, ebx);
365080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ Check(equal, "Unexpected type for RegExp data, FixedArray expected");
365180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
365280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
365380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // ecx: RegExp data (FixedArray)
365480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check the type of the RegExp. Only continue if type is JSRegExp::IRREGEXP.
365580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(ebx, FieldOperand(ecx, JSRegExp::kDataTagOffset));
36563ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ cmp(ebx, Immediate(Smi::FromInt(JSRegExp::IRREGEXP)));
365780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(not_equal, &runtime);
365880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
365980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // ecx: RegExp data (FixedArray)
366080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check that the number of captures fit in the static offsets vector buffer.
366180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(edx, FieldOperand(ecx, JSRegExp::kIrregexpCaptureCountOffset));
366280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Calculate number of capture registers (number_of_captures + 1) * 2. This
366380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // uses the asumption that smis are 2 * their untagged value.
366480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  STATIC_ASSERT(kSmiTag == 0);
366580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  STATIC_ASSERT(kSmiTagSize + kSmiShiftSize == 1);
36663ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ add(edx, Immediate(2));  // edx was a smi.
366780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check that the static offsets vector buffer is large enough.
366880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cmp(edx, OffsetsVector::kStaticOffsetsVectorSize);
366980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(above, &runtime);
367080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
367180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // ecx: RegExp data (FixedArray)
367280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // edx: Number of capture registers
367380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check that the second argument is a string.
367480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(eax, Operand(esp, kSubjectOffset));
36753fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ JumpIfSmi(eax, &runtime);
367680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Condition is_string = masm->IsObjectStringType(eax, ebx, ebx);
367780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(NegateCondition(is_string), &runtime);
367880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Get the length of the string to ebx.
367980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(ebx, FieldOperand(eax, String::kLengthOffset));
368080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
368180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // ebx: Length of subject string as a smi
368280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // ecx: RegExp data (FixedArray)
368380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // edx: Number of capture registers
368480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check that the third argument is a positive smi less than the subject
368580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // string length. A negative value will be greater (unsigned comparison).
368680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(eax, Operand(esp, kPreviousIndexOffset));
36873fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ JumpIfNotSmi(eax, &runtime);
36883ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ cmp(eax, ebx);
368980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(above_equal, &runtime);
369080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
369180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // ecx: RegExp data (FixedArray)
369280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // edx: Number of capture registers
369380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check that the fourth object is a JSArray object.
369480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(eax, Operand(esp, kLastMatchInfoOffset));
36953fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ JumpIfSmi(eax, &runtime);
369680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ CmpObjectType(eax, JS_ARRAY_TYPE, ebx);
369780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(not_equal, &runtime);
369880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check that the JSArray is in fast case.
369980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(ebx, FieldOperand(eax, JSArray::kElementsOffset));
370080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(eax, FieldOperand(ebx, HeapObject::kMapOffset));
370144f0eee88ff00398ff7f715fab053374d808c90dSteve Block  Factory* factory = masm->isolate()->factory();
370244f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ cmp(eax, factory->fixed_array_map());
370380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(not_equal, &runtime);
370480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check that the last match info has space for the capture registers and the
370580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // additional information.
370680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(eax, FieldOperand(ebx, FixedArray::kLengthOffset));
370780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiUntag(eax);
37083ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ add(edx, Immediate(RegExpImpl::kLastMatchOverhead));
37093ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ cmp(edx, eax);
371080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(greater, &runtime);
371180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
371269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  // Reset offset for possibly sliced string.
371369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ Set(edi, Immediate(0));
371480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // ecx: RegExp data (FixedArray)
371580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check the representation and encoding of the subject string.
371680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label seq_ascii_string, seq_two_byte_string, check_code;
371780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(eax, Operand(esp, kSubjectOffset));
371880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset));
371980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movzx_b(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset));
372080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // First check for flat two byte string.
37213ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ and_(ebx, kIsNotStringMask |
37223ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch               kStringRepresentationMask |
37233ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch               kStringEncodingMask |
37243ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch               kShortExternalStringMask);
372580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  STATIC_ASSERT((kStringTag | kSeqStringTag | kTwoByteStringTag) == 0);
372669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ j(zero, &seq_two_byte_string, Label::kNear);
37273ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Any other flat string must be a flat ASCII string.  None of the following
37283ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // string type tests will succeed if subject is not a string or a short
37293ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // external string.
37303ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ and_(ebx, Immediate(kIsNotStringMask |
37313ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                         kStringRepresentationMask |
37323ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                         kShortExternalStringMask));
373369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ j(zero, &seq_ascii_string, Label::kNear);
373480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
37353ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // ebx: whether subject is a string and if yes, its string representation
373669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  // Check for flat cons string or sliced string.
373780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // A flat cons string is a cons string where the second part is the empty
373880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // string. In that case the subject string is just the first part of the cons
373980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // string. Also in this case the first part of the cons string is known to be
374080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // a sequential string or an external string.
374169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  // In the case of a sliced string its offset has to be taken into account.
37423ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  Label cons_string, external_string, check_encoding;
374369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  STATIC_ASSERT(kConsStringTag < kExternalStringTag);
374469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  STATIC_ASSERT(kSlicedStringTag > kExternalStringTag);
37453ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  STATIC_ASSERT(kIsNotStringMask > kExternalStringTag);
37463ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  STATIC_ASSERT(kShortExternalStringTag > kExternalStringTag);
37473ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ cmp(ebx, Immediate(kExternalStringTag));
374869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ j(less, &cons_string);
37493ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ j(equal, &external_string);
37503ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
37513ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Catch non-string subject or short external string.
37523ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  STATIC_ASSERT(kNotStringTag != 0 && kShortExternalStringTag !=0);
37533ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ test(ebx, Immediate(kIsNotStringMask | kShortExternalStringTag));
37543ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ j(not_zero, &runtime);
375569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch
375669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  // String is sliced.
375769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ mov(edi, FieldOperand(eax, SlicedString::kOffsetOffset));
375869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ mov(eax, FieldOperand(eax, SlicedString::kParentOffset));
375969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  // edi: offset of sliced string, smi-tagged.
376069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  // eax: parent string.
376169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ jmp(&check_encoding, Label::kNear);
376269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  // String is a cons string, check whether it is flat.
376369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ bind(&cons_string);
376469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ cmp(FieldOperand(eax, ConsString::kSecondOffset), factory->empty_string());
376580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(not_equal, &runtime);
376680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(eax, FieldOperand(eax, ConsString::kFirstOffset));
376769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ bind(&check_encoding);
376880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset));
376969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  // eax: first part of cons string or parent of sliced string.
377069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  // ebx: map of first part of cons string or map of parent of sliced string.
377169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  // Is first part of cons or parent of slice a flat two byte string?
377280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ test_b(FieldOperand(ebx, Map::kInstanceTypeOffset),
377380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen            kStringRepresentationMask | kStringEncodingMask);
377480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  STATIC_ASSERT((kSeqStringTag | kTwoByteStringTag) == 0);
377569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ j(zero, &seq_two_byte_string, Label::kNear);
37763ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Any other flat string must be sequential ASCII or external.
377780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ test_b(FieldOperand(ebx, Map::kInstanceTypeOffset),
377880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen            kStringRepresentationMask);
37793ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ j(not_zero, &external_string);
378080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
378180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&seq_ascii_string);
37823ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // eax: subject string (flat ASCII)
378380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // ecx: RegExp data (FixedArray)
378480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(edx, FieldOperand(ecx, JSRegExp::kDataAsciiCodeOffset));
37853ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ Set(ecx, Immediate(1));  // Type is ASCII.
378669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ jmp(&check_code, Label::kNear);
378780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
378880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&seq_two_byte_string);
378980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // eax: subject string (flat two byte)
379080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // ecx: RegExp data (FixedArray)
379180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(edx, FieldOperand(ecx, JSRegExp::kDataUC16CodeOffset));
379269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ Set(ecx, Immediate(0));  // Type is two byte.
379380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
379480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&check_code);
379580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check that the irregexp code has been generated for the actual string
379680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // encoding. If it has, the field contains a code object otherwise it contains
3797257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // a smi (code flushing support).
3798257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ JumpIfSmi(edx, &runtime);
379980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
380080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // eax: subject string
380180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // edx: code
38023ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // ecx: encoding of subject string (1 if ASCII, 0 if two_byte);
380380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Load used arguments before starting to push arguments for call to native
380480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // RegExp code to avoid handling changing stack height.
380580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(ebx, Operand(esp, kPreviousIndexOffset));
380680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiUntag(ebx);  // Previous index from smi.
380780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
380880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // eax: subject string
380980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // ebx: previous index
381080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // edx: code
38113ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // ecx: encoding of subject string (1 if ASCII 0 if two_byte);
381280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // All checks done. Now push arguments for native regexp code.
381344f0eee88ff00398ff7f715fab053374d808c90dSteve Block  Counters* counters = masm->isolate()->counters();
381444f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ IncrementCounter(counters->regexp_entry_native(), 1);
381580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
381644f0eee88ff00398ff7f715fab053374d808c90dSteve Block  // Isolates: note we add an additional parameter here (isolate pointer).
381744f0eee88ff00398ff7f715fab053374d808c90dSteve Block  static const int kRegExpExecuteArguments = 8;
3818e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ EnterApiExitFrame(kRegExpExecuteArguments);
381980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
382044f0eee88ff00398ff7f715fab053374d808c90dSteve Block  // Argument 8: Pass current isolate address.
382144f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ mov(Operand(esp, 7 * kPointerSize),
382244f0eee88ff00398ff7f715fab053374d808c90dSteve Block      Immediate(ExternalReference::isolate_address()));
382344f0eee88ff00398ff7f715fab053374d808c90dSteve Block
382480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Argument 7: Indicate that this is a direct call from JavaScript.
382580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(Operand(esp, 6 * kPointerSize), Immediate(1));
382680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
382780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Argument 6: Start (high end) of backtracking stack memory area.
382869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ mov(esi, Operand::StaticVariable(address_of_regexp_stack_memory_address));
382969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ add(esi, Operand::StaticVariable(address_of_regexp_stack_memory_size));
383069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ mov(Operand(esp, 5 * kPointerSize), esi);
383180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
383280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Argument 5: static offsets vector buffer.
383380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(Operand(esp, 4 * kPointerSize),
383444f0eee88ff00398ff7f715fab053374d808c90dSteve Block         Immediate(ExternalReference::address_of_static_offsets_vector(
383544f0eee88ff00398ff7f715fab053374d808c90dSteve Block             masm->isolate())));
383680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
383769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  // Argument 2: Previous index.
383869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ mov(Operand(esp, 1 * kPointerSize), ebx);
383969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch
384069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  // Argument 1: Original subject string.
384169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  // The original subject is in the previous stack frame. Therefore we have to
384269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  // use ebp, which points exactly to one pointer size below the previous esp.
384369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  // (Because creating a new stack frame pushes the previous ebp onto the stack
384469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  // and thereby moves up esp by one kPointerSize.)
384569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ mov(esi, Operand(ebp, kSubjectOffset + kPointerSize));
384669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ mov(Operand(esp, 0 * kPointerSize), esi);
384769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch
384869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  // esi: original subject string
384969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  // eax: underlying subject string
385069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  // ebx: previous index
38513ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // ecx: encoding of subject string (1 if ASCII 0 if two_byte);
385269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  // edx: code
385380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Argument 4: End of string data
385480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Argument 3: Start of string data
385569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  // Prepare start and end index of the input.
385669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  // Load the length from the original sliced string if that is the case.
385769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ mov(esi, FieldOperand(esi, String::kLengthOffset));
38583ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ add(esi, edi);  // Calculate input end wrt offset.
385969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ SmiUntag(edi);
38603ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ add(ebx, edi);  // Calculate input start wrt offset.
386169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch
386269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  // ebx: start index of the input string
386369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  // esi: end index of the input string
3864257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label setup_two_byte, setup_rest;
38653ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ test(ecx, ecx);
3866257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(zero, &setup_two_byte, Label::kNear);
386769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ SmiUntag(esi);
386869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ lea(ecx, FieldOperand(eax, esi, times_1, SeqAsciiString::kHeaderSize));
386980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(Operand(esp, 3 * kPointerSize), ecx);  // Argument 4.
387080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ lea(ecx, FieldOperand(eax, ebx, times_1, SeqAsciiString::kHeaderSize));
387180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(Operand(esp, 2 * kPointerSize), ecx);  // Argument 3.
3872257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ jmp(&setup_rest, Label::kNear);
387380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
387480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&setup_two_byte);
387580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  STATIC_ASSERT(kSmiTag == 0);
387669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  STATIC_ASSERT(kSmiTagSize == 1);  // esi is smi (powered by 2).
387769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ lea(ecx, FieldOperand(eax, esi, times_1, SeqTwoByteString::kHeaderSize));
387880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(Operand(esp, 3 * kPointerSize), ecx);  // Argument 4.
387980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ lea(ecx, FieldOperand(eax, ebx, times_2, SeqTwoByteString::kHeaderSize));
388080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(Operand(esp, 2 * kPointerSize), ecx);  // Argument 3.
388180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
388280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&setup_rest);
388380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
388480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Locate the code entry and call it.
38853ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ add(edx, Immediate(Code::kHeaderSize - kHeapObjectTag));
38863ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ call(edx);
3887e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
3888e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  // Drop arguments and come back to JS mode.
3889e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ LeaveApiExitFrame();
389080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
389180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check the result.
389280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label success;
389380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cmp(eax, NativeRegExpMacroAssembler::SUCCESS);
3894257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(equal, &success);
389580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label failure;
389680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cmp(eax, NativeRegExpMacroAssembler::FAILURE);
3897257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(equal, &failure);
389880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cmp(eax, NativeRegExpMacroAssembler::EXCEPTION);
389980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // If not exception it can only be retry. Handle that in the runtime system.
390080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(not_equal, &runtime);
390180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Result must now be exception. If there is no pending exception already a
390280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // stack overflow (on the backtrack stack) was detected in RegExp code but
390380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // haven't created the exception yet. Handle that in the runtime system.
390480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // TODO(592): Rerunning the RegExp to get the stack overflow exception.
3905589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch  ExternalReference pending_exception(Isolate::kPendingExceptionAddress,
390644f0eee88ff00398ff7f715fab053374d808c90dSteve Block                                      masm->isolate());
39073ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ mov(edx, Immediate(masm->isolate()->factory()->the_hole_value()));
3908e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ mov(eax, Operand::StaticVariable(pending_exception));
39093ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ cmp(edx, eax);
391080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(equal, &runtime);
3911e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  // For exception, throw the exception again.
3912e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
3913e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  // Clear the pending exception variable.
3914e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ mov(Operand::StaticVariable(pending_exception), edx);
3915e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
3916e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  // Special handling of termination exceptions which are uncatchable
3917e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  // by javascript code.
391844f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ cmp(eax, factory->termination_exception());
3919e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  Label throw_termination_exception;
392069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ j(equal, &throw_termination_exception, Label::kNear);
3921e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
3922e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  // Handle normal exception by following handler chain.
3923e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ Throw(eax);
3924e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
3925e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ bind(&throw_termination_exception);
39263ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ ThrowUncatchable(eax);
3927e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
392880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&failure);
3929e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  // For failure to match, return null.
39303ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ mov(eax, factory->null_value());
393180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ ret(4 * kPointerSize);
393280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
393380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Load RegExp data.
393480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&success);
393580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(eax, Operand(esp, kJSRegExpOffset));
393680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(ecx, FieldOperand(eax, JSRegExp::kDataOffset));
393780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(edx, FieldOperand(ecx, JSRegExp::kIrregexpCaptureCountOffset));
393880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Calculate number of capture registers (number_of_captures + 1) * 2.
393980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  STATIC_ASSERT(kSmiTag == 0);
394080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  STATIC_ASSERT(kSmiTagSize + kSmiShiftSize == 1);
39413ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ add(edx, Immediate(2));  // edx was a smi.
394280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
394380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // edx: Number of capture registers
394480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Load last_match_info which is still known to be a fast case JSArray.
394580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(eax, Operand(esp, kLastMatchInfoOffset));
394680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(ebx, FieldOperand(eax, JSArray::kElementsOffset));
394780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
394880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // ebx: last_match_info backing store (FixedArray)
394980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // edx: number of capture registers
395080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Store the capture count.
395180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiTag(edx);  // Number of capture registers to smi.
395280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(FieldOperand(ebx, RegExpImpl::kLastCaptureCountOffset), edx);
395380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiUntag(edx);  // Number of capture registers back from smi.
395480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Store last subject and last input.
395580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(eax, Operand(esp, kSubjectOffset));
395680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(FieldOperand(ebx, RegExpImpl::kLastSubjectOffset), eax);
39573ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ RecordWriteField(ebx,
39583ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                      RegExpImpl::kLastSubjectOffset,
39593ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                      eax,
39603ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                      edi,
39613ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                      kDontSaveFPRegs);
396280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(eax, Operand(esp, kSubjectOffset));
396380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(FieldOperand(ebx, RegExpImpl::kLastInputOffset), eax);
39643ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ RecordWriteField(ebx,
39653ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                      RegExpImpl::kLastInputOffset,
39663ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                      eax,
39673ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                      edi,
39683ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                      kDontSaveFPRegs);
396980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
397080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Get the static offsets vector filled by the native regexp code.
397180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  ExternalReference address_of_static_offsets_vector =
397244f0eee88ff00398ff7f715fab053374d808c90dSteve Block      ExternalReference::address_of_static_offsets_vector(masm->isolate());
397380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(ecx, Immediate(address_of_static_offsets_vector));
397480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
397580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // ebx: last_match_info backing store (FixedArray)
397680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // ecx: offsets vector
397780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // edx: number of capture registers
3978257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label next_capture, done;
397980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Capture register counter starts from number of capture registers and
398080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // counts down until wraping after zero.
398180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&next_capture);
39823ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ sub(edx, Immediate(1));
3983257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(negative, &done, Label::kNear);
398480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Read the value from the static offsets vector buffer.
398580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(edi, Operand(ecx, edx, times_int_size, 0));
398680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiTag(edi);
398780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Store the smi value in the last match info.
398880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(FieldOperand(ebx,
398980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                      edx,
399080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                      times_pointer_size,
399180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                      RegExpImpl::kFirstCaptureOffset),
399280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                      edi);
399380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ jmp(&next_capture);
399480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&done);
399580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
399680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Return last match info.
399780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(eax, Operand(esp, kLastMatchInfoOffset));
399880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ ret(4 * kPointerSize);
399980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
40003ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // External string.  Short external strings have already been ruled out.
40013ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // eax: subject string (expected to be external)
40023ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // ebx: scratch
40033ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ bind(&external_string);
40043ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset));
40053ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ movzx_b(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset));
40063ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  if (FLAG_debug_code) {
40073ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    // Assert that we do not have a cons or slice (indirect strings) here.
40083ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    // Sequential strings have already been ruled out.
40093ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ test_b(ebx, kIsIndirectStringMask);
40103ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ Assert(zero, "external string expected, but not found");
40113ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  }
40123ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ mov(eax, FieldOperand(eax, ExternalString::kResourceDataOffset));
40133ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Move the pointer so that offset-wise, it looks like a sequential string.
40143ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqAsciiString::kHeaderSize);
40153ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ sub(eax, Immediate(SeqTwoByteString::kHeaderSize - kHeapObjectTag));
40163ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  STATIC_ASSERT(kTwoByteStringTag == 0);
40173ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ test_b(ebx, kStringEncodingMask);
40183ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ j(not_zero, &seq_ascii_string);
40193ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ jmp(&seq_two_byte_string);
40203ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
402180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Do the runtime call to execute the regexp.
402280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&runtime);
402380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ TailCallRuntime(Runtime::kRegExpExec, 4, 1);
402480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#endif  // V8_INTERPRETED_REGEXP
402580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
402680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
402780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
4028b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdochvoid RegExpConstructResultStub::Generate(MacroAssembler* masm) {
4029b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  const int kMaxInlineLength = 100;
4030b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  Label slowcase;
4031257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label done;
4032b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ mov(ebx, Operand(esp, kPointerSize * 3));
40333fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ JumpIfNotSmi(ebx, &slowcase);
40343ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ cmp(ebx, Immediate(Smi::FromInt(kMaxInlineLength)));
4035b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ j(above, &slowcase);
4036b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Smi-tagging is equivalent to multiplying by 2.
4037b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  STATIC_ASSERT(kSmiTag == 0);
4038b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  STATIC_ASSERT(kSmiTagSize == 1);
4039b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Allocate RegExpResult followed by FixedArray with size in ebx.
4040b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // JSArray:   [Map][empty properties][Elements][Length-smi][index][input]
4041b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Elements:  [Map][Length][..elements..]
4042b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ AllocateInNewSpace(JSRegExpResult::kSize + FixedArray::kHeaderSize,
4043b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                        times_half_pointer_size,
4044b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                        ebx,  // In: Number of elements (times 2, being a smi)
4045b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                        eax,  // Out: Start of allocation (tagged).
4046b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                        ecx,  // Out: End of allocation.
4047b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                        edx,  // Scratch register
4048b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                        &slowcase,
4049b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                        TAG_OBJECT);
4050b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // eax: Start of allocated area, object-tagged.
4051b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
4052b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Set JSArray map to global.regexp_result_map().
4053b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Set empty properties FixedArray.
4054b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Set elements to point to FixedArray allocated right after the JSArray.
4055b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Interleave operations for better latency.
4056b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ mov(edx, ContextOperand(esi, Context::GLOBAL_INDEX));
405744f0eee88ff00398ff7f715fab053374d808c90dSteve Block  Factory* factory = masm->isolate()->factory();
405844f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ mov(ecx, Immediate(factory->empty_fixed_array()));
4059b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ lea(ebx, Operand(eax, JSRegExpResult::kSize));
4060b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalContextOffset));
4061b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ mov(FieldOperand(eax, JSObject::kElementsOffset), ebx);
4062b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ mov(FieldOperand(eax, JSObject::kPropertiesOffset), ecx);
4063b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ mov(edx, ContextOperand(edx, Context::REGEXP_RESULT_MAP_INDEX));
4064b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ mov(FieldOperand(eax, HeapObject::kMapOffset), edx);
4065b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
4066b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Set input, index and length fields from arguments.
4067b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ mov(ecx, Operand(esp, kPointerSize * 1));
4068b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ mov(FieldOperand(eax, JSRegExpResult::kInputOffset), ecx);
4069b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ mov(ecx, Operand(esp, kPointerSize * 2));
4070b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ mov(FieldOperand(eax, JSRegExpResult::kIndexOffset), ecx);
4071b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ mov(ecx, Operand(esp, kPointerSize * 3));
4072b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ mov(FieldOperand(eax, JSArray::kLengthOffset), ecx);
4073b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
4074b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Fill out the elements FixedArray.
4075b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // eax: JSArray.
4076b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // ebx: FixedArray.
4077b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // ecx: Number of elements in array, as smi.
4078b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
4079b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Set map.
4080b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ mov(FieldOperand(ebx, HeapObject::kMapOffset),
408144f0eee88ff00398ff7f715fab053374d808c90dSteve Block         Immediate(factory->fixed_array_map()));
4082b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Set length.
4083b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ mov(FieldOperand(ebx, FixedArray::kLengthOffset), ecx);
4084b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Fill contents of fixed-array with the-hole.
4085b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ SmiUntag(ecx);
408644f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ mov(edx, Immediate(factory->the_hole_value()));
4087b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ lea(ebx, FieldOperand(ebx, FixedArray::kHeaderSize));
4088b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Fill fixed array elements with hole.
4089b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // eax: JSArray.
4090b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // ecx: Number of elements to fill.
4091b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // ebx: Start of elements in FixedArray.
4092b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // edx: the hole.
4093b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  Label loop;
40943ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ test(ecx, ecx);
4095b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ bind(&loop);
4096257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(less_equal, &done, Label::kNear);  // Jump if ecx is negative or zero.
40973ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ sub(ecx, Immediate(1));
4098b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ mov(Operand(ebx, ecx, times_pointer_size, 0), edx);
4099b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ jmp(&loop);
4100b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
4101b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ bind(&done);
4102b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ ret(3 * kPointerSize);
4103b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
4104b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ bind(&slowcase);
4105b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ TailCallRuntime(Runtime::kRegExpConstructResult, 3, 1);
4106b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch}
4107b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
4108b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
410980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid NumberToStringStub::GenerateLookupNumberStringCache(MacroAssembler* masm,
411080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                                         Register object,
411180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                                         Register result,
411280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                                         Register scratch1,
411380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                                         Register scratch2,
411480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                                         bool object_is_smi,
411580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                                         Label* not_found) {
411680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Use of registers. Register result is used as a temporary.
411780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Register number_string_cache = result;
411880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Register mask = scratch1;
411980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Register scratch = scratch2;
412080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
412180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Load the number string cache.
41223ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  ExternalReference roots_array_start =
41233ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      ExternalReference::roots_array_start(masm->isolate());
412480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(scratch, Immediate(Heap::kNumberStringCacheRootIndex));
412580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(number_string_cache,
41263ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch         Operand::StaticArray(scratch, times_pointer_size, roots_array_start));
412780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Make the hash mask from the length of the number string cache. It
412880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // contains two elements (number and string) for each cache entry.
412980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(mask, FieldOperand(number_string_cache, FixedArray::kLengthOffset));
413080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ shr(mask, kSmiTagSize + 1);  // Untag length and divide it by two.
41313ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ sub(mask, Immediate(1));  // Make mask.
413280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
413380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Calculate the entry in the number string cache. The hash value in the
413480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // number string cache for smis is just the smi value, and the hash for
413580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // doubles is the xor of the upper and lower words. See
413680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Heap::GetNumberStringCache.
4137257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label smi_hash_calculated;
4138257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label load_result_from_cache;
413980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  if (object_is_smi) {
414080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ mov(scratch, object);
414180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ SmiUntag(scratch);
414280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  } else {
4143257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Label not_smi;
414480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    STATIC_ASSERT(kSmiTag == 0);
41453fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    __ JumpIfNotSmi(object, &not_smi, Label::kNear);
414680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ mov(scratch, object);
414780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ SmiUntag(scratch);
4148257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ jmp(&smi_hash_calculated, Label::kNear);
414980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ bind(&not_smi);
415080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ cmp(FieldOperand(object, HeapObject::kMapOffset),
415144f0eee88ff00398ff7f715fab053374d808c90dSteve Block           masm->isolate()->factory()->heap_number_map());
415280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ j(not_equal, not_found);
415380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    STATIC_ASSERT(8 == kDoubleSize);
415480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ mov(scratch, FieldOperand(object, HeapNumber::kValueOffset));
415580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ xor_(scratch, FieldOperand(object, HeapNumber::kValueOffset + 4));
415680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // Object is heap number and hash is now in scratch. Calculate cache index.
41573ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ and_(scratch, mask);
415880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    Register index = scratch;
415980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    Register probe = mask;
416080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ mov(probe,
416180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen           FieldOperand(number_string_cache,
416280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                        index,
416380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                        times_twice_pointer_size,
416480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                        FixedArray::kHeaderSize));
41653fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    __ JumpIfSmi(probe, not_found);
41668b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch    if (CpuFeatures::IsSupported(SSE2)) {
416780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      CpuFeatures::Scope fscope(SSE2);
416880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ movdbl(xmm0, FieldOperand(object, HeapNumber::kValueOffset));
416980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ movdbl(xmm1, FieldOperand(probe, HeapNumber::kValueOffset));
417080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ ucomisd(xmm0, xmm1);
417180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    } else {
417280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ fld_d(FieldOperand(object, HeapNumber::kValueOffset));
417380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ fld_d(FieldOperand(probe, HeapNumber::kValueOffset));
417480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ FCmp();
417580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    }
417680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ j(parity_even, not_found);  // Bail out if NaN is involved.
417780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ j(not_equal, not_found);  // The cache did not contain this value.
4178257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ jmp(&load_result_from_cache, Label::kNear);
417980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
418080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
418180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&smi_hash_calculated);
418280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Object is smi and hash is now in scratch. Calculate cache index.
41833ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ and_(scratch, mask);
418480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Register index = scratch;
418580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check if the entry is the smi we are looking for.
418680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cmp(object,
418780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen         FieldOperand(number_string_cache,
418880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                      index,
418980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                      times_twice_pointer_size,
419080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                      FixedArray::kHeaderSize));
419180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(not_equal, not_found);
419280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
419380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Get the result from the cache.
419480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&load_result_from_cache);
419580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(result,
419680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen         FieldOperand(number_string_cache,
419780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                      index,
419880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                      times_twice_pointer_size,
419980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                      FixedArray::kHeaderSize + kPointerSize));
420044f0eee88ff00398ff7f715fab053374d808c90dSteve Block  Counters* counters = masm->isolate()->counters();
420144f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ IncrementCounter(counters->number_to_string_native(), 1);
420280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
420380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
420480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
420580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid NumberToStringStub::Generate(MacroAssembler* masm) {
420680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label runtime;
420780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
420880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(ebx, Operand(esp, kPointerSize));
420980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
421080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Generate code to lookup number in the number string cache.
421180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  GenerateLookupNumberStringCache(masm, ebx, eax, ecx, edx, false, &runtime);
421280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ ret(1 * kPointerSize);
421380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
421480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&runtime);
421580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Handle number to string in the runtime system if not found in the cache.
421680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ TailCallRuntime(Runtime::kNumberToStringSkipCache, 1, 1);
421780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
421880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
421980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
422080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenstatic int NegativeComparisonResult(Condition cc) {
422180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  ASSERT(cc != equal);
422280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  ASSERT((cc == less) || (cc == less_equal)
422380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      || (cc == greater) || (cc == greater_equal));
422480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  return (cc == greater || cc == greater_equal) ? LESS : GREATER;
422580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
422680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
422780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid CompareStub::Generate(MacroAssembler* masm) {
422880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  ASSERT(lhs_.is(no_reg) && rhs_.is(no_reg));
422980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
423069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  Label check_unequal_objects;
423180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
42320d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  // Compare two smis if required.
42330d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  if (include_smi_compare_) {
42340d5e116f6aee03185f237311a943491bb079a768Kristian Monsen    Label non_smi, smi_done;
42353ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ mov(ecx, edx);
42363ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ or_(ecx, eax);
423769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    __ JumpIfNotSmi(ecx, &non_smi, Label::kNear);
42383ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ sub(edx, eax);  // Return on the result of the subtraction.
423969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    __ j(no_overflow, &smi_done, Label::kNear);
4240f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    __ not_(edx);  // Correct sign in case of overflow. edx is never 0 here.
42410d5e116f6aee03185f237311a943491bb079a768Kristian Monsen    __ bind(&smi_done);
42420d5e116f6aee03185f237311a943491bb079a768Kristian Monsen    __ mov(eax, edx);
42430d5e116f6aee03185f237311a943491bb079a768Kristian Monsen    __ ret(0);
42440d5e116f6aee03185f237311a943491bb079a768Kristian Monsen    __ bind(&non_smi);
42450d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  } else if (FLAG_debug_code) {
42463ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ mov(ecx, edx);
42473ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ or_(ecx, eax);
42480d5e116f6aee03185f237311a943491bb079a768Kristian Monsen    __ test(ecx, Immediate(kSmiTagMask));
42490d5e116f6aee03185f237311a943491bb079a768Kristian Monsen    __ Assert(not_zero, "Unexpected smi operands.");
42500d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  }
42510d5e116f6aee03185f237311a943491bb079a768Kristian Monsen
425280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // NOTICE! This code is only reached after a smi-fast-case check, so
425380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // it is certain that at least one operand isn't a smi.
425480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
425580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Identical objects can be compared fast, but there are some tricky cases
425680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // for NaN and undefined.
425780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  {
425880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    Label not_identical;
42593ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ cmp(eax, edx);
426080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ j(not_equal, &not_identical);
426180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
426280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    if (cc_ != equal) {
426380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      // Check for undefined.  undefined OP undefined is false even though
426480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      // undefined == undefined.
4265257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      Label check_for_nan;
426644f0eee88ff00398ff7f715fab053374d808c90dSteve Block      __ cmp(edx, masm->isolate()->factory()->undefined_value());
4267257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ j(not_equal, &check_for_nan, Label::kNear);
426880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ Set(eax, Immediate(Smi::FromInt(NegativeComparisonResult(cc_))));
426980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ ret(0);
427080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ bind(&check_for_nan);
427180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    }
427280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
427344f0eee88ff00398ff7f715fab053374d808c90dSteve Block    // Test for NaN. Sadly, we can't just compare to factory->nan_value(),
427480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // so we do the second best thing - test it ourselves.
427580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // Note: if cc_ != equal, never_nan_nan_ is not used.
427680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    if (never_nan_nan_ && (cc_ == equal)) {
427780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ Set(eax, Immediate(Smi::FromInt(EQUAL)));
427880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ ret(0);
427980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    } else {
4280257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      Label heap_number;
428180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ cmp(FieldOperand(edx, HeapObject::kMapOffset),
428244f0eee88ff00398ff7f715fab053374d808c90dSteve Block             Immediate(masm->isolate()->factory()->heap_number_map()));
4283257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ j(equal, &heap_number, Label::kNear);
428480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      if (cc_ != equal) {
428580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen        // Call runtime on identical JSObjects.  Otherwise return equal.
42863fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch        __ CmpObjectType(eax, FIRST_SPEC_OBJECT_TYPE, ecx);
428780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen        __ j(above_equal, &not_identical);
428880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      }
428980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ Set(eax, Immediate(Smi::FromInt(EQUAL)));
429080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ ret(0);
429180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
429280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ bind(&heap_number);
429380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      // It is a heap number, so return non-equal if it's NaN and equal if
429480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      // it's not NaN.
429580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      // The representation of NaN values has all exponent bits (52..62) set,
429680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      // and not all mantissa bits (0..51) clear.
429780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      // We only accept QNaNs, which have bit 51 set.
429880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      // Read top bits of double representation (second word of value).
429980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
430080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      // Value is a QNaN if value & kQuietNaNMask == kQuietNaNMask, i.e.,
430180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      // all bits in the mask are set. We only need to check the word
430280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      // that contains the exponent and high bit of the mantissa.
430380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      STATIC_ASSERT(((kQuietNaNHighBitsMask << 1) & 0x80000000u) != 0);
430480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ mov(edx, FieldOperand(edx, HeapNumber::kExponentOffset));
43059fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block      __ Set(eax, Immediate(0));
430680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      // Shift value and mask so kQuietNaNHighBitsMask applies to topmost
430780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      // bits.
43083ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      __ add(edx, edx);
430980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ cmp(edx, kQuietNaNHighBitsMask << 1);
431080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      if (cc_ == equal) {
431180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen        STATIC_ASSERT(EQUAL != 1);
431280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen        __ setcc(above_equal, eax);
431380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen        __ ret(0);
431480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      } else {
4315257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        Label nan;
4316257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        __ j(above_equal, &nan, Label::kNear);
431780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen        __ Set(eax, Immediate(Smi::FromInt(EQUAL)));
431880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen        __ ret(0);
431980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen        __ bind(&nan);
432080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen        __ Set(eax, Immediate(Smi::FromInt(NegativeComparisonResult(cc_))));
432180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen        __ ret(0);
432280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      }
432380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    }
432480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
432580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ bind(&not_identical);
432680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
432780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
432880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Strict equality can quickly decide whether objects are equal.
432980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Non-strict object equality is slower, so it is handled later in the stub.
433080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  if (cc_ == equal && strict_) {
433180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    Label slow;  // Fallthrough label.
4332257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Label not_smis;
433380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // If we're doing a strict equality comparison, we don't have to do
433480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // type conversion, so we generate code to do fast comparison for objects
433580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // and oddballs. Non-smi numbers and strings still go through the usual
433680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // slow-case code.
433780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // If either is a Smi (we know that not both are), then they can only
433880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // be equal if the other is a HeapNumber. If so, use the slow case.
433980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    STATIC_ASSERT(kSmiTag == 0);
434080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    ASSERT_EQ(0, Smi::FromInt(0));
434180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ mov(ecx, Immediate(kSmiTagMask));
43423ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ and_(ecx, eax);
43433ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ test(ecx, edx);
4344257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ j(not_zero, &not_smis, Label::kNear);
434580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // One operand is a smi.
434680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
434780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // Check whether the non-smi is a heap number.
434880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    STATIC_ASSERT(kSmiTagMask == 1);
434980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // ecx still holds eax & kSmiTag, which is either zero or one.
43503ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ sub(ecx, Immediate(0x01));
435180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ mov(ebx, edx);
43523ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ xor_(ebx, eax);
43533ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ and_(ebx, ecx);  // ebx holds either 0 or eax ^ edx.
43543ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ xor_(ebx, eax);
435580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // if eax was smi, ebx is now edx, else eax.
435680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
435780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // Check if the non-smi operand is a heap number.
435880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ cmp(FieldOperand(ebx, HeapObject::kMapOffset),
435944f0eee88ff00398ff7f715fab053374d808c90dSteve Block           Immediate(masm->isolate()->factory()->heap_number_map()));
436080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // If heap number, handle it in the slow case.
436169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    __ j(equal, &slow, Label::kNear);
436280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // Return non-equal (ebx is not zero)
436380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ mov(eax, ebx);
436480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ ret(0);
436580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
436680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ bind(&not_smis);
436780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // If either operand is a JSObject or an oddball value, then they are not
436880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // equal since their pointers are different
436980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // There is no test for undetectability in strict equality.
437080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
437180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // Get the type of the first operand.
437280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // If the first object is a JS object, we have done pointer comparison.
4373257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Label first_non_object;
43743fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    STATIC_ASSERT(LAST_TYPE == LAST_SPEC_OBJECT_TYPE);
43753fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    __ CmpObjectType(eax, FIRST_SPEC_OBJECT_TYPE, ecx);
4376257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ j(below, &first_non_object, Label::kNear);
437780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
437880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // Return non-zero (eax is not zero)
4379257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Label return_not_equal;
438080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    STATIC_ASSERT(kHeapObjectTag != 0);
438180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ bind(&return_not_equal);
438280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ ret(0);
438380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
438480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ bind(&first_non_object);
438580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // Check for oddballs: true, false, null, undefined.
438680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ CmpInstanceType(ecx, ODDBALL_TYPE);
438780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ j(equal, &return_not_equal);
438880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
43893fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    __ CmpObjectType(edx, FIRST_SPEC_OBJECT_TYPE, ecx);
439080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ j(above_equal, &return_not_equal);
439180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
439280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // Check for oddballs: true, false, null, undefined.
439380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ CmpInstanceType(ecx, ODDBALL_TYPE);
439480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ j(equal, &return_not_equal);
439580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
439680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // Fall through to the general case.
439780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ bind(&slow);
439880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
439980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
440080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Generate the number comparison code.
440180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  if (include_number_compare_) {
440280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    Label non_number_comparison;
440380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    Label unordered;
44048b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch    if (CpuFeatures::IsSupported(SSE2)) {
440580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      CpuFeatures::Scope use_sse2(SSE2);
440680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      CpuFeatures::Scope use_cmov(CMOV);
440780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
440880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      FloatingPointHelper::LoadSSE2Operands(masm, &non_number_comparison);
440980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ ucomisd(xmm0, xmm1);
441080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
441180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      // Don't base result on EFLAGS when a NaN is involved.
441269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch      __ j(parity_even, &unordered, Label::kNear);
441380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      // Return a result of -1, 0, or 1, based on EFLAGS.
441480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ mov(eax, 0);  // equal
441580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ mov(ecx, Immediate(Smi::FromInt(1)));
44163ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      __ cmov(above, eax, ecx);
441780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ mov(ecx, Immediate(Smi::FromInt(-1)));
44183ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      __ cmov(below, eax, ecx);
441980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ ret(0);
442080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    } else {
442180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      FloatingPointHelper::CheckFloatOperands(
442280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen          masm, &non_number_comparison, ebx);
442380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      FloatingPointHelper::LoadFloatOperand(masm, eax);
442480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      FloatingPointHelper::LoadFloatOperand(masm, edx);
442580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ FCmp();
442680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
442780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      // Don't base result on EFLAGS when a NaN is involved.
442869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch      __ j(parity_even, &unordered, Label::kNear);
442980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
4430257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      Label below_label, above_label;
443180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      // Return a result of -1, 0, or 1, based on EFLAGS.
443269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch      __ j(below, &below_label, Label::kNear);
443369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch      __ j(above, &above_label, Label::kNear);
443480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
44359fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block      __ Set(eax, Immediate(0));
443680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ ret(0);
443780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
443880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ bind(&below_label);
443980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ mov(eax, Immediate(Smi::FromInt(-1)));
444080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ ret(0);
444180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
444280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ bind(&above_label);
444380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ mov(eax, Immediate(Smi::FromInt(1)));
444480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ ret(0);
444580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    }
444680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
444780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // If one of the numbers was NaN, then the result is always false.
444880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // The cc is never not-equal.
444980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ bind(&unordered);
445080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    ASSERT(cc_ != not_equal);
445180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    if (cc_ == less || cc_ == less_equal) {
445280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ mov(eax, Immediate(Smi::FromInt(1)));
445380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    } else {
445480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ mov(eax, Immediate(Smi::FromInt(-1)));
445580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    }
445680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ ret(0);
445780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
445880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // The number comparison code did not provide a valid result.
445980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ bind(&non_number_comparison);
446080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
446180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
446280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Fast negative check for symbol-to-symbol equality.
446380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label check_for_strings;
446480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  if (cc_ == equal) {
446580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    BranchIfNonSymbol(masm, &check_for_strings, eax, ecx);
446680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    BranchIfNonSymbol(masm, &check_for_strings, edx, ecx);
446780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
446880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // We've already checked for object identity, so if both operands
446980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // are symbols they aren't equal. Register eax already holds a
447080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // non-zero value, which indicates not equal, so just return.
447180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ ret(0);
447280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
447380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
447480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&check_for_strings);
447580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
447680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ JumpIfNotBothSequentialAsciiStrings(edx, eax, ecx, ebx,
447780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                         &check_unequal_objects);
447880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
44793ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Inline comparison of ASCII strings.
4480257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  if (cc_ == equal) {
4481257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    StringCompareStub::GenerateFlatAsciiStringEquals(masm,
448280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                                     edx,
448380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                                     eax,
448480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                                     ecx,
4485257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                                     ebx);
4486257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  } else {
4487257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    StringCompareStub::GenerateCompareFlatAsciiStrings(masm,
4488257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                                       edx,
4489257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                                       eax,
4490257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                                       ecx,
4491257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                                       ebx,
4492257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                                       edi);
4493257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
449480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#ifdef DEBUG
449580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ Abort("Unexpected fall-through from string comparison");
449680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#endif
449780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
449880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&check_unequal_objects);
449980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  if (cc_ == equal && !strict_) {
450080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // Non-strict equality.  Objects are unequal if
450180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // they are both JSObjects and not undetectable,
450280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // and their pointers are different.
4503257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Label not_both_objects;
4504257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Label return_unequal;
450580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // At most one is a smi, so we can test for smi by adding the two.
450680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // A smi plus a heap object has the low bit set, a heap object plus
450780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // a heap object has the low bit clear.
450880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    STATIC_ASSERT(kSmiTag == 0);
450980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    STATIC_ASSERT(kSmiTagMask == 1);
451080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ lea(ecx, Operand(eax, edx, times_1, 0));
451180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ test(ecx, Immediate(kSmiTagMask));
4512257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ j(not_zero, &not_both_objects, Label::kNear);
45133fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    __ CmpObjectType(eax, FIRST_SPEC_OBJECT_TYPE, ecx);
4514257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ j(below, &not_both_objects, Label::kNear);
45153fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    __ CmpObjectType(edx, FIRST_SPEC_OBJECT_TYPE, ebx);
4516257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ j(below, &not_both_objects, Label::kNear);
451780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // We do not bail out after this point.  Both are JSObjects, and
451880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // they are equal if and only if both are undetectable.
451980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // The and of the undetectable flags is 1 if and only if they are equal.
452080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ test_b(FieldOperand(ecx, Map::kBitFieldOffset),
452180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen              1 << Map::kIsUndetectable);
4522257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ j(zero, &return_unequal, Label::kNear);
452380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ test_b(FieldOperand(ebx, Map::kBitFieldOffset),
452480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen              1 << Map::kIsUndetectable);
4525257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ j(zero, &return_unequal, Label::kNear);
452680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // The objects are both undetectable, so they both compare as the value
452780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // undefined, and are equal.
452880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ Set(eax, Immediate(EQUAL));
452980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ bind(&return_unequal);
453080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // Return non-equal by returning the non-zero object pointer in eax,
453180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // or return equal if we fell through to here.
453280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ ret(0);  // rax, rdx were pushed
453380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ bind(&not_both_objects);
453480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
453580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
453680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Push arguments below the return address.
453780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ pop(ecx);
453880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ push(edx);
453980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ push(eax);
454080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
454180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Figure out which native to call and setup the arguments.
454280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Builtins::JavaScript builtin;
454380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  if (cc_ == equal) {
454480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    builtin = strict_ ? Builtins::STRICT_EQUALS : Builtins::EQUALS;
454580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  } else {
454680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    builtin = Builtins::COMPARE;
454780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ push(Immediate(Smi::FromInt(NegativeComparisonResult(cc_))));
454880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
454980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
455080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Restore return address on the stack.
455180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ push(ecx);
455280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
455380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Call the native; it returns -1 (less), 0 (equal), or 1 (greater)
455480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // tagged as a small integer.
455580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ InvokeBuiltin(builtin, JUMP_FUNCTION);
455680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
455780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
455880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
455980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid CompareStub::BranchIfNonSymbol(MacroAssembler* masm,
456080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                    Label* label,
456180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                    Register object,
456280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                    Register scratch) {
45633fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ JumpIfSmi(object, label);
456480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(scratch, FieldOperand(object, HeapObject::kMapOffset));
456580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movzx_b(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset));
456680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ and_(scratch, kIsSymbolMask | kIsNotStringMask);
456780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cmp(scratch, kSymbolTag | kStringTag);
456880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(not_equal, label);
456980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
457080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
457180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
457280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StackCheckStub::Generate(MacroAssembler* masm) {
4573f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  __ TailCallRuntime(Runtime::kStackGuard, 0, 1);
457480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
457580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
457680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
45773ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochvoid InterruptStub::Generate(MacroAssembler* masm) {
45783ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ TailCallRuntime(Runtime::kInterrupt, 0, 1);
45793ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch}
45803ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
45813ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
45823ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochstatic void GenerateRecordCallTarget(MacroAssembler* masm) {
45833ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Cache the called function in a global property cell.  Cache states
45843ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // are uninitialized, monomorphic (indicated by a JSFunction), and
45853ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // megamorphic.
45863ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // ebx : cache cell for call target
45873ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // edi : the function to call
45883ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  Isolate* isolate = masm->isolate();
45893ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  Label initialize, done;
45903ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
45913ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Load the cache state into ecx.
45923ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ mov(ecx, FieldOperand(ebx, JSGlobalPropertyCell::kValueOffset));
45933ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
45943ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // A monomorphic cache hit or an already megamorphic state: invoke the
45953ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // function without changing the state.
45963ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ cmp(ecx, edi);
45973ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ j(equal, &done, Label::kNear);
45983ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ cmp(ecx, Immediate(TypeFeedbackCells::MegamorphicSentinel(isolate)));
45993ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ j(equal, &done, Label::kNear);
46003ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
46013ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // A monomorphic miss (i.e, here the cache is not uninitialized) goes
46023ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // megamorphic.
46033ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ cmp(ecx, Immediate(TypeFeedbackCells::UninitializedSentinel(isolate)));
46043ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ j(equal, &initialize, Label::kNear);
46053ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // MegamorphicSentinel is an immortal immovable object (undefined) so no
46063ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // write-barrier is needed.
46073ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ mov(FieldOperand(ebx, JSGlobalPropertyCell::kValueOffset),
46083ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch         Immediate(TypeFeedbackCells::MegamorphicSentinel(isolate)));
46093ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ jmp(&done, Label::kNear);
46103ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
46113ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // An uninitialized cache is patched with the function.
46123ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ bind(&initialize);
46133ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ mov(FieldOperand(ebx, JSGlobalPropertyCell::kValueOffset), edi);
46143ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // No need for a write barrier here - cells are rescanned.
46153ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
46163ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ bind(&done);
46173ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch}
46183ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
46193ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
462080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid CallFunctionStub::Generate(MacroAssembler* masm) {
46213ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // ebx : cache cell for call target
46223ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // edi : the function to call
46233ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  Isolate* isolate = masm->isolate();
4624589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch  Label slow, non_function;
462580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
4626257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // The receiver might implicitly be the global object. This is
4627257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // indicated by passing the hole as the receiver to the call
4628257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // function stub.
4629257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  if (ReceiverMightBeImplicit()) {
46303ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    Label receiver_ok;
463180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // Get the receiver from the stack.
463280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // +1 ~ return address
463380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ mov(eax, Operand(esp, (argc_ + 1) * kPointerSize));
4634257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Call as function is indicated with the hole.
46353ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ cmp(eax, isolate->factory()->the_hole_value());
46363ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ j(not_equal, &receiver_ok, Label::kNear);
4637257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Patch the receiver on the stack with the global receiver object.
46383ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ mov(ecx, GlobalObjectOperand());
46393ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ mov(ecx, FieldOperand(ecx, GlobalObject::kGlobalReceiverOffset));
46403ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ mov(Operand(esp, (argc_ + 1) * kPointerSize), ecx);
46413ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ bind(&receiver_ok);
464280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
464380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
464480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check that the function really is a JavaScript function.
4645589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch  __ JumpIfSmi(edi, &non_function);
464680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Goto slow case if we do not have a function.
464780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx);
4648257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(not_equal, &slow);
464980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
46503ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  if (RecordCallTarget()) {
46513ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    GenerateRecordCallTarget(masm);
46523ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  }
46533ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
465480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Fast-case: Just invoke the function.
465580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  ParameterCount actual(argc_);
4656257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
4657257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  if (ReceiverMightBeImplicit()) {
4658257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Label call_as_function;
46593ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ cmp(eax, isolate->factory()->the_hole_value());
4660257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ j(equal, &call_as_function);
4661257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ InvokeFunction(edi,
4662257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                      actual,
4663257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                      JUMP_FUNCTION,
4664257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                      NullCallWrapper(),
4665257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                      CALL_AS_METHOD);
4666257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ bind(&call_as_function);
4667257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
4668257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ InvokeFunction(edi,
4669257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                    actual,
4670257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                    JUMP_FUNCTION,
4671257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                    NullCallWrapper(),
4672257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                    CALL_AS_FUNCTION);
467380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
467480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Slow-case: Non-function called.
467580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&slow);
46763ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  if (RecordCallTarget()) {
46773ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    // If there is a call target cache, mark it megamorphic in the
46783ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    // non-function case.  MegamorphicSentinel is an immortal immovable
46793ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    // object (undefined) so no write barrier is needed.
46803ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ mov(FieldOperand(ebx, JSGlobalPropertyCell::kValueOffset),
46813ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch           Immediate(TypeFeedbackCells::MegamorphicSentinel(isolate)));
46823ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  }
4683589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch  // Check for function proxy.
4684589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch  __ CmpInstanceType(ecx, JS_FUNCTION_PROXY_TYPE);
4685589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch  __ j(not_equal, &non_function);
4686589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch  __ pop(ecx);
4687589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch  __ push(edi);  // put proxy as additional argument under return address
4688589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch  __ push(ecx);
4689589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch  __ Set(eax, Immediate(argc_ + 1));
4690589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch  __ Set(ebx, Immediate(0));
4691589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch  __ SetCallKind(ecx, CALL_AS_FUNCTION);
4692589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch  __ GetBuiltinEntry(edx, Builtins::CALL_FUNCTION_PROXY);
4693589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch  {
46943ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    Handle<Code> adaptor = isolate->builtins()->ArgumentsAdaptorTrampoline();
4695589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch    __ jmp(adaptor, RelocInfo::CODE_TARGET);
4696589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch  }
4697589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch
469880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // CALL_NON_FUNCTION expects the non-function callee as receiver (instead
469980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // of the original receiver from the call site).
4700589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch  __ bind(&non_function);
470180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(Operand(esp, (argc_ + 1) * kPointerSize), edi);
470280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ Set(eax, Immediate(argc_));
470380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ Set(ebx, Immediate(0));
4704589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch  __ SetCallKind(ecx, CALL_AS_METHOD);
470580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ GetBuiltinEntry(edx, Builtins::CALL_NON_FUNCTION);
47063ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  Handle<Code> adaptor = isolate->builtins()->ArgumentsAdaptorTrampoline();
470785b71799222b55eb5dd74ea26efe0c64ab655c8cBen Murdoch  __ jmp(adaptor, RelocInfo::CODE_TARGET);
47085d4cdbf7a67d3662fa0bee4efdb7edd8daec9b0bBen Murdoch}
47095d4cdbf7a67d3662fa0bee4efdb7edd8daec9b0bBen Murdoch
47105d4cdbf7a67d3662fa0bee4efdb7edd8daec9b0bBen Murdoch
47113ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochvoid CallConstructStub::Generate(MacroAssembler* masm) {
47123ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // eax : number of arguments
47133ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // ebx : cache cell for call target
47143ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // edi : constructor function
47153ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  Label slow, non_function_call;
47163ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
47173ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Check that function is not a smi.
47183ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ JumpIfSmi(edi, &non_function_call);
47193ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Check that function is a JSFunction.
47203ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx);
47213ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ j(not_equal, &slow);
47223ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
47233ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  if (RecordCallTarget()) {
47243ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    GenerateRecordCallTarget(masm);
47253ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  }
47263ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
47273ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Jump to the function-specific construct stub.
47283ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ mov(ebx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
47293ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ mov(ebx, FieldOperand(ebx, SharedFunctionInfo::kConstructStubOffset));
47303ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ lea(ebx, FieldOperand(ebx, Code::kHeaderSize));
47313ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ jmp(ebx);
47323ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
47333ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // edi: called object
47343ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // eax: number of arguments
47353ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // ecx: object map
47363ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  Label do_call;
47373ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ bind(&slow);
47383ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ CmpInstanceType(ecx, JS_FUNCTION_PROXY_TYPE);
47393ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ j(not_equal, &non_function_call);
47403ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ GetBuiltinEntry(edx, Builtins::CALL_FUNCTION_PROXY_AS_CONSTRUCTOR);
47413ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ jmp(&do_call);
47423ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
47433ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ bind(&non_function_call);
47443ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ GetBuiltinEntry(edx, Builtins::CALL_NON_FUNCTION_AS_CONSTRUCTOR);
47453ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ bind(&do_call);
47463ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Set expected number of arguments to zero (not changing eax).
47473ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ Set(ebx, Immediate(0));
47483ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  Handle<Code> arguments_adaptor =
47493ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      masm->isolate()->builtins()->ArgumentsAdaptorTrampoline();
47503ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ SetCallKind(ecx, CALL_AS_METHOD);
47513ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ jmp(arguments_adaptor, RelocInfo::CODE_TARGET);
47523ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch}
47533ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
47543ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
475544f0eee88ff00398ff7f715fab053374d808c90dSteve Blockbool CEntryStub::NeedsImmovableCode() {
475644f0eee88ff00398ff7f715fab053374d808c90dSteve Block  return false;
475744f0eee88ff00398ff7f715fab053374d808c90dSteve Block}
475844f0eee88ff00398ff7f715fab053374d808c90dSteve Block
475944f0eee88ff00398ff7f715fab053374d808c90dSteve Block
47603ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochbool CEntryStub::IsPregenerated() {
47613ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  return (!save_doubles_ || ISOLATE->fp_stubs_generated()) &&
47623ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch          result_size_ == 1;
47633ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch}
47643ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
47653ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
47663ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochvoid CodeStub::GenerateStubsAheadOfTime() {
47673ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  CEntryStub::GenerateAheadOfTime();
47683ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  StoreBufferOverflowStub::GenerateFixedRegStubsAheadOfTime();
47693ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // It is important that the store buffer overflow stubs are generated first.
47703ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  RecordWriteStub::GenerateFixedRegStubsAheadOfTime();
47713ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch}
47723ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
47733ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
47743ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochvoid CodeStub::GenerateFPStubs() {
47753ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  CEntryStub save_doubles(1, kSaveFPRegs);
47763ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  Handle<Code> code = save_doubles.GetCode();
47773ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  code->set_is_pregenerated(true);
47783ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  code->GetIsolate()->set_fp_stubs_generated(true);
47793ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch}
47803ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
47813ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
47823ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochvoid CEntryStub::GenerateAheadOfTime() {
47833ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  CEntryStub stub(1, kDontSaveFPRegs);
47843ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  Handle<Code> code = stub.GetCode();
47853ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  code->set_is_pregenerated(true);
4786592a9fc1d8ea420377a2e7efd0600e20b058be2bBen Murdoch}
4787592a9fc1d8ea420377a2e7efd0600e20b058be2bBen Murdoch
4788592a9fc1d8ea420377a2e7efd0600e20b058be2bBen Murdoch
478980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid CEntryStub::GenerateCore(MacroAssembler* masm,
479080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                              Label* throw_normal_exception,
479180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                              Label* throw_termination_exception,
479280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                              Label* throw_out_of_memory_exception,
479380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                              bool do_gc,
47941e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block                              bool always_allocate_scope) {
479580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // eax: result parameter for PerformGC, if any
479680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // ebx: pointer to C function  (C callee-saved)
479780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // ebp: frame pointer  (restored after C call)
479880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // esp: stack pointer  (restored after C call)
479980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // edi: number of arguments including receiver  (C callee-saved)
480080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // esi: pointer to the first argument (C callee-saved)
480180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
480280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Result returned in eax, or eax+edx if result_size_ is 2.
480380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
480480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check stack alignment.
480580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  if (FLAG_debug_code) {
480680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ CheckStackAlignment();
480780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
480880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
480980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  if (do_gc) {
481080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // Pass failure code returned from last attempt as first argument to
481180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // PerformGC. No need to use PrepareCallCFunction/CallCFunction here as the
481280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // stack alignment is known to be correct. This function takes one argument
481380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // which is passed on the stack, and we know that the stack has been
481480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // prepared to pass at least one argument.
481580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ mov(Operand(esp, 0 * kPointerSize), eax);  // Result.
481680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ call(FUNCTION_ADDR(Runtime::PerformGC), RelocInfo::RUNTIME_ENTRY);
481780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
481880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
481980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  ExternalReference scope_depth =
482044f0eee88ff00398ff7f715fab053374d808c90dSteve Block      ExternalReference::heap_always_allocate_scope_depth(masm->isolate());
482180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  if (always_allocate_scope) {
482280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ inc(Operand::StaticVariable(scope_depth));
482380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
482480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
482580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Call C function.
482680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(Operand(esp, 0 * kPointerSize), edi);  // argc.
482780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(Operand(esp, 1 * kPointerSize), esi);  // argv.
482844f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ mov(Operand(esp, 2 * kPointerSize),
482944f0eee88ff00398ff7f715fab053374d808c90dSteve Block         Immediate(ExternalReference::isolate_address()));
48303ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ call(ebx);
483180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Result is in eax or edx:eax - do not destroy these registers!
483280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
483380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  if (always_allocate_scope) {
483480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ dec(Operand::StaticVariable(scope_depth));
483580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
483680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
483780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Make sure we're not trying to return 'the hole' from the runtime
483880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // call as this may lead to crashes in the IC code later.
483980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  if (FLAG_debug_code) {
4840257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Label okay;
484144f0eee88ff00398ff7f715fab053374d808c90dSteve Block    __ cmp(eax, masm->isolate()->factory()->the_hole_value());
4842257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ j(not_equal, &okay, Label::kNear);
484380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ int3();
484480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ bind(&okay);
484580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
484680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
484780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check for failure result.
484880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label failure_returned;
484980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  STATIC_ASSERT(((kFailureTag + 1) & kFailureTagMask) == 0);
485080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ lea(ecx, Operand(eax, 1));
485180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Lower 2 bits of ecx are 0 iff eax has failure tag.
485280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ test(ecx, Immediate(kFailureTagMask));
4853257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(zero, &failure_returned);
485480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
485544f0eee88ff00398ff7f715fab053374d808c90dSteve Block  ExternalReference pending_exception_address(
4856589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch      Isolate::kPendingExceptionAddress, masm->isolate());
48571e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
48581e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  // Check that there is no pending exception, otherwise we
48591e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  // should have returned some failure value.
48601e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  if (FLAG_debug_code) {
48611e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    __ push(edx);
48623ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ mov(edx, Immediate(masm->isolate()->factory()->the_hole_value()));
4863257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Label okay;
48641e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    __ cmp(edx, Operand::StaticVariable(pending_exception_address));
48651e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    // Cannot use check here as it attempts to generate call into runtime.
4866257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ j(equal, &okay, Label::kNear);
48671e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    __ int3();
48681e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    __ bind(&okay);
48691e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    __ pop(edx);
48701e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  }
48711e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
487280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Exit the JavaScript to C++ exit frame.
48733ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ LeaveExitFrame(save_doubles_ == kSaveFPRegs);
487480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ ret(0);
487580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
487680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Handling of failure.
487780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&failure_returned);
487880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
487980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label retry;
488080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // If the returned exception is RETRY_AFTER_GC continue at retry label
488180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  STATIC_ASSERT(Failure::RETRY_AFTER_GC == 0);
488280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ test(eax, Immediate(((1 << kFailureTypeTagSize) - 1) << kFailureTagSize));
488369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ j(zero, &retry, Label::kNear);
488480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
488580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Special handling of out of memory exceptions.
488680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cmp(eax, reinterpret_cast<int32_t>(Failure::OutOfMemoryException()));
488780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(equal, throw_out_of_memory_exception);
488880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
488980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Retrieve the pending exception and clear the variable.
489080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(eax, Operand::StaticVariable(pending_exception_address));
48913ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ mov(edx, Immediate(masm->isolate()->factory()->the_hole_value()));
489280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(Operand::StaticVariable(pending_exception_address), edx);
489380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
489480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Special handling of termination exceptions which are uncatchable
489580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // by javascript code.
489644f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ cmp(eax, masm->isolate()->factory()->termination_exception());
489780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(equal, throw_termination_exception);
489880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
489980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Handle normal exception.
490080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ jmp(throw_normal_exception);
490180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
490280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Retry.
490380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&retry);
490480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
490580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
490680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
490780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid CEntryStub::Generate(MacroAssembler* masm) {
490880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // eax: number of arguments including receiver
490980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // ebx: pointer to C function  (C callee-saved)
491080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // ebp: frame pointer  (restored after C call)
491180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // esp: stack pointer  (restored after C call)
491280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // esi: current context (C callee-saved)
491380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // edi: JS function of the caller (C callee-saved)
491480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
491580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // NOTE: Invocations of builtins may return failure objects instead
491680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // of a proper result. The builtin entry handles this by performing
491780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // a garbage collection and retrying the builtin (twice).
491880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
491980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Enter the exit frame that transitions from JavaScript to C++.
49203ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ EnterExitFrame(save_doubles_ == kSaveFPRegs);
492180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
492280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // eax: result parameter for PerformGC, if any (setup below)
492380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // ebx: pointer to builtin function  (C callee-saved)
492480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // ebp: frame pointer  (restored after C call)
492580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // esp: stack pointer  (restored after C call)
492680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // edi: number of arguments including receiver (C callee-saved)
492780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // esi: argv pointer (C callee-saved)
492880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
492980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label throw_normal_exception;
493080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label throw_termination_exception;
493180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label throw_out_of_memory_exception;
493280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
493380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Call into the runtime system.
493480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  GenerateCore(masm,
493580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen               &throw_normal_exception,
493680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen               &throw_termination_exception,
493780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen               &throw_out_of_memory_exception,
493880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen               false,
493980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen               false);
494080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
494180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Do space-specific GC and retry runtime call.
494280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  GenerateCore(masm,
494380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen               &throw_normal_exception,
494480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen               &throw_termination_exception,
494580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen               &throw_out_of_memory_exception,
494680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen               true,
494780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen               false);
494880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
494980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Do full GC and retry runtime call one final time.
495080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Failure* failure = Failure::InternalError();
495180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(eax, Immediate(reinterpret_cast<int32_t>(failure)));
495280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  GenerateCore(masm,
495380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen               &throw_normal_exception,
495480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen               &throw_termination_exception,
495580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen               &throw_out_of_memory_exception,
495680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen               true,
495780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen               true);
495880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
495980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&throw_out_of_memory_exception);
49603ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Set external caught exception to false.
49613ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  Isolate* isolate = masm->isolate();
49623ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  ExternalReference external_caught(Isolate::kExternalCaughtExceptionAddress,
49633ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                                    isolate);
49643ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ mov(Operand::StaticVariable(external_caught), Immediate(false));
49653ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
49663ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Set pending exception and eax to out of memory exception.
49673ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  ExternalReference pending_exception(Isolate::kPendingExceptionAddress,
49683ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                                      isolate);
49693ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ mov(eax, reinterpret_cast<int32_t>(Failure::OutOfMemoryException()));
49703ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ mov(Operand::StaticVariable(pending_exception), eax);
49713ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Fall through to the next label.
497280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
497380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&throw_termination_exception);
49743ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ ThrowUncatchable(eax);
497580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
497680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&throw_normal_exception);
49773ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ Throw(eax);
497880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
497980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
498080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
498180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid JSEntryStub::GenerateBody(MacroAssembler* masm, bool is_construct) {
49823ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  Label invoke, handler_entry, exit;
498380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label not_outermost_js, not_outermost_js_2;
498480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
49853ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Set up frame.
498680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ push(ebp);
49873ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ mov(ebp, esp);
498880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
498980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Push marker in two places.
499080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  int marker = is_construct ? StackFrame::ENTRY_CONSTRUCT : StackFrame::ENTRY;
499180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ push(Immediate(Smi::FromInt(marker)));  // context slot
499280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ push(Immediate(Smi::FromInt(marker)));  // function slot
499380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Save callee-saved registers (C calling conventions).
499480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ push(edi);
499580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ push(esi);
499680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ push(ebx);
499780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
499880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Save copies of the top frame descriptor on the stack.
4999589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch  ExternalReference c_entry_fp(Isolate::kCEntryFPAddress, masm->isolate());
500080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ push(Operand::StaticVariable(c_entry_fp));
500180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
500280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // If this is the outermost JS call, set js_entry_sp value.
5003589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch  ExternalReference js_entry_sp(Isolate::kJSEntrySPAddress,
500444f0eee88ff00398ff7f715fab053374d808c90dSteve Block                                masm->isolate());
500580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cmp(Operand::StaticVariable(js_entry_sp), Immediate(0));
500669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ j(not_equal, &not_outermost_js, Label::kNear);
500780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(Operand::StaticVariable(js_entry_sp), ebp);
5008053d10c438f14580aaf4ab1b2aad93a5a4fe8b82Steve Block  __ push(Immediate(Smi::FromInt(StackFrame::OUTERMOST_JSENTRY_FRAME)));
5009053d10c438f14580aaf4ab1b2aad93a5a4fe8b82Steve Block  Label cont;
501069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ jmp(&cont, Label::kNear);
501180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&not_outermost_js);
5012053d10c438f14580aaf4ab1b2aad93a5a4fe8b82Steve Block  __ push(Immediate(Smi::FromInt(StackFrame::INNER_JSENTRY_FRAME)));
5013053d10c438f14580aaf4ab1b2aad93a5a4fe8b82Steve Block  __ bind(&cont);
501480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
50153ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Jump to a faked try block that does the invoke, with a faked catch
50163ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // block that sets the pending exception.
50173ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ jmp(&invoke);
50183ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ bind(&handler_entry);
50193ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  handler_offset_ = handler_entry.pos();
50203ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Caught exception: Store result (exception) in the pending exception
50213ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // field in the JSEnv and return a failure sentinel.
5022589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch  ExternalReference pending_exception(Isolate::kPendingExceptionAddress,
502344f0eee88ff00398ff7f715fab053374d808c90dSteve Block                                      masm->isolate());
502480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(Operand::StaticVariable(pending_exception), eax);
502580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(eax, reinterpret_cast<int32_t>(Failure::Exception()));
502680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ jmp(&exit);
502780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
50283ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Invoke: Link this frame into the handler chain.  There's only one
50293ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // handler block in this code object, so its index is 0.
503080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&invoke);
50313ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ PushTryHandler(StackHandler::JS_ENTRY, 0);
503280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
503380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Clear any pending exceptions.
50343ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ mov(edx, Immediate(masm->isolate()->factory()->the_hole_value()));
503580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(Operand::StaticVariable(pending_exception), edx);
503680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
503780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Fake a receiver (NULL).
503880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ push(Immediate(0));  // receiver
503980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
50403ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Invoke the function by calling through JS entry trampoline builtin and
50413ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // pop the faked function when we return. Notice that we cannot store a
50423ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // reference to the trampoline code directly in this stub, because the
50433ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // builtin stubs may not have been generated yet.
504480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  if (is_construct) {
50453ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    ExternalReference construct_entry(Builtins::kJSConstructEntryTrampoline,
50463ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                                      masm->isolate());
504780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ mov(edx, Immediate(construct_entry));
504880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  } else {
504944f0eee88ff00398ff7f715fab053374d808c90dSteve Block    ExternalReference entry(Builtins::kJSEntryTrampoline,
505044f0eee88ff00398ff7f715fab053374d808c90dSteve Block                            masm->isolate());
505180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ mov(edx, Immediate(entry));
505280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
505380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(edx, Operand(edx, 0));  // deref address
505480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ lea(edx, FieldOperand(edx, Code::kHeaderSize));
50553ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ call(edx);
505680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
505780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Unlink this frame from the handler chain.
5058053d10c438f14580aaf4ab1b2aad93a5a4fe8b82Steve Block  __ PopTryHandler();
505980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
5060053d10c438f14580aaf4ab1b2aad93a5a4fe8b82Steve Block  __ bind(&exit);
5061053d10c438f14580aaf4ab1b2aad93a5a4fe8b82Steve Block  // Check if the current stack frame is marked as the outermost JS frame.
5062053d10c438f14580aaf4ab1b2aad93a5a4fe8b82Steve Block  __ pop(ebx);
50633ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ cmp(ebx, Immediate(Smi::FromInt(StackFrame::OUTERMOST_JSENTRY_FRAME)));
506480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(not_equal, &not_outermost_js_2);
506580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(Operand::StaticVariable(js_entry_sp), Immediate(0));
506680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&not_outermost_js_2);
506780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
506880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Restore the top frame descriptor from the stack.
506944f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ pop(Operand::StaticVariable(ExternalReference(
5070589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch      Isolate::kCEntryFPAddress,
507144f0eee88ff00398ff7f715fab053374d808c90dSteve Block      masm->isolate())));
507280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
507380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Restore callee-saved registers (C calling conventions).
507480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ pop(ebx);
507580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ pop(esi);
507680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ pop(edi);
50773ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ add(esp, Immediate(2 * kPointerSize));  // remove markers
507880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
507980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Restore frame pointer and return.
508080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ pop(ebp);
508180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ ret(0);
508280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
508380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
508480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
5085086aeeaae12517475c22695a200be45495516549Ben Murdoch// Generate stub code for instanceof.
5086086aeeaae12517475c22695a200be45495516549Ben Murdoch// This code can patch a call site inlined cache of the instance of check,
5087086aeeaae12517475c22695a200be45495516549Ben Murdoch// which looks like this.
5088086aeeaae12517475c22695a200be45495516549Ben Murdoch//
5089086aeeaae12517475c22695a200be45495516549Ben Murdoch//   81 ff XX XX XX XX   cmp    edi, <the hole, patched to a map>
5090086aeeaae12517475c22695a200be45495516549Ben Murdoch//   75 0a               jne    <some near label>
5091086aeeaae12517475c22695a200be45495516549Ben Murdoch//   b8 XX XX XX XX      mov    eax, <the hole, patched to either true or false>
5092086aeeaae12517475c22695a200be45495516549Ben Murdoch//
5093086aeeaae12517475c22695a200be45495516549Ben Murdoch// If call site patching is requested the stack will have the delta from the
5094086aeeaae12517475c22695a200be45495516549Ben Murdoch// return address to the cmp instruction just below the return address. This
5095086aeeaae12517475c22695a200be45495516549Ben Murdoch// also means that call site patching can only take place with arguments in
5096086aeeaae12517475c22695a200be45495516549Ben Murdoch// registers. TOS looks like this when call site patching is requested
5097086aeeaae12517475c22695a200be45495516549Ben Murdoch//
5098086aeeaae12517475c22695a200be45495516549Ben Murdoch//   esp[0] : return address
5099086aeeaae12517475c22695a200be45495516549Ben Murdoch//   esp[4] : delta from return address to cmp instruction
5100086aeeaae12517475c22695a200be45495516549Ben Murdoch//
510180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid InstanceofStub::Generate(MacroAssembler* masm) {
5102086aeeaae12517475c22695a200be45495516549Ben Murdoch  // Call site inlining and patching implies arguments in registers.
5103086aeeaae12517475c22695a200be45495516549Ben Murdoch  ASSERT(HasArgsInRegisters() || !HasCallSiteInlineCheck());
5104086aeeaae12517475c22695a200be45495516549Ben Murdoch
5105b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Fixed register usage throughout the stub.
5106b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  Register object = eax;  // Object (lhs).
5107b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  Register map = ebx;  // Map of the object.
5108b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  Register function = edx;  // Function (rhs).
5109b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  Register prototype = edi;  // Prototype of the function.
5110b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  Register scratch = ecx;
5111b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
5112086aeeaae12517475c22695a200be45495516549Ben Murdoch  // Constants describing the call site code to patch.
5113086aeeaae12517475c22695a200be45495516549Ben Murdoch  static const int kDeltaToCmpImmediate = 2;
5114086aeeaae12517475c22695a200be45495516549Ben Murdoch  static const int kDeltaToMov = 8;
5115086aeeaae12517475c22695a200be45495516549Ben Murdoch  static const int kDeltaToMovImmediate = 9;
51163ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  static const int8_t kCmpEdiOperandByte1 = BitCast<int8_t, uint8_t>(0x3b);
51173ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  static const int8_t kCmpEdiOperandByte2 = BitCast<int8_t, uint8_t>(0x3d);
5118086aeeaae12517475c22695a200be45495516549Ben Murdoch  static const int8_t kMovEaxImmediateByte = BitCast<int8_t, uint8_t>(0xb8);
5119086aeeaae12517475c22695a200be45495516549Ben Murdoch
51203ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  ExternalReference roots_array_start =
51213ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      ExternalReference::roots_array_start(masm->isolate());
5122086aeeaae12517475c22695a200be45495516549Ben Murdoch
5123086aeeaae12517475c22695a200be45495516549Ben Murdoch  ASSERT_EQ(object.code(), InstanceofStub::left().code());
5124086aeeaae12517475c22695a200be45495516549Ben Murdoch  ASSERT_EQ(function.code(), InstanceofStub::right().code());
5125086aeeaae12517475c22695a200be45495516549Ben Murdoch
5126b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Get the object and function - they are always both needed.
5127b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  Label slow, not_js_object;
5128086aeeaae12517475c22695a200be45495516549Ben Murdoch  if (!HasArgsInRegisters()) {
5129b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ mov(object, Operand(esp, 2 * kPointerSize));
5130b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ mov(function, Operand(esp, 1 * kPointerSize));
5131b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  }
513280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
513380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check that the left hand is a JS object.
51343fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ JumpIfSmi(object, &not_js_object);
5135b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ IsObjectJSObjectType(object, map, scratch, &not_js_object);
513680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
5137086aeeaae12517475c22695a200be45495516549Ben Murdoch  // If there is a call site cache don't look in the global cache, but do the
5138086aeeaae12517475c22695a200be45495516549Ben Murdoch  // real lookup and update the call site cache.
5139086aeeaae12517475c22695a200be45495516549Ben Murdoch  if (!HasCallSiteInlineCheck()) {
5140086aeeaae12517475c22695a200be45495516549Ben Murdoch    // Look up the function and the map in the instanceof cache.
5141257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Label miss;
5142086aeeaae12517475c22695a200be45495516549Ben Murdoch    __ mov(scratch, Immediate(Heap::kInstanceofCacheFunctionRootIndex));
51433ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ cmp(function, Operand::StaticArray(scratch,
51443ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                                          times_pointer_size,
51453ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                                          roots_array_start));
5146257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ j(not_equal, &miss, Label::kNear);
5147086aeeaae12517475c22695a200be45495516549Ben Murdoch    __ mov(scratch, Immediate(Heap::kInstanceofCacheMapRootIndex));
5148086aeeaae12517475c22695a200be45495516549Ben Murdoch    __ cmp(map, Operand::StaticArray(
51493ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch        scratch, times_pointer_size, roots_array_start));
5150257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ j(not_equal, &miss, Label::kNear);
5151086aeeaae12517475c22695a200be45495516549Ben Murdoch    __ mov(scratch, Immediate(Heap::kInstanceofCacheAnswerRootIndex));
5152086aeeaae12517475c22695a200be45495516549Ben Murdoch    __ mov(eax, Operand::StaticArray(
51533ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch        scratch, times_pointer_size, roots_array_start));
5154086aeeaae12517475c22695a200be45495516549Ben Murdoch    __ ret((HasArgsInRegisters() ? 0 : 2) * kPointerSize);
5155086aeeaae12517475c22695a200be45495516549Ben Murdoch    __ bind(&miss);
5156086aeeaae12517475c22695a200be45495516549Ben Murdoch  }
5157086aeeaae12517475c22695a200be45495516549Ben Murdoch
5158b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Get the prototype of the function.
51593ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ TryGetFunctionPrototype(function, prototype, scratch, &slow, true);
516080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
516180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check that the function prototype is a JS object.
51623fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ JumpIfSmi(prototype, &slow);
5163b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ IsObjectJSObjectType(prototype, scratch, scratch, &slow);
5164b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
5165086aeeaae12517475c22695a200be45495516549Ben Murdoch  // Update the global instanceof or call site inlined cache with the current
5166086aeeaae12517475c22695a200be45495516549Ben Murdoch  // map and function. The cached answer will be set when it is known below.
5167086aeeaae12517475c22695a200be45495516549Ben Murdoch  if (!HasCallSiteInlineCheck()) {
5168b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ mov(scratch, Immediate(Heap::kInstanceofCacheMapRootIndex));
51693ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ mov(Operand::StaticArray(scratch, times_pointer_size, roots_array_start),
51703ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch         map);
5171b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ mov(scratch, Immediate(Heap::kInstanceofCacheFunctionRootIndex));
51723ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ mov(Operand::StaticArray(scratch, times_pointer_size, roots_array_start),
5173b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch         function);
5174086aeeaae12517475c22695a200be45495516549Ben Murdoch  } else {
5175086aeeaae12517475c22695a200be45495516549Ben Murdoch    // The constants for the code patching are based on no push instructions
5176086aeeaae12517475c22695a200be45495516549Ben Murdoch    // at the call site.
5177086aeeaae12517475c22695a200be45495516549Ben Murdoch    ASSERT(HasArgsInRegisters());
5178086aeeaae12517475c22695a200be45495516549Ben Murdoch    // Get return address and delta to inlined map check.
5179086aeeaae12517475c22695a200be45495516549Ben Murdoch    __ mov(scratch, Operand(esp, 0 * kPointerSize));
5180086aeeaae12517475c22695a200be45495516549Ben Murdoch    __ sub(scratch, Operand(esp, 1 * kPointerSize));
5181086aeeaae12517475c22695a200be45495516549Ben Murdoch    if (FLAG_debug_code) {
51823ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      __ cmpb(Operand(scratch, 0), kCmpEdiOperandByte1);
5183086aeeaae12517475c22695a200be45495516549Ben Murdoch      __ Assert(equal, "InstanceofStub unexpected call site cache (cmp 1)");
51843ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      __ cmpb(Operand(scratch, 1), kCmpEdiOperandByte2);
5185086aeeaae12517475c22695a200be45495516549Ben Murdoch      __ Assert(equal, "InstanceofStub unexpected call site cache (cmp 2)");
5186086aeeaae12517475c22695a200be45495516549Ben Murdoch    }
51873ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ mov(scratch, Operand(scratch, kDeltaToCmpImmediate));
51883ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ mov(Operand(scratch, 0), map);
5189086aeeaae12517475c22695a200be45495516549Ben Murdoch  }
5190b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
5191b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Loop through the prototype chain of the object looking for the function
5192b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // prototype.
5193b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ mov(scratch, FieldOperand(map, Map::kPrototypeOffset));
5194257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label loop, is_instance, is_not_instance;
519580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&loop);
51963ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ cmp(scratch, prototype);
5197257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(equal, &is_instance, Label::kNear);
519844f0eee88ff00398ff7f715fab053374d808c90dSteve Block  Factory* factory = masm->isolate()->factory();
51993ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ cmp(scratch, Immediate(factory->null_value()));
5200257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(equal, &is_not_instance, Label::kNear);
5201b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ mov(scratch, FieldOperand(scratch, HeapObject::kMapOffset));
5202b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ mov(scratch, FieldOperand(scratch, Map::kPrototypeOffset));
520380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ jmp(&loop);
520480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
520580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&is_instance);
5206086aeeaae12517475c22695a200be45495516549Ben Murdoch  if (!HasCallSiteInlineCheck()) {
5207086aeeaae12517475c22695a200be45495516549Ben Murdoch    __ Set(eax, Immediate(0));
5208086aeeaae12517475c22695a200be45495516549Ben Murdoch    __ mov(scratch, Immediate(Heap::kInstanceofCacheAnswerRootIndex));
5209086aeeaae12517475c22695a200be45495516549Ben Murdoch    __ mov(Operand::StaticArray(scratch,
52103ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                                times_pointer_size, roots_array_start), eax);
5211086aeeaae12517475c22695a200be45495516549Ben Murdoch  } else {
5212086aeeaae12517475c22695a200be45495516549Ben Murdoch    // Get return address and delta to inlined map check.
521344f0eee88ff00398ff7f715fab053374d808c90dSteve Block    __ mov(eax, factory->true_value());
5214086aeeaae12517475c22695a200be45495516549Ben Murdoch    __ mov(scratch, Operand(esp, 0 * kPointerSize));
5215086aeeaae12517475c22695a200be45495516549Ben Murdoch    __ sub(scratch, Operand(esp, 1 * kPointerSize));
5216086aeeaae12517475c22695a200be45495516549Ben Murdoch    if (FLAG_debug_code) {
5217086aeeaae12517475c22695a200be45495516549Ben Murdoch      __ cmpb(Operand(scratch, kDeltaToMov), kMovEaxImmediateByte);
5218086aeeaae12517475c22695a200be45495516549Ben Murdoch      __ Assert(equal, "InstanceofStub unexpected call site cache (mov)");
5219086aeeaae12517475c22695a200be45495516549Ben Murdoch    }
5220086aeeaae12517475c22695a200be45495516549Ben Murdoch    __ mov(Operand(scratch, kDeltaToMovImmediate), eax);
5221086aeeaae12517475c22695a200be45495516549Ben Murdoch    if (!ReturnTrueFalseObject()) {
5222086aeeaae12517475c22695a200be45495516549Ben Murdoch      __ Set(eax, Immediate(0));
5223086aeeaae12517475c22695a200be45495516549Ben Murdoch    }
5224086aeeaae12517475c22695a200be45495516549Ben Murdoch  }
5225086aeeaae12517475c22695a200be45495516549Ben Murdoch  __ ret((HasArgsInRegisters() ? 0 : 2) * kPointerSize);
522680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
522780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&is_not_instance);
5228086aeeaae12517475c22695a200be45495516549Ben Murdoch  if (!HasCallSiteInlineCheck()) {
5229086aeeaae12517475c22695a200be45495516549Ben Murdoch    __ Set(eax, Immediate(Smi::FromInt(1)));
5230086aeeaae12517475c22695a200be45495516549Ben Murdoch    __ mov(scratch, Immediate(Heap::kInstanceofCacheAnswerRootIndex));
5231086aeeaae12517475c22695a200be45495516549Ben Murdoch    __ mov(Operand::StaticArray(
52323ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch        scratch, times_pointer_size, roots_array_start), eax);
5233086aeeaae12517475c22695a200be45495516549Ben Murdoch  } else {
5234086aeeaae12517475c22695a200be45495516549Ben Murdoch    // Get return address and delta to inlined map check.
523544f0eee88ff00398ff7f715fab053374d808c90dSteve Block    __ mov(eax, factory->false_value());
5236086aeeaae12517475c22695a200be45495516549Ben Murdoch    __ mov(scratch, Operand(esp, 0 * kPointerSize));
5237086aeeaae12517475c22695a200be45495516549Ben Murdoch    __ sub(scratch, Operand(esp, 1 * kPointerSize));
5238086aeeaae12517475c22695a200be45495516549Ben Murdoch    if (FLAG_debug_code) {
5239086aeeaae12517475c22695a200be45495516549Ben Murdoch      __ cmpb(Operand(scratch, kDeltaToMov), kMovEaxImmediateByte);
5240086aeeaae12517475c22695a200be45495516549Ben Murdoch      __ Assert(equal, "InstanceofStub unexpected call site cache (mov)");
5241086aeeaae12517475c22695a200be45495516549Ben Murdoch    }
5242086aeeaae12517475c22695a200be45495516549Ben Murdoch    __ mov(Operand(scratch, kDeltaToMovImmediate), eax);
5243086aeeaae12517475c22695a200be45495516549Ben Murdoch    if (!ReturnTrueFalseObject()) {
5244086aeeaae12517475c22695a200be45495516549Ben Murdoch      __ Set(eax, Immediate(Smi::FromInt(1)));
5245086aeeaae12517475c22695a200be45495516549Ben Murdoch    }
5246086aeeaae12517475c22695a200be45495516549Ben Murdoch  }
5247086aeeaae12517475c22695a200be45495516549Ben Murdoch  __ ret((HasArgsInRegisters() ? 0 : 2) * kPointerSize);
5248b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
5249b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  Label object_not_null, object_not_null_or_smi;
5250b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ bind(&not_js_object);
5251b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Before null, smi and string value checks, check that the rhs is a function
5252b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // as for a non-function rhs an exception needs to be thrown.
525369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ JumpIfSmi(function, &slow, Label::kNear);
5254b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ CmpObjectType(function, JS_FUNCTION_TYPE, scratch);
525569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ j(not_equal, &slow, Label::kNear);
5256b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
5257b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Null is not instance of anything.
525844f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ cmp(object, factory->null_value());
525969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ j(not_equal, &object_not_null, Label::kNear);
5260b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ Set(eax, Immediate(Smi::FromInt(1)));
5261086aeeaae12517475c22695a200be45495516549Ben Murdoch  __ ret((HasArgsInRegisters() ? 0 : 2) * kPointerSize);
5262b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
5263b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ bind(&object_not_null);
5264b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Smi values is not instance of anything.
526569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ JumpIfNotSmi(object, &object_not_null_or_smi, Label::kNear);
5266b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ Set(eax, Immediate(Smi::FromInt(1)));
5267086aeeaae12517475c22695a200be45495516549Ben Murdoch  __ ret((HasArgsInRegisters() ? 0 : 2) * kPointerSize);
5268b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
5269b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ bind(&object_not_null_or_smi);
5270b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // String values is not instance of anything.
5271b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  Condition is_string = masm->IsObjectStringType(object, scratch, scratch);
527269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ j(NegateCondition(is_string), &slow, Label::kNear);
5273b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ Set(eax, Immediate(Smi::FromInt(1)));
5274086aeeaae12517475c22695a200be45495516549Ben Murdoch  __ ret((HasArgsInRegisters() ? 0 : 2) * kPointerSize);
527580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
527680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Slow-case: Go through the JavaScript implementation.
527780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&slow);
5278086aeeaae12517475c22695a200be45495516549Ben Murdoch  if (!ReturnTrueFalseObject()) {
5279086aeeaae12517475c22695a200be45495516549Ben Murdoch    // Tail call the builtin which returns 0 or 1.
5280086aeeaae12517475c22695a200be45495516549Ben Murdoch    if (HasArgsInRegisters()) {
5281086aeeaae12517475c22695a200be45495516549Ben Murdoch      // Push arguments below return address.
5282086aeeaae12517475c22695a200be45495516549Ben Murdoch      __ pop(scratch);
5283086aeeaae12517475c22695a200be45495516549Ben Murdoch      __ push(object);
5284086aeeaae12517475c22695a200be45495516549Ben Murdoch      __ push(function);
5285086aeeaae12517475c22695a200be45495516549Ben Murdoch      __ push(scratch);
5286086aeeaae12517475c22695a200be45495516549Ben Murdoch    }
5287086aeeaae12517475c22695a200be45495516549Ben Murdoch    __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION);
5288086aeeaae12517475c22695a200be45495516549Ben Murdoch  } else {
5289086aeeaae12517475c22695a200be45495516549Ben Murdoch    // Call the builtin and convert 0/1 to true/false.
52903ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    {
52913ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      FrameScope scope(masm, StackFrame::INTERNAL);
52923ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      __ push(object);
52933ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      __ push(function);
52943ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      __ InvokeBuiltin(Builtins::INSTANCE_OF, CALL_FUNCTION);
52953ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    }
5296257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Label true_value, done;
52973ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ test(eax, eax);
5298257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ j(zero, &true_value, Label::kNear);
529944f0eee88ff00398ff7f715fab053374d808c90dSteve Block    __ mov(eax, factory->false_value());
5300257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ jmp(&done, Label::kNear);
5301086aeeaae12517475c22695a200be45495516549Ben Murdoch    __ bind(&true_value);
530244f0eee88ff00398ff7f715fab053374d808c90dSteve Block    __ mov(eax, factory->true_value());
5303086aeeaae12517475c22695a200be45495516549Ben Murdoch    __ bind(&done);
5304086aeeaae12517475c22695a200be45495516549Ben Murdoch    __ ret((HasArgsInRegisters() ? 0 : 2) * kPointerSize);
5305b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  }
530680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
530780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
530880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
5309086aeeaae12517475c22695a200be45495516549Ben MurdochRegister InstanceofStub::left() { return eax; }
5310086aeeaae12517475c22695a200be45495516549Ben Murdoch
5311086aeeaae12517475c22695a200be45495516549Ben Murdoch
5312086aeeaae12517475c22695a200be45495516549Ben MurdochRegister InstanceofStub::right() { return edx; }
5313086aeeaae12517475c22695a200be45495516549Ben Murdoch
5314086aeeaae12517475c22695a200be45495516549Ben Murdoch
531580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenint CompareStub::MinorKey() {
531680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Encode the three parameters in a unique 16 bit value. To avoid duplicate
531780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // stubs the never NaN NaN condition is only taken into account if the
531880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // condition is equals.
531980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  ASSERT(static_cast<unsigned>(cc_) < (1 << 12));
532080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  ASSERT(lhs_.is(no_reg) && rhs_.is(no_reg));
532180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  return ConditionField::encode(static_cast<unsigned>(cc_))
532280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen         | RegisterField::encode(false)   // lhs_ and rhs_ are not used
532380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen         | StrictField::encode(strict_)
532480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen         | NeverNanNanField::encode(cc_ == equal ? never_nan_nan_ : false)
53250d5e116f6aee03185f237311a943491bb079a768Kristian Monsen         | IncludeNumberCompareField::encode(include_number_compare_)
53260d5e116f6aee03185f237311a943491bb079a768Kristian Monsen         | IncludeSmiCompareField::encode(include_smi_compare_);
532780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
532880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
532980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
533080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// Unfortunately you have to run without snapshots to see most of these
533180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// names in the profile since most compare stubs end up in the snapshot.
53323fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdochvoid CompareStub::PrintName(StringStream* stream) {
533380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  ASSERT(lhs_.is(no_reg) && rhs_.is(no_reg));
533480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  const char* cc_name;
533580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  switch (cc_) {
533680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    case less: cc_name = "LT"; break;
533780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    case greater: cc_name = "GT"; break;
533880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    case less_equal: cc_name = "LE"; break;
533980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    case greater_equal: cc_name = "GE"; break;
534080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    case equal: cc_name = "EQ"; break;
534180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    case not_equal: cc_name = "NE"; break;
534280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    default: cc_name = "UnknownCondition"; break;
534380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
53443fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  bool is_equality = cc_ == equal || cc_ == not_equal;
53453fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  stream->Add("CompareStub_%s", cc_name);
53463fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  if (strict_ && is_equality) stream->Add("_STRICT");
53473fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  if (never_nan_nan_ && is_equality) stream->Add("_NO_NAN");
53483fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  if (!include_number_compare_) stream->Add("_NO_NUMBER");
53493fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  if (!include_smi_compare_) stream->Add("_NO_SMI");
535080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
535180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
535280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
535380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// -------------------------------------------------------------------------
535480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// StringCharCodeAtGenerator
535580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
535680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StringCharCodeAtGenerator::GenerateFast(MacroAssembler* masm) {
535780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // If the receiver is a smi trigger the non-string case.
535880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  STATIC_ASSERT(kSmiTag == 0);
53593fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ JumpIfSmi(object_, receiver_not_string_);
536080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
536180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Fetch the instance type of the receiver into result register.
536280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(result_, FieldOperand(object_, HeapObject::kMapOffset));
536380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movzx_b(result_, FieldOperand(result_, Map::kInstanceTypeOffset));
536480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // If the receiver is not a string trigger the non-string case.
536580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ test(result_, Immediate(kIsNotStringMask));
536680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(not_zero, receiver_not_string_);
536780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
536880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // If the index is non-smi trigger the non-smi case.
536980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  STATIC_ASSERT(kSmiTag == 0);
53703fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ JumpIfNotSmi(index_, &index_not_smi_);
537180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&got_smi_index_);
537280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
537380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check for index out of range.
53743ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ cmp(index_, FieldOperand(object_, String::kLengthOffset));
537580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(above_equal, index_out_of_range_);
537680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
53773ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ SmiUntag(index_);
537885b71799222b55eb5dd74ea26efe0c64ab655c8cBen Murdoch
53793ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  Factory* factory = masm->isolate()->factory();
53803ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  StringCharLoadGenerator::Generate(
53813ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      masm, factory, object_, index_, result_, &call_runtime_);
538280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
538380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiTag(result_);
538480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&exit_);
538580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
538680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
538780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
538880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StringCharCodeAtGenerator::GenerateSlow(
53893ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    MacroAssembler* masm,
53903ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    const RuntimeCallHelper& call_helper) {
539180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ Abort("Unexpected fallthrough to CharCodeAt slow case");
539280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
539380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Index is not a smi.
539480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&index_not_smi_);
539580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // If index is a heap number, try converting it to an integer.
539644f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ CheckMap(index_,
539744f0eee88ff00398ff7f715fab053374d808c90dSteve Block              masm->isolate()->factory()->heap_number_map(),
539844f0eee88ff00398ff7f715fab053374d808c90dSteve Block              index_not_number_,
5399257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch              DONT_DO_SMI_CHECK);
540080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  call_helper.BeforeCall(masm);
540180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ push(object_);
540280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ push(index_);  // Consumed by runtime conversion function.
540380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  if (index_flags_ == STRING_INDEX_IS_NUMBER) {
540480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ CallRuntime(Runtime::kNumberToIntegerMapMinusZero, 1);
540580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  } else {
540680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    ASSERT(index_flags_ == STRING_INDEX_IS_ARRAY_INDEX);
540780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // NumberToSmi discards numbers that are not exact integers.
540880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ CallRuntime(Runtime::kNumberToSmi, 1);
540980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
54103ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  if (!index_.is(eax)) {
541180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // Save the conversion result before the pop instructions below
541280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // have a chance to overwrite it.
54133ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ mov(index_, eax);
541480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
541580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ pop(object_);
541680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Reload the instance type.
541780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(result_, FieldOperand(object_, HeapObject::kMapOffset));
541880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movzx_b(result_, FieldOperand(result_, Map::kInstanceTypeOffset));
541980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  call_helper.AfterCall(masm);
542080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // If index is still not a smi, it must be out of range.
542180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  STATIC_ASSERT(kSmiTag == 0);
54223ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ JumpIfNotSmi(index_, index_out_of_range_);
542380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Otherwise, return to the fast path.
542480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ jmp(&got_smi_index_);
542580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
542680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Call runtime. We get here when the receiver is a string and the
542780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // index is a number, but the code of getting the actual character
542880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // is too complex (e.g., when the string needs to be flattened).
542980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&call_runtime_);
543080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  call_helper.BeforeCall(masm);
543180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ push(object_);
54323ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ SmiTag(index_);
543380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ push(index_);
543480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ CallRuntime(Runtime::kStringCharCodeAt, 2);
543580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  if (!result_.is(eax)) {
543680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ mov(result_, eax);
543780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
543880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  call_helper.AfterCall(masm);
543980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ jmp(&exit_);
544080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
544180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ Abort("Unexpected fallthrough from CharCodeAt slow case");
544280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
544380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
544480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
544580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// -------------------------------------------------------------------------
544680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// StringCharFromCodeGenerator
544780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
544880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StringCharFromCodeGenerator::GenerateFast(MacroAssembler* masm) {
544980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Fast case of Heap::LookupSingleCharacterStringFromCode.
545080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  STATIC_ASSERT(kSmiTag == 0);
545180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  STATIC_ASSERT(kSmiShiftSize == 0);
545280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  ASSERT(IsPowerOf2(String::kMaxAsciiCharCode + 1));
545380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ test(code_,
545480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen          Immediate(kSmiTagMask |
545580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                    ((~String::kMaxAsciiCharCode) << kSmiTagSize)));
5456257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(not_zero, &slow_case_);
545780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
545844f0eee88ff00398ff7f715fab053374d808c90dSteve Block  Factory* factory = masm->isolate()->factory();
545944f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ Set(result_, Immediate(factory->single_character_string_cache()));
546080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  STATIC_ASSERT(kSmiTag == 0);
546180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  STATIC_ASSERT(kSmiTagSize == 1);
546280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  STATIC_ASSERT(kSmiShiftSize == 0);
54633ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // At this point code register contains smi tagged ASCII char code.
546480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(result_, FieldOperand(result_,
546580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                               code_, times_half_pointer_size,
546680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                               FixedArray::kHeaderSize));
546744f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ cmp(result_, factory->undefined_value());
5468257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(equal, &slow_case_);
546980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&exit_);
547080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
547180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
547280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
547380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StringCharFromCodeGenerator::GenerateSlow(
54743ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    MacroAssembler* masm,
54753ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    const RuntimeCallHelper& call_helper) {
547680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ Abort("Unexpected fallthrough to CharFromCode slow case");
547780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
547880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&slow_case_);
547980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  call_helper.BeforeCall(masm);
548080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ push(code_);
548180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ CallRuntime(Runtime::kCharFromCode, 1);
548280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  if (!result_.is(eax)) {
548380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ mov(result_, eax);
548480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
548580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  call_helper.AfterCall(masm);
548680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ jmp(&exit_);
548780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
548880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ Abort("Unexpected fallthrough from CharFromCode slow case");
548980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
549080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
549180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
549280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// -------------------------------------------------------------------------
549380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// StringCharAtGenerator
549480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
549580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StringCharAtGenerator::GenerateFast(MacroAssembler* masm) {
549680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  char_code_at_generator_.GenerateFast(masm);
549780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  char_from_code_generator_.GenerateFast(masm);
549880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
549980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
550080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
550180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StringCharAtGenerator::GenerateSlow(
55023ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    MacroAssembler* masm,
55033ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    const RuntimeCallHelper& call_helper) {
550480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  char_code_at_generator_.GenerateSlow(masm, call_helper);
550580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  char_from_code_generator_.GenerateSlow(masm, call_helper);
550680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
550780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
550880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
550980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StringAddStub::Generate(MacroAssembler* masm) {
55103ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  Label call_runtime, call_builtin;
55119ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick  Builtins::JavaScript builtin_id = Builtins::ADD;
551280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
551380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Load the two arguments.
551480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(eax, Operand(esp, 2 * kPointerSize));  // First argument.
551580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(edx, Operand(esp, 1 * kPointerSize));  // Second argument.
551680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
551780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Make sure that both arguments are strings if not known in advance.
55189ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick  if (flags_ == NO_STRING_ADD_FLAGS) {
55193ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ JumpIfSmi(eax, &call_runtime);
552080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ CmpObjectType(eax, FIRST_NONSTRING_TYPE, ebx);
55213ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ j(above_equal, &call_runtime);
552280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
552380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // First argument is a a string, test second.
55243ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ JumpIfSmi(edx, &call_runtime);
552580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ CmpObjectType(edx, FIRST_NONSTRING_TYPE, ebx);
55263ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ j(above_equal, &call_runtime);
55279ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick  } else {
55289ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick    // Here at least one of the arguments is definitely a string.
55299ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick    // We convert the one that is not known to be a string.
55309ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick    if ((flags_ & NO_STRING_CHECK_LEFT_IN_STUB) == 0) {
55319ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick      ASSERT((flags_ & NO_STRING_CHECK_RIGHT_IN_STUB) != 0);
55329ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick      GenerateConvertArgument(masm, 2 * kPointerSize, eax, ebx, ecx, edi,
55339ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick                              &call_builtin);
55349ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick      builtin_id = Builtins::STRING_ADD_RIGHT;
55359ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick    } else if ((flags_ & NO_STRING_CHECK_RIGHT_IN_STUB) == 0) {
55369ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick      ASSERT((flags_ & NO_STRING_CHECK_LEFT_IN_STUB) != 0);
55379ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick      GenerateConvertArgument(masm, 1 * kPointerSize, edx, ebx, ecx, edi,
55389ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick                              &call_builtin);
55399ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick      builtin_id = Builtins::STRING_ADD_LEFT;
55409ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick    }
554180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
554280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
554380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Both arguments are strings.
554480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // eax: first string
554580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // edx: second string
554680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check if either of the strings are empty. In that case return the other.
5547257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label second_not_zero_length, both_not_zero_length;
554880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(ecx, FieldOperand(edx, String::kLengthOffset));
554980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  STATIC_ASSERT(kSmiTag == 0);
55503ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ test(ecx, ecx);
5551257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(not_zero, &second_not_zero_length, Label::kNear);
555280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Second string is empty, result is first string which is already in eax.
555344f0eee88ff00398ff7f715fab053374d808c90dSteve Block  Counters* counters = masm->isolate()->counters();
555444f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ IncrementCounter(counters->string_add_native(), 1);
555580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ ret(2 * kPointerSize);
555680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&second_not_zero_length);
555780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(ebx, FieldOperand(eax, String::kLengthOffset));
555880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  STATIC_ASSERT(kSmiTag == 0);
55593ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ test(ebx, ebx);
5560257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(not_zero, &both_not_zero_length, Label::kNear);
556180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // First string is empty, result is second string which is in edx.
556280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(eax, edx);
556344f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ IncrementCounter(counters->string_add_native(), 1);
556480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ ret(2 * kPointerSize);
556580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
556680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Both strings are non-empty.
556780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // eax: first string
556880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // ebx: length of first string as a smi
556980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // ecx: length of second string as a smi
557080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // edx: second string
557180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Look at the length of the result of adding the two strings.
557280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label string_add_flat_result, longer_than_two;
557380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&both_not_zero_length);
55743ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ add(ebx, ecx);
557580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  STATIC_ASSERT(Smi::kMaxValue == String::kMaxLength);
557680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Handle exceptionally long strings in the runtime system.
55773ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ j(overflow, &call_runtime);
557844f0eee88ff00398ff7f715fab053374d808c90dSteve Block  // Use the symbol table when adding two one character strings, as it
557944f0eee88ff00398ff7f715fab053374d808c90dSteve Block  // helps later optimizations to return a symbol here.
55803ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ cmp(ebx, Immediate(Smi::FromInt(2)));
558180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(not_equal, &longer_than_two);
558280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
55833ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Check that both strings are non-external ASCII strings.
55843ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ JumpIfNotBothSequentialAsciiStrings(eax, edx, ebx, ecx, &call_runtime);
558580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
55869ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick  // Get the two characters forming the new string.
558780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movzx_b(ebx, FieldOperand(eax, SeqAsciiString::kHeaderSize));
558880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movzx_b(ecx, FieldOperand(edx, SeqAsciiString::kHeaderSize));
558980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
559080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Try to lookup two character string in symbol table. If it is not found
559180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // just allocate a new one.
55929ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick  Label make_two_character_string, make_two_character_string_no_reload;
559380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  StringHelper::GenerateTwoCharacterSymbolTableProbe(
55949ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick      masm, ebx, ecx, eax, edx, edi,
55959ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick      &make_two_character_string_no_reload, &make_two_character_string);
559644f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ IncrementCounter(counters->string_add_native(), 1);
559780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ ret(2 * kPointerSize);
559880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
55999ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick  // Allocate a two character string.
560080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&make_two_character_string);
56019ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick  // Reload the arguments.
56029ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick  __ mov(eax, Operand(esp, 2 * kPointerSize));  // First argument.
56039ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick  __ mov(edx, Operand(esp, 1 * kPointerSize));  // Second argument.
56049ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick  // Get the two characters forming the new string.
56059ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick  __ movzx_b(ebx, FieldOperand(eax, SeqAsciiString::kHeaderSize));
56069ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick  __ movzx_b(ecx, FieldOperand(edx, SeqAsciiString::kHeaderSize));
56079ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick  __ bind(&make_two_character_string_no_reload);
560844f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ IncrementCounter(counters->string_add_make_two_char(), 1);
56093ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ AllocateAsciiString(eax, 2, edi, edx, &call_runtime);
56109ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick  // Pack both characters in ebx.
56119ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick  __ shl(ecx, kBitsPerByte);
56123ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ or_(ebx, ecx);
56139ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick  // Set the characters in the new string.
56149ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick  __ mov_w(FieldOperand(eax, SeqAsciiString::kHeaderSize), ebx);
561544f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ IncrementCounter(counters->string_add_native(), 1);
56169ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick  __ ret(2 * kPointerSize);
561780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
561880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&longer_than_two);
561980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check if resulting string will be flat.
56203ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ cmp(ebx, Immediate(Smi::FromInt(ConsString::kMinLength)));
562180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(below, &string_add_flat_result);
562280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
562380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // If result is not supposed to be flat allocate a cons string object. If both
56243ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // strings are ASCII the result is an ASCII cons string.
562580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label non_ascii, allocated, ascii_data;
562680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(edi, FieldOperand(eax, HeapObject::kMapOffset));
562780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movzx_b(ecx, FieldOperand(edi, Map::kInstanceTypeOffset));
562880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(edi, FieldOperand(edx, HeapObject::kMapOffset));
562980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movzx_b(edi, FieldOperand(edi, Map::kInstanceTypeOffset));
56303ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ and_(ecx, edi);
5631589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch  STATIC_ASSERT((kStringEncodingMask & kAsciiStringTag) != 0);
5632589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch  STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0);
5633589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch  __ test(ecx, Immediate(kStringEncodingMask));
563480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(zero, &non_ascii);
563580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&ascii_data);
56363ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Allocate an ASCII cons string.
56373ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ AllocateAsciiConsString(ecx, edi, no_reg, &call_runtime);
563880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&allocated);
563980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Fill the fields of the cons string.
564080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  if (FLAG_debug_code) __ AbortIfNotSmi(ebx);
564180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(FieldOperand(ecx, ConsString::kLengthOffset), ebx);
564280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(FieldOperand(ecx, ConsString::kHashFieldOffset),
564380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen         Immediate(String::kEmptyHashField));
564480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(FieldOperand(ecx, ConsString::kFirstOffset), eax);
564580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(FieldOperand(ecx, ConsString::kSecondOffset), edx);
564680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(eax, ecx);
564744f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ IncrementCounter(counters->string_add_native(), 1);
564880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ ret(2 * kPointerSize);
564980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&non_ascii);
565080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // At least one of the strings is two-byte. Check whether it happens
56513ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // to contain only ASCII characters.
565280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // ecx: first instance type AND second instance type.
565380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // edi: second instance type.
565480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ test(ecx, Immediate(kAsciiDataHintMask));
565580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(not_zero, &ascii_data);
565680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(ecx, FieldOperand(eax, HeapObject::kMapOffset));
565780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset));
56583ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ xor_(edi, ecx);
565980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  STATIC_ASSERT(kAsciiStringTag != 0 && kAsciiDataHintTag != 0);
566080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ and_(edi, kAsciiStringTag | kAsciiDataHintTag);
566180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cmp(edi, kAsciiStringTag | kAsciiDataHintTag);
566280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(equal, &ascii_data);
566380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Allocate a two byte cons string.
56643ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ AllocateTwoByteConsString(ecx, edi, no_reg, &call_runtime);
566580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ jmp(&allocated);
566680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
56673ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // We cannot encounter sliced strings or cons strings here since:
56683ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  STATIC_ASSERT(SlicedString::kMinLength >= ConsString::kMinLength);
56693ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Handle creating a flat result from either external or sequential strings.
56703ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Locate the first characters' locations.
567180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // eax: first string
567280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // ebx: length of resulting flat string as a smi
567380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // edx: second string
56743ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  Label first_prepared, second_prepared;
56753ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  Label first_is_sequential, second_is_sequential;
567680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&string_add_flat_result);
567780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(ecx, FieldOperand(eax, HeapObject::kMapOffset));
567880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset));
56793ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // ecx: instance type of first string
56803ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  STATIC_ASSERT(kSeqStringTag == 0);
56813ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ test_b(ecx, kStringRepresentationMask);
56823ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ j(zero, &first_is_sequential, Label::kNear);
56833ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Rule out short external string and load string resource.
56843ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  STATIC_ASSERT(kShortExternalStringTag != 0);
56853ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ test_b(ecx, kShortExternalStringMask);
56863ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ j(not_zero, &call_runtime);
56873ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ mov(eax, FieldOperand(eax, ExternalString::kResourceDataOffset));
56883ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  STATIC_ASSERT(SeqAsciiString::kHeaderSize == SeqTwoByteString::kHeaderSize);
56893ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ jmp(&first_prepared, Label::kNear);
56903ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ bind(&first_is_sequential);
56913ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ add(eax, Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag));
56923ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ bind(&first_prepared);
56933ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
56943ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ mov(edi, FieldOperand(edx, HeapObject::kMapOffset));
56953ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ movzx_b(edi, FieldOperand(edi, Map::kInstanceTypeOffset));
56963ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Check whether both strings have same encoding.
56973ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // edi: instance type of second string
56983ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ xor_(ecx, edi);
56993ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ test_b(ecx, kStringEncodingMask);
57003ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ j(not_zero, &call_runtime);
57013ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  STATIC_ASSERT(kSeqStringTag == 0);
57023ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ test_b(edi, kStringRepresentationMask);
57033ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ j(zero, &second_is_sequential, Label::kNear);
57043ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Rule out short external string and load string resource.
57053ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  STATIC_ASSERT(kShortExternalStringTag != 0);
57063ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ test_b(edi, kShortExternalStringMask);
57073ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ j(not_zero, &call_runtime);
57083ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ mov(edx, FieldOperand(edx, ExternalString::kResourceDataOffset));
57093ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  STATIC_ASSERT(SeqAsciiString::kHeaderSize == SeqTwoByteString::kHeaderSize);
57103ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ jmp(&second_prepared, Label::kNear);
57113ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ bind(&second_is_sequential);
57123ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ add(edx, Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag));
57133ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ bind(&second_prepared);
57143ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
57153ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Push the addresses of both strings' first characters onto the stack.
57163ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ push(edx);
57173ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ push(eax);
57183ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
57193ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  Label non_ascii_string_add_flat_result, call_runtime_drop_two;
57203ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // edi: instance type of second string
57213ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // First string and second string have the same encoding.
57223ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  STATIC_ASSERT(kTwoByteStringTag == 0);
57233ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ test_b(edi, kStringEncodingMask);
572480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(zero, &non_ascii_string_add_flat_result);
572580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
57263ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Both strings are ASCII strings.
572780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // ebx: length of resulting flat string as a smi
572880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiUntag(ebx);
57293ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ AllocateAsciiString(eax, ebx, ecx, edx, edi, &call_runtime_drop_two);
573080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // eax: result string
573180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(ecx, eax);
573280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Locate first character of result.
57333ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ add(ecx, Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag));
57343ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Load first argument's length and first character location.  Account for
57353ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // values currently on the stack when fetching arguments from it.
57363ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ mov(edx, Operand(esp, 4 * kPointerSize));
573780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(edi, FieldOperand(edx, String::kLengthOffset));
573880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiUntag(edi);
57393ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ pop(edx);
574080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // eax: result string
574180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // ecx: first character of result
574280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // edx: first char of first argument
574380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // edi: length of first argument
574480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  StringHelper::GenerateCopyCharacters(masm, ecx, edx, edi, ebx, true);
57453ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Load second argument's length and first character location.  Account for
57463ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // values currently on the stack when fetching arguments from it.
57473ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ mov(edx, Operand(esp, 2 * kPointerSize));
574880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(edi, FieldOperand(edx, String::kLengthOffset));
574980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiUntag(edi);
57503ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ pop(edx);
575180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // eax: result string
575280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // ecx: next character of result
575380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // edx: first char of second argument
575480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // edi: length of second argument
575580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  StringHelper::GenerateCopyCharacters(masm, ecx, edx, edi, ebx, true);
575644f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ IncrementCounter(counters->string_add_native(), 1);
575780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ ret(2 * kPointerSize);
575880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
575980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Handle creating a flat two byte result.
576080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // eax: first string - known to be two byte
576180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // ebx: length of resulting flat string as a smi
576280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // edx: second string
576380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&non_ascii_string_add_flat_result);
57643ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Both strings are two byte strings.
576580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiUntag(ebx);
57663ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ AllocateTwoByteString(eax, ebx, ecx, edx, edi, &call_runtime_drop_two);
576780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // eax: result string
576880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(ecx, eax);
576980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Locate first character of result.
57703ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ add(ecx, Immediate(SeqTwoByteString::kHeaderSize - kHeapObjectTag));
57713ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Load second argument's length and first character location.  Account for
57723ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // values currently on the stack when fetching arguments from it.
57733ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ mov(edx, Operand(esp, 4 * kPointerSize));
577480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(edi, FieldOperand(edx, String::kLengthOffset));
577580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiUntag(edi);
57763ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ pop(edx);
577780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // eax: result string
577880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // ecx: first character of result
577980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // edx: first char of first argument
578080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // edi: length of first argument
578180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  StringHelper::GenerateCopyCharacters(masm, ecx, edx, edi, ebx, false);
57823ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Load second argument's length and first character location.  Account for
57833ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // values currently on the stack when fetching arguments from it.
57843ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ mov(edx, Operand(esp, 2 * kPointerSize));
578580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(edi, FieldOperand(edx, String::kLengthOffset));
578680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiUntag(edi);
57873ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ pop(edx);
578880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // eax: result string
578980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // ecx: next character of result
579080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // edx: first char of second argument
579180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // edi: length of second argument
579280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  StringHelper::GenerateCopyCharacters(masm, ecx, edx, edi, ebx, false);
579344f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ IncrementCounter(counters->string_add_native(), 1);
579480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ ret(2 * kPointerSize);
579580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
57963ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Recover stack pointer before jumping to runtime.
57973ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ bind(&call_runtime_drop_two);
57983ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ Drop(2);
579980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Just jump to runtime to add the two strings.
58003ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ bind(&call_runtime);
580180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ TailCallRuntime(Runtime::kStringAdd, 2, 1);
58029ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick
58039ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick  if (call_builtin.is_linked()) {
58049ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick    __ bind(&call_builtin);
58059ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick    __ InvokeBuiltin(builtin_id, JUMP_FUNCTION);
58069ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick  }
58079ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick}
58089ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick
58099ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick
58109ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrickvoid StringAddStub::GenerateConvertArgument(MacroAssembler* masm,
58119ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick                                            int stack_offset,
58129ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick                                            Register arg,
58139ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick                                            Register scratch1,
58149ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick                                            Register scratch2,
58159ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick                                            Register scratch3,
58169ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick                                            Label* slow) {
58179ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick  // First check if the argument is already a string.
58189ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick  Label not_string, done;
58193fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ JumpIfSmi(arg, &not_string);
58209ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick  __ CmpObjectType(arg, FIRST_NONSTRING_TYPE, scratch1);
58219ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick  __ j(below, &done);
58229ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick
58239ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick  // Check the number to string cache.
58249ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick  Label not_cached;
58259ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick  __ bind(&not_string);
58269ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick  // Puts the cached result into scratch1.
58279ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick  NumberToStringStub::GenerateLookupNumberStringCache(masm,
58289ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick                                                      arg,
58299ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick                                                      scratch1,
58309ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick                                                      scratch2,
58319ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick                                                      scratch3,
58329ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick                                                      false,
58339ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick                                                      &not_cached);
58349ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick  __ mov(arg, scratch1);
58359ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick  __ mov(Operand(esp, stack_offset), arg);
58369ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick  __ jmp(&done);
58379ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick
58389ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick  // Check if the argument is a safe string wrapper.
58399ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick  __ bind(&not_cached);
58403fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ JumpIfSmi(arg, slow);
58419ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick  __ CmpObjectType(arg, JS_VALUE_TYPE, scratch1);  // map -> scratch1.
58429ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick  __ j(not_equal, slow);
58439ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick  __ test_b(FieldOperand(scratch1, Map::kBitField2Offset),
58449ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick            1 << Map::kStringWrapperSafeForDefaultValueOf);
58459ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick  __ j(zero, slow);
58469ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick  __ mov(arg, FieldOperand(arg, JSValue::kValueOffset));
58479ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick  __ mov(Operand(esp, stack_offset), arg);
58489ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick
58499ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick  __ bind(&done);
585080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
585180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
585280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
585380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StringHelper::GenerateCopyCharacters(MacroAssembler* masm,
585480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                          Register dest,
585580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                          Register src,
585680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                          Register count,
585780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                          Register scratch,
585880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                          bool ascii) {
5859257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label loop;
586080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&loop);
586180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // This loop just copies one character at a time, as it is only used for very
586280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // short strings.
586380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  if (ascii) {
586480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ mov_b(scratch, Operand(src, 0));
586580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ mov_b(Operand(dest, 0), scratch);
58663ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ add(src, Immediate(1));
58673ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ add(dest, Immediate(1));
586880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  } else {
586980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ mov_w(scratch, Operand(src, 0));
587080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ mov_w(Operand(dest, 0), scratch);
58713ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ add(src, Immediate(2));
58723ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ add(dest, Immediate(2));
587380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
58743ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ sub(count, Immediate(1));
587580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(not_zero, &loop);
587680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
587780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
587880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
587980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StringHelper::GenerateCopyCharactersREP(MacroAssembler* masm,
588080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                             Register dest,
588180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                             Register src,
588280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                             Register count,
588380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                             Register scratch,
588480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                             bool ascii) {
588580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Copy characters using rep movs of doublewords.
588680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // The destination is aligned on a 4 byte boundary because we are
588780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // copying to the beginning of a newly allocated string.
588880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  ASSERT(dest.is(edi));  // rep movs destination
588980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  ASSERT(src.is(esi));  // rep movs source
589080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  ASSERT(count.is(ecx));  // rep movs count
589180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  ASSERT(!scratch.is(dest));
589280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  ASSERT(!scratch.is(src));
589380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  ASSERT(!scratch.is(count));
589480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
589580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Nothing to do for zero characters.
589680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label done;
58973ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ test(count, count);
589880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(zero, &done);
589980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
590080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Make count the number of bytes to copy.
590180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  if (!ascii) {
590280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ shl(count, 1);
590380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
590480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
590580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Don't enter the rep movs if there are less than 4 bytes to copy.
5906257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label last_bytes;
590780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ test(count, Immediate(~3));
5908257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(zero, &last_bytes, Label::kNear);
590980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
591080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Copy from edi to esi using rep movs instruction.
591180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(scratch, count);
591280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ sar(count, 2);  // Number of doublewords to copy.
591380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cld();
591480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ rep_movs();
591580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
591680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Find number of bytes left.
591780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(count, scratch);
591880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ and_(count, 3);
591980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
592080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check if there are more bytes to copy.
592180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&last_bytes);
59223ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ test(count, count);
592380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(zero, &done);
592480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
592580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Copy remaining characters.
5926257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label loop;
592780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&loop);
592880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov_b(scratch, Operand(src, 0));
592980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov_b(Operand(dest, 0), scratch);
59303ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ add(src, Immediate(1));
59313ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ add(dest, Immediate(1));
59323ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ sub(count, Immediate(1));
593380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(not_zero, &loop);
593480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
593580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&done);
593680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
593780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
593880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
593980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StringHelper::GenerateTwoCharacterSymbolTableProbe(MacroAssembler* masm,
594080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                                        Register c1,
594180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                                        Register c2,
594280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                                        Register scratch1,
594380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                                        Register scratch2,
594480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                                        Register scratch3,
59459ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick                                                        Label* not_probed,
594680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                                        Label* not_found) {
594780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Register scratch3 is the general scratch register in this function.
594880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Register scratch = scratch3;
594980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
595080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Make sure that both characters are not digits as such strings has a
595180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // different hash algorithm. Don't try to look for these in the symbol table.
5952257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label not_array_index;
595380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(scratch, c1);
59543ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ sub(scratch, Immediate(static_cast<int>('0')));
59553ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ cmp(scratch, Immediate(static_cast<int>('9' - '0')));
5956257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(above, &not_array_index, Label::kNear);
595780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(scratch, c2);
59583ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ sub(scratch, Immediate(static_cast<int>('0')));
59593ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ cmp(scratch, Immediate(static_cast<int>('9' - '0')));
59609ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick  __ j(below_equal, not_probed);
596180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
596280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&not_array_index);
596380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Calculate the two character string hash.
596480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Register hash = scratch1;
596580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  GenerateHashInit(masm, hash, c1, scratch);
596680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  GenerateHashAddCharacter(masm, hash, c2, scratch);
596780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  GenerateHashGetHash(masm, hash, scratch);
596880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
596980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Collect the two characters in a register.
597080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Register chars = c1;
597180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ shl(c2, kBitsPerByte);
59723ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ or_(chars, c2);
597380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
597480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // chars: two character string, char 1 in byte 0 and char 2 in byte 1.
597580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // hash:  hash of two character string.
597680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
597780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Load the symbol table.
597880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Register symbol_table = c2;
59793ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  ExternalReference roots_array_start =
59803ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      ExternalReference::roots_array_start(masm->isolate());
598180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(scratch, Immediate(Heap::kSymbolTableRootIndex));
598280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(symbol_table,
59833ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch         Operand::StaticArray(scratch, times_pointer_size, roots_array_start));
598480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
598580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Calculate capacity mask from the symbol table capacity.
598680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Register mask = scratch2;
598780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(mask, FieldOperand(symbol_table, SymbolTable::kCapacityOffset));
598880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiUntag(mask);
59893ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ sub(mask, Immediate(1));
599080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
599180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Registers
599280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // chars:        two character string, char 1 in byte 0 and char 2 in byte 1.
599380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // hash:         hash of two character string
599480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // symbol_table: symbol table
599580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // mask:         capacity mask
599680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // scratch:      -
599780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
599880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Perform a number of probes in the symbol table.
599980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  static const int kProbes = 4;
600080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label found_in_symbol_table;
600180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label next_probe[kProbes], next_probe_pop_mask[kProbes];
6002692be65d6b06edd9ff4cfc4c308555b7c99c1191Ben Murdoch  Register candidate = scratch;  // Scratch register contains candidate.
600380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  for (int i = 0; i < kProbes; i++) {
600480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // Calculate entry in symbol table.
600580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ mov(scratch, hash);
600680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    if (i > 0) {
60073ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      __ add(scratch, Immediate(SymbolTable::GetProbeOffset(i)));
600880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    }
60093ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ and_(scratch, mask);
601080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
601180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // Load the entry from the symbol table.
601280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    STATIC_ASSERT(SymbolTable::kEntrySize == 1);
601380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ mov(candidate,
601480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen           FieldOperand(symbol_table,
601580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                        scratch,
601680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                        times_pointer_size,
601780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                        SymbolTable::kElementsStartOffset));
601880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
601980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // If entry is undefined no string with this hash can be found.
602044f0eee88ff00398ff7f715fab053374d808c90dSteve Block    Factory* factory = masm->isolate()->factory();
602144f0eee88ff00398ff7f715fab053374d808c90dSteve Block    __ cmp(candidate, factory->undefined_value());
602280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ j(equal, not_found);
60233ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ cmp(candidate, factory->the_hole_value());
602444f0eee88ff00398ff7f715fab053374d808c90dSteve Block    __ j(equal, &next_probe[i]);
602580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
602680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // If length is not 2 the string is not a candidate.
602780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ cmp(FieldOperand(candidate, String::kLengthOffset),
602880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen           Immediate(Smi::FromInt(2)));
602980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ j(not_equal, &next_probe[i]);
603080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
603180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // As we are out of registers save the mask on the stack and use that
603280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // register as a temporary.
603380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ push(mask);
603480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    Register temp = mask;
603580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
60363ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    // Check that the candidate is a non-external ASCII string.
603780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ mov(temp, FieldOperand(candidate, HeapObject::kMapOffset));
603880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ movzx_b(temp, FieldOperand(temp, Map::kInstanceTypeOffset));
603980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ JumpIfInstanceTypeIsNotSequentialAscii(
604080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen        temp, temp, &next_probe_pop_mask[i]);
604180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
604280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // Check if the two characters match.
604380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ mov(temp, FieldOperand(candidate, SeqAsciiString::kHeaderSize));
604480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ and_(temp, 0x0000ffff);
60453ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ cmp(chars, temp);
604680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ j(equal, &found_in_symbol_table);
604780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ bind(&next_probe_pop_mask[i]);
604880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ pop(mask);
604980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ bind(&next_probe[i]);
605080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
605180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
605280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // No matching 2 character string found by probing.
605380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ jmp(not_found);
605480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
605580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Scratch register contains result when we fall through to here.
6056692be65d6b06edd9ff4cfc4c308555b7c99c1191Ben Murdoch  Register result = candidate;
605780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&found_in_symbol_table);
605880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ pop(mask);  // Pop saved mask from the stack.
605980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  if (!result.is(eax)) {
606080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ mov(eax, result);
606180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
606280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
606380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
606480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
606580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StringHelper::GenerateHashInit(MacroAssembler* masm,
606680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                    Register hash,
606780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                    Register character,
606880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                    Register scratch) {
6069c7cc028aaeedbbfa11c11d0b7b243b3d9e837ed9Ben Murdoch  // hash = (seed + character) + ((seed + character) << 10);
6070c7cc028aaeedbbfa11c11d0b7b243b3d9e837ed9Ben Murdoch  if (Serializer::enabled()) {
60713ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    ExternalReference roots_array_start =
60723ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch        ExternalReference::roots_array_start(masm->isolate());
6073c7cc028aaeedbbfa11c11d0b7b243b3d9e837ed9Ben Murdoch    __ mov(scratch, Immediate(Heap::kHashSeedRootIndex));
6074c7cc028aaeedbbfa11c11d0b7b243b3d9e837ed9Ben Murdoch    __ mov(scratch, Operand::StaticArray(scratch,
6075c7cc028aaeedbbfa11c11d0b7b243b3d9e837ed9Ben Murdoch                                         times_pointer_size,
60763ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                                         roots_array_start));
6077c7cc028aaeedbbfa11c11d0b7b243b3d9e837ed9Ben Murdoch    __ SmiUntag(scratch);
60783ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ add(scratch, character);
6079c7cc028aaeedbbfa11c11d0b7b243b3d9e837ed9Ben Murdoch    __ mov(hash, scratch);
6080c7cc028aaeedbbfa11c11d0b7b243b3d9e837ed9Ben Murdoch    __ shl(scratch, 10);
60813ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ add(hash, scratch);
6082c7cc028aaeedbbfa11c11d0b7b243b3d9e837ed9Ben Murdoch  } else {
6083c7cc028aaeedbbfa11c11d0b7b243b3d9e837ed9Ben Murdoch    int32_t seed = masm->isolate()->heap()->HashSeed();
6084c7cc028aaeedbbfa11c11d0b7b243b3d9e837ed9Ben Murdoch    __ lea(scratch, Operand(character, seed));
6085c7cc028aaeedbbfa11c11d0b7b243b3d9e837ed9Ben Murdoch    __ shl(scratch, 10);
6086c7cc028aaeedbbfa11c11d0b7b243b3d9e837ed9Ben Murdoch    __ lea(hash, Operand(scratch, character, times_1, seed));
6087c7cc028aaeedbbfa11c11d0b7b243b3d9e837ed9Ben Murdoch  }
608880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // hash ^= hash >> 6;
608980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(scratch, hash);
6090692be65d6b06edd9ff4cfc4c308555b7c99c1191Ben Murdoch  __ shr(scratch, 6);
60913ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ xor_(hash, scratch);
609280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
609380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
609480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
609580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StringHelper::GenerateHashAddCharacter(MacroAssembler* masm,
609680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                            Register hash,
609780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                            Register character,
609880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                            Register scratch) {
609980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // hash += character;
61003ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ add(hash, character);
610180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // hash += hash << 10;
610280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(scratch, hash);
610380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ shl(scratch, 10);
61043ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ add(hash, scratch);
610580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // hash ^= hash >> 6;
610680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(scratch, hash);
6107692be65d6b06edd9ff4cfc4c308555b7c99c1191Ben Murdoch  __ shr(scratch, 6);
61083ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ xor_(hash, scratch);
610980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
611080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
611180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
611280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StringHelper::GenerateHashGetHash(MacroAssembler* masm,
611380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                       Register hash,
611480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                       Register scratch) {
611580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // hash += hash << 3;
611680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(scratch, hash);
611780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ shl(scratch, 3);
61183ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ add(hash, scratch);
611980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // hash ^= hash >> 11;
612080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(scratch, hash);
6121692be65d6b06edd9ff4cfc4c308555b7c99c1191Ben Murdoch  __ shr(scratch, 11);
61223ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ xor_(hash, scratch);
612380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // hash += hash << 15;
612480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(scratch, hash);
612580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ shl(scratch, 15);
61263ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ add(hash, scratch);
612780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
6128c7cc028aaeedbbfa11c11d0b7b243b3d9e837ed9Ben Murdoch  __ and_(hash, String::kHashBitMask);
6129692be65d6b06edd9ff4cfc4c308555b7c99c1191Ben Murdoch
613080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // if (hash == 0) hash = 27;
6131257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label hash_not_zero;
6132257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(not_zero, &hash_not_zero, Label::kNear);
6133c7cc028aaeedbbfa11c11d0b7b243b3d9e837ed9Ben Murdoch  __ mov(hash, Immediate(StringHasher::kZeroHash));
613480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&hash_not_zero);
613580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
613680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
613780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
613880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid SubStringStub::Generate(MacroAssembler* masm) {
613980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label runtime;
614080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
614180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Stack frame on entry.
614280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  //  esp[0]: return address
614380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  //  esp[4]: to
614480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  //  esp[8]: from
614580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  //  esp[12]: string
614680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
614780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Make sure first argument is a string.
614880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(eax, Operand(esp, 3 * kPointerSize));
614980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  STATIC_ASSERT(kSmiTag == 0);
61503fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ JumpIfSmi(eax, &runtime);
615180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Condition is_string = masm->IsObjectStringType(eax, ebx, ebx);
615280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(NegateCondition(is_string), &runtime);
615380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
615480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // eax: string
615580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // ebx: instance type
615680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
615780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Calculate length of sub string using the smi values.
615880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(ecx, Operand(esp, 1 * kPointerSize));  // To index.
61593fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ JumpIfNotSmi(ecx, &runtime);
616080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(edx, Operand(esp, 2 * kPointerSize));  // From index.
61613fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ JumpIfNotSmi(edx, &runtime);
61623ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ sub(ecx, edx);
616380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cmp(ecx, FieldOperand(eax, String::kLengthOffset));
61643ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  Label not_original_string;
61653ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ j(not_equal, &not_original_string, Label::kNear);
61663ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  Counters* counters = masm->isolate()->counters();
61673ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ IncrementCounter(counters->sub_string_native(), 1);
61683ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ ret(3 * kPointerSize);
61693ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ bind(&not_original_string);
61703ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
6171c7cc028aaeedbbfa11c11d0b7b243b3d9e837ed9Ben Murdoch  // eax: string
6172c7cc028aaeedbbfa11c11d0b7b243b3d9e837ed9Ben Murdoch  // ebx: instance type
61733ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // ecx: sub string length (smi)
6174c7cc028aaeedbbfa11c11d0b7b243b3d9e837ed9Ben Murdoch  // edx: from index (smi)
61753ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Deal with different string types: update the index if necessary
61763ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // and put the underlying string into edi.
61773ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  Label underlying_unpacked, sliced_string, seq_or_external_string;
61783ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // If the string is not indirect, it can only be sequential or external.
61793ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  STATIC_ASSERT(kIsIndirectStringMask == (kSlicedStringTag & kConsStringTag));
61803ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  STATIC_ASSERT(kIsIndirectStringMask != 0);
61813ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ test(ebx, Immediate(kIsIndirectStringMask));
61823ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ j(zero, &seq_or_external_string, Label::kNear);
6183c7cc028aaeedbbfa11c11d0b7b243b3d9e837ed9Ben Murdoch
61843ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  Factory* factory = masm->isolate()->factory();
61853ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ test(ebx, Immediate(kSlicedNotConsMask));
61863ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ j(not_zero, &sliced_string, Label::kNear);
61873ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Cons string.  Check whether it is flat, then fetch first part.
61883ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Flat cons strings have an empty second part.
61893ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ cmp(FieldOperand(eax, ConsString::kSecondOffset),
61903ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch         factory->empty_string());
61913ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ j(not_equal, &runtime);
61923ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ mov(edi, FieldOperand(eax, ConsString::kFirstOffset));
61933ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Update instance type.
61943ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ mov(ebx, FieldOperand(edi, HeapObject::kMapOffset));
61953ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ movzx_b(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset));
61963ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ jmp(&underlying_unpacked, Label::kNear);
6197c7cc028aaeedbbfa11c11d0b7b243b3d9e837ed9Ben Murdoch
61983ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ bind(&sliced_string);
61993ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Sliced string.  Fetch parent and adjust start index by offset.
62003ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ add(edx, FieldOperand(eax, SlicedString::kOffsetOffset));
62013ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ mov(edi, FieldOperand(eax, SlicedString::kParentOffset));
62023ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Update instance type.
62033ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ mov(ebx, FieldOperand(edi, HeapObject::kMapOffset));
620485b71799222b55eb5dd74ea26efe0c64ab655c8cBen Murdoch  __ movzx_b(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset));
62053ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ jmp(&underlying_unpacked, Label::kNear);
62063ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
62073ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ bind(&seq_or_external_string);
62083ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Sequential or external string.  Just move string to the expected register.
62093ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ mov(edi, eax);
62103ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
62113ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ bind(&underlying_unpacked);
621280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
621369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  if (FLAG_string_slices) {
621469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    Label copy_routine;
62153ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    // edi: underlying subject string
62163ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    // ebx: instance type of underlying subject string
62173ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    // edx: adjusted start index (smi)
62183ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    // ecx: length (smi)
62193ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ cmp(ecx, Immediate(Smi::FromInt(SlicedString::kMinLength)));
622069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    // Short slice.  Copy instead of slicing.
622169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    __ j(less, &copy_routine);
622269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    // Allocate new sliced string.  At this point we do not reload the instance
622369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    // type including the string encoding because we simply rely on the info
622469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    // provided by the original string.  It does not matter if the original
622569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    // string's encoding is wrong because we always have to recheck encoding of
622669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    // the newly created string's parent anyways due to externalized strings.
622769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    Label two_byte_slice, set_slice_header;
6228589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch    STATIC_ASSERT((kStringEncodingMask & kAsciiStringTag) != 0);
6229589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch    STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0);
6230589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch    __ test(ebx, Immediate(kStringEncodingMask));
623169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    __ j(zero, &two_byte_slice, Label::kNear);
623269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    __ AllocateAsciiSlicedString(eax, ebx, no_reg, &runtime);
623369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    __ jmp(&set_slice_header, Label::kNear);
623469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    __ bind(&two_byte_slice);
6235589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch    __ AllocateTwoByteSlicedString(eax, ebx, no_reg, &runtime);
623669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    __ bind(&set_slice_header);
623769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    __ mov(FieldOperand(eax, SlicedString::kLengthOffset), ecx);
623869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    __ mov(FieldOperand(eax, SlicedString::kHashFieldOffset),
623969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch           Immediate(String::kEmptyHashField));
62403ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ mov(FieldOperand(eax, SlicedString::kParentOffset), edi);
62413ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ mov(FieldOperand(eax, SlicedString::kOffsetOffset), edx);
62423ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ IncrementCounter(counters->sub_string_native(), 1);
62433ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ ret(3 * kPointerSize);
624469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch
624569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    __ bind(&copy_routine);
624669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  }
624769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch
62483ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // edi: underlying subject string
62493ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // ebx: instance type of underlying subject string
62503ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // edx: adjusted start index (smi)
62513ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // ecx: length (smi)
62523ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // The subject string can only be external or sequential string of either
62533ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // encoding at this point.
62543ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  Label two_byte_sequential, runtime_drop_two, sequential_string;
62553ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  STATIC_ASSERT(kExternalStringTag != 0);
62563ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  STATIC_ASSERT(kSeqStringTag == 0);
62573ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ test_b(ebx, kExternalStringTag);
62583ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ j(zero, &sequential_string);
62593ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
62603ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Handle external string.
62613ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Rule out short external strings.
62623ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  STATIC_CHECK(kShortExternalStringTag != 0);
62633ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ test_b(ebx, kShortExternalStringMask);
62643ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ j(not_zero, &runtime);
62653ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ mov(edi, FieldOperand(edi, ExternalString::kResourceDataOffset));
62663ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Move the pointer so that offset-wise, it looks like a sequential string.
62673ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqAsciiString::kHeaderSize);
62683ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ sub(edi, Immediate(SeqTwoByteString::kHeaderSize - kHeapObjectTag));
626980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
62703ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ bind(&sequential_string);
62713ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Stash away (adjusted) index and (underlying) string.
62723ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ push(edx);
62733ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ push(edi);
62743ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ SmiUntag(ecx);
62753ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  STATIC_ASSERT((kAsciiStringTag & kStringEncodingMask) != 0);
62763ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ test_b(ebx, kStringEncodingMask);
62773ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ j(zero, &two_byte_sequential);
62783ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
62793ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Sequential ASCII string.  Allocate the result.
62803ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ AllocateAsciiString(eax, ecx, ebx, edx, edi, &runtime_drop_two);
628180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
628280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // eax: result string
628380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // ecx: result string length
628480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(edx, esi);  // esi used by following code.
628580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Locate first character of result.
628680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(edi, eax);
62873ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ add(edi, Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag));
628880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Load string argument and locate character of sub string start.
62893ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ pop(esi);
62903ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ pop(ebx);
629180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiUntag(ebx);
62923ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ lea(esi, FieldOperand(esi, ebx, times_1, SeqAsciiString::kHeaderSize));
629380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
629480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // eax: result string
629580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // ecx: result length
629680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // edx: original value of esi
629780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // edi: first character of result
629880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // esi: character of sub string start
629980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  StringHelper::GenerateCopyCharactersREP(masm, edi, esi, ecx, ebx, true);
630080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(esi, edx);  // Restore esi.
630144f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ IncrementCounter(counters->sub_string_native(), 1);
630280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ ret(3 * kPointerSize);
630380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
63043ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ bind(&two_byte_sequential);
63053ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Sequential two-byte string.  Allocate the result.
63063ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ AllocateTwoByteString(eax, ecx, ebx, edx, edi, &runtime_drop_two);
630780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
630880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // eax: result string
630980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // ecx: result string length
631080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(edx, esi);  // esi used by following code.
631180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Locate first character of result.
631280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(edi, eax);
63133ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ add(edi,
631480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen         Immediate(SeqTwoByteString::kHeaderSize - kHeapObjectTag));
631580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Load string argument and locate character of sub string start.
63163ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ pop(esi);
63173ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ pop(ebx);
631880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // As from is a smi it is 2 times the value which matches the size of a two
631980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // byte character.
632080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  STATIC_ASSERT(kSmiTag == 0);
632180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  STATIC_ASSERT(kSmiTagSize + kSmiShiftSize == 1);
63223ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ lea(esi, FieldOperand(esi, ebx, times_1, SeqTwoByteString::kHeaderSize));
632380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
632480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // eax: result string
632580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // ecx: result length
632680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // edx: original value of esi
632780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // edi: first character of result
632880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // esi: character of sub string start
632980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  StringHelper::GenerateCopyCharactersREP(masm, edi, esi, ecx, ebx, false);
633080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(esi, edx);  // Restore esi.
633144f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ IncrementCounter(counters->sub_string_native(), 1);
633280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ ret(3 * kPointerSize);
633380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
63343ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Drop pushed values on the stack before tail call.
63353ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ bind(&runtime_drop_two);
63363ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ Drop(2);
63373ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
633880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Just jump to runtime to create the sub string.
633980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&runtime);
634080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ TailCallRuntime(Runtime::kSubString, 3, 1);
634180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
634280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
634380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
6344257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid StringCompareStub::GenerateFlatAsciiStringEquals(MacroAssembler* masm,
6345257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                                      Register left,
6346257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                                      Register right,
6347257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                                      Register scratch1,
6348257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                                      Register scratch2) {
6349257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Register length = scratch1;
6350257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6351257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Compare lengths.
6352257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label strings_not_equal, check_zero_length;
6353257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ mov(length, FieldOperand(left, String::kLengthOffset));
6354257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ cmp(length, FieldOperand(right, String::kLengthOffset));
6355257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(equal, &check_zero_length, Label::kNear);
6356257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&strings_not_equal);
6357257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Set(eax, Immediate(Smi::FromInt(NOT_EQUAL)));
6358257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ ret(0);
6359257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6360257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Check if the length is zero.
6361257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label compare_chars;
6362257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&check_zero_length);
6363257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  STATIC_ASSERT(kSmiTag == 0);
63643ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ test(length, length);
6365257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(not_zero, &compare_chars, Label::kNear);
6366257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Set(eax, Immediate(Smi::FromInt(EQUAL)));
6367257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ ret(0);
6368257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6369257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Compare characters.
6370257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&compare_chars);
6371257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  GenerateAsciiCharsCompareLoop(masm, left, right, length, scratch2,
6372257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                &strings_not_equal, Label::kNear);
6373257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6374257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Characters are equal.
6375257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Set(eax, Immediate(Smi::FromInt(EQUAL)));
6376257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ ret(0);
6377257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch}
6378257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6379257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
638080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StringCompareStub::GenerateCompareFlatAsciiStrings(MacroAssembler* masm,
638180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                                        Register left,
638280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                                        Register right,
638380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                                        Register scratch1,
638480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                                        Register scratch2,
638580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                                        Register scratch3) {
638644f0eee88ff00398ff7f715fab053374d808c90dSteve Block  Counters* counters = masm->isolate()->counters();
638744f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ IncrementCounter(counters->string_compare_native(), 1);
638880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
638980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Find minimum length.
6390257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label left_shorter;
639180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(scratch1, FieldOperand(left, String::kLengthOffset));
639280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(scratch3, scratch1);
639380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ sub(scratch3, FieldOperand(right, String::kLengthOffset));
639480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
639580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Register length_delta = scratch3;
639680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
6397257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(less_equal, &left_shorter, Label::kNear);
639880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Right string is shorter. Change scratch1 to be length of right string.
63993ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ sub(scratch1, length_delta);
640080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&left_shorter);
640180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
640280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Register min_length = scratch1;
640380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
640480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // If either length is zero, just compare lengths.
6405257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label compare_lengths;
64063ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ test(min_length, min_length);
6407257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(zero, &compare_lengths, Label::kNear);
640880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
6409257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Compare characters.
6410257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label result_not_equal;
6411257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  GenerateAsciiCharsCompareLoop(masm, left, right, min_length, scratch2,
6412257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                &result_not_equal, Label::kNear);
641380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
641480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Compare lengths -  strings up to min-length are equal.
641580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&compare_lengths);
64163ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ test(length_delta, length_delta);
6417257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(not_zero, &result_not_equal, Label::kNear);
641880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
641980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Result is EQUAL.
642080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  STATIC_ASSERT(EQUAL == 0);
642180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  STATIC_ASSERT(kSmiTag == 0);
642280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ Set(eax, Immediate(Smi::FromInt(EQUAL)));
642380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ ret(0);
642480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
6425257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label result_greater;
642680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&result_not_equal);
6427257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(greater, &result_greater, Label::kNear);
642880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
642980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Result is LESS.
643080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ Set(eax, Immediate(Smi::FromInt(LESS)));
643180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ ret(0);
643280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
643380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Result is GREATER.
643480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&result_greater);
643580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ Set(eax, Immediate(Smi::FromInt(GREATER)));
643680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ ret(0);
643780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
643880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
643980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
6440257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid StringCompareStub::GenerateAsciiCharsCompareLoop(
6441257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    MacroAssembler* masm,
6442257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Register left,
6443257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Register right,
6444257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Register length,
6445257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Register scratch,
6446257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Label* chars_not_equal,
6447257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Label::Distance chars_not_equal_near) {
6448257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Change index to run from -length to -1 by adding length to string
6449257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // start. This means that loop ends when index reaches zero, which
6450257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // doesn't need an additional compare.
6451257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ SmiUntag(length);
6452257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ lea(left,
6453257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch         FieldOperand(left, length, times_1, SeqAsciiString::kHeaderSize));
6454257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ lea(right,
6455257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch         FieldOperand(right, length, times_1, SeqAsciiString::kHeaderSize));
6456257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ neg(length);
6457257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Register index = length;  // index = -length;
6458257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6459257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Compare loop.
6460257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label loop;
6461257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&loop);
6462257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ mov_b(scratch, Operand(left, index, times_1, 0));
6463257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ cmpb(scratch, Operand(right, index, times_1, 0));
6464257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(not_equal, chars_not_equal, chars_not_equal_near);
64653ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ inc(index);
6466257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(not_zero, &loop);
6467257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch}
6468257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6469257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
647080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StringCompareStub::Generate(MacroAssembler* masm) {
647180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label runtime;
647280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
647380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Stack frame on entry.
647480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  //  esp[0]: return address
647580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  //  esp[4]: right string
647680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  //  esp[8]: left string
647780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
647880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(edx, Operand(esp, 2 * kPointerSize));  // left
647980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(eax, Operand(esp, 1 * kPointerSize));  // right
648080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
6481257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label not_same;
64823ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ cmp(edx, eax);
6483257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(not_equal, &not_same, Label::kNear);
648480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  STATIC_ASSERT(EQUAL == 0);
648580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  STATIC_ASSERT(kSmiTag == 0);
648680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ Set(eax, Immediate(Smi::FromInt(EQUAL)));
648744f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ IncrementCounter(masm->isolate()->counters()->string_compare_native(), 1);
648880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ ret(2 * kPointerSize);
648980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
649080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&not_same);
649180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
64923ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Check that both objects are sequential ASCII strings.
649380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ JumpIfNotBothSequentialAsciiStrings(edx, eax, ecx, ebx, &runtime);
649480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
64953ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Compare flat ASCII strings.
649680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Drop arguments from the stack.
649780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ pop(ecx);
64983ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ add(esp, Immediate(2 * kPointerSize));
649980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ push(ecx);
650080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  GenerateCompareFlatAsciiStrings(masm, edx, eax, ecx, ebx, edi);
650180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
650280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Call the runtime; it returns -1 (less), 0 (equal), or 1 (greater)
650380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // tagged as a small integer.
650480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&runtime);
650580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ TailCallRuntime(Runtime::kStringCompare, 2, 1);
650680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
650780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
6508b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
6509b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdochvoid ICCompareStub::GenerateSmis(MacroAssembler* masm) {
6510b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  ASSERT(state_ == CompareIC::SMIS);
6511257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label miss;
65123ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ mov(ecx, edx);
65133ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ or_(ecx, eax);
65143fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ JumpIfNotSmi(ecx, &miss, Label::kNear);
6515b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
6516b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  if (GetCondition() == equal) {
6517b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    // For equality we do not care about the sign of the result.
65183ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ sub(eax, edx);
6519b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  } else {
6520257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Label done;
65213ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ sub(edx, eax);
6522257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ j(no_overflow, &done, Label::kNear);
6523b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    // Correct sign of result in case of overflow.
6524b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ not_(edx);
6525b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ bind(&done);
6526b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ mov(eax, edx);
6527b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  }
6528b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ ret(0);
6529b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
6530b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ bind(&miss);
6531b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  GenerateMiss(masm);
6532b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch}
6533b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
6534b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
6535b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdochvoid ICCompareStub::GenerateHeapNumbers(MacroAssembler* masm) {
6536b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  ASSERT(state_ == CompareIC::HEAP_NUMBERS);
6537b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
6538257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label generic_stub;
65393ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  Label unordered, maybe_undefined1, maybe_undefined2;
6540257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label miss;
65413ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ mov(ecx, edx);
65423ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ and_(ecx, eax);
65433fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ JumpIfSmi(ecx, &generic_stub, Label::kNear);
6544b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
6545b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ CmpObjectType(eax, HEAP_NUMBER_TYPE, ecx);
65463ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ j(not_equal, &maybe_undefined1, Label::kNear);
6547b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ CmpObjectType(edx, HEAP_NUMBER_TYPE, ecx);
65483ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ j(not_equal, &maybe_undefined2, Label::kNear);
6549b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
6550b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Inlining the double comparison and falling back to the general compare
6551b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // stub if NaN is involved or SS2 or CMOV is unsupported.
65528b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  if (CpuFeatures::IsSupported(SSE2) && CpuFeatures::IsSupported(CMOV)) {
6553b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    CpuFeatures::Scope scope1(SSE2);
6554b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    CpuFeatures::Scope scope2(CMOV);
6555b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
6556b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    // Load left and right operand
6557b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ movdbl(xmm0, FieldOperand(edx, HeapNumber::kValueOffset));
6558b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ movdbl(xmm1, FieldOperand(eax, HeapNumber::kValueOffset));
6559b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
6560b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    // Compare operands
6561b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ ucomisd(xmm0, xmm1);
6562b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
6563b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    // Don't base result on EFLAGS when a NaN is involved.
6564257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ j(parity_even, &unordered, Label::kNear);
6565b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
6566b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    // Return a result of -1, 0, or 1, based on EFLAGS.
6567b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    // Performing mov, because xor would destroy the flag register.
6568b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ mov(eax, 0);  // equal
6569b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ mov(ecx, Immediate(Smi::FromInt(1)));
65703ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ cmov(above, eax, ecx);
6571b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ mov(ecx, Immediate(Smi::FromInt(-1)));
65723ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ cmov(below, eax, ecx);
6573b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ ret(0);
6574b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  }
6575b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
65763ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ bind(&unordered);
6577b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  CompareStub stub(GetCondition(), strict(), NO_COMPARE_FLAGS);
6578b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ bind(&generic_stub);
6579b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ jmp(stub.GetCode(), RelocInfo::CODE_TARGET);
6580b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
65813ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ bind(&maybe_undefined1);
65823ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  if (Token::IsOrderedRelationalCompareOp(op_)) {
65833ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ cmp(eax, Immediate(masm->isolate()->factory()->undefined_value()));
65843ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ j(not_equal, &miss);
65853ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ CmpObjectType(edx, HEAP_NUMBER_TYPE, ecx);
65863ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ j(not_equal, &maybe_undefined2, Label::kNear);
65873ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ jmp(&unordered);
65883ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  }
65893ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
65903ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ bind(&maybe_undefined2);
65913ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  if (Token::IsOrderedRelationalCompareOp(op_)) {
65923ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ cmp(edx, Immediate(masm->isolate()->factory()->undefined_value()));
65933ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ j(equal, &unordered);
65943ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  }
65953ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
6596b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ bind(&miss);
6597b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  GenerateMiss(masm);
6598b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch}
6599b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
6600b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
6601257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid ICCompareStub::GenerateSymbols(MacroAssembler* masm) {
6602257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  ASSERT(state_ == CompareIC::SYMBOLS);
6603257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  ASSERT(GetCondition() == equal);
6604257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6605257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Registers containing left and right operands respectively.
6606257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Register left = edx;
6607257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Register right = eax;
6608257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Register tmp1 = ecx;
6609257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Register tmp2 = ebx;
6610257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6611257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Check that both operands are heap objects.
6612257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label miss;
66133ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ mov(tmp1, left);
6614257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  STATIC_ASSERT(kSmiTag == 0);
66153ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ and_(tmp1, right);
66163fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ JumpIfSmi(tmp1, &miss, Label::kNear);
6617257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6618257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Check that both operands are symbols.
6619257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ mov(tmp1, FieldOperand(left, HeapObject::kMapOffset));
6620257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ mov(tmp2, FieldOperand(right, HeapObject::kMapOffset));
6621257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ movzx_b(tmp1, FieldOperand(tmp1, Map::kInstanceTypeOffset));
6622257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ movzx_b(tmp2, FieldOperand(tmp2, Map::kInstanceTypeOffset));
6623257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  STATIC_ASSERT(kSymbolTag != 0);
66243ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ and_(tmp1, tmp2);
6625257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ test(tmp1, Immediate(kIsSymbolMask));
6626257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(zero, &miss, Label::kNear);
6627257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6628257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Symbols are compared by identity.
6629257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label done;
66303ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ cmp(left, right);
6631257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Make sure eax is non-zero. At this point input operands are
6632257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // guaranteed to be non-zero.
6633257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  ASSERT(right.is(eax));
6634257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(not_equal, &done, Label::kNear);
6635257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  STATIC_ASSERT(EQUAL == 0);
6636257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  STATIC_ASSERT(kSmiTag == 0);
6637257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Set(eax, Immediate(Smi::FromInt(EQUAL)));
6638257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&done);
6639257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ ret(0);
6640257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6641257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&miss);
6642257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  GenerateMiss(masm);
6643257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch}
6644257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6645257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6646257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid ICCompareStub::GenerateStrings(MacroAssembler* masm) {
6647257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  ASSERT(state_ == CompareIC::STRINGS);
6648257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label miss;
6649257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
66503ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  bool equality = Token::IsEqualityOp(op_);
66513ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
6652257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Registers containing left and right operands respectively.
6653257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Register left = edx;
6654257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Register right = eax;
6655257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Register tmp1 = ecx;
6656257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Register tmp2 = ebx;
6657257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Register tmp3 = edi;
6658257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6659257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Check that both operands are heap objects.
66603ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ mov(tmp1, left);
6661257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  STATIC_ASSERT(kSmiTag == 0);
66623ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ and_(tmp1, right);
66633fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ JumpIfSmi(tmp1, &miss);
6664257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6665257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Check that both operands are strings. This leaves the instance
6666257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // types loaded in tmp1 and tmp2.
6667257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ mov(tmp1, FieldOperand(left, HeapObject::kMapOffset));
6668257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ mov(tmp2, FieldOperand(right, HeapObject::kMapOffset));
6669257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ movzx_b(tmp1, FieldOperand(tmp1, Map::kInstanceTypeOffset));
6670257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ movzx_b(tmp2, FieldOperand(tmp2, Map::kInstanceTypeOffset));
6671257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ mov(tmp3, tmp1);
6672257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  STATIC_ASSERT(kNotStringTag != 0);
66733ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ or_(tmp3, tmp2);
6674257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ test(tmp3, Immediate(kIsNotStringMask));
6675257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(not_zero, &miss);
6676257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6677257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Fast check for identical strings.
6678257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label not_same;
66793ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ cmp(left, right);
6680257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(not_equal, &not_same, Label::kNear);
6681257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  STATIC_ASSERT(EQUAL == 0);
6682257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  STATIC_ASSERT(kSmiTag == 0);
6683257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Set(eax, Immediate(Smi::FromInt(EQUAL)));
6684257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ ret(0);
6685257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6686257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Handle not identical strings.
6687257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&not_same);
6688257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6689257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Check that both strings are symbols. If they are, we're done
66903ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // because we already know they are not identical.  But in the case of
66913ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // non-equality compare, we still need to determine the order.
66923ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  if (equality) {
66933ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    Label do_compare;
66943ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    STATIC_ASSERT(kSymbolTag != 0);
66953ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ and_(tmp1, tmp2);
66963ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ test(tmp1, Immediate(kIsSymbolMask));
66973ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ j(zero, &do_compare, Label::kNear);
66983ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    // Make sure eax is non-zero. At this point input operands are
66993ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    // guaranteed to be non-zero.
67003ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    ASSERT(right.is(eax));
67013ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ ret(0);
67023ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ bind(&do_compare);
67033ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  }
6704257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6705257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Check that both strings are sequential ASCII.
6706257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label runtime;
6707257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ JumpIfNotBothSequentialAsciiStrings(left, right, tmp1, tmp2, &runtime);
6708257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6709257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Compare flat ASCII strings. Returns when done.
67103ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  if (equality) {
67113ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    StringCompareStub::GenerateFlatAsciiStringEquals(
67123ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch        masm, left, right, tmp1, tmp2);
67133ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  } else {
67143ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    StringCompareStub::GenerateCompareFlatAsciiStrings(
67153ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch        masm, left, right, tmp1, tmp2, tmp3);
67163ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  }
6717257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6718257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Handle more complex cases in runtime.
6719257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&runtime);
6720257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ pop(tmp1);  // Return address.
6721257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ push(left);
6722257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ push(right);
6723257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ push(tmp1);
67243ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  if (equality) {
67253ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ TailCallRuntime(Runtime::kStringEquals, 2, 1);
67263ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  } else {
67273ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ TailCallRuntime(Runtime::kStringCompare, 2, 1);
67283ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  }
6729257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6730257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&miss);
6731257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  GenerateMiss(masm);
6732257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch}
6733257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6734257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6735b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdochvoid ICCompareStub::GenerateObjects(MacroAssembler* masm) {
6736b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  ASSERT(state_ == CompareIC::OBJECTS);
6737257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label miss;
67383ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ mov(ecx, edx);
67393ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ and_(ecx, eax);
67403fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ JumpIfSmi(ecx, &miss, Label::kNear);
6741b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
6742b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ CmpObjectType(eax, JS_OBJECT_TYPE, ecx);
6743257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(not_equal, &miss, Label::kNear);
6744b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ CmpObjectType(edx, JS_OBJECT_TYPE, ecx);
6745257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(not_equal, &miss, Label::kNear);
6746b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
6747b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  ASSERT(GetCondition() == equal);
67483ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ sub(eax, edx);
6749b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ ret(0);
6750b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
6751b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ bind(&miss);
6752b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  GenerateMiss(masm);
6753b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch}
6754b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
6755b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
67563ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochvoid ICCompareStub::GenerateKnownObjects(MacroAssembler* masm) {
67573ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  Label miss;
67583ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ mov(ecx, edx);
67593ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ and_(ecx, eax);
67603ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ JumpIfSmi(ecx, &miss, Label::kNear);
6761c7cc028aaeedbbfa11c11d0b7b243b3d9e837ed9Ben Murdoch
67623ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ mov(ecx, FieldOperand(eax, HeapObject::kMapOffset));
67633ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ mov(ebx, FieldOperand(edx, HeapObject::kMapOffset));
67643ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ cmp(ecx, known_map_);
67653ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ j(not_equal, &miss, Label::kNear);
67663ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ cmp(ebx, known_map_);
67673ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ j(not_equal, &miss, Label::kNear);
6768b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
67693ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ sub(eax, edx);
67703ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ ret(0);
67713ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
67723ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ bind(&miss);
67733ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  GenerateMiss(masm);
67743ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch}
6775c7cc028aaeedbbfa11c11d0b7b243b3d9e837ed9Ben Murdoch
67763ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
67773ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochvoid ICCompareStub::GenerateMiss(MacroAssembler* masm) {
67783ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  {
67793ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    // Call the runtime system in a fresh internal frame.
67803ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    ExternalReference miss = ExternalReference(IC_Utility(IC::kCompareIC_Miss),
67813ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                                               masm->isolate());
67823ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    FrameScope scope(masm, StackFrame::INTERNAL);
67833ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ push(edx);  // Preserve edx and eax.
67843ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ push(eax);
67853ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ push(edx);  // And also use them as the arguments.
67863ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ push(eax);
67873ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ push(Immediate(Smi::FromInt(op_)));
67883ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ CallExternalReference(miss, 3);
67893ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    // Compute the entry point of the rewritten stub.
67903ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ lea(edi, FieldOperand(eax, Code::kHeaderSize));
67913ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ pop(eax);
67923ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ pop(edx);
67933ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  }
6794b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
6795b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Do a tail call to the rewritten stub.
67963ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ jmp(edi);
6797b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch}
6798b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
6799b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
6800257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// Helper function used to check that the dictionary doesn't contain
6801257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// the property. This function may return false negatives, so miss_label
6802257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// must always call a backup property check that is complete.
6803257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// This function is safe to call if the receiver has fast properties.
6804257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// Name must be a symbol and receiver must be a heap object.
68053ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochvoid StringDictionaryLookupStub::GenerateNegativeLookup(MacroAssembler* masm,
68063ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                                                        Label* miss,
68073ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                                                        Label* done,
68083ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                                                        Register properties,
68093ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                                                        Handle<String> name,
68103ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                                                        Register r0) {
6811257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  ASSERT(name->IsSymbol());
6812257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6813257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // If names of slots in range from 1 to kProbes - 1 for the hash value are
6814257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // not equal to the name and kProbes-th slot is not used (its name is the
6815257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // undefined value), it guarantees the hash table doesn't contain the
6816257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // property. It's true even if some slots represent deleted properties
68173ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // (their names are the hole value).
6818257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  for (int i = 0; i < kInlinedProbes; i++) {
6819257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Compute the masked index: (hash + i + i * i) & mask.
6820257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Register index = r0;
6821257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Capacity is smi 2^n.
6822257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ mov(index, FieldOperand(properties, kCapacityOffset));
6823257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ dec(index);
68243ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ and_(index,
68253ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch            Immediate(Smi::FromInt(name->Hash() +
6826257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                   StringDictionary::GetProbeOffset(i))));
6827257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6828257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Scale the index by multiplying by the entry size.
6829257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    ASSERT(StringDictionary::kEntrySize == 3);
6830257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ lea(index, Operand(index, index, times_2, 0));  // index *= 3.
6831257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Register entity_name = r0;
6832257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Having undefined at this place means the name is not contained.
6833257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    ASSERT_EQ(kSmiTagSize, 1);
6834257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ mov(entity_name, Operand(properties, index, times_half_pointer_size,
6835257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                kElementsStartOffset - kHeapObjectTag));
6836257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ cmp(entity_name, masm->isolate()->factory()->undefined_value());
6837257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ j(equal, done);
6838257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6839257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Stop if found the property.
6840257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ cmp(entity_name, Handle<String>(name));
6841257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ j(equal, miss);
6842257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
68433ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    Label the_hole;
68443ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    // Check for the hole and skip.
68453ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ cmp(entity_name, masm->isolate()->factory()->the_hole_value());
68463ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ j(equal, &the_hole, Label::kNear);
68473ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
6848257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Check if the entry name is not a symbol.
6849257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ mov(entity_name, FieldOperand(entity_name, HeapObject::kMapOffset));
6850257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ test_b(FieldOperand(entity_name, Map::kInstanceTypeOffset),
6851257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch              kIsSymbolMask);
6852257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ j(zero, miss);
68533ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ bind(&the_hole);
6854257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
6855257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6856257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  StringDictionaryLookupStub stub(properties,
6857257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                  r0,
6858257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                  r0,
6859257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                  StringDictionaryLookupStub::NEGATIVE_LOOKUP);
6860257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ push(Immediate(Handle<Object>(name)));
6861257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ push(Immediate(name->Hash()));
68623ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ CallStub(&stub);
68633ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ test(r0, r0);
6864257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(not_zero, miss);
6865257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ jmp(done);
6866257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch}
6867257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6868257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6869257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// Probe the string dictionary in the |elements| register. Jump to the
6870257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// |done| label if a property with the given name is found leaving the
6871257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// index into the dictionary in |r0|. Jump to the |miss| label
6872257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// otherwise.
6873257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid StringDictionaryLookupStub::GeneratePositiveLookup(MacroAssembler* masm,
6874257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                                        Label* miss,
6875257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                                        Label* done,
6876257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                                        Register elements,
6877257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                                        Register name,
6878257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                                        Register r0,
6879257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                                        Register r1) {
68803ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  ASSERT(!elements.is(r0));
68813ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  ASSERT(!elements.is(r1));
68823ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  ASSERT(!name.is(r0));
68833ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  ASSERT(!name.is(r1));
68843ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
6885257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Assert that name contains a string.
6886257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  if (FLAG_debug_code) __ AbortIfNotString(name);
6887257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6888257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ mov(r1, FieldOperand(elements, kCapacityOffset));
6889257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ shr(r1, kSmiTagSize);  // convert smi to int
6890257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ dec(r1);
6891257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6892257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Generate an unrolled loop that performs a few probes before
6893257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // giving up. Measurements done on Gmail indicate that 2 probes
6894257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // cover ~93% of loads from dictionaries.
6895257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  for (int i = 0; i < kInlinedProbes; i++) {
6896257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Compute the masked index: (hash + i + i * i) & mask.
6897257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ mov(r0, FieldOperand(name, String::kHashFieldOffset));
6898257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ shr(r0, String::kHashShift);
6899257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    if (i > 0) {
69003ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      __ add(r0, Immediate(StringDictionary::GetProbeOffset(i)));
6901257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    }
69023ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ and_(r0, r1);
6903257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6904257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Scale the index by multiplying by the entry size.
6905257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    ASSERT(StringDictionary::kEntrySize == 3);
6906257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ lea(r0, Operand(r0, r0, times_2, 0));  // r0 = r0 * 3
6907257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6908257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Check if the key is identical to the name.
6909257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ cmp(name, Operand(elements,
6910257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                         r0,
6911257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                         times_4,
6912257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                         kElementsStartOffset - kHeapObjectTag));
6913257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ j(equal, done);
6914257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
6915257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6916257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  StringDictionaryLookupStub stub(elements,
6917257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                  r1,
6918257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                  r0,
6919257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                  POSITIVE_LOOKUP);
6920257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ push(name);
6921257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ mov(r0, FieldOperand(name, String::kHashFieldOffset));
6922257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ shr(r0, String::kHashShift);
6923257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ push(r0);
6924257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ CallStub(&stub);
6925257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
69263ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ test(r1, r1);
6927257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(zero, miss);
6928257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ jmp(done);
6929257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch}
6930257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6931257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6932257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid StringDictionaryLookupStub::Generate(MacroAssembler* masm) {
69333ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // This stub overrides SometimesSetsUpAFrame() to return false.  That means
69343ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // we cannot call anything that could cause a GC from this stub.
6935257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Stack frame on entry:
6936257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  //  esp[0 * kPointerSize]: return address.
6937257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  //  esp[1 * kPointerSize]: key's hash.
6938257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  //  esp[2 * kPointerSize]: key.
6939257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Registers:
6940257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  //  dictionary_: StringDictionary to probe.
6941257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  //  result_: used as scratch.
6942257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  //  index_: will hold an index of entry if lookup is successful.
6943257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  //          might alias with result_.
6944257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Returns:
6945257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  //  result_ is zero if lookup failed, non zero otherwise.
6946257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6947257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label in_dictionary, maybe_in_dictionary, not_in_dictionary;
6948257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6949257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Register scratch = result_;
6950257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6951257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ mov(scratch, FieldOperand(dictionary_, kCapacityOffset));
6952257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ dec(scratch);
6953257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ SmiUntag(scratch);
6954257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ push(scratch);
6955257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6956257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // If names of slots in range from 1 to kProbes - 1 for the hash value are
6957257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // not equal to the name and kProbes-th slot is not used (its name is the
6958257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // undefined value), it guarantees the hash table doesn't contain the
6959257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // property. It's true even if some slots represent deleted properties
6960257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // (their names are the null value).
6961257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  for (int i = kInlinedProbes; i < kTotalProbes; i++) {
6962257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Compute the masked index: (hash + i + i * i) & mask.
6963257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ mov(scratch, Operand(esp, 2 * kPointerSize));
6964257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    if (i > 0) {
69653ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      __ add(scratch, Immediate(StringDictionary::GetProbeOffset(i)));
6966257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    }
6967257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ and_(scratch, Operand(esp, 0));
6968257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6969257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Scale the index by multiplying by the entry size.
6970257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    ASSERT(StringDictionary::kEntrySize == 3);
6971257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ lea(index_, Operand(scratch, scratch, times_2, 0));  // index *= 3.
6972257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6973257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Having undefined at this place means the name is not contained.
6974257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    ASSERT_EQ(kSmiTagSize, 1);
6975257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ mov(scratch, Operand(dictionary_,
6976257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                            index_,
6977257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                            times_pointer_size,
6978257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                            kElementsStartOffset - kHeapObjectTag));
6979257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ cmp(scratch, masm->isolate()->factory()->undefined_value());
6980257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ j(equal, &not_in_dictionary);
6981257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6982257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Stop if found the property.
6983257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ cmp(scratch, Operand(esp, 3 * kPointerSize));
6984257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ j(equal, &in_dictionary);
6985257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6986257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    if (i != kTotalProbes - 1 && mode_ == NEGATIVE_LOOKUP) {
6987257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // If we hit a non symbol key during negative lookup
6988257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // we have to bailout as this key might be equal to the
6989257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // key we are looking for.
6990257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6991257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // Check if the entry name is not a symbol.
6992257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ mov(scratch, FieldOperand(scratch, HeapObject::kMapOffset));
6993257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ test_b(FieldOperand(scratch, Map::kInstanceTypeOffset),
6994257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                kIsSymbolMask);
6995257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ j(zero, &maybe_in_dictionary);
6996257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    }
6997257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
6998257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6999257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&maybe_in_dictionary);
7000257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // If we are doing negative lookup then probing failure should be
7001257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // treated as a lookup success. For positive lookup probing failure
7002257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // should be treated as lookup failure.
7003257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  if (mode_ == POSITIVE_LOOKUP) {
7004257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ mov(result_, Immediate(0));
7005257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ Drop(1);
7006257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ ret(2 * kPointerSize);
7007257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
7008257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
7009257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&in_dictionary);
7010257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ mov(result_, Immediate(1));
7011257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Drop(1);
7012257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ ret(2 * kPointerSize);
7013257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
7014257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&not_in_dictionary);
7015257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ mov(result_, Immediate(0));
7016257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Drop(1);
7017257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ ret(2 * kPointerSize);
7018257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch}
7019257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
7020257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
70213ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochstruct AheadOfTimeWriteBarrierStubList {
70223ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  Register object, value, address;
70233ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  RememberedSetAction action;
70243ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch};
70253ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
70263ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
70273ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch#define REG(Name) { kRegister_ ## Name ## _Code }
70283ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
70293ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochstatic const AheadOfTimeWriteBarrierStubList kAheadOfTime[] = {
70303ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Used in RegExpExecStub.
70313ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  { REG(ebx), REG(eax), REG(edi), EMIT_REMEMBERED_SET },
70323ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Used in CompileArrayPushCall.
70333ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  { REG(ebx), REG(ecx), REG(edx), EMIT_REMEMBERED_SET },
70343ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  { REG(ebx), REG(edi), REG(edx), OMIT_REMEMBERED_SET },
70353ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Used in CompileStoreGlobal and CallFunctionStub.
70363ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  { REG(ebx), REG(ecx), REG(edx), OMIT_REMEMBERED_SET },
70373ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Used in StoreStubCompiler::CompileStoreField and
70383ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // KeyedStoreStubCompiler::CompileStoreField via GenerateStoreField.
70393ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  { REG(edx), REG(ecx), REG(ebx), EMIT_REMEMBERED_SET },
70403ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // GenerateStoreField calls the stub with two different permutations of
70413ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // registers.  This is the second.
70423ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  { REG(ebx), REG(ecx), REG(edx), EMIT_REMEMBERED_SET },
70433ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // StoreIC::GenerateNormal via GenerateDictionaryStore
70443ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  { REG(ebx), REG(edi), REG(edx), EMIT_REMEMBERED_SET },
70453ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // KeyedStoreIC::GenerateGeneric.
70463ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  { REG(ebx), REG(edx), REG(ecx), EMIT_REMEMBERED_SET},
70473ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // KeyedStoreStubCompiler::GenerateStoreFastElement.
70483ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  { REG(edi), REG(ebx), REG(ecx), EMIT_REMEMBERED_SET},
70493ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  { REG(edx), REG(edi), REG(ebx), EMIT_REMEMBERED_SET},
70503ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // ElementsTransitionGenerator::GenerateSmiOnlyToObject
70513ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // and ElementsTransitionGenerator::GenerateSmiOnlyToDouble
70523ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // and ElementsTransitionGenerator::GenerateDoubleToObject
70533ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  { REG(edx), REG(ebx), REG(edi), EMIT_REMEMBERED_SET},
70543ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  { REG(edx), REG(ebx), REG(edi), OMIT_REMEMBERED_SET},
70553ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // ElementsTransitionGenerator::GenerateDoubleToObject
70563ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  { REG(eax), REG(edx), REG(esi), EMIT_REMEMBERED_SET},
70573ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  { REG(edx), REG(eax), REG(edi), EMIT_REMEMBERED_SET},
70583ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // StoreArrayLiteralElementStub::Generate
70593ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  { REG(ebx), REG(eax), REG(ecx), EMIT_REMEMBERED_SET},
70603ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Null termination.
70613ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  { REG(no_reg), REG(no_reg), REG(no_reg), EMIT_REMEMBERED_SET}
70623ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch};
70633ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
70643ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch#undef REG
70653ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
70663ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochbool RecordWriteStub::IsPregenerated() {
70673ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  for (const AheadOfTimeWriteBarrierStubList* entry = kAheadOfTime;
70683ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch       !entry->object.is(no_reg);
70693ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch       entry++) {
70703ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    if (object_.is(entry->object) &&
70713ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch        value_.is(entry->value) &&
70723ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch        address_.is(entry->address) &&
70733ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch        remembered_set_action_ == entry->action &&
70743ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch        save_fp_regs_mode_ == kDontSaveFPRegs) {
70753ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      return true;
70763ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    }
70773ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  }
70783ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  return false;
70793ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch}
70803ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
70813ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
70823ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochvoid StoreBufferOverflowStub::GenerateFixedRegStubsAheadOfTime() {
70833ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  StoreBufferOverflowStub stub1(kDontSaveFPRegs);
70843ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  stub1.GetCode()->set_is_pregenerated(true);
70853ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
70863ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  CpuFeatures::TryForceFeatureScope scope(SSE2);
70873ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  if (CpuFeatures::IsSupported(SSE2)) {
70883ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    StoreBufferOverflowStub stub2(kSaveFPRegs);
70893ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    stub2.GetCode()->set_is_pregenerated(true);
70903ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  }
70913ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch}
70923ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
70933ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
70943ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochvoid RecordWriteStub::GenerateFixedRegStubsAheadOfTime() {
70953ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  for (const AheadOfTimeWriteBarrierStubList* entry = kAheadOfTime;
70963ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch       !entry->object.is(no_reg);
70973ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch       entry++) {
70983ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    RecordWriteStub stub(entry->object,
70993ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                         entry->value,
71003ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                         entry->address,
71013ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                         entry->action,
71023ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                         kDontSaveFPRegs);
71033ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    stub.GetCode()->set_is_pregenerated(true);
71043ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  }
71053ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch}
71063ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
71073ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
71083ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch// Takes the input in 3 registers: address_ value_ and object_.  A pointer to
71093ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch// the value has just been written into the object, now this stub makes sure
71103ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch// we keep the GC informed.  The word in the object where the value has been
71113ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch// written is in the address register.
71123ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochvoid RecordWriteStub::Generate(MacroAssembler* masm) {
71133ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  Label skip_to_incremental_noncompacting;
71143ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  Label skip_to_incremental_compacting;
71153ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
71163ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // The first two instructions are generated with labels so as to get the
71173ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // offset fixed up correctly by the bind(Label*) call.  We patch it back and
71183ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // forth between a compare instructions (a nop in this position) and the
71193ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // real branch when we start and stop incremental heap marking.
71203ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ jmp(&skip_to_incremental_noncompacting, Label::kNear);
71213ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ jmp(&skip_to_incremental_compacting, Label::kFar);
71223ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
71233ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  if (remembered_set_action_ == EMIT_REMEMBERED_SET) {
71243ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ RememberedSetHelper(object_,
71253ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                           address_,
71263ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                           value_,
71273ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                           save_fp_regs_mode_,
71283ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                           MacroAssembler::kReturnAtEnd);
71293ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  } else {
71303ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ ret(0);
71313ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  }
71323ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
71333ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ bind(&skip_to_incremental_noncompacting);
71343ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  GenerateIncremental(masm, INCREMENTAL);
71353ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
71363ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ bind(&skip_to_incremental_compacting);
71373ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  GenerateIncremental(masm, INCREMENTAL_COMPACTION);
71383ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
71393ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Initial mode of the stub is expected to be STORE_BUFFER_ONLY.
71403ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Will be checked in IncrementalMarking::ActivateGeneratedStub.
71413ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  masm->set_byte_at(0, kTwoByteNopInstruction);
71423ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  masm->set_byte_at(2, kFiveByteNopInstruction);
71433ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch}
71443ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
71453ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
71463ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochvoid RecordWriteStub::GenerateIncremental(MacroAssembler* masm, Mode mode) {
71473ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  regs_.Save(masm);
71483ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
71493ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  if (remembered_set_action_ == EMIT_REMEMBERED_SET) {
71503ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    Label dont_need_remembered_set;
71513ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
71523ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ mov(regs_.scratch0(), Operand(regs_.address(), 0));
71533ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ JumpIfNotInNewSpace(regs_.scratch0(),  // Value.
71543ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                           regs_.scratch0(),
71553ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                           &dont_need_remembered_set);
71563ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
71573ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ CheckPageFlag(regs_.object(),
71583ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                     regs_.scratch0(),
71593ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                     1 << MemoryChunk::SCAN_ON_SCAVENGE,
71603ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                     not_zero,
71613ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                     &dont_need_remembered_set);
71623ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
71633ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    // First notify the incremental marker if necessary, then update the
71643ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    // remembered set.
71653ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    CheckNeedsToInformIncrementalMarker(
71663ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch        masm,
71673ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch        kUpdateRememberedSetOnNoNeedToInformIncrementalMarker,
71683ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch        mode);
71693ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    InformIncrementalMarker(masm, mode);
71703ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    regs_.Restore(masm);
71713ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ RememberedSetHelper(object_,
71723ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                           address_,
71733ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                           value_,
71743ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                           save_fp_regs_mode_,
71753ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                           MacroAssembler::kReturnAtEnd);
71763ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
71773ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ bind(&dont_need_remembered_set);
71783ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  }
71793ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
71803ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  CheckNeedsToInformIncrementalMarker(
71813ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      masm,
71823ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      kReturnOnNoNeedToInformIncrementalMarker,
71833ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      mode);
71843ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  InformIncrementalMarker(masm, mode);
71853ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  regs_.Restore(masm);
71863ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ ret(0);
71873ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch}
71883ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
71893ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
71903ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochvoid RecordWriteStub::InformIncrementalMarker(MacroAssembler* masm, Mode mode) {
71913ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  regs_.SaveCallerSaveRegisters(masm, save_fp_regs_mode_);
71923ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  int argument_count = 3;
71933ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ PrepareCallCFunction(argument_count, regs_.scratch0());
71943ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ mov(Operand(esp, 0 * kPointerSize), regs_.object());
71953ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  if (mode == INCREMENTAL_COMPACTION) {
71963ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ mov(Operand(esp, 1 * kPointerSize), regs_.address());  // Slot.
71973ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  } else {
71983ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    ASSERT(mode == INCREMENTAL);
71993ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ mov(regs_.scratch0(), Operand(regs_.address(), 0));
72003ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ mov(Operand(esp, 1 * kPointerSize), regs_.scratch0());  // Value.
72013ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  }
72023ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ mov(Operand(esp, 2 * kPointerSize),
72033ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch         Immediate(ExternalReference::isolate_address()));
72043ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
72053ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  AllowExternalCallThatCantCauseGC scope(masm);
72063ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  if (mode == INCREMENTAL_COMPACTION) {
72073ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ CallCFunction(
72083ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch        ExternalReference::incremental_evacuation_record_write_function(
72093ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch            masm->isolate()),
72103ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch        argument_count);
72113ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  } else {
72123ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    ASSERT(mode == INCREMENTAL);
72133ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ CallCFunction(
72143ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch        ExternalReference::incremental_marking_record_write_function(
72153ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch            masm->isolate()),
72163ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch        argument_count);
72173ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  }
72183ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  regs_.RestoreCallerSaveRegisters(masm, save_fp_regs_mode_);
72193ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch}
72203ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
72213ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
72223ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochvoid RecordWriteStub::CheckNeedsToInformIncrementalMarker(
72233ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    MacroAssembler* masm,
72243ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    OnNoNeedToInformIncrementalMarker on_no_need,
72253ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    Mode mode) {
72263ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  Label object_is_black, need_incremental, need_incremental_pop_object;
72273ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
72283ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Let's look at the color of the object:  If it is not black we don't have
72293ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // to inform the incremental marker.
72303ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ JumpIfBlack(regs_.object(),
72313ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                 regs_.scratch0(),
72323ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                 regs_.scratch1(),
72333ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                 &object_is_black,
72343ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                 Label::kNear);
72353ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
72363ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  regs_.Restore(masm);
72373ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  if (on_no_need == kUpdateRememberedSetOnNoNeedToInformIncrementalMarker) {
72383ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ RememberedSetHelper(object_,
72393ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                           address_,
72403ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                           value_,
72413ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                           save_fp_regs_mode_,
72423ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                           MacroAssembler::kReturnAtEnd);
72433ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  } else {
72443ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ ret(0);
72453ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  }
72463ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
72473ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ bind(&object_is_black);
72483ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
72493ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Get the value from the slot.
72503ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ mov(regs_.scratch0(), Operand(regs_.address(), 0));
72513ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
72523ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  if (mode == INCREMENTAL_COMPACTION) {
72533ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    Label ensure_not_white;
72543ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
72553ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ CheckPageFlag(regs_.scratch0(),  // Contains value.
72563ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                     regs_.scratch1(),  // Scratch.
72573ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                     MemoryChunk::kEvacuationCandidateMask,
72583ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                     zero,
72593ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                     &ensure_not_white,
72603ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                     Label::kNear);
72613ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
72623ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ CheckPageFlag(regs_.object(),
72633ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                     regs_.scratch1(),  // Scratch.
72643ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                     MemoryChunk::kSkipEvacuationSlotsRecordingMask,
72653ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                     not_zero,
72663ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                     &ensure_not_white,
72673ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                     Label::kNear);
72683ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
72693ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ jmp(&need_incremental);
72703ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
72713ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ bind(&ensure_not_white);
72723ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  }
72733ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
72743ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // We need an extra register for this, so we push the object register
72753ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // temporarily.
72763ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ push(regs_.object());
72773ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ EnsureNotWhite(regs_.scratch0(),  // The value.
72783ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                    regs_.scratch1(),  // Scratch.
72793ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                    regs_.object(),  // Scratch.
72803ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                    &need_incremental_pop_object,
72813ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                    Label::kNear);
72823ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ pop(regs_.object());
72833ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
72843ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  regs_.Restore(masm);
72853ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  if (on_no_need == kUpdateRememberedSetOnNoNeedToInformIncrementalMarker) {
72863ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ RememberedSetHelper(object_,
72873ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                           address_,
72883ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                           value_,
72893ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                           save_fp_regs_mode_,
72903ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                           MacroAssembler::kReturnAtEnd);
72913ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  } else {
72923ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ ret(0);
72933ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  }
72943ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
72953ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ bind(&need_incremental_pop_object);
72963ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ pop(regs_.object());
72973ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
72983ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ bind(&need_incremental);
72993ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
73003ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Fall through when we need to inform the incremental marker.
73013ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch}
73023ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
73033ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
73043ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochvoid StoreArrayLiteralElementStub::Generate(MacroAssembler* masm) {
73053ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // ----------- S t a t e -------------
73063ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  //  -- eax    : element value to store
73073ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  //  -- ebx    : array literal
73083ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  //  -- edi    : map of array literal
73093ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  //  -- ecx    : element index as smi
73103ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  //  -- edx    : array literal index in function
73113ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  //  -- esp[0] : return address
73123ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // -----------------------------------
73133ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
73143ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  Label element_done;
73153ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  Label double_elements;
73163ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  Label smi_element;
73173ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  Label slow_elements;
73183ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  Label slow_elements_from_double;
73193ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  Label fast_elements;
73203ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
73213ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ CheckFastElements(edi, &double_elements);
73223ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
73233ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // FAST_SMI_ONLY_ELEMENTS or FAST_ELEMENTS
73243ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ JumpIfSmi(eax, &smi_element);
73253ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ CheckFastSmiOnlyElements(edi, &fast_elements, Label::kNear);
73263ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
73273ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Store into the array literal requires a elements transition. Call into
73283ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // the runtime.
73293ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
73303ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ bind(&slow_elements);
73313ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ pop(edi);  // Pop return address and remember to put back later for tail
73323ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                // call.
73333ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ push(ebx);
73343ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ push(ecx);
73353ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ push(eax);
73363ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ mov(ebx, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
73373ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ push(FieldOperand(ebx, JSFunction::kLiteralsOffset));
73383ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ push(edx);
73393ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ push(edi);  // Return return address so that tail call returns to right
73403ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                 // place.
73413ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ TailCallRuntime(Runtime::kStoreArrayLiteralElement, 5, 1);
73423ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
73433ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ bind(&slow_elements_from_double);
73443ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ pop(edx);
73453ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ jmp(&slow_elements);
73463ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
73473ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Array literal has ElementsKind of FAST_ELEMENTS and value is an object.
73483ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ bind(&fast_elements);
73493ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ mov(ebx, FieldOperand(ebx, JSObject::kElementsOffset));
73503ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ lea(ecx, FieldOperand(ebx, ecx, times_half_pointer_size,
73513ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                           FixedArrayBase::kHeaderSize));
73523ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ mov(Operand(ecx, 0), eax);
73533ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Update the write barrier for the array store.
73543ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ RecordWrite(ebx, ecx, eax,
73553ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                 kDontSaveFPRegs,
73563ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                 EMIT_REMEMBERED_SET,
73573ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                 OMIT_SMI_CHECK);
73583ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ ret(0);
73593ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
73603ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Array literal has ElementsKind of FAST_SMI_ONLY_ELEMENTS or
73613ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // FAST_ELEMENTS, and value is Smi.
73623ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ bind(&smi_element);
73633ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ mov(ebx, FieldOperand(ebx, JSObject::kElementsOffset));
73643ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ mov(FieldOperand(ebx, ecx, times_half_pointer_size,
73653ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                      FixedArrayBase::kHeaderSize), eax);
73663ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ ret(0);
73673ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
73683ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Array literal has ElementsKind of FAST_DOUBLE_ELEMENTS.
73693ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ bind(&double_elements);
73703ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
73713ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ push(edx);
73723ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ mov(edx, FieldOperand(ebx, JSObject::kElementsOffset));
73733ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ StoreNumberToDoubleElements(eax,
73743ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                                 edx,
73753ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                                 ecx,
73763ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                                 edi,
73773ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                                 xmm0,
73783ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                                 &slow_elements_from_double,
73793ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                                 false);
73803ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ pop(edx);
73813ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ ret(0);
73823ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch}
73833ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
738480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#undef __
738580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
738680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} }  // namespace v8::internal
738780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
738880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#endif  // V8_TARGET_ARCH_IA32
7389