code-stubs-ia32.cc revision 692be65d6b06edd9ff4cfc4c308555b7c99c1191
11e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block// Copyright 2011 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"
3780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
3880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsennamespace v8 {
3980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsennamespace internal {
4080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
4180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#define __ ACCESS_MASM(masm)
421e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
431e0659c275bb392c045087af4f6b0d7565cb3d77Steve Blockvoid ToNumberStub::Generate(MacroAssembler* masm) {
441e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  // The ToNumber stub takes one argument in eax.
45257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label check_heap_number, call_builtin;
463fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ JumpIfNotSmi(eax, &check_heap_number, Label::kNear);
471e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  __ ret(0);
481e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
491e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  __ bind(&check_heap_number);
501e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset));
5144f0eee88ff00398ff7f715fab053374d808c90dSteve Block  Factory* factory = masm->isolate()->factory();
5244f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ cmp(Operand(ebx), Immediate(factory->heap_number_map()));
53257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(not_equal, &call_builtin, Label::kNear);
541e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  __ ret(0);
551e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
561e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  __ bind(&call_builtin);
571e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  __ pop(ecx);  // Pop return address.
581e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  __ push(eax);
591e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  __ push(ecx);  // Push return address.
601e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  __ InvokeBuiltin(Builtins::TO_NUMBER, JUMP_FUNCTION);
611e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block}
621e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
631e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
6480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid FastNewClosureStub::Generate(MacroAssembler* masm) {
6580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Create a new closure from the given function info in new
6680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // space. Set the context to the current context in esi.
6780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label gc;
6880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ AllocateInNewSpace(JSFunction::kSize, eax, ebx, ecx, &gc, TAG_OBJECT);
6980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
7080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Get the function info from the stack.
7180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(edx, Operand(esp, 1 * kPointerSize));
7280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
7344f0eee88ff00398ff7f715fab053374d808c90dSteve Block  int map_index = strict_mode_ == kStrictMode
7444f0eee88ff00398ff7f715fab053374d808c90dSteve Block      ? Context::STRICT_MODE_FUNCTION_MAP_INDEX
7544f0eee88ff00398ff7f715fab053374d808c90dSteve Block      : Context::FUNCTION_MAP_INDEX;
7644f0eee88ff00398ff7f715fab053374d808c90dSteve Block
7780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Compute the function map in the current global context and set that
7880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // as the map of the allocated object.
7980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(ecx, Operand(esi, Context::SlotOffset(Context::GLOBAL_INDEX)));
8080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(ecx, FieldOperand(ecx, GlobalObject::kGlobalContextOffset));
8144f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ mov(ecx, Operand(ecx, Context::SlotOffset(map_index)));
8280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(FieldOperand(eax, JSObject::kMapOffset), ecx);
8380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
8480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Initialize the rest of the function. We don't have to update the
8580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // write barrier because the allocated object is in new space.
8644f0eee88ff00398ff7f715fab053374d808c90dSteve Block  Factory* factory = masm->isolate()->factory();
8744f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ mov(ebx, Immediate(factory->empty_fixed_array()));
8880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(FieldOperand(eax, JSObject::kPropertiesOffset), ebx);
8980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(FieldOperand(eax, JSObject::kElementsOffset), ebx);
9080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(FieldOperand(eax, JSFunction::kPrototypeOrInitialMapOffset),
9144f0eee88ff00398ff7f715fab053374d808c90dSteve Block         Immediate(factory->the_hole_value()));
9280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(FieldOperand(eax, JSFunction::kSharedFunctionInfoOffset), edx);
9380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(FieldOperand(eax, JSFunction::kContextOffset), esi);
9480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(FieldOperand(eax, JSFunction::kLiteralsOffset), ebx);
95b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ mov(FieldOperand(eax, JSFunction::kNextFunctionLinkOffset),
9644f0eee88ff00398ff7f715fab053374d808c90dSteve Block         Immediate(factory->undefined_value()));
9780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
9880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Initialize the code pointer in the function to be the one
9980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // found in the shared function info object.
10080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(edx, FieldOperand(edx, SharedFunctionInfo::kCodeOffset));
10180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ lea(edx, FieldOperand(edx, Code::kHeaderSize));
10280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(FieldOperand(eax, JSFunction::kCodeEntryOffset), edx);
10380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
10480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Return and remove the on-stack parameter.
10580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ ret(1 * kPointerSize);
10680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
10780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Create a new closure through the slower runtime call.
10880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&gc);
10980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ pop(ecx);  // Temporarily remove return address.
11080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ pop(edx);
11180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ push(esi);
11280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ push(edx);
11344f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ push(Immediate(factory->false_value()));
11480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ push(ecx);  // Restore return address.
1158a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  __ TailCallRuntime(Runtime::kNewClosure, 3, 1);
11680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
11780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
11880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
11980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid FastNewContextStub::Generate(MacroAssembler* masm) {
12080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Try to allocate the context in new space.
12180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label gc;
12280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  int length = slots_ + Context::MIN_CONTEXT_SLOTS;
12380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ AllocateInNewSpace((length * kPointerSize) + FixedArray::kHeaderSize,
12480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                        eax, ebx, ecx, &gc, TAG_OBJECT);
12580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
12680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Get the function from the stack.
12780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(ecx, Operand(esp, 1 * kPointerSize));
12880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
12980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Setup the object header.
13044f0eee88ff00398ff7f715fab053374d808c90dSteve Block  Factory* factory = masm->isolate()->factory();
1313fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ mov(FieldOperand(eax, HeapObject::kMapOffset),
1323fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch         factory->function_context_map());
13380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(FieldOperand(eax, Context::kLengthOffset),
13480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen         Immediate(Smi::FromInt(length)));
13580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
13680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Setup the fixed slots.
1379fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ Set(ebx, Immediate(0));  // Set to NULL.
13880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(Operand(eax, Context::SlotOffset(Context::CLOSURE_INDEX)), ecx);
1393fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ mov(Operand(eax, Context::SlotOffset(Context::PREVIOUS_INDEX)), esi);
14080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(Operand(eax, Context::SlotOffset(Context::EXTENSION_INDEX)), ebx);
14180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
1423fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // Copy the global object from the previous context.
1433fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ mov(ebx, Operand(esi, Context::SlotOffset(Context::GLOBAL_INDEX)));
14480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(Operand(eax, Context::SlotOffset(Context::GLOBAL_INDEX)), ebx);
14580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
14680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Initialize the rest of the slots to undefined.
14744f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ mov(ebx, factory->undefined_value());
14880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  for (int i = Context::MIN_CONTEXT_SLOTS; i < length; i++) {
14980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ mov(Operand(eax, Context::SlotOffset(i)), ebx);
15080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
15180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
15280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Return and remove the on-stack parameter.
15380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(esi, Operand(eax));
15480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ ret(1 * kPointerSize);
15580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
15680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Need to collect. Call into runtime system.
15780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&gc);
1583fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ TailCallRuntime(Runtime::kNewFunctionContext, 1, 1);
15980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
16080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
16180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
16280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid FastCloneShallowArrayStub::Generate(MacroAssembler* masm) {
16380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Stack layout on entry:
16480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  //
16580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // [esp + kPointerSize]: constant elements.
16680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // [esp + (2 * kPointerSize)]: literal index.
16780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // [esp + (3 * kPointerSize)]: literals array.
16880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
16980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // All sizes here are multiples of kPointerSize.
17080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  int elements_size = (length_ > 0) ? FixedArray::SizeFor(length_) : 0;
17180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  int size = JSArray::kSize + elements_size;
17280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
17380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Load boilerplate object into ecx and check if we need to create a
17480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // boilerplate.
17580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label slow_case;
17680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(ecx, Operand(esp, 3 * kPointerSize));
17780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(eax, Operand(esp, 2 * kPointerSize));
17880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  STATIC_ASSERT(kPointerSize == 4);
17980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  STATIC_ASSERT(kSmiTagSize == 1);
18080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  STATIC_ASSERT(kSmiTag == 0);
18180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(ecx, FieldOperand(ecx, eax, times_half_pointer_size,
18280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                           FixedArray::kHeaderSize));
18344f0eee88ff00398ff7f715fab053374d808c90dSteve Block  Factory* factory = masm->isolate()->factory();
18444f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ cmp(ecx, factory->undefined_value());
18580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(equal, &slow_case);
18680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
18780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  if (FLAG_debug_code) {
18880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    const char* message;
18980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    Handle<Map> expected_map;
19080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    if (mode_ == CLONE_ELEMENTS) {
19180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      message = "Expected (writable) fixed array";
19244f0eee88ff00398ff7f715fab053374d808c90dSteve Block      expected_map = factory->fixed_array_map();
19380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    } else {
19480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      ASSERT(mode_ == COPY_ON_WRITE_ELEMENTS);
19580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      message = "Expected copy-on-write fixed array";
19644f0eee88ff00398ff7f715fab053374d808c90dSteve Block      expected_map = factory->fixed_cow_array_map();
19780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    }
19880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ push(ecx);
19980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ mov(ecx, FieldOperand(ecx, JSArray::kElementsOffset));
20080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ cmp(FieldOperand(ecx, HeapObject::kMapOffset), expected_map);
20180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ Assert(equal, message);
20280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ pop(ecx);
20380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
20480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
20580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Allocate both the JS array and the elements array in one big
20680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // allocation. This avoids multiple limit checks.
20780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ AllocateInNewSpace(size, eax, ebx, edx, &slow_case, TAG_OBJECT);
20880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
20980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Copy the JS array part.
21080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  for (int i = 0; i < JSArray::kSize; i += kPointerSize) {
21180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    if ((i != JSArray::kElementsOffset) || (length_ == 0)) {
21280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ mov(ebx, FieldOperand(ecx, i));
21380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ mov(FieldOperand(eax, i), ebx);
21480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    }
21580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
21680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
21780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  if (length_ > 0) {
21880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // Get hold of the elements array of the boilerplate and setup the
21980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // elements pointer in the resulting object.
22080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ mov(ecx, FieldOperand(ecx, JSArray::kElementsOffset));
22180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ lea(edx, Operand(eax, JSArray::kSize));
22280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ mov(FieldOperand(eax, JSArray::kElementsOffset), edx);
22380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
22480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // Copy the elements array.
22580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    for (int i = 0; i < elements_size; i += kPointerSize) {
22680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ mov(ebx, FieldOperand(ecx, i));
22780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ mov(FieldOperand(edx, i), ebx);
22880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    }
22980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
23080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
23180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Return and remove the on-stack parameters.
23280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ ret(3 * kPointerSize);
23380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
23480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&slow_case);
23580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ TailCallRuntime(Runtime::kCreateArrayLiteralShallow, 3, 1);
23680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
23780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
23880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
23969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch// The stub expects its argument on the stack and returns its result in tos_:
24069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch// zero for false, and a non-zero value for true.
24180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid ToBooleanStub::Generate(MacroAssembler* masm) {
24269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  Label patch;
243257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Factory* factory = masm->isolate()->factory();
24469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  const Register argument = eax;
2453fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  const Register map = edx;
2463fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
24769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  if (!types_.IsEmpty()) {
24869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    __ mov(argument, Operand(esp, 1 * kPointerSize));
24969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  }
250257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
251257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // undefined -> false
25269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  CheckOddball(masm, UNDEFINED, Heap::kUndefinedValueRootIndex, false);
253257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
254257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Boolean -> its value
25569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  CheckOddball(masm, BOOLEAN, Heap::kFalseValueRootIndex, false);
25669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  CheckOddball(masm, BOOLEAN, Heap::kTrueValueRootIndex, true);
25780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
2583fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // 'null' -> false.
25969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  CheckOddball(masm, NULL_TYPE, Heap::kNullValueRootIndex, false);
26080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
26169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  if (types_.Contains(SMI)) {
26269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    // Smis: 0 -> false, all other -> true
26369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    Label not_smi;
26469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    __ JumpIfNotSmi(argument, &not_smi, Label::kNear);
26569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    // argument contains the correct return value already.
26669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    if (!tos_.is(argument)) {
26769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch      __ mov(tos_, argument);
26869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    }
26969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    __ ret(1 * kPointerSize);
27069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    __ bind(&not_smi);
27169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  } else if (types_.NeedsMap()) {
27269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    // If we need a map later and have a Smi -> patch.
27369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    __ JumpIfSmi(argument, &patch, Label::kNear);
27469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  }
27580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
27669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  if (types_.NeedsMap()) {
27769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    __ mov(map, FieldOperand(argument, HeapObject::kMapOffset));
27869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch
27969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    if (types_.CanBeUndetectable()) {
28069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch      __ test_b(FieldOperand(map, Map::kBitFieldOffset),
28169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch                1 << Map::kIsUndetectable);
28269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch      // Undetectable -> false.
28369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch      Label not_undetectable;
28469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch      __ j(zero, &not_undetectable, Label::kNear);
28569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch      __ Set(tos_, Immediate(0));
28669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch      __ ret(1 * kPointerSize);
28769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch      __ bind(&not_undetectable);
28869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    }
28969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  }
29080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
29169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  if (types_.Contains(SPEC_OBJECT)) {
29269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    // spec object -> true.
29369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    Label not_js_object;
29469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    __ CmpInstanceType(map, FIRST_SPEC_OBJECT_TYPE);
29569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    __ j(below, &not_js_object, Label::kNear);
29669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    // argument contains the correct return value already.
29769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    if (!tos_.is(argument)) {
29869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch      __ Set(tos_, Immediate(1));
29969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    }
30069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    __ ret(1 * kPointerSize);
30169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    __ bind(&not_js_object);
30269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  }
30380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
30469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  if (types_.Contains(STRING)) {
30569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    // String value -> false iff empty.
30669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    Label not_string;
30769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    __ CmpInstanceType(map, FIRST_NONSTRING_TYPE);
30869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    __ j(above_equal, &not_string, Label::kNear);
30969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    __ mov(tos_, FieldOperand(argument, String::kLengthOffset));
31069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    __ ret(1 * kPointerSize);  // the string length is OK as the return value
31169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    __ bind(&not_string);
31269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  }
31380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
31469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  if (types_.Contains(HEAP_NUMBER)) {
31569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    // heap number -> false iff +0, -0, or NaN.
31669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    Label not_heap_number, false_result;
31769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    __ cmp(map, factory->heap_number_map());
31869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    __ j(not_equal, &not_heap_number, Label::kNear);
31969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    __ fldz();
32069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    __ fld_d(FieldOperand(argument, HeapNumber::kValueOffset));
32169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    __ FCmp();
32269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    __ j(zero, &false_result, Label::kNear);
32369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    // argument contains the correct return value already.
32469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    if (!tos_.is(argument)) {
32569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch      __ Set(tos_, Immediate(1));
32669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    }
32769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    __ ret(1 * kPointerSize);
32869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    __ bind(&false_result);
32969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    __ Set(tos_, Immediate(0));
33069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    __ ret(1 * kPointerSize);
33169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    __ bind(&not_heap_number);
33269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  }
33369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch
33469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ bind(&patch);
33569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  GenerateTypeTransition(masm);
33669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch}
33769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch
33869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch
33969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdochvoid ToBooleanStub::CheckOddball(MacroAssembler* masm,
34069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch                                 Type type,
34169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch                                 Heap::RootListIndex value,
34269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch                                 bool result) {
34369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  const Register argument = eax;
34469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  if (types_.Contains(type)) {
34569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    // If we see an expected oddball, return its ToBoolean value tos_.
34669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    Label different_value;
34769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    __ CompareRoot(argument, value);
34869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    __ j(not_equal, &different_value, Label::kNear);
34969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    if (!result) {
35069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch      // If we have to return zero, there is no way around clearing tos_.
35169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch      __ Set(tos_, Immediate(0));
35269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    } else if (!tos_.is(argument)) {
35369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch      // If we have to return non-zero, we can re-use the argument if it is the
35469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch      // same register as the result, because we never see Smi-zero here.
35569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch      __ Set(tos_, Immediate(1));
35669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    }
35769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    __ ret(1 * kPointerSize);
35869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    __ bind(&different_value);
35969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  }
36069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch}
36169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch
36269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch
36369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdochvoid ToBooleanStub::GenerateTypeTransition(MacroAssembler* masm) {
36469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ pop(ecx);  // Get return address, operand is now on top of stack.
36569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ push(Immediate(Smi::FromInt(tos_.code())));
36669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ push(Immediate(Smi::FromInt(types_.ToByte())));
36769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ push(ecx);  // Push return address.
36869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  // Patch the caller to an appropriate specialized stub and return the
36969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  // operation result to the caller of the stub.
37069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ TailCallExternalReference(
37169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch      ExternalReference(IC_Utility(IC::kToBoolean_Patch), masm->isolate()),
37269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch      3,
37369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch      1);
37480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
37580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
37680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
3778b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdochclass FloatingPointHelper : public AllStatic {
3788b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch public:
3798b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  enum ArgLocation {
3808b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch    ARGS_ON_STACK,
3818b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch    ARGS_IN_REGISTERS
3828b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  };
38380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
3848b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  // Code pattern for loading a floating point value. Input value must
3858b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  // be either a smi or a heap number object (fp value). Requirements:
3868b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  // operand in register number. Returns operand as floating point number
3878b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  // on FPU stack.
3888b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  static void LoadFloatOperand(MacroAssembler* masm, Register number);
38980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
3908b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  // Code pattern for loading floating point values. Input values must
3918b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  // be either smi or heap number objects (fp values). Requirements:
3928b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  // operand_1 on TOS+1 or in edx, operand_2 on TOS+2 or in eax.
3938b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  // Returns operands as floating point numbers on FPU stack.
3948b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  static void LoadFloatOperands(MacroAssembler* masm,
3958b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch                                Register scratch,
3968b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch                                ArgLocation arg_location = ARGS_ON_STACK);
39780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
3988b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  // Similar to LoadFloatOperand but assumes that both operands are smis.
3998b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  // Expects operands in edx, eax.
4008b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  static void LoadFloatSmis(MacroAssembler* masm, Register scratch);
401b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
4028b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  // Test if operands are smi or number objects (fp). Requirements:
4038b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  // operand_1 in eax, operand_2 in edx; falls through on float
4048b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  // operands, jumps to the non_float label otherwise.
4058b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  static void CheckFloatOperands(MacroAssembler* masm,
4068b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch                                 Label* non_float,
4078b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch                                 Register scratch);
408b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
4098b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  // Checks that the two floating point numbers on top of the FPU stack
4108b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  // have int32 values.
4118b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  static void CheckFloatOperandsAreInt32(MacroAssembler* masm,
4128b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch                                         Label* non_int32);
413b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
4148b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  // Takes the operands in edx and eax and loads them as integers in eax
4158b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  // and ecx.
4168b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  static void LoadUnknownsAsIntegers(MacroAssembler* masm,
4178b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch                                     bool use_sse3,
4188b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch                                     Label* operand_conversion_failure);
419b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
4208b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  // Must only be called after LoadUnknownsAsIntegers.  Assumes that the
4218b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  // operands are pushed on the stack, and that their conversions to int32
4228b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  // are in eax and ecx.  Checks that the original numbers were in the int32
4238b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  // range.
4248b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  static void CheckLoadedIntegersWereInt32(MacroAssembler* masm,
4258b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch                                           bool use_sse3,
4268b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch                                           Label* not_int32);
427b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
4288b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  // Assumes that operands are smis or heap numbers and loads them
4298b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  // into xmm0 and xmm1. Operands are in edx and eax.
4308b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  // Leaves operands unchanged.
4318b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  static void LoadSSE2Operands(MacroAssembler* masm);
432b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
4338b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  // Test if operands are numbers (smi or HeapNumber objects), and load
4348b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  // them into xmm0 and xmm1 if they are.  Jump to label not_numbers if
4358b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  // either operand is not a number.  Operands are in edx and eax.
4368b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  // Leaves operands unchanged.
4378b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  static void LoadSSE2Operands(MacroAssembler* masm, Label* not_numbers);
438b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
4398b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  // Similar to LoadSSE2Operands but assumes that both operands are smis.
4408b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  // Expects operands in edx, eax.
4418b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  static void LoadSSE2Smis(MacroAssembler* masm, Register scratch);
442b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
443257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Checks that the two floating point numbers loaded into xmm0 and xmm1
444257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // have int32 values.
445257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  static void CheckSSE2OperandsAreInt32(MacroAssembler* masm,
446257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                        Label* non_int32,
447257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                        Register scratch);
448257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch};
449257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
450257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
451257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// Get the integer part of a heap number.  Surprisingly, all this bit twiddling
452257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// is faster than using the built-in instructions on floating point registers.
453257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// Trashes edi and ebx.  Dest is ecx.  Source cannot be ecx or one of the
454257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// trashed registers.
455257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochstatic void IntegerConvert(MacroAssembler* masm,
456257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                           Register source,
457257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                           bool use_sse3,
458257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                           Label* conversion_failure) {
459257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  ASSERT(!source.is(ecx) && !source.is(edi) && !source.is(ebx));
460257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label done, right_exponent, normal_exponent;
461257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Register scratch = ebx;
462257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Register scratch2 = edi;
463257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Get exponent word.
464257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ mov(scratch, FieldOperand(source, HeapNumber::kExponentOffset));
465257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Get exponent alone in scratch2.
466257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ mov(scratch2, scratch);
467257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ and_(scratch2, HeapNumber::kExponentMask);
468257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  if (use_sse3) {
469257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    CpuFeatures::Scope scope(SSE3);
470257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Check whether the exponent is too big for a 64 bit signed integer.
471257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    static const uint32_t kTooBigExponent =
472257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        (HeapNumber::kExponentBias + 63) << HeapNumber::kExponentShift;
473257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ cmp(Operand(scratch2), Immediate(kTooBigExponent));
474257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ j(greater_equal, conversion_failure);
475257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Load x87 register with heap number.
476257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ fld_d(FieldOperand(source, HeapNumber::kValueOffset));
477257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Reserve space for 64 bit answer.
478257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ sub(Operand(esp), Immediate(sizeof(uint64_t)));  // Nolint.
479257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Do conversion, which cannot fail because we checked the exponent.
480257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ fisttp_d(Operand(esp, 0));
481257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ mov(ecx, Operand(esp, 0));  // Load low word of answer into ecx.
482257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ add(Operand(esp), Immediate(sizeof(uint64_t)));  // Nolint.
483257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  } else {
484257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Load ecx with zero.  We use this either for the final shift or
485257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // for the answer.
486257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ xor_(ecx, Operand(ecx));
487257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Check whether the exponent matches a 32 bit signed int that cannot be
488257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // represented by a Smi.  A non-smi 32 bit integer is 1.xxx * 2^30 so the
489257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // exponent is 30 (biased).  This is the exponent that we are fastest at and
490257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // also the highest exponent we can handle here.
491257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    const uint32_t non_smi_exponent =
492257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        (HeapNumber::kExponentBias + 30) << HeapNumber::kExponentShift;
493257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ cmp(Operand(scratch2), Immediate(non_smi_exponent));
494257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // If we have a match of the int32-but-not-Smi exponent then skip some
495257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // logic.
49669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    __ j(equal, &right_exponent, Label::kNear);
497257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // If the exponent is higher than that then go to slow case.  This catches
498257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // numbers that don't fit in a signed int32, infinities and NaNs.
49969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    __ j(less, &normal_exponent, Label::kNear);
500257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
501257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    {
502257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // Handle a big exponent.  The only reason we have this code is that the
503257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // >>> operator has a tendency to generate numbers with an exponent of 31.
504257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      const uint32_t big_non_smi_exponent =
505257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          (HeapNumber::kExponentBias + 31) << HeapNumber::kExponentShift;
506257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ cmp(Operand(scratch2), Immediate(big_non_smi_exponent));
507257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ j(not_equal, conversion_failure);
508257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // We have the big exponent, typically from >>>.  This means the number is
509257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // in the range 2^31 to 2^32 - 1.  Get the top bits of the mantissa.
510257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ mov(scratch2, scratch);
511257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ and_(scratch2, HeapNumber::kMantissaMask);
512257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // Put back the implicit 1.
513257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ or_(scratch2, 1 << HeapNumber::kExponentShift);
514257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // Shift up the mantissa bits to take up the space the exponent used to
515257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // take. We just orred in the implicit bit so that took care of one and
516257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // we want to use the full unsigned range so we subtract 1 bit from the
517257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // shift distance.
518257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      const int big_shift_distance = HeapNumber::kNonMantissaBitsInTopWord - 1;
519257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ shl(scratch2, big_shift_distance);
520257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // Get the second half of the double.
521257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ mov(ecx, FieldOperand(source, HeapNumber::kMantissaOffset));
522257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // Shift down 21 bits to get the most significant 11 bits or the low
523257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // mantissa word.
524257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ shr(ecx, 32 - big_shift_distance);
525257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ or_(ecx, Operand(scratch2));
526257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // We have the answer in ecx, but we may need to negate it.
527257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ test(scratch, Operand(scratch));
52869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch      __ j(positive, &done, Label::kNear);
529257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ neg(ecx);
53069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch      __ jmp(&done, Label::kNear);
531257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    }
532257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
533257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ bind(&normal_exponent);
534257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Exponent word in scratch, exponent part of exponent word in scratch2.
535257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Zero in ecx.
536257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // We know the exponent is smaller than 30 (biased).  If it is less than
537257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // 0 (biased) then the number is smaller in magnitude than 1.0 * 2^0, ie
538257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // it rounds to zero.
539257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    const uint32_t zero_exponent =
540257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        (HeapNumber::kExponentBias + 0) << HeapNumber::kExponentShift;
541257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ sub(Operand(scratch2), Immediate(zero_exponent));
542257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // ecx already has a Smi zero.
54369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    __ j(less, &done, Label::kNear);
544257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
545257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // We have a shifted exponent between 0 and 30 in scratch2.
546257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ shr(scratch2, HeapNumber::kExponentShift);
547257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ mov(ecx, Immediate(30));
548257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ sub(ecx, Operand(scratch2));
549257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
550257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ bind(&right_exponent);
551257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Here ecx is the shift, scratch is the exponent word.
552257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Get the top bits of the mantissa.
553257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ and_(scratch, HeapNumber::kMantissaMask);
554257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Put back the implicit 1.
555257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ or_(scratch, 1 << HeapNumber::kExponentShift);
556257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Shift up the mantissa bits to take up the space the exponent used to
557257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // take. We have kExponentShift + 1 significant bits int he low end of the
558257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // word.  Shift them to the top bits.
559257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    const int shift_distance = HeapNumber::kNonMantissaBitsInTopWord - 2;
560257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ shl(scratch, shift_distance);
561257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Get the second half of the double. For some exponents we don't
562257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // actually need this because the bits get shifted out again, but
563257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // it's probably slower to test than just to do it.
564257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ mov(scratch2, FieldOperand(source, HeapNumber::kMantissaOffset));
565257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Shift down 22 bits to get the most significant 10 bits or the low
566257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // mantissa word.
567257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ shr(scratch2, 32 - shift_distance);
568257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ or_(scratch2, Operand(scratch));
569257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Move down according to the exponent.
570257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ shr_cl(scratch2);
571257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Now the unsigned answer is in scratch2.  We need to move it to ecx and
572257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // we may need to fix the sign.
573257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Label negative;
574257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ xor_(ecx, Operand(ecx));
575257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ cmp(ecx, FieldOperand(source, HeapNumber::kExponentOffset));
576257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ j(greater, &negative, Label::kNear);
577257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ mov(ecx, scratch2);
578257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ jmp(&done, Label::kNear);
579257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ bind(&negative);
580257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ sub(ecx, Operand(scratch2));
581257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ bind(&done);
582257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
583257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch}
584257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
585257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5863fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdochvoid UnaryOpStub::PrintName(StringStream* stream) {
587257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  const char* op_name = Token::Name(op_);
588257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  const char* overwrite_name = NULL;  // Make g++ happy.
589257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  switch (mode_) {
590257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case UNARY_NO_OVERWRITE: overwrite_name = "Alloc"; break;
591257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case UNARY_OVERWRITE: overwrite_name = "Overwrite"; break;
592257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
5933fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  stream->Add("UnaryOpStub_%s_%s_%s",
5943fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch              op_name,
5953fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch              overwrite_name,
5963fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch              UnaryOpIC::GetName(operand_type_));
597257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch}
598257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
599257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
600257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// TODO(svenpanne): Use virtual functions instead of switch.
601257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::Generate(MacroAssembler* masm) {
602257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  switch (operand_type_) {
603257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case UnaryOpIC::UNINITIALIZED:
604257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      GenerateTypeTransition(masm);
605257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      break;
606257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case UnaryOpIC::SMI:
607257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      GenerateSmiStub(masm);
608257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      break;
609257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case UnaryOpIC::HEAP_NUMBER:
610257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      GenerateHeapNumberStub(masm);
611257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      break;
612257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case UnaryOpIC::GENERIC:
613257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      GenerateGenericStub(masm);
614257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      break;
615257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
616257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch}
617257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
618257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
619257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::GenerateTypeTransition(MacroAssembler* masm) {
620257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ pop(ecx);  // Save return address.
6213fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
6223fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ push(eax);  // the operand
623257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ push(Immediate(Smi::FromInt(op_)));
6243fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ push(Immediate(Smi::FromInt(mode_)));
625257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ push(Immediate(Smi::FromInt(operand_type_)));
626257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
627257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ push(ecx);  // Push return address.
628257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
629257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Patch the caller to an appropriate specialized stub and return the
630257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // operation result to the caller of the stub.
631257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ TailCallExternalReference(
6323fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch      ExternalReference(IC_Utility(IC::kUnaryOp_Patch), masm->isolate()), 4, 1);
633257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch}
634257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
635257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
636257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// TODO(svenpanne): Use virtual functions instead of switch.
637257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::GenerateSmiStub(MacroAssembler* masm) {
638257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  switch (op_) {
639257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case Token::SUB:
640257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      GenerateSmiStubSub(masm);
641257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      break;
642257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case Token::BIT_NOT:
643257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      GenerateSmiStubBitNot(masm);
644257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      break;
645257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    default:
646257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      UNREACHABLE();
647257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
648257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch}
649257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
650257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
651257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::GenerateSmiStubSub(MacroAssembler* masm) {
652257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label non_smi, undo, slow;
653257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  GenerateSmiCodeSub(masm, &non_smi, &undo, &slow,
654257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                     Label::kNear, Label::kNear, Label::kNear);
655257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&undo);
656257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  GenerateSmiCodeUndo(masm);
657257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&non_smi);
658257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&slow);
659257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  GenerateTypeTransition(masm);
660257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch}
661257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
662257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
663257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::GenerateSmiStubBitNot(MacroAssembler* masm) {
664257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label non_smi;
665257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  GenerateSmiCodeBitNot(masm, &non_smi);
666257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&non_smi);
667257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  GenerateTypeTransition(masm);
668257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch}
669257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
670257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
671257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::GenerateSmiCodeSub(MacroAssembler* masm,
672257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                     Label* non_smi,
673257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                     Label* undo,
674257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                     Label* slow,
675257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                     Label::Distance non_smi_near,
676257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                     Label::Distance undo_near,
677257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                     Label::Distance slow_near) {
678257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Check whether the value is a smi.
6793fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ JumpIfNotSmi(eax, non_smi, non_smi_near);
680257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
681257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // We can't handle -0 with smis, so use a type transition for that case.
682257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ test(eax, Operand(eax));
683257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(zero, slow, slow_near);
684257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
685257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Try optimistic subtraction '0 - value', saving operand in eax for undo.
686257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ mov(edx, Operand(eax));
687257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Set(eax, Immediate(0));
688257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ sub(eax, Operand(edx));
689257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(overflow, undo, undo_near);
690257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ ret(0);
691257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch}
692257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
693257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
694257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::GenerateSmiCodeBitNot(
695257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    MacroAssembler* masm,
696257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Label* non_smi,
697257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Label::Distance non_smi_near) {
698257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Check whether the value is a smi.
6993fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ JumpIfNotSmi(eax, non_smi, non_smi_near);
700257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
701257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Flip bits and revert inverted smi-tag.
702257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ not_(eax);
703257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ and_(eax, ~kSmiTagMask);
704257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ ret(0);
705257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch}
706257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
707257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
708257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::GenerateSmiCodeUndo(MacroAssembler* masm) {
709257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ mov(eax, Operand(edx));
710257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch}
711257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
712257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
713257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// TODO(svenpanne): Use virtual functions instead of switch.
714257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::GenerateHeapNumberStub(MacroAssembler* masm) {
715257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  switch (op_) {
716257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case Token::SUB:
717257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      GenerateHeapNumberStubSub(masm);
718257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      break;
719257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case Token::BIT_NOT:
720257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      GenerateHeapNumberStubBitNot(masm);
721257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      break;
722257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    default:
723257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      UNREACHABLE();
724257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
725257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch}
726257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
727257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
728257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::GenerateHeapNumberStubSub(MacroAssembler* masm) {
729257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label non_smi, undo, slow, call_builtin;
730257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  GenerateSmiCodeSub(masm, &non_smi, &undo, &call_builtin, Label::kNear);
731257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&non_smi);
732257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  GenerateHeapNumberCodeSub(masm, &slow);
733257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&undo);
734257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  GenerateSmiCodeUndo(masm);
735257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&slow);
736257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  GenerateTypeTransition(masm);
737257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&call_builtin);
738257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  GenerateGenericCodeFallback(masm);
739257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch}
740257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
741257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
742257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::GenerateHeapNumberStubBitNot(
743257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    MacroAssembler* masm) {
744257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label non_smi, slow;
745257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  GenerateSmiCodeBitNot(masm, &non_smi, Label::kNear);
746257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&non_smi);
747257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  GenerateHeapNumberCodeBitNot(masm, &slow);
748257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&slow);
749257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  GenerateTypeTransition(masm);
750257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch}
751257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
752257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
753257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::GenerateHeapNumberCodeSub(MacroAssembler* masm,
754257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                            Label* slow) {
755257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ mov(edx, FieldOperand(eax, HeapObject::kMapOffset));
756257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ cmp(edx, masm->isolate()->factory()->heap_number_map());
757257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(not_equal, slow);
758257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
759257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  if (mode_ == UNARY_OVERWRITE) {
760257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ xor_(FieldOperand(eax, HeapNumber::kExponentOffset),
761257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch            Immediate(HeapNumber::kSignMask));  // Flip sign.
762257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  } else {
763257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ mov(edx, Operand(eax));
764257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // edx: operand
765257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
766257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Label slow_allocate_heapnumber, heapnumber_allocated;
767257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ AllocateHeapNumber(eax, ebx, ecx, &slow_allocate_heapnumber);
76869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    __ jmp(&heapnumber_allocated, Label::kNear);
769257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
770257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ bind(&slow_allocate_heapnumber);
771257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ EnterInternalFrame();
772257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ push(edx);
773257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ CallRuntime(Runtime::kNumberAlloc, 0);
774257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ pop(edx);
775257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ LeaveInternalFrame();
776257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
777257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ bind(&heapnumber_allocated);
778257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // eax: allocated 'empty' number
779257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ mov(ecx, FieldOperand(edx, HeapNumber::kExponentOffset));
780257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ xor_(ecx, HeapNumber::kSignMask);  // Flip sign.
781257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ mov(FieldOperand(eax, HeapNumber::kExponentOffset), ecx);
782257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ mov(ecx, FieldOperand(edx, HeapNumber::kMantissaOffset));
783257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ mov(FieldOperand(eax, HeapNumber::kMantissaOffset), ecx);
784257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
785257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ ret(0);
786257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch}
787257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
788257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
789257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::GenerateHeapNumberCodeBitNot(MacroAssembler* masm,
790257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                               Label* slow) {
791257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ mov(edx, FieldOperand(eax, HeapObject::kMapOffset));
792257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ cmp(edx, masm->isolate()->factory()->heap_number_map());
793257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(not_equal, slow);
794257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
795257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Convert the heap number in eax to an untagged integer in ecx.
796257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  IntegerConvert(masm, eax, CpuFeatures::IsSupported(SSE3), slow);
797257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
798257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Do the bitwise operation and check if the result fits in a smi.
799257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label try_float;
800257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ not_(ecx);
801257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ cmp(ecx, 0xc0000000);
802257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(sign, &try_float, Label::kNear);
803257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
804257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Tag the result as a smi and we're done.
805257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  STATIC_ASSERT(kSmiTagSize == 1);
806257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ lea(eax, Operand(ecx, times_2, kSmiTag));
807257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ ret(0);
808257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
809257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Try to store the result in a heap number.
810257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&try_float);
811257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  if (mode_ == UNARY_NO_OVERWRITE) {
812257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Label slow_allocate_heapnumber, heapnumber_allocated;
813257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ mov(ebx, eax);
814257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ AllocateHeapNumber(eax, edx, edi, &slow_allocate_heapnumber);
815257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ jmp(&heapnumber_allocated);
816257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
817257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ bind(&slow_allocate_heapnumber);
818257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ EnterInternalFrame();
819257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Push the original HeapNumber on the stack. The integer value can't
820257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // be stored since it's untagged and not in the smi range (so we can't
821257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // smi-tag it). We'll recalculate the value after the GC instead.
822257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ push(ebx);
823257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ CallRuntime(Runtime::kNumberAlloc, 0);
824257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // New HeapNumber is in eax.
825257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ pop(edx);
826257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ LeaveInternalFrame();
827257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // IntegerConvert uses ebx and edi as scratch registers.
828257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // This conversion won't go slow-case.
829257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    IntegerConvert(masm, edx, CpuFeatures::IsSupported(SSE3), slow);
830257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ not_(ecx);
831257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
832257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ bind(&heapnumber_allocated);
833257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
834257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  if (CpuFeatures::IsSupported(SSE2)) {
835257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    CpuFeatures::Scope use_sse2(SSE2);
836257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ cvtsi2sd(xmm0, Operand(ecx));
837257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0);
838257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  } else {
839257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ push(ecx);
840257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ fild_s(Operand(esp, 0));
841257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ pop(ecx);
842257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset));
843257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
844257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ ret(0);
845257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch}
846257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
847257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
848257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// TODO(svenpanne): Use virtual functions instead of switch.
849257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::GenerateGenericStub(MacroAssembler* masm) {
850257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  switch (op_) {
851257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case Token::SUB:
852257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      GenerateGenericStubSub(masm);
853257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      break;
854257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case Token::BIT_NOT:
855257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      GenerateGenericStubBitNot(masm);
856257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      break;
857257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    default:
858257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      UNREACHABLE();
859257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
860257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch}
861257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
862257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
863257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::GenerateGenericStubSub(MacroAssembler* masm)  {
864257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label non_smi, undo, slow;
865257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  GenerateSmiCodeSub(masm, &non_smi, &undo, &slow, Label::kNear);
866257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&non_smi);
867257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  GenerateHeapNumberCodeSub(masm, &slow);
868257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&undo);
869257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  GenerateSmiCodeUndo(masm);
870257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&slow);
871257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  GenerateGenericCodeFallback(masm);
872257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch}
873257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
874257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
875257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::GenerateGenericStubBitNot(MacroAssembler* masm) {
876257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label non_smi, slow;
877257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  GenerateSmiCodeBitNot(masm, &non_smi, Label::kNear);
878257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&non_smi);
879257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  GenerateHeapNumberCodeBitNot(masm, &slow);
880257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&slow);
881257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  GenerateGenericCodeFallback(masm);
882257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch}
883257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
884257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
885257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::GenerateGenericCodeFallback(MacroAssembler* masm) {
886257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Handle the slow case by jumping to the corresponding JavaScript builtin.
887257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ pop(ecx);  // pop return address.
888257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ push(eax);
889257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ push(ecx);  // push return address
890257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  switch (op_) {
891257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case Token::SUB:
892257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ InvokeBuiltin(Builtins::UNARY_MINUS, JUMP_FUNCTION);
893257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      break;
894257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case Token::BIT_NOT:
895257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ InvokeBuiltin(Builtins::BIT_NOT, JUMP_FUNCTION);
896257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      break;
897257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    default:
898257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      UNREACHABLE();
899257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
900257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch}
901b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
902b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
903257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid BinaryOpStub::GenerateTypeTransition(MacroAssembler* masm) {
904b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ pop(ecx);  // Save return address.
905b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ push(edx);
906b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ push(eax);
907b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Left and right arguments are now on top.
908b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Push this stub's key. Although the operation and the type info are
909b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // encoded into the key, the encoding is opaque, so push them too.
910b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ push(Immediate(Smi::FromInt(MinorKey())));
911b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ push(Immediate(Smi::FromInt(op_)));
912b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ push(Immediate(Smi::FromInt(operands_type_)));
913b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
914b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ push(ecx);  // Push return address.
915b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
916b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Patch the caller to an appropriate specialized stub and return the
917b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // operation result to the caller of the stub.
918b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ TailCallExternalReference(
919257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      ExternalReference(IC_Utility(IC::kBinaryOp_Patch),
92044f0eee88ff00398ff7f715fab053374d808c90dSteve Block                        masm->isolate()),
921b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      5,
922b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      1);
923b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch}
924b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
925b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
926b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch// Prepare for a type transition runtime call when the args are already on
927b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch// the stack, under the return address.
928257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid BinaryOpStub::GenerateTypeTransitionWithSavedArgs(MacroAssembler* masm) {
929b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ pop(ecx);  // Save return address.
930b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Left and right arguments are already on top of the stack.
931b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Push this stub's key. Although the operation and the type info are
932b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // encoded into the key, the encoding is opaque, so push them too.
933b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ push(Immediate(Smi::FromInt(MinorKey())));
934b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ push(Immediate(Smi::FromInt(op_)));
935b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ push(Immediate(Smi::FromInt(operands_type_)));
936b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
937b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ push(ecx);  // Push return address.
938b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
939b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Patch the caller to an appropriate specialized stub and return the
940b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // operation result to the caller of the stub.
941b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ TailCallExternalReference(
942257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      ExternalReference(IC_Utility(IC::kBinaryOp_Patch),
94344f0eee88ff00398ff7f715fab053374d808c90dSteve Block                        masm->isolate()),
944b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      5,
945b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      1);
946b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch}
947b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
948b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
949257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid BinaryOpStub::Generate(MacroAssembler* masm) {
950b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  switch (operands_type_) {
951257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case BinaryOpIC::UNINITIALIZED:
952b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      GenerateTypeTransition(masm);
953b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
954257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case BinaryOpIC::SMI:
955b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      GenerateSmiStub(masm);
956b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
957257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case BinaryOpIC::INT32:
958b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      GenerateInt32Stub(masm);
959b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
960257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case BinaryOpIC::HEAP_NUMBER:
961b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      GenerateHeapNumberStub(masm);
962b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
963257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case BinaryOpIC::ODDBALL:
96444f0eee88ff00398ff7f715fab053374d808c90dSteve Block      GenerateOddballStub(masm);
96544f0eee88ff00398ff7f715fab053374d808c90dSteve Block      break;
966257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case BinaryOpIC::BOTH_STRING:
967257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      GenerateBothStringStub(masm);
968257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      break;
969257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case BinaryOpIC::STRING:
970b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      GenerateStringStub(masm);
971b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
972257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case BinaryOpIC::GENERIC:
973b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      GenerateGeneric(masm);
974b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
975b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    default:
976b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      UNREACHABLE();
977b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  }
978b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch}
979b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
980b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
9813fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdochvoid BinaryOpStub::PrintName(StringStream* stream) {
982b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  const char* op_name = Token::Name(op_);
983b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  const char* overwrite_name;
984b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  switch (mode_) {
985b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case NO_OVERWRITE: overwrite_name = "Alloc"; break;
986b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case OVERWRITE_RIGHT: overwrite_name = "OverwriteRight"; break;
987b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case OVERWRITE_LEFT: overwrite_name = "OverwriteLeft"; break;
988b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    default: overwrite_name = "UnknownOverwrite"; break;
989b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  }
9903fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  stream->Add("BinaryOpStub_%s_%s_%s",
9913fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch              op_name,
9923fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch              overwrite_name,
9933fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch              BinaryOpIC::GetName(operands_type_));
994b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch}
995b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
996b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
997257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid BinaryOpStub::GenerateSmiCode(
998257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    MacroAssembler* masm,
999b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    Label* slow,
1000b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    SmiCodeGenerateHeapNumberResults allow_heapnumber_results) {
1001b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // 1. Move arguments into edx, eax except for DIV and MOD, which need the
1002b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // dividend in eax and edx free for the division.  Use eax, ebx for those.
1003b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  Comment load_comment(masm, "-- Load arguments");
1004b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  Register left = edx;
1005b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  Register right = eax;
1006b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  if (op_ == Token::DIV || op_ == Token::MOD) {
1007b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    left = eax;
1008b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    right = ebx;
1009b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ mov(ebx, eax);
1010b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ mov(eax, edx);
1011b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  }
1012b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1013b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1014b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // 2. Prepare the smi check of both operands by oring them together.
1015b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  Comment smi_check_comment(masm, "-- Smi check arguments");
1016b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  Label not_smis;
1017b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  Register combined = ecx;
1018b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  ASSERT(!left.is(combined) && !right.is(combined));
1019b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  switch (op_) {
1020b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::BIT_OR:
1021b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // Perform the operation into eax and smi check the result.  Preserve
1022b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // eax in case the result is not a smi.
1023b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      ASSERT(!left.is(ecx) && !right.is(ecx));
1024b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ mov(ecx, right);
1025b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ or_(right, Operand(left));  // Bitwise or is commutative.
1026b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      combined = right;
1027b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1028b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1029b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::BIT_XOR:
1030b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::BIT_AND:
1031b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::ADD:
1032b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::SUB:
1033b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::MUL:
1034b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::DIV:
1035b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::MOD:
1036b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ mov(combined, right);
1037b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ or_(combined, Operand(left));
1038b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1039b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1040b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::SHL:
1041b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::SAR:
1042b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::SHR:
1043b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // Move the right operand into ecx for the shift operation, use eax
1044b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // for the smi check register.
1045b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      ASSERT(!left.is(ecx) && !right.is(ecx));
1046b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ mov(ecx, right);
1047b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ or_(right, Operand(left));
1048b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      combined = right;
1049b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1050b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1051b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    default:
1052b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1053b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  }
1054b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1055b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // 3. Perform the smi check of the operands.
1056b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  STATIC_ASSERT(kSmiTag == 0);  // Adjust zero check if not the case.
10573fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ JumpIfNotSmi(combined, &not_smis);
1058b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1059b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // 4. Operands are both smis, perform the operation leaving the result in
1060b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // eax and check the result if necessary.
1061b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  Comment perform_smi(masm, "-- Perform smi operation");
1062b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  Label use_fp_on_smis;
1063b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  switch (op_) {
1064b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::BIT_OR:
1065b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // Nothing to do.
1066b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1067b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1068b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::BIT_XOR:
1069b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      ASSERT(right.is(eax));
1070b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ xor_(right, Operand(left));  // Bitwise xor is commutative.
1071b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1072b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1073b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::BIT_AND:
1074b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      ASSERT(right.is(eax));
1075b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ and_(right, Operand(left));  // Bitwise and is commutative.
1076b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1077b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1078b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::SHL:
1079b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // Remove tags from operands (but keep sign).
1080b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ SmiUntag(left);
1081b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ SmiUntag(ecx);
1082b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // Perform the operation.
1083b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ shl_cl(left);
1084b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // Check that the *signed* result fits in a smi.
1085b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ cmp(left, 0xc0000000);
1086257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ j(sign, &use_fp_on_smis);
1087b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // Tag the result and store it in register eax.
1088b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ SmiTag(left);
1089b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ mov(eax, left);
1090b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1091b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1092b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::SAR:
1093b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // Remove tags from operands (but keep sign).
1094b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ SmiUntag(left);
1095b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ SmiUntag(ecx);
1096b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // Perform the operation.
1097b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ sar_cl(left);
1098b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // Tag the result and store it in register eax.
1099b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ SmiTag(left);
1100b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ mov(eax, left);
1101b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1102b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1103b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::SHR:
1104b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // Remove tags from operands (but keep sign).
1105b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ SmiUntag(left);
1106b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ SmiUntag(ecx);
1107b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // Perform the operation.
1108b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ shr_cl(left);
1109b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // Check that the *unsigned* result fits in a smi.
1110b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // Neither of the two high-order bits can be set:
1111b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // - 0x80000000: high bit would be lost when smi tagging.
1112b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // - 0x40000000: this number would convert to negative when
1113b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // Smi tagging these two cases can only happen with shifts
1114b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // by 0 or 1 when handed a valid smi.
1115b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ test(left, Immediate(0xc0000000));
1116257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ j(not_zero, &use_fp_on_smis);
1117b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // Tag the result and store it in register eax.
1118b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ SmiTag(left);
1119b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ mov(eax, left);
1120b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1121b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1122b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::ADD:
1123b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      ASSERT(right.is(eax));
1124b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ add(right, Operand(left));  // Addition is commutative.
1125257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ j(overflow, &use_fp_on_smis);
1126b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1127b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1128b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::SUB:
1129b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ sub(left, Operand(right));
1130257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ j(overflow, &use_fp_on_smis);
1131b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ mov(eax, left);
1132b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1133b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1134b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::MUL:
1135b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // If the smi tag is 0 we can just leave the tag on one operand.
1136b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      STATIC_ASSERT(kSmiTag == 0);  // Adjust code below if not the case.
1137b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // We can't revert the multiplication if the result is not a smi
1138b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // so save the right operand.
1139b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ mov(ebx, right);
1140b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // Remove tag from one of the operands (but keep sign).
1141b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ SmiUntag(right);
1142b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // Do multiplication.
1143b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ imul(right, Operand(left));  // Multiplication is commutative.
1144257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ j(overflow, &use_fp_on_smis);
1145b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // Check for negative zero result.  Use combined = left | right.
1146b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ NegativeZeroTest(right, combined, &use_fp_on_smis);
1147b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1148b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1149b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::DIV:
1150b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // We can't revert the division if the result is not a smi so
1151b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // save the left operand.
1152b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ mov(edi, left);
1153b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // Check for 0 divisor.
1154b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ test(right, Operand(right));
1155257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ j(zero, &use_fp_on_smis);
1156b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // Sign extend left into edx:eax.
1157b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      ASSERT(left.is(eax));
1158b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ cdq();
1159b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // Divide edx:eax by right.
1160b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ idiv(right);
1161b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // Check for the corner case of dividing the most negative smi by
1162b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // -1. We cannot use the overflow flag, since it is not set by idiv
1163b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // instruction.
1164b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize == 1);
1165b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ cmp(eax, 0x40000000);
1166b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ j(equal, &use_fp_on_smis);
1167b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // Check for negative zero result.  Use combined = left | right.
1168b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ NegativeZeroTest(eax, combined, &use_fp_on_smis);
1169b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // Check that the remainder is zero.
1170b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ test(edx, Operand(edx));
1171b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ j(not_zero, &use_fp_on_smis);
1172b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // Tag the result and store it in register eax.
1173b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ SmiTag(eax);
1174b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1175b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1176b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::MOD:
1177b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // Check for 0 divisor.
1178b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ test(right, Operand(right));
1179257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ j(zero, &not_smis);
1180b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1181b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // Sign extend left into edx:eax.
1182b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      ASSERT(left.is(eax));
1183b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ cdq();
1184b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // Divide edx:eax by right.
1185b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ idiv(right);
1186b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // Check for negative zero result.  Use combined = left | right.
1187b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ NegativeZeroTest(edx, combined, slow);
1188b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // Move remainder to register eax.
1189b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ mov(eax, edx);
1190b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1191b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1192b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    default:
1193b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      UNREACHABLE();
1194b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  }
1195b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1196b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // 5. Emit return of result in eax.  Some operations have registers pushed.
1197b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  switch (op_) {
1198b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::ADD:
1199b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::SUB:
1200b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::MUL:
1201b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::DIV:
1202b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ ret(0);
1203b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1204b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::MOD:
1205b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::BIT_OR:
1206b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::BIT_AND:
1207b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::BIT_XOR:
1208b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::SAR:
1209b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::SHL:
1210b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::SHR:
1211b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ ret(2 * kPointerSize);
1212b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1213b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    default:
1214b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      UNREACHABLE();
1215b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  }
1216b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1217b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // 6. For some operations emit inline code to perform floating point
1218b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // operations on known smis (e.g., if the result of the operation
1219b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // overflowed the smi range).
1220b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  if (allow_heapnumber_results == NO_HEAPNUMBER_RESULTS) {
1221b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ bind(&use_fp_on_smis);
1222b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    switch (op_) {
1223b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // Undo the effects of some operations, and some register moves.
1224b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      case Token::SHL:
1225b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        // The arguments are saved on the stack, and only used from there.
1226b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        break;
1227b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      case Token::ADD:
1228b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        // Revert right = right + left.
1229b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        __ sub(right, Operand(left));
1230b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        break;
1231b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      case Token::SUB:
1232b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        // Revert left = left - right.
1233b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        __ add(left, Operand(right));
1234b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        break;
1235b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      case Token::MUL:
1236b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        // Right was clobbered but a copy is in ebx.
1237b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        __ mov(right, ebx);
1238b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        break;
1239b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      case Token::DIV:
1240b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        // Left was clobbered but a copy is in edi.  Right is in ebx for
1241b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        // division.  They should be in eax, ebx for jump to not_smi.
1242b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        __ mov(eax, edi);
1243b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        break;
1244b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      default:
1245b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        // No other operators jump to use_fp_on_smis.
1246b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        break;
1247b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    }
1248b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ jmp(&not_smis);
1249b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  } else {
1250b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    ASSERT(allow_heapnumber_results == ALLOW_HEAPNUMBER_RESULTS);
1251b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    switch (op_) {
1252257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      case Token::SHL:
1253257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      case Token::SHR: {
1254b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        Comment perform_float(masm, "-- Perform float operation on smis");
1255b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        __ bind(&use_fp_on_smis);
1256b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        // Result we want is in left == edx, so we can put the allocated heap
1257b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        // number in eax.
1258b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        __ AllocateHeapNumber(eax, ecx, ebx, slow);
1259b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        // Store the result in the HeapNumber and return.
1260257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        // It's OK to overwrite the arguments on the stack because we
1261257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        // are about to return.
1262257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        if (op_ == Token::SHR) {
1263b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          __ mov(Operand(esp, 1 * kPointerSize), left);
1264257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          __ mov(Operand(esp, 2 * kPointerSize), Immediate(0));
1265257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          __ fild_d(Operand(esp, 1 * kPointerSize));
1266b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset));
1267257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        } else {
1268257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          ASSERT_EQ(Token::SHL, op_);
1269257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          if (CpuFeatures::IsSupported(SSE2)) {
1270257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch            CpuFeatures::Scope use_sse2(SSE2);
1271257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch            __ cvtsi2sd(xmm0, Operand(left));
1272257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch            __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0);
1273257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          } else {
1274257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch            __ mov(Operand(esp, 1 * kPointerSize), left);
1275257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch            __ fild_s(Operand(esp, 1 * kPointerSize));
1276257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch            __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset));
1277257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          }
1278b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        }
1279257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        __ ret(2 * kPointerSize);
1280257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        break;
1281b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      }
1282b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1283b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      case Token::ADD:
1284b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      case Token::SUB:
1285b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      case Token::MUL:
1286b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      case Token::DIV: {
1287b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        Comment perform_float(masm, "-- Perform float operation on smis");
1288b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        __ bind(&use_fp_on_smis);
1289b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        // Restore arguments to edx, eax.
1290b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        switch (op_) {
1291b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          case Token::ADD:
1292b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            // Revert right = right + left.
1293b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            __ sub(right, Operand(left));
1294b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            break;
1295b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          case Token::SUB:
1296b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            // Revert left = left - right.
1297b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            __ add(left, Operand(right));
1298b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            break;
1299b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          case Token::MUL:
1300b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            // Right was clobbered but a copy is in ebx.
1301b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            __ mov(right, ebx);
1302b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            break;
1303b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          case Token::DIV:
1304b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            // Left was clobbered but a copy is in edi.  Right is in ebx for
1305b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            // division.
1306b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            __ mov(edx, edi);
1307b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            __ mov(eax, right);
1308b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            break;
1309b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          default: UNREACHABLE();
1310b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            break;
1311b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        }
1312b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        __ AllocateHeapNumber(ecx, ebx, no_reg, slow);
13138b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch        if (CpuFeatures::IsSupported(SSE2)) {
1314b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          CpuFeatures::Scope use_sse2(SSE2);
1315b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          FloatingPointHelper::LoadSSE2Smis(masm, ebx);
1316b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          switch (op_) {
1317b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            case Token::ADD: __ addsd(xmm0, xmm1); break;
1318b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            case Token::SUB: __ subsd(xmm0, xmm1); break;
1319b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            case Token::MUL: __ mulsd(xmm0, xmm1); break;
1320b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            case Token::DIV: __ divsd(xmm0, xmm1); break;
1321b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            default: UNREACHABLE();
1322b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          }
1323b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          __ movdbl(FieldOperand(ecx, HeapNumber::kValueOffset), xmm0);
1324b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        } else {  // SSE2 not available, use FPU.
1325b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          FloatingPointHelper::LoadFloatSmis(masm, ebx);
1326b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          switch (op_) {
1327b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            case Token::ADD: __ faddp(1); break;
1328b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            case Token::SUB: __ fsubp(1); break;
1329b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            case Token::MUL: __ fmulp(1); break;
1330b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            case Token::DIV: __ fdivp(1); break;
1331b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            default: UNREACHABLE();
1332b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          }
1333b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          __ fstp_d(FieldOperand(ecx, HeapNumber::kValueOffset));
1334b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        }
1335b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        __ mov(eax, ecx);
1336b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        __ ret(0);
1337b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        break;
1338b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      }
1339b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1340b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      default:
1341b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        break;
1342b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    }
1343b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  }
1344b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1345b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // 7. Non-smi operands, fall out to the non-smi code with the operands in
1346b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // edx and eax.
1347b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  Comment done_comment(masm, "-- Enter non-smi code");
1348b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ bind(&not_smis);
1349b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  switch (op_) {
1350b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::BIT_OR:
1351b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::SHL:
1352b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::SAR:
1353b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::SHR:
1354b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // Right operand is saved in ecx and eax was destroyed by the smi
1355b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // check.
1356b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ mov(eax, ecx);
1357b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1358b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1359b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::DIV:
1360b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::MOD:
1361b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // Operands are in eax, ebx at this point.
1362b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ mov(edx, eax);
1363b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ mov(eax, ebx);
1364b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1365b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1366b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    default:
1367b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1368b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  }
1369b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch}
1370b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1371b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1372257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid BinaryOpStub::GenerateSmiStub(MacroAssembler* masm) {
1373b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  Label call_runtime;
1374b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1375b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  switch (op_) {
1376b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::ADD:
1377b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::SUB:
1378b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::MUL:
1379b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::DIV:
1380b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1381b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::MOD:
1382b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::BIT_OR:
1383b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::BIT_AND:
1384b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::BIT_XOR:
1385b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::SAR:
1386b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::SHL:
1387b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::SHR:
1388b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      GenerateRegisterArgsPush(masm);
1389b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1390b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    default:
1391b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      UNREACHABLE();
1392b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  }
1393b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1394257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  if (result_type_ == BinaryOpIC::UNINITIALIZED ||
1395257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      result_type_ == BinaryOpIC::SMI) {
1396b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    GenerateSmiCode(masm, &call_runtime, NO_HEAPNUMBER_RESULTS);
1397b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  } else {
1398b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    GenerateSmiCode(masm, &call_runtime, ALLOW_HEAPNUMBER_RESULTS);
1399b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  }
1400b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ bind(&call_runtime);
1401b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  switch (op_) {
1402b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::ADD:
1403b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::SUB:
1404b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::MUL:
1405b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::DIV:
1406b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      GenerateTypeTransition(masm);
1407b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1408b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::MOD:
1409b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::BIT_OR:
1410b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::BIT_AND:
1411b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::BIT_XOR:
1412b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::SAR:
1413b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::SHL:
1414b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::SHR:
1415b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      GenerateTypeTransitionWithSavedArgs(masm);
1416b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1417b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    default:
1418b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      UNREACHABLE();
1419b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  }
1420b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch}
1421b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1422b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1423257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid BinaryOpStub::GenerateStringStub(MacroAssembler* masm) {
1424257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  ASSERT(operands_type_ == BinaryOpIC::STRING);
1425b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  ASSERT(op_ == Token::ADD);
14261e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  // Try to add arguments as strings, otherwise, transition to the generic
1427257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // BinaryOpIC type.
14281e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  GenerateAddStrings(masm);
1429b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  GenerateTypeTransition(masm);
1430b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch}
1431b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1432b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1433257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid BinaryOpStub::GenerateBothStringStub(MacroAssembler* masm) {
1434257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label call_runtime;
1435257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  ASSERT(operands_type_ == BinaryOpIC::BOTH_STRING);
1436257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  ASSERT(op_ == Token::ADD);
1437257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // If both arguments are strings, call the string add stub.
1438257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Otherwise, do a transition.
1439257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1440257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Registers containing left and right operands respectively.
1441257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Register left = edx;
1442257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Register right = eax;
1443257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1444257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Test if left operand is a string.
144569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ JumpIfSmi(left, &call_runtime, Label::kNear);
1446257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ CmpObjectType(left, FIRST_NONSTRING_TYPE, ecx);
144769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ j(above_equal, &call_runtime, Label::kNear);
1448257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1449257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Test if right operand is a string.
145069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ JumpIfSmi(right, &call_runtime, Label::kNear);
1451257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ CmpObjectType(right, FIRST_NONSTRING_TYPE, ecx);
145269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ j(above_equal, &call_runtime, Label::kNear);
1453257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1454257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  StringAddStub string_add_stub(NO_STRING_CHECK_IN_STUB);
1455257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  GenerateRegisterArgsPush(masm);
1456257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ TailCallStub(&string_add_stub);
1457257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1458257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&call_runtime);
1459257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  GenerateTypeTransition(masm);
1460257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch}
1461257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1462257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1463257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid BinaryOpStub::GenerateInt32Stub(MacroAssembler* masm) {
1464b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  Label call_runtime;
1465257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  ASSERT(operands_type_ == BinaryOpIC::INT32);
1466b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1467b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Floating point case.
1468b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  switch (op_) {
1469b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::ADD:
1470b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::SUB:
1471b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::MUL:
1472b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::DIV: {
1473b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      Label not_floats;
1474b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      Label not_int32;
14758b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch      if (CpuFeatures::IsSupported(SSE2)) {
1476b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        CpuFeatures::Scope use_sse2(SSE2);
1477b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        FloatingPointHelper::LoadSSE2Operands(masm, &not_floats);
1478b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        FloatingPointHelper::CheckSSE2OperandsAreInt32(masm, &not_int32, ecx);
1479b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        switch (op_) {
1480b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          case Token::ADD: __ addsd(xmm0, xmm1); break;
1481b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          case Token::SUB: __ subsd(xmm0, xmm1); break;
1482b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          case Token::MUL: __ mulsd(xmm0, xmm1); break;
1483b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          case Token::DIV: __ divsd(xmm0, xmm1); break;
1484b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          default: UNREACHABLE();
1485b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        }
1486b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        // Check result type if it is currently Int32.
1487257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        if (result_type_ <= BinaryOpIC::INT32) {
1488b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          __ cvttsd2si(ecx, Operand(xmm0));
1489b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          __ cvtsi2sd(xmm2, Operand(ecx));
1490b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          __ ucomisd(xmm0, xmm2);
1491b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          __ j(not_zero, &not_int32);
1492b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          __ j(carry, &not_int32);
1493b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        }
1494b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        GenerateHeapResultAllocation(masm, &call_runtime);
1495b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0);
1496b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        __ ret(0);
1497b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      } else {  // SSE2 not available, use FPU.
1498b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        FloatingPointHelper::CheckFloatOperands(masm, &not_floats, ebx);
1499b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        FloatingPointHelper::LoadFloatOperands(
1500b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            masm,
1501b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            ecx,
1502b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            FloatingPointHelper::ARGS_IN_REGISTERS);
1503b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        FloatingPointHelper::CheckFloatOperandsAreInt32(masm, &not_int32);
1504b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        switch (op_) {
1505b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          case Token::ADD: __ faddp(1); break;
1506b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          case Token::SUB: __ fsubp(1); break;
1507b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          case Token::MUL: __ fmulp(1); break;
1508b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          case Token::DIV: __ fdivp(1); break;
1509b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          default: UNREACHABLE();
1510b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        }
1511b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        Label after_alloc_failure;
1512b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        GenerateHeapResultAllocation(masm, &after_alloc_failure);
1513b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset));
1514b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        __ ret(0);
1515b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        __ bind(&after_alloc_failure);
1516b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        __ ffree();
1517b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        __ jmp(&call_runtime);
1518b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      }
1519b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1520b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ bind(&not_floats);
1521b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ bind(&not_int32);
1522b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      GenerateTypeTransition(masm);
1523b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1524b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    }
1525b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1526b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::MOD: {
1527b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // For MOD we go directly to runtime in the non-smi case.
1528b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1529b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    }
1530b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::BIT_OR:
1531b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::BIT_AND:
1532b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::BIT_XOR:
1533b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::SAR:
1534b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::SHL:
1535b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::SHR: {
1536b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      GenerateRegisterArgsPush(masm);
1537b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      Label not_floats;
1538b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      Label not_int32;
1539b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      Label non_smi_result;
1540b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      /*  {
1541b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        CpuFeatures::Scope use_sse2(SSE2);
1542b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        FloatingPointHelper::LoadSSE2Operands(masm, &not_floats);
1543b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        FloatingPointHelper::CheckSSE2OperandsAreInt32(masm, &not_int32, ecx);
1544b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        }*/
1545b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      FloatingPointHelper::LoadUnknownsAsIntegers(masm,
1546b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                                                  use_sse3_,
1547b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                                                  &not_floats);
1548b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      FloatingPointHelper::CheckLoadedIntegersWereInt32(masm, use_sse3_,
1549b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                                                        &not_int32);
1550b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      switch (op_) {
1551b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        case Token::BIT_OR:  __ or_(eax, Operand(ecx)); break;
1552b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        case Token::BIT_AND: __ and_(eax, Operand(ecx)); break;
1553b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        case Token::BIT_XOR: __ xor_(eax, Operand(ecx)); break;
1554b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        case Token::SAR: __ sar_cl(eax); break;
1555b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        case Token::SHL: __ shl_cl(eax); break;
1556b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        case Token::SHR: __ shr_cl(eax); break;
1557b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        default: UNREACHABLE();
1558b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      }
1559b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      if (op_ == Token::SHR) {
1560b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        // Check if result is non-negative and fits in a smi.
1561b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        __ test(eax, Immediate(0xc0000000));
1562b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        __ j(not_zero, &call_runtime);
1563b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      } else {
1564b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        // Check if result fits in a smi.
1565b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        __ cmp(eax, 0xc0000000);
156669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch        __ j(negative, &non_smi_result, Label::kNear);
1567b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      }
1568b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // Tag smi result and return.
1569b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ SmiTag(eax);
1570b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ ret(2 * kPointerSize);  // Drop two pushed arguments from the stack.
1571b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1572b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // All ops except SHR return a signed int32 that we load in
1573b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // a HeapNumber.
1574b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      if (op_ != Token::SHR) {
1575b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        __ bind(&non_smi_result);
1576b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        // Allocate a heap number if needed.
1577b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        __ mov(ebx, Operand(eax));  // ebx: result
1578257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        Label skip_allocation;
1579b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        switch (mode_) {
1580b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          case OVERWRITE_LEFT:
1581b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          case OVERWRITE_RIGHT:
1582b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            // If the operand was an object, we skip the
1583b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            // allocation of a heap number.
1584b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            __ mov(eax, Operand(esp, mode_ == OVERWRITE_RIGHT ?
1585b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                                1 * kPointerSize : 2 * kPointerSize));
15863fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch            __ JumpIfNotSmi(eax, &skip_allocation, Label::kNear);
1587b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            // Fall through!
1588b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          case NO_OVERWRITE:
1589b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            __ AllocateHeapNumber(eax, ecx, edx, &call_runtime);
1590b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            __ bind(&skip_allocation);
1591b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            break;
1592b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          default: UNREACHABLE();
1593b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        }
1594b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        // Store the result in the HeapNumber and return.
15958b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch        if (CpuFeatures::IsSupported(SSE2)) {
1596b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          CpuFeatures::Scope use_sse2(SSE2);
1597b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          __ cvtsi2sd(xmm0, Operand(ebx));
1598b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0);
1599b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        } else {
1600b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          __ mov(Operand(esp, 1 * kPointerSize), ebx);
1601b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          __ fild_s(Operand(esp, 1 * kPointerSize));
1602b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset));
1603b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        }
1604b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        __ ret(2 * kPointerSize);  // Drop two pushed arguments from the stack.
1605b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      }
1606b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1607b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ bind(&not_floats);
1608b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ bind(&not_int32);
1609b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      GenerateTypeTransitionWithSavedArgs(masm);
1610b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1611b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    }
1612b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    default: UNREACHABLE(); break;
1613b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  }
1614b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1615b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // If an allocation fails, or SHR or MOD hit a hard case,
1616b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // use the runtime system to get the correct result.
1617b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ bind(&call_runtime);
1618b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1619b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  switch (op_) {
1620b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::ADD:
1621b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      GenerateRegisterArgsPush(masm);
1622b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ InvokeBuiltin(Builtins::ADD, JUMP_FUNCTION);
1623b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1624b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::SUB:
1625b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      GenerateRegisterArgsPush(masm);
1626b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ InvokeBuiltin(Builtins::SUB, JUMP_FUNCTION);
1627b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1628b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::MUL:
1629b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      GenerateRegisterArgsPush(masm);
1630b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ InvokeBuiltin(Builtins::MUL, JUMP_FUNCTION);
1631b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1632b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::DIV:
1633b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      GenerateRegisterArgsPush(masm);
1634b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ InvokeBuiltin(Builtins::DIV, JUMP_FUNCTION);
1635b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1636b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::MOD:
1637b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      GenerateRegisterArgsPush(masm);
1638b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ InvokeBuiltin(Builtins::MOD, JUMP_FUNCTION);
1639b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1640b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::BIT_OR:
1641b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ InvokeBuiltin(Builtins::BIT_OR, JUMP_FUNCTION);
1642b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1643b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::BIT_AND:
1644b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ InvokeBuiltin(Builtins::BIT_AND, JUMP_FUNCTION);
1645b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1646b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::BIT_XOR:
1647b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ InvokeBuiltin(Builtins::BIT_XOR, JUMP_FUNCTION);
1648b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1649b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::SAR:
1650b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ InvokeBuiltin(Builtins::SAR, JUMP_FUNCTION);
1651b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1652b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::SHL:
1653b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ InvokeBuiltin(Builtins::SHL, JUMP_FUNCTION);
1654b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1655b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::SHR:
1656b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ InvokeBuiltin(Builtins::SHR, JUMP_FUNCTION);
1657b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1658b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    default:
1659b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      UNREACHABLE();
1660b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  }
1661b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch}
1662b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1663b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1664257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid BinaryOpStub::GenerateOddballStub(MacroAssembler* masm) {
166544f0eee88ff00398ff7f715fab053374d808c90dSteve Block  if (op_ == Token::ADD) {
166644f0eee88ff00398ff7f715fab053374d808c90dSteve Block    // Handle string addition here, because it is the only operation
166744f0eee88ff00398ff7f715fab053374d808c90dSteve Block    // that does not do a ToNumber conversion on the operands.
166844f0eee88ff00398ff7f715fab053374d808c90dSteve Block    GenerateAddStrings(masm);
166944f0eee88ff00398ff7f715fab053374d808c90dSteve Block  }
167044f0eee88ff00398ff7f715fab053374d808c90dSteve Block
1671257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Factory* factory = masm->isolate()->factory();
1672257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
167344f0eee88ff00398ff7f715fab053374d808c90dSteve Block  // Convert odd ball arguments to numbers.
1674257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label check, done;
1675257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ cmp(edx, factory->undefined_value());
1676257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(not_equal, &check, Label::kNear);
167744f0eee88ff00398ff7f715fab053374d808c90dSteve Block  if (Token::IsBitOp(op_)) {
167844f0eee88ff00398ff7f715fab053374d808c90dSteve Block    __ xor_(edx, Operand(edx));
167944f0eee88ff00398ff7f715fab053374d808c90dSteve Block  } else {
1680257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ mov(edx, Immediate(factory->nan_value()));
168144f0eee88ff00398ff7f715fab053374d808c90dSteve Block  }
1682257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ jmp(&done, Label::kNear);
168344f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ bind(&check);
1684257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ cmp(eax, factory->undefined_value());
1685257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(not_equal, &done, Label::kNear);
168644f0eee88ff00398ff7f715fab053374d808c90dSteve Block  if (Token::IsBitOp(op_)) {
168744f0eee88ff00398ff7f715fab053374d808c90dSteve Block    __ xor_(eax, Operand(eax));
168844f0eee88ff00398ff7f715fab053374d808c90dSteve Block  } else {
1689257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ mov(eax, Immediate(factory->nan_value()));
169044f0eee88ff00398ff7f715fab053374d808c90dSteve Block  }
169144f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ bind(&done);
169244f0eee88ff00398ff7f715fab053374d808c90dSteve Block
169344f0eee88ff00398ff7f715fab053374d808c90dSteve Block  GenerateHeapNumberStub(masm);
169444f0eee88ff00398ff7f715fab053374d808c90dSteve Block}
169544f0eee88ff00398ff7f715fab053374d808c90dSteve Block
169644f0eee88ff00398ff7f715fab053374d808c90dSteve Block
1697257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid BinaryOpStub::GenerateHeapNumberStub(MacroAssembler* masm) {
1698b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  Label call_runtime;
1699b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1700b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Floating point case.
1701b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  switch (op_) {
1702b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::ADD:
1703b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::SUB:
1704b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::MUL:
1705b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::DIV: {
1706b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      Label not_floats;
17078b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch      if (CpuFeatures::IsSupported(SSE2)) {
1708b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        CpuFeatures::Scope use_sse2(SSE2);
1709b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        FloatingPointHelper::LoadSSE2Operands(masm, &not_floats);
1710b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1711b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        switch (op_) {
1712b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          case Token::ADD: __ addsd(xmm0, xmm1); break;
1713b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          case Token::SUB: __ subsd(xmm0, xmm1); break;
1714b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          case Token::MUL: __ mulsd(xmm0, xmm1); break;
1715b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          case Token::DIV: __ divsd(xmm0, xmm1); break;
1716b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          default: UNREACHABLE();
1717b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        }
1718b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        GenerateHeapResultAllocation(masm, &call_runtime);
1719b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0);
1720b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        __ ret(0);
1721b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      } else {  // SSE2 not available, use FPU.
1722b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        FloatingPointHelper::CheckFloatOperands(masm, &not_floats, ebx);
1723b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        FloatingPointHelper::LoadFloatOperands(
1724b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            masm,
1725b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            ecx,
1726b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            FloatingPointHelper::ARGS_IN_REGISTERS);
1727b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        switch (op_) {
1728b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          case Token::ADD: __ faddp(1); break;
1729b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          case Token::SUB: __ fsubp(1); break;
1730b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          case Token::MUL: __ fmulp(1); break;
1731b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          case Token::DIV: __ fdivp(1); break;
1732b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          default: UNREACHABLE();
1733b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        }
1734b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        Label after_alloc_failure;
1735b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        GenerateHeapResultAllocation(masm, &after_alloc_failure);
1736b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset));
1737b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        __ ret(0);
1738b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        __ bind(&after_alloc_failure);
1739b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        __ ffree();
1740b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        __ jmp(&call_runtime);
1741b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      }
1742b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1743b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ bind(&not_floats);
1744b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      GenerateTypeTransition(masm);
1745b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1746b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    }
1747b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1748b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::MOD: {
1749b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // For MOD we go directly to runtime in the non-smi case.
1750b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1751b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    }
1752b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::BIT_OR:
1753b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::BIT_AND:
1754b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::BIT_XOR:
1755b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::SAR:
1756b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::SHL:
1757b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::SHR: {
1758b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      GenerateRegisterArgsPush(masm);
1759b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      Label not_floats;
1760b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      Label non_smi_result;
1761b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      FloatingPointHelper::LoadUnknownsAsIntegers(masm,
1762b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                                                  use_sse3_,
1763b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                                                  &not_floats);
1764b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      switch (op_) {
1765b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        case Token::BIT_OR:  __ or_(eax, Operand(ecx)); break;
1766b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        case Token::BIT_AND: __ and_(eax, Operand(ecx)); break;
1767b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        case Token::BIT_XOR: __ xor_(eax, Operand(ecx)); break;
1768b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        case Token::SAR: __ sar_cl(eax); break;
1769b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        case Token::SHL: __ shl_cl(eax); break;
1770b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        case Token::SHR: __ shr_cl(eax); break;
1771b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        default: UNREACHABLE();
1772b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      }
1773b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      if (op_ == Token::SHR) {
1774b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        // Check if result is non-negative and fits in a smi.
1775b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        __ test(eax, Immediate(0xc0000000));
1776b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        __ j(not_zero, &call_runtime);
1777b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      } else {
1778b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        // Check if result fits in a smi.
1779b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        __ cmp(eax, 0xc0000000);
178069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch        __ j(negative, &non_smi_result, Label::kNear);
1781b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      }
1782b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // Tag smi result and return.
1783b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ SmiTag(eax);
1784b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ ret(2 * kPointerSize);  // Drop two pushed arguments from the stack.
1785b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1786b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // All ops except SHR return a signed int32 that we load in
1787b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // a HeapNumber.
1788b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      if (op_ != Token::SHR) {
1789b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        __ bind(&non_smi_result);
1790b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        // Allocate a heap number if needed.
1791b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        __ mov(ebx, Operand(eax));  // ebx: result
1792257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        Label skip_allocation;
1793b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        switch (mode_) {
1794b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          case OVERWRITE_LEFT:
1795b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          case OVERWRITE_RIGHT:
1796b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            // If the operand was an object, we skip the
1797b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            // allocation of a heap number.
1798b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            __ mov(eax, Operand(esp, mode_ == OVERWRITE_RIGHT ?
1799b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                                1 * kPointerSize : 2 * kPointerSize));
18003fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch            __ JumpIfNotSmi(eax, &skip_allocation, Label::kNear);
1801b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            // Fall through!
1802b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          case NO_OVERWRITE:
1803b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            __ AllocateHeapNumber(eax, ecx, edx, &call_runtime);
1804b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            __ bind(&skip_allocation);
1805b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            break;
1806b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          default: UNREACHABLE();
1807b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        }
1808b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        // Store the result in the HeapNumber and return.
18098b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch        if (CpuFeatures::IsSupported(SSE2)) {
1810b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          CpuFeatures::Scope use_sse2(SSE2);
1811b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          __ cvtsi2sd(xmm0, Operand(ebx));
1812b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0);
1813b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        } else {
1814b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          __ mov(Operand(esp, 1 * kPointerSize), ebx);
1815b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          __ fild_s(Operand(esp, 1 * kPointerSize));
1816b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset));
1817b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        }
1818b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        __ ret(2 * kPointerSize);  // Drop two pushed arguments from the stack.
1819b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      }
1820b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1821b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ bind(&not_floats);
1822b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      GenerateTypeTransitionWithSavedArgs(masm);
1823b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1824b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    }
1825b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    default: UNREACHABLE(); break;
1826b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  }
1827b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1828b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // If an allocation fails, or SHR or MOD hit a hard case,
1829b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // use the runtime system to get the correct result.
1830b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ bind(&call_runtime);
1831b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1832b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  switch (op_) {
1833b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::ADD:
1834b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      GenerateRegisterArgsPush(masm);
1835b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ InvokeBuiltin(Builtins::ADD, JUMP_FUNCTION);
1836b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1837b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::SUB:
1838b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      GenerateRegisterArgsPush(masm);
1839b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ InvokeBuiltin(Builtins::SUB, JUMP_FUNCTION);
1840b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1841b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::MUL:
1842b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      GenerateRegisterArgsPush(masm);
1843b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ InvokeBuiltin(Builtins::MUL, JUMP_FUNCTION);
1844b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1845b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::DIV:
1846b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      GenerateRegisterArgsPush(masm);
1847b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ InvokeBuiltin(Builtins::DIV, JUMP_FUNCTION);
1848b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1849b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::MOD:
1850b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      GenerateRegisterArgsPush(masm);
1851b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ InvokeBuiltin(Builtins::MOD, JUMP_FUNCTION);
1852b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1853b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::BIT_OR:
1854b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ InvokeBuiltin(Builtins::BIT_OR, JUMP_FUNCTION);
1855b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1856b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::BIT_AND:
1857b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ InvokeBuiltin(Builtins::BIT_AND, JUMP_FUNCTION);
1858b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1859b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::BIT_XOR:
1860b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ InvokeBuiltin(Builtins::BIT_XOR, JUMP_FUNCTION);
1861b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1862b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::SAR:
1863b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ InvokeBuiltin(Builtins::SAR, JUMP_FUNCTION);
1864b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1865b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::SHL:
1866b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ InvokeBuiltin(Builtins::SHL, JUMP_FUNCTION);
1867b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1868b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::SHR:
1869b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ InvokeBuiltin(Builtins::SHR, JUMP_FUNCTION);
1870b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1871b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    default:
1872b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      UNREACHABLE();
1873b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  }
1874b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch}
1875b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1876b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1877257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid BinaryOpStub::GenerateGeneric(MacroAssembler* masm) {
1878b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  Label call_runtime;
1879b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
188044f0eee88ff00398ff7f715fab053374d808c90dSteve Block  Counters* counters = masm->isolate()->counters();
188144f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ IncrementCounter(counters->generic_binary_stub_calls(), 1);
1882b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1883b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  switch (op_) {
1884b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::ADD:
1885b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::SUB:
1886b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::MUL:
1887b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::DIV:
1888b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1889b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::MOD:
1890b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::BIT_OR:
1891b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::BIT_AND:
1892b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::BIT_XOR:
1893b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::SAR:
1894b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::SHL:
1895b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::SHR:
1896b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      GenerateRegisterArgsPush(masm);
1897b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1898b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    default:
1899b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      UNREACHABLE();
1900b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  }
1901b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1902b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  GenerateSmiCode(masm, &call_runtime, ALLOW_HEAPNUMBER_RESULTS);
1903b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1904b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Floating point case.
1905b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  switch (op_) {
1906b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::ADD:
1907b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::SUB:
1908b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::MUL:
1909b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::DIV: {
1910b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      Label not_floats;
19118b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch      if (CpuFeatures::IsSupported(SSE2)) {
1912b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        CpuFeatures::Scope use_sse2(SSE2);
1913b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        FloatingPointHelper::LoadSSE2Operands(masm, &not_floats);
1914b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1915b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        switch (op_) {
1916b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          case Token::ADD: __ addsd(xmm0, xmm1); break;
1917b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          case Token::SUB: __ subsd(xmm0, xmm1); break;
1918b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          case Token::MUL: __ mulsd(xmm0, xmm1); break;
1919b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          case Token::DIV: __ divsd(xmm0, xmm1); break;
1920b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          default: UNREACHABLE();
1921b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        }
1922b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        GenerateHeapResultAllocation(masm, &call_runtime);
1923b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0);
1924b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        __ ret(0);
1925b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      } else {  // SSE2 not available, use FPU.
1926b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        FloatingPointHelper::CheckFloatOperands(masm, &not_floats, ebx);
1927b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        FloatingPointHelper::LoadFloatOperands(
1928b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            masm,
1929b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            ecx,
1930b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            FloatingPointHelper::ARGS_IN_REGISTERS);
1931b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        switch (op_) {
1932b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          case Token::ADD: __ faddp(1); break;
1933b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          case Token::SUB: __ fsubp(1); break;
1934b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          case Token::MUL: __ fmulp(1); break;
1935b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          case Token::DIV: __ fdivp(1); break;
1936b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          default: UNREACHABLE();
1937b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        }
1938b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        Label after_alloc_failure;
1939b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        GenerateHeapResultAllocation(masm, &after_alloc_failure);
1940b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset));
1941b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        __ ret(0);
1942b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        __ bind(&after_alloc_failure);
1943b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          __ ffree();
1944b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          __ jmp(&call_runtime);
1945b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      }
1946b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        __ bind(&not_floats);
1947b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        break;
1948b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      }
1949b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::MOD: {
1950b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // For MOD we go directly to runtime in the non-smi case.
1951b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1952b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    }
1953b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::BIT_OR:
1954b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::BIT_AND:
1955b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      case Token::BIT_XOR:
1956b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::SAR:
1957b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::SHL:
1958b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::SHR: {
1959b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      Label non_smi_result;
1960b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      FloatingPointHelper::LoadUnknownsAsIntegers(masm,
1961b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                                                  use_sse3_,
1962b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                                                  &call_runtime);
1963b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      switch (op_) {
1964b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        case Token::BIT_OR:  __ or_(eax, Operand(ecx)); break;
1965b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        case Token::BIT_AND: __ and_(eax, Operand(ecx)); break;
1966b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        case Token::BIT_XOR: __ xor_(eax, Operand(ecx)); break;
1967b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        case Token::SAR: __ sar_cl(eax); break;
1968b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        case Token::SHL: __ shl_cl(eax); break;
1969b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        case Token::SHR: __ shr_cl(eax); break;
1970b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        default: UNREACHABLE();
1971b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      }
1972b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      if (op_ == Token::SHR) {
1973b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        // Check if result is non-negative and fits in a smi.
1974b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        __ test(eax, Immediate(0xc0000000));
1975b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        __ j(not_zero, &call_runtime);
1976b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      } else {
1977b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        // Check if result fits in a smi.
1978b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        __ cmp(eax, 0xc0000000);
197969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch        __ j(negative, &non_smi_result, Label::kNear);
1980b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      }
1981b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // Tag smi result and return.
1982b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ SmiTag(eax);
1983b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ ret(2 * kPointerSize);  // Drop the arguments from the stack.
1984b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1985b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // All ops except SHR return a signed int32 that we load in
1986b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // a HeapNumber.
1987b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      if (op_ != Token::SHR) {
1988b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        __ bind(&non_smi_result);
1989b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        // Allocate a heap number if needed.
1990b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        __ mov(ebx, Operand(eax));  // ebx: result
1991257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        Label skip_allocation;
1992b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        switch (mode_) {
1993b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          case OVERWRITE_LEFT:
1994b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          case OVERWRITE_RIGHT:
1995b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            // If the operand was an object, we skip the
1996b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch              // allocation of a heap number.
1997b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            __ mov(eax, Operand(esp, mode_ == OVERWRITE_RIGHT ?
1998b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                                1 * kPointerSize : 2 * kPointerSize));
19993fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch            __ JumpIfNotSmi(eax, &skip_allocation, Label::kNear);
2000b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            // Fall through!
2001b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          case NO_OVERWRITE:
2002b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            __ AllocateHeapNumber(eax, ecx, edx, &call_runtime);
2003b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            __ bind(&skip_allocation);
2004b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            break;
2005b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          default: UNREACHABLE();
2006b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        }
2007b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        // Store the result in the HeapNumber and return.
20088b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch        if (CpuFeatures::IsSupported(SSE2)) {
2009b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          CpuFeatures::Scope use_sse2(SSE2);
2010b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          __ cvtsi2sd(xmm0, Operand(ebx));
2011b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0);
2012b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        } else {
2013b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          __ mov(Operand(esp, 1 * kPointerSize), ebx);
2014b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          __ fild_s(Operand(esp, 1 * kPointerSize));
2015b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset));
2016b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        }
2017b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        __ ret(2 * kPointerSize);
2018b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      }
2019b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
2020b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    }
2021b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    default: UNREACHABLE(); break;
2022b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  }
2023b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
2024b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // If all else fails, use the runtime system to get the correct
2025b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // result.
2026b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ bind(&call_runtime);
2027b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  switch (op_) {
2028b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::ADD: {
20291e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      GenerateAddStrings(masm);
2030b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      GenerateRegisterArgsPush(masm);
2031b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ InvokeBuiltin(Builtins::ADD, JUMP_FUNCTION);
2032b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
2033b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    }
2034b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::SUB:
2035b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      GenerateRegisterArgsPush(masm);
2036b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ InvokeBuiltin(Builtins::SUB, JUMP_FUNCTION);
2037b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
2038b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::MUL:
2039b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      GenerateRegisterArgsPush(masm);
2040b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ InvokeBuiltin(Builtins::MUL, JUMP_FUNCTION);
2041b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
2042b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::DIV:
2043b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      GenerateRegisterArgsPush(masm);
2044b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ InvokeBuiltin(Builtins::DIV, JUMP_FUNCTION);
2045b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
2046b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::MOD:
2047b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ InvokeBuiltin(Builtins::MOD, JUMP_FUNCTION);
2048b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
2049b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::BIT_OR:
2050b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ InvokeBuiltin(Builtins::BIT_OR, JUMP_FUNCTION);
2051b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
2052b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::BIT_AND:
2053b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ InvokeBuiltin(Builtins::BIT_AND, JUMP_FUNCTION);
2054b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
2055b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::BIT_XOR:
2056b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ InvokeBuiltin(Builtins::BIT_XOR, JUMP_FUNCTION);
2057b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
2058b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::SAR:
2059b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ InvokeBuiltin(Builtins::SAR, JUMP_FUNCTION);
2060b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
2061b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::SHL:
2062b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ InvokeBuiltin(Builtins::SHL, JUMP_FUNCTION);
2063b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
2064b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::SHR:
2065b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ InvokeBuiltin(Builtins::SHR, JUMP_FUNCTION);
2066b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
2067b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    default:
2068b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      UNREACHABLE();
2069b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  }
2070b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch}
2071b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
2072b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
2073257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid BinaryOpStub::GenerateAddStrings(MacroAssembler* masm) {
2074e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  ASSERT(op_ == Token::ADD);
2075257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label left_not_string, call_runtime;
20761e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
20771e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  // Registers containing left and right operands respectively.
20781e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  Register left = edx;
20791e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  Register right = eax;
20801e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
20811e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  // Test if left operand is a string.
20823fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ JumpIfSmi(left, &left_not_string, Label::kNear);
20831e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  __ CmpObjectType(left, FIRST_NONSTRING_TYPE, ecx);
2084257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(above_equal, &left_not_string, Label::kNear);
20851e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
20861e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  StringAddStub string_add_left_stub(NO_STRING_CHECK_LEFT_IN_STUB);
20871e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  GenerateRegisterArgsPush(masm);
20881e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  __ TailCallStub(&string_add_left_stub);
20891e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
20901e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  // Left operand is not a string, test right.
20911e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  __ bind(&left_not_string);
20923fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ JumpIfSmi(right, &call_runtime, Label::kNear);
20931e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  __ CmpObjectType(right, FIRST_NONSTRING_TYPE, ecx);
2094257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(above_equal, &call_runtime, Label::kNear);
20951e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
20961e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  StringAddStub string_add_right_stub(NO_STRING_CHECK_RIGHT_IN_STUB);
20971e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  GenerateRegisterArgsPush(masm);
20981e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  __ TailCallStub(&string_add_right_stub);
20991e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
21001e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  // Neither argument is a string.
21011e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  __ bind(&call_runtime);
21021e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block}
21031e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
21041e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
2105257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid BinaryOpStub::GenerateHeapResultAllocation(
2106b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    MacroAssembler* masm,
2107b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    Label* alloc_failure) {
2108b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  Label skip_allocation;
2109b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  OverwriteMode mode = mode_;
2110b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  switch (mode) {
2111b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case OVERWRITE_LEFT: {
2112b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // If the argument in edx is already an object, we skip the
2113b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // allocation of a heap number.
21143fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch      __ JumpIfNotSmi(edx, &skip_allocation, Label::kNear);
2115b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // Allocate a heap number for the result. Keep eax and edx intact
2116b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // for the possible runtime call.
2117b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ AllocateHeapNumber(ebx, ecx, no_reg, alloc_failure);
2118b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // Now edx can be overwritten losing one of the arguments as we are
2119b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // now done and will not need it any more.
2120b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ mov(edx, Operand(ebx));
2121b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ bind(&skip_allocation);
2122b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // Use object in edx as a result holder
2123b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ mov(eax, Operand(edx));
2124b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
2125b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    }
2126b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case OVERWRITE_RIGHT:
2127b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // If the argument in eax is already an object, we skip the
2128b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // allocation of a heap number.
21293fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch      __ JumpIfNotSmi(eax, &skip_allocation, Label::kNear);
2130b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // Fall through!
2131b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case NO_OVERWRITE:
2132b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // Allocate a heap number for the result. Keep eax and edx intact
2133b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // for the possible runtime call.
2134b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ AllocateHeapNumber(ebx, ecx, no_reg, alloc_failure);
2135b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // Now eax can be overwritten losing one of the arguments as we are
2136b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // now done and will not need it any more.
2137b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ mov(eax, ebx);
2138b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ bind(&skip_allocation);
2139b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
2140b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    default: UNREACHABLE();
2141b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  }
2142b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch}
2143b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
2144b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
2145257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid BinaryOpStub::GenerateRegisterArgsPush(MacroAssembler* masm) {
214680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ pop(ecx);
2147b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ push(edx);
2148b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ push(eax);
214980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ push(ecx);
215080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
215180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
215280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
215380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid TranscendentalCacheStub::Generate(MacroAssembler* masm) {
2154b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // TAGGED case:
2155b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  //   Input:
2156b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  //     esp[4]: tagged number input argument (should be number).
2157b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  //     esp[0]: return address.
2158b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  //   Output:
2159b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  //     eax: tagged double result.
2160b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // UNTAGGED case:
2161b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  //   Input::
2162b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  //     esp[0]: return address.
2163b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  //     xmm1: untagged double input argument
2164b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  //   Output:
2165b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  //     xmm1: untagged double result.
2166b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
216780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label runtime_call;
216880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label runtime_call_clear_stack;
2169b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  Label skip_cache;
2170b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  const bool tagged = (argument_type_ == TAGGED);
2171b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  if (tagged) {
2172b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    // Test that eax is a number.
2173257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Label input_not_smi;
2174257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Label loaded;
2175b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ mov(eax, Operand(esp, kPointerSize));
21763fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    __ JumpIfNotSmi(eax, &input_not_smi, Label::kNear);
2177b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    // Input is a smi. Untag and load it onto the FPU stack.
2178b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    // Then load the low and high words of the double into ebx, edx.
2179b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    STATIC_ASSERT(kSmiTagSize == 1);
2180b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ sar(eax, 1);
2181b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ sub(Operand(esp), Immediate(2 * kPointerSize));
2182b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ mov(Operand(esp, 0), eax);
2183b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ fild_s(Operand(esp, 0));
2184b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ fst_d(Operand(esp, 0));
2185b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ pop(edx);
2186b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ pop(ebx);
2187257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ jmp(&loaded, Label::kNear);
2188b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ bind(&input_not_smi);
2189b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    // Check if input is a HeapNumber.
2190b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset));
219144f0eee88ff00398ff7f715fab053374d808c90dSteve Block    Factory* factory = masm->isolate()->factory();
219244f0eee88ff00398ff7f715fab053374d808c90dSteve Block    __ cmp(Operand(ebx), Immediate(factory->heap_number_map()));
2193b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ j(not_equal, &runtime_call);
2194b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    // Input is a HeapNumber. Push it on the FPU stack and load its
2195b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    // low and high words into ebx, edx.
2196b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ fld_d(FieldOperand(eax, HeapNumber::kValueOffset));
2197b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ mov(edx, FieldOperand(eax, HeapNumber::kExponentOffset));
2198b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ mov(ebx, FieldOperand(eax, HeapNumber::kMantissaOffset));
2199b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
2200b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ bind(&loaded);
2201b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  } else {  // UNTAGGED.
22028b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch    if (CpuFeatures::IsSupported(SSE4_1)) {
2203b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      CpuFeatures::Scope sse4_scope(SSE4_1);
2204b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ pextrd(Operand(edx), xmm1, 0x1);  // copy xmm1[63..32] to edx.
2205b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    } else {
2206b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ pshufd(xmm0, xmm1, 0x1);
2207b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ movd(Operand(edx), xmm0);
2208b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    }
2209b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ movd(Operand(ebx), xmm1);
2210b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  }
221180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
2212b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // ST[0] or xmm1  == double value
221380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // ebx = low 32 bits of double value
221480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // edx = high 32 bits of double value
221580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Compute hash (the shifts are arithmetic):
221680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  //   h = (low ^ high); h ^= h >> 16; h ^= h >> 8; h = h & (cacheSize - 1);
221780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(ecx, ebx);
221880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ xor_(ecx, Operand(edx));
221980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(eax, ecx);
222080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ sar(eax, 16);
222180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ xor_(ecx, Operand(eax));
222280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(eax, ecx);
222380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ sar(eax, 8);
222480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ xor_(ecx, Operand(eax));
222544f0eee88ff00398ff7f715fab053374d808c90dSteve Block  ASSERT(IsPowerOf2(TranscendentalCache::SubCache::kCacheSize));
222644f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ and_(Operand(ecx),
222744f0eee88ff00398ff7f715fab053374d808c90dSteve Block          Immediate(TranscendentalCache::SubCache::kCacheSize - 1));
222880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
2229b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // ST[0] or xmm1 == double value.
223080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // ebx = low 32 bits of double value.
223180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // edx = high 32 bits of double value.
223280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // ecx = TranscendentalCache::hash(double value).
223344f0eee88ff00398ff7f715fab053374d808c90dSteve Block  ExternalReference cache_array =
223444f0eee88ff00398ff7f715fab053374d808c90dSteve Block      ExternalReference::transcendental_cache_array_address(masm->isolate());
223544f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ mov(eax, Immediate(cache_array));
223644f0eee88ff00398ff7f715fab053374d808c90dSteve Block  int cache_array_index =
223744f0eee88ff00398ff7f715fab053374d808c90dSteve Block      type_ * sizeof(masm->isolate()->transcendental_cache()->caches_[0]);
223844f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ mov(eax, Operand(eax, cache_array_index));
223980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Eax points to the cache for the type type_.
224080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // If NULL, the cache hasn't been initialized yet, so go through runtime.
224180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ test(eax, Operand(eax));
224280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(zero, &runtime_call_clear_stack);
224380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#ifdef DEBUG
224480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check that the layout of cache elements match expectations.
224544f0eee88ff00398ff7f715fab053374d808c90dSteve Block  { TranscendentalCache::SubCache::Element test_elem[2];
224680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    char* elem_start = reinterpret_cast<char*>(&test_elem[0]);
224780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    char* elem2_start = reinterpret_cast<char*>(&test_elem[1]);
224880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    char* elem_in0  = reinterpret_cast<char*>(&(test_elem[0].in[0]));
224980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    char* elem_in1  = reinterpret_cast<char*>(&(test_elem[0].in[1]));
225080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    char* elem_out = reinterpret_cast<char*>(&(test_elem[0].output));
225180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    CHECK_EQ(12, elem2_start - elem_start);  // Two uint_32's and a pointer.
225280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    CHECK_EQ(0, elem_in0 - elem_start);
225380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    CHECK_EQ(kIntSize, elem_in1 - elem_start);
225480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    CHECK_EQ(2 * kIntSize, elem_out - elem_start);
225580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
225680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#endif
225780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Find the address of the ecx'th entry in the cache, i.e., &eax[ecx*12].
225880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ lea(ecx, Operand(ecx, ecx, times_2, 0));
225980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ lea(ecx, Operand(eax, ecx, times_4, 0));
226080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check if cache matches: Double value is stored in uint32_t[2] array.
2261257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label cache_miss;
226280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cmp(ebx, Operand(ecx, 0));
2263257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(not_equal, &cache_miss, Label::kNear);
226480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cmp(edx, Operand(ecx, kIntSize));
2265257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(not_equal, &cache_miss, Label::kNear);
226680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Cache hit!
226780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(eax, Operand(ecx, 2 * kIntSize));
2268b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  if (tagged) {
2269b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ fstp(0);
2270b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ ret(kPointerSize);
2271b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  } else {  // UNTAGGED.
2272b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ movdbl(xmm1, FieldOperand(eax, HeapNumber::kValueOffset));
2273b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ Ret();
2274b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  }
227580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
227680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&cache_miss);
227780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Update cache with new value.
227880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // We are short on registers, so use no_reg as scratch.
227980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // This gives slightly larger code.
2280b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  if (tagged) {
2281b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ AllocateHeapNumber(eax, edi, no_reg, &runtime_call_clear_stack);
2282b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  } else {  // UNTAGGED.
2283b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ AllocateHeapNumber(eax, edi, no_reg, &skip_cache);
2284b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ sub(Operand(esp), Immediate(kDoubleSize));
2285b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ movdbl(Operand(esp, 0), xmm1);
2286b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ fld_d(Operand(esp, 0));
2287b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ add(Operand(esp), Immediate(kDoubleSize));
2288b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  }
228980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  GenerateOperation(masm);
229080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(Operand(ecx, 0), ebx);
229180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(Operand(ecx, kIntSize), edx);
229280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(Operand(ecx, 2 * kIntSize), eax);
229380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset));
2294b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  if (tagged) {
2295b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ ret(kPointerSize);
2296b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  } else {  // UNTAGGED.
2297b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ movdbl(xmm1, FieldOperand(eax, HeapNumber::kValueOffset));
2298b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ Ret();
2299b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
2300b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    // Skip cache and return answer directly, only in untagged case.
2301b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ bind(&skip_cache);
2302b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ sub(Operand(esp), Immediate(kDoubleSize));
2303b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ movdbl(Operand(esp, 0), xmm1);
2304b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ fld_d(Operand(esp, 0));
2305b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    GenerateOperation(masm);
2306b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ fstp_d(Operand(esp, 0));
2307b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ movdbl(xmm1, Operand(esp, 0));
2308b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ add(Operand(esp), Immediate(kDoubleSize));
2309b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    // We return the value in xmm1 without adding it to the cache, but
2310b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    // we cause a scavenging GC so that future allocations will succeed.
2311b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ EnterInternalFrame();
2312b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    // Allocate an unused object bigger than a HeapNumber.
2313b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ push(Immediate(Smi::FromInt(2 * kDoubleSize)));
2314b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ CallRuntimeSaveDoubles(Runtime::kAllocateInNewSpace);
2315b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ LeaveInternalFrame();
2316b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ Ret();
2317b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  }
231880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
2319b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Call runtime, doing whatever allocation and cleanup is necessary.
2320b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  if (tagged) {
2321b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ bind(&runtime_call_clear_stack);
2322b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ fstp(0);
2323b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ bind(&runtime_call);
232444f0eee88ff00398ff7f715fab053374d808c90dSteve Block    ExternalReference runtime =
232544f0eee88ff00398ff7f715fab053374d808c90dSteve Block        ExternalReference(RuntimeFunction(), masm->isolate());
232644f0eee88ff00398ff7f715fab053374d808c90dSteve Block    __ TailCallExternalReference(runtime, 1, 1);
2327b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  } else {  // UNTAGGED.
2328b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ bind(&runtime_call_clear_stack);
2329b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ bind(&runtime_call);
2330b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ AllocateHeapNumber(eax, edi, no_reg, &skip_cache);
2331b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm1);
2332b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ EnterInternalFrame();
2333b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ push(eax);
2334b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ CallRuntime(RuntimeFunction(), 1);
2335b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ LeaveInternalFrame();
2336b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ movdbl(xmm1, FieldOperand(eax, HeapNumber::kValueOffset));
2337b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ Ret();
2338b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  }
233980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
234080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
234180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
234280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian MonsenRuntime::FunctionId TranscendentalCacheStub::RuntimeFunction() {
234380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  switch (type_) {
234480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    case TranscendentalCache::SIN: return Runtime::kMath_sin;
234580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    case TranscendentalCache::COS: return Runtime::kMath_cos;
2346b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case TranscendentalCache::LOG: return Runtime::kMath_log;
234780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    default:
234880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      UNIMPLEMENTED();
234980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      return Runtime::kAbort;
235080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
235180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
235280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
235380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
235480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid TranscendentalCacheStub::GenerateOperation(MacroAssembler* masm) {
235580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Only free register is edi.
2356b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Input value is on FP stack, and also in ebx/edx.
2357b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Input value is possibly in xmm1.
2358b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Address of result (a newly allocated HeapNumber) may be in eax.
2359b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  if (type_ == TranscendentalCache::SIN || type_ == TranscendentalCache::COS) {
2360b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    // Both fsin and fcos require arguments in the range +/-2^63 and
2361b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    // return NaN for infinities and NaN. They can share all code except
2362b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    // the actual fsin/fcos operation.
2363257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Label in_range, done;
2364b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    // If argument is outside the range -2^63..2^63, fsin/cos doesn't
2365b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    // work. We must reduce it to the appropriate range.
2366b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ mov(edi, edx);
2367b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ and_(Operand(edi), Immediate(0x7ff00000));  // Exponent only.
2368b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    int supported_exponent_limit =
2369b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        (63 + HeapNumber::kExponentBias) << HeapNumber::kExponentShift;
2370b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ cmp(Operand(edi), Immediate(supported_exponent_limit));
2371257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ j(below, &in_range, Label::kNear);
2372b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    // Check for infinity and NaN. Both return NaN for sin.
2373b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ cmp(Operand(edi), Immediate(0x7ff00000));
2374257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Label non_nan_result;
2375257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ j(not_equal, &non_nan_result, Label::kNear);
2376b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    // Input is +/-Infinity or NaN. Result is NaN.
2377b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ fstp(0);
2378b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    // NaN is represented by 0x7ff8000000000000.
2379b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ push(Immediate(0x7ff80000));
2380b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ push(Immediate(0));
2381b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ fld_d(Operand(esp, 0));
2382b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ add(Operand(esp), Immediate(2 * kPointerSize));
2383257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ jmp(&done, Label::kNear);
238480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
2385257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ bind(&non_nan_result);
238680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
2387257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Use fpmod to restrict argument to the range +/-2*PI.
2388257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ mov(edi, eax);  // Save eax before using fnstsw_ax.
2389257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ fldpi();
2390257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ fadd(0);
2391257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ fld(1);
2392257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // FPU Stack: input, 2*pi, input.
2393257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    {
2394257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      Label no_exceptions;
2395257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ fwait();
2396257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ fnstsw_ax();
2397257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // Clear if Illegal Operand or Zero Division exceptions are set.
2398257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ test(Operand(eax), Immediate(5));
2399257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ j(zero, &no_exceptions, Label::kNear);
2400257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ fnclex();
2401257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ bind(&no_exceptions);
2402257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    }
240380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
2404257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Compute st(0) % st(1)
2405257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    {
2406257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      Label partial_remainder_loop;
2407257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ bind(&partial_remainder_loop);
2408257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ fprem1();
2409257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ fwait();
2410257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ fnstsw_ax();
2411257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ test(Operand(eax), Immediate(0x400 /* C2 */));
2412257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // If C2 is set, computation only has partial result. Loop to
2413257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // continue computation.
2414257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ j(not_zero, &partial_remainder_loop);
2415257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    }
2416257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // FPU Stack: input, 2*pi, input % 2*pi
2417257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ fstp(2);
2418257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ fstp(0);
2419257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ mov(eax, edi);  // Restore eax (allocated HeapNumber pointer).
242080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
2421257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // FPU Stack: input % 2*pi
2422257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ bind(&in_range);
2423257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    switch (type_) {
2424257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      case TranscendentalCache::SIN:
2425257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        __ fsin();
2426257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        break;
2427257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      case TranscendentalCache::COS:
2428257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        __ fcos();
2429257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        break;
2430257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      default:
2431257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        UNREACHABLE();
243280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    }
2433257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ bind(&done);
2434257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  } else {
2435257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    ASSERT(type_ == TranscendentalCache::LOG);
2436257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ fldln2();
2437257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ fxch();
2438257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ fyl2x();
243980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
244080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
244180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
244280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
244380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// Input: edx, eax are the left and right objects of a bit op.
244480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// Output: eax, ecx are left and right integers for a bit op.
244580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid FloatingPointHelper::LoadUnknownsAsIntegers(MacroAssembler* masm,
244680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                                 bool use_sse3,
244780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                                 Label* conversion_failure) {
244880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check float operands.
244980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label arg1_is_object, check_undefined_arg1;
245080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label arg2_is_object, check_undefined_arg2;
245180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label load_arg2, done;
245280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
245380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Test if arg1 is a Smi.
245469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ JumpIfNotSmi(edx, &arg1_is_object, Label::kNear);
245580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
245680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiUntag(edx);
245780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ jmp(&load_arg2);
245880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
245980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // If the argument is undefined it converts to zero (ECMA-262, section 9.5).
246080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&check_undefined_arg1);
246144f0eee88ff00398ff7f715fab053374d808c90dSteve Block  Factory* factory = masm->isolate()->factory();
246244f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ cmp(edx, factory->undefined_value());
246380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(not_equal, conversion_failure);
246480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(edx, Immediate(0));
246580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ jmp(&load_arg2);
246680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
246780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&arg1_is_object);
246880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(ebx, FieldOperand(edx, HeapObject::kMapOffset));
246944f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ cmp(ebx, factory->heap_number_map());
247080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(not_equal, &check_undefined_arg1);
247180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
247280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Get the untagged integer version of the edx heap number in ecx.
2473257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  IntegerConvert(masm, edx, use_sse3, conversion_failure);
247480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(edx, ecx);
247580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
247680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Here edx has the untagged integer, eax has a Smi or a heap number.
247780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&load_arg2);
247880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
247980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Test if arg2 is a Smi.
248069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ JumpIfNotSmi(eax, &arg2_is_object, Label::kNear);
248180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
248280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiUntag(eax);
248380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(ecx, eax);
248480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ jmp(&done);
248580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
248680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // If the argument is undefined it converts to zero (ECMA-262, section 9.5).
248780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&check_undefined_arg2);
248844f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ cmp(eax, factory->undefined_value());
248980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(not_equal, conversion_failure);
249080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(ecx, Immediate(0));
249180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ jmp(&done);
249280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
249380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&arg2_is_object);
249480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset));
249544f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ cmp(ebx, factory->heap_number_map());
249680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(not_equal, &check_undefined_arg2);
249780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
249880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Get the untagged integer version of the eax heap number in ecx.
2499257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  IntegerConvert(masm, eax, use_sse3, conversion_failure);
250080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&done);
250180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(eax, edx);
250280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
250380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
250480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
2505b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdochvoid FloatingPointHelper::CheckLoadedIntegersWereInt32(MacroAssembler* masm,
2506b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                                                       bool use_sse3,
2507b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                                                       Label* not_int32) {
2508b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  return;
2509b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch}
2510b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
2511b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
251280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid FloatingPointHelper::LoadFloatOperand(MacroAssembler* masm,
251380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                           Register number) {
2514257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label load_smi, done;
251580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
25163fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ JumpIfSmi(number, &load_smi, Label::kNear);
251780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ fld_d(FieldOperand(number, HeapNumber::kValueOffset));
2518257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ jmp(&done, Label::kNear);
251980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
252080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&load_smi);
252180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiUntag(number);
252280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ push(number);
252380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ fild_s(Operand(esp, 0));
252480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ pop(number);
252580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
252680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&done);
252780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
252880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
252980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
253080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid FloatingPointHelper::LoadSSE2Operands(MacroAssembler* masm) {
2531257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label load_smi_edx, load_eax, load_smi_eax, done;
253280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Load operand in edx into xmm0.
25333fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ JumpIfSmi(edx, &load_smi_edx, Label::kNear);
253480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movdbl(xmm0, FieldOperand(edx, HeapNumber::kValueOffset));
253580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
253680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&load_eax);
253780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Load operand in eax into xmm1.
25383fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ JumpIfSmi(eax, &load_smi_eax, Label::kNear);
253980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movdbl(xmm1, FieldOperand(eax, HeapNumber::kValueOffset));
2540257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ jmp(&done, Label::kNear);
254180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
254280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&load_smi_edx);
254380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiUntag(edx);  // Untag smi before converting to float.
254480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cvtsi2sd(xmm0, Operand(edx));
254580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiTag(edx);  // Retag smi for heap number overwriting test.
254680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ jmp(&load_eax);
254780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
254880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&load_smi_eax);
254980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiUntag(eax);  // Untag smi before converting to float.
255080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cvtsi2sd(xmm1, Operand(eax));
255180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiTag(eax);  // Retag smi for heap number overwriting test.
255280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
255380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&done);
255480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
255580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
255680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
255780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid FloatingPointHelper::LoadSSE2Operands(MacroAssembler* masm,
255880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                           Label* not_numbers) {
2559257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label load_smi_edx, load_eax, load_smi_eax, load_float_eax, done;
256080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Load operand in edx into xmm0, or branch to not_numbers.
25613fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ JumpIfSmi(edx, &load_smi_edx, Label::kNear);
256244f0eee88ff00398ff7f715fab053374d808c90dSteve Block  Factory* factory = masm->isolate()->factory();
256344f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ cmp(FieldOperand(edx, HeapObject::kMapOffset), factory->heap_number_map());
256480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(not_equal, not_numbers);  // Argument in edx is not a number.
256580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movdbl(xmm0, FieldOperand(edx, HeapNumber::kValueOffset));
256680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&load_eax);
256780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Load operand in eax into xmm1, or branch to not_numbers.
25683fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ JumpIfSmi(eax, &load_smi_eax, Label::kNear);
256944f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ cmp(FieldOperand(eax, HeapObject::kMapOffset), factory->heap_number_map());
2570257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(equal, &load_float_eax, Label::kNear);
257180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ jmp(not_numbers);  // Argument in eax is not a number.
257280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&load_smi_edx);
257380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiUntag(edx);  // Untag smi before converting to float.
257480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cvtsi2sd(xmm0, Operand(edx));
257580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiTag(edx);  // Retag smi for heap number overwriting test.
257680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ jmp(&load_eax);
257780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&load_smi_eax);
257880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiUntag(eax);  // Untag smi before converting to float.
257980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cvtsi2sd(xmm1, Operand(eax));
258080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiTag(eax);  // Retag smi for heap number overwriting test.
2581257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ jmp(&done, Label::kNear);
258280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&load_float_eax);
258380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movdbl(xmm1, FieldOperand(eax, HeapNumber::kValueOffset));
258480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&done);
258580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
258680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
258780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
258880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid FloatingPointHelper::LoadSSE2Smis(MacroAssembler* masm,
258980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                       Register scratch) {
259080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  const Register left = edx;
259180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  const Register right = eax;
259280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(scratch, left);
259380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  ASSERT(!scratch.is(right));  // We're about to clobber scratch.
259480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiUntag(scratch);
259580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cvtsi2sd(xmm0, Operand(scratch));
259680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
259780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(scratch, right);
259880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiUntag(scratch);
259980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cvtsi2sd(xmm1, Operand(scratch));
260080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
260180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
260280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
2603b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdochvoid FloatingPointHelper::CheckSSE2OperandsAreInt32(MacroAssembler* masm,
2604b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                                                    Label* non_int32,
2605b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                                                    Register scratch) {
2606b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ cvttsd2si(scratch, Operand(xmm0));
2607b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ cvtsi2sd(xmm2, Operand(scratch));
2608b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ ucomisd(xmm0, xmm2);
2609b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ j(not_zero, non_int32);
2610b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ j(carry, non_int32);
2611b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ cvttsd2si(scratch, Operand(xmm1));
2612b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ cvtsi2sd(xmm2, Operand(scratch));
2613b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ ucomisd(xmm1, xmm2);
2614b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ j(not_zero, non_int32);
2615b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ j(carry, non_int32);
2616b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch}
2617b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
2618b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
261980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid FloatingPointHelper::LoadFloatOperands(MacroAssembler* masm,
262080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                            Register scratch,
262180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                            ArgLocation arg_location) {
2622257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label load_smi_1, load_smi_2, done_load_1, done;
262380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  if (arg_location == ARGS_IN_REGISTERS) {
262480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ mov(scratch, edx);
262580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  } else {
262680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ mov(scratch, Operand(esp, 2 * kPointerSize));
262780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
26283fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ JumpIfSmi(scratch, &load_smi_1, Label::kNear);
262980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ fld_d(FieldOperand(scratch, HeapNumber::kValueOffset));
263080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&done_load_1);
263180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
263280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  if (arg_location == ARGS_IN_REGISTERS) {
263380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ mov(scratch, eax);
263480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  } else {
263580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ mov(scratch, Operand(esp, 1 * kPointerSize));
263680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
26373fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ JumpIfSmi(scratch, &load_smi_2, Label::kNear);
263880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ fld_d(FieldOperand(scratch, HeapNumber::kValueOffset));
2639257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ jmp(&done, Label::kNear);
264080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
264180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&load_smi_1);
264280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiUntag(scratch);
264380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ push(scratch);
264480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ fild_s(Operand(esp, 0));
264580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ pop(scratch);
264680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ jmp(&done_load_1);
264780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
264880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&load_smi_2);
264980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiUntag(scratch);
265080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ push(scratch);
265180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ fild_s(Operand(esp, 0));
265280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ pop(scratch);
265380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
265480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&done);
265580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
265680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
265780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
265880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid FloatingPointHelper::LoadFloatSmis(MacroAssembler* masm,
265980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                        Register scratch) {
266080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  const Register left = edx;
266180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  const Register right = eax;
266280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(scratch, left);
266380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  ASSERT(!scratch.is(right));  // We're about to clobber scratch.
266480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiUntag(scratch);
266580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ push(scratch);
266680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ fild_s(Operand(esp, 0));
266780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
266880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(scratch, right);
266980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiUntag(scratch);
267080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(Operand(esp, 0), scratch);
267180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ fild_s(Operand(esp, 0));
267280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ pop(scratch);
267380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
267480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
267580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
267680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid FloatingPointHelper::CheckFloatOperands(MacroAssembler* masm,
267780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                             Label* non_float,
267880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                             Register scratch) {
2679257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label test_other, done;
268080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Test if both operands are floats or smi -> scratch=k_is_float;
268180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Otherwise scratch = k_not_float.
26823fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ JumpIfSmi(edx, &test_other, Label::kNear);
268380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(scratch, FieldOperand(edx, HeapObject::kMapOffset));
268444f0eee88ff00398ff7f715fab053374d808c90dSteve Block  Factory* factory = masm->isolate()->factory();
268544f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ cmp(scratch, factory->heap_number_map());
268680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(not_equal, non_float);  // argument in edx is not a number -> NaN
268780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
268880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&test_other);
26893fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ JumpIfSmi(eax, &done, Label::kNear);
269080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(scratch, FieldOperand(eax, HeapObject::kMapOffset));
269144f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ cmp(scratch, factory->heap_number_map());
269280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(not_equal, non_float);  // argument in eax is not a number -> NaN
269380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
269480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Fall-through: Both operands are numbers.
269580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&done);
269680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
269780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
269880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
2699b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdochvoid FloatingPointHelper::CheckFloatOperandsAreInt32(MacroAssembler* masm,
2700b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                                                     Label* non_int32) {
2701b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  return;
2702b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch}
2703b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
2704b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
2705b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdochvoid MathPowStub::Generate(MacroAssembler* masm) {
2706b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Registers are used as follows:
2707b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // edx = base
2708b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // eax = exponent
2709b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // ecx = temporary, result
2710b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
2711b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  CpuFeatures::Scope use_sse2(SSE2);
2712b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  Label allocate_return, call_runtime;
2713b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
2714b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Load input parameters.
2715b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ mov(edx, Operand(esp, 2 * kPointerSize));
2716b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ mov(eax, Operand(esp, 1 * kPointerSize));
2717b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
2718b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Save 1 in xmm3 - we need this several times later on.
2719b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ mov(ecx, Immediate(1));
2720b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ cvtsi2sd(xmm3, Operand(ecx));
2721b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
2722b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  Label exponent_nonsmi;
2723b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  Label base_nonsmi;
2724b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // If the exponent is a heap number go to that specific case.
27253fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ JumpIfNotSmi(eax, &exponent_nonsmi);
27263fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ JumpIfNotSmi(edx, &base_nonsmi);
2727b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
2728e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  // Optimized version when both exponent and base are smis.
2729b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  Label powi;
2730b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ SmiUntag(edx);
2731b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ cvtsi2sd(xmm0, Operand(edx));
2732b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ jmp(&powi);
2733b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // exponent is smi and base is a heapnumber.
2734b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ bind(&base_nonsmi);
273544f0eee88ff00398ff7f715fab053374d808c90dSteve Block  Factory* factory = masm->isolate()->factory();
2736b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ cmp(FieldOperand(edx, HeapObject::kMapOffset),
273744f0eee88ff00398ff7f715fab053374d808c90dSteve Block         factory->heap_number_map());
2738b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ j(not_equal, &call_runtime);
2739b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
2740b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ movdbl(xmm0, FieldOperand(edx, HeapNumber::kValueOffset));
2741b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
2742b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Optimized version of pow if exponent is a smi.
2743b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // xmm0 contains the base.
2744b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ bind(&powi);
2745b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ SmiUntag(eax);
2746b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
2747b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Save exponent in base as we need to check if exponent is negative later.
2748b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // We know that base and exponent are in different registers.
2749b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ mov(edx, eax);
2750b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
2751b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Get absolute value of exponent.
2752257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label no_neg;
2753b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ cmp(eax, 0);
2754257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(greater_equal, &no_neg, Label::kNear);
2755b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ neg(eax);
2756b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ bind(&no_neg);
2757b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
2758b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Load xmm1 with 1.
2759b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ movsd(xmm1, xmm3);
2760257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label while_true;
2761257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label no_multiply;
2762b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
2763b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ bind(&while_true);
2764b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ shr(eax, 1);
2765257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(not_carry, &no_multiply, Label::kNear);
2766b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ mulsd(xmm1, xmm0);
2767b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ bind(&no_multiply);
2768b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ mulsd(xmm0, xmm0);
2769b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ j(not_zero, &while_true);
2770b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
2771b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // base has the original value of the exponent - if the exponent  is
2772b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // negative return 1/result.
2773b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ test(edx, Operand(edx));
2774b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ j(positive, &allocate_return);
2775b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Special case if xmm1 has reached infinity.
2776b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ mov(ecx, Immediate(0x7FB00000));
2777b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ movd(xmm0, Operand(ecx));
2778b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ cvtss2sd(xmm0, xmm0);
2779b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ ucomisd(xmm0, xmm1);
2780b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ j(equal, &call_runtime);
2781b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ divsd(xmm3, xmm1);
2782b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ movsd(xmm1, xmm3);
2783b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ jmp(&allocate_return);
2784b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
2785b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // exponent (or both) is a heapnumber - no matter what we should now work
2786b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // on doubles.
2787b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ bind(&exponent_nonsmi);
2788b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ cmp(FieldOperand(eax, HeapObject::kMapOffset),
278944f0eee88ff00398ff7f715fab053374d808c90dSteve Block         factory->heap_number_map());
2790b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ j(not_equal, &call_runtime);
2791b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ movdbl(xmm1, FieldOperand(eax, HeapNumber::kValueOffset));
2792b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Test if exponent is nan.
2793b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ ucomisd(xmm1, xmm1);
2794b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ j(parity_even, &call_runtime);
2795b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
2796257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label base_not_smi;
2797257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label handle_special_cases;
27983fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ JumpIfNotSmi(edx, &base_not_smi, Label::kNear);
2799b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ SmiUntag(edx);
2800b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ cvtsi2sd(xmm0, Operand(edx));
2801257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ jmp(&handle_special_cases, Label::kNear);
2802b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
2803b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ bind(&base_not_smi);
2804b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ cmp(FieldOperand(edx, HeapObject::kMapOffset),
280544f0eee88ff00398ff7f715fab053374d808c90dSteve Block         factory->heap_number_map());
2806b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ j(not_equal, &call_runtime);
2807b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ mov(ecx, FieldOperand(edx, HeapNumber::kExponentOffset));
2808b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ and_(ecx, HeapNumber::kExponentMask);
2809b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ cmp(Operand(ecx), Immediate(HeapNumber::kExponentMask));
2810b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // base is NaN or +/-Infinity
2811b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ j(greater_equal, &call_runtime);
2812b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ movdbl(xmm0, FieldOperand(edx, HeapNumber::kValueOffset));
2813b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
2814b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // base is in xmm0 and exponent is in xmm1.
2815b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ bind(&handle_special_cases);
2816257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label not_minus_half;
2817b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Test for -0.5.
2818b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Load xmm2 with -0.5.
2819b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ mov(ecx, Immediate(0xBF000000));
2820b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ movd(xmm2, Operand(ecx));
2821b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ cvtss2sd(xmm2, xmm2);
2822b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // xmm2 now has -0.5.
2823b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ ucomisd(xmm2, xmm1);
2824257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(not_equal, &not_minus_half, Label::kNear);
2825b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
2826b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Calculates reciprocal of square root.
28271e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  // sqrtsd returns -0 when input is -0.  ECMA spec requires +0.
2828257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ xorps(xmm1, xmm1);
28291e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  __ addsd(xmm1, xmm0);
2830b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ sqrtsd(xmm1, xmm1);
28311e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  __ divsd(xmm3, xmm1);
28321e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  __ movsd(xmm1, xmm3);
2833b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ jmp(&allocate_return);
2834b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
2835b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Test for 0.5.
2836b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ bind(&not_minus_half);
2837b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Load xmm2 with 0.5.
2838b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Since xmm3 is 1 and xmm2 is -0.5 this is simply xmm2 + xmm3.
2839b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ addsd(xmm2, xmm3);
2840b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // xmm2 now has 0.5.
2841b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ ucomisd(xmm2, xmm1);
2842b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ j(not_equal, &call_runtime);
2843b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Calculates square root.
28441e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  // sqrtsd returns -0 when input is -0.  ECMA spec requires +0.
2845257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ xorps(xmm1, xmm1);
28461e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  __ addsd(xmm1, xmm0);
2847b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ sqrtsd(xmm1, xmm1);
2848b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
2849b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ bind(&allocate_return);
2850b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ AllocateHeapNumber(ecx, eax, edx, &call_runtime);
2851b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ movdbl(FieldOperand(ecx, HeapNumber::kValueOffset), xmm1);
2852b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ mov(eax, ecx);
2853e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ ret(2 * kPointerSize);
2854b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
2855b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ bind(&call_runtime);
2856b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ TailCallRuntime(Runtime::kMath_pow_cfunction, 2, 1);
2857b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch}
2858b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
2859b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
286080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid ArgumentsAccessStub::GenerateReadElement(MacroAssembler* masm) {
286180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // The key is in edx and the parameter count is in eax.
286280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
286380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // The displacement is used for skipping the frame pointer on the
286480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // stack. It is the offset of the last parameter (if any) relative
286580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // to the frame pointer.
286680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  static const int kDisplacement = 1 * kPointerSize;
286780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
286880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check that the key is a smi.
286980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label slow;
287069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ JumpIfNotSmi(edx, &slow, Label::kNear);
287180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
287280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check if the calling frame is an arguments adaptor frame.
2873257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label adaptor;
287480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(ebx, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
287580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(ecx, Operand(ebx, StandardFrameConstants::kContextOffset));
287680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cmp(Operand(ecx), Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
2877257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(equal, &adaptor, Label::kNear);
287880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
287980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check index against formal parameters count limit passed in
288080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // through register eax. Use unsigned comparison to get negative
288180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // check for free.
288280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cmp(edx, Operand(eax));
288369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ j(above_equal, &slow, Label::kNear);
288480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
288580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Read the argument from the stack and return it.
288680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  STATIC_ASSERT(kSmiTagSize == 1);
288780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  STATIC_ASSERT(kSmiTag == 0);  // Shifting code depends on these.
288880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ lea(ebx, Operand(ebp, eax, times_2, 0));
288980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ neg(edx);
289080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(eax, Operand(ebx, edx, times_2, kDisplacement));
289180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ ret(0);
289280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
289380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Arguments adaptor case: Check index against actual arguments
289480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // limit found in the arguments adaptor frame. Use unsigned
289580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // comparison to get negative check for free.
289680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&adaptor);
289780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(ecx, Operand(ebx, ArgumentsAdaptorFrameConstants::kLengthOffset));
289880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cmp(edx, Operand(ecx));
289969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ j(above_equal, &slow, Label::kNear);
290080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
290180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Read the argument from the stack and return it.
290280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  STATIC_ASSERT(kSmiTagSize == 1);
290380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  STATIC_ASSERT(kSmiTag == 0);  // Shifting code depends on these.
290480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ lea(ebx, Operand(ebx, ecx, times_2, 0));
290580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ neg(edx);
290680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(eax, Operand(ebx, edx, times_2, kDisplacement));
290780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ ret(0);
290880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
290980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Slow-case: Handle non-smi or out-of-bounds access to arguments
291080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // by calling the runtime system.
291180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&slow);
291280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ pop(ebx);  // Return address.
291380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ push(edx);
291480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ push(ebx);
291580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ TailCallRuntime(Runtime::kGetArgumentsProperty, 1, 1);
291680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
291780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
291880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
29193fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdochvoid ArgumentsAccessStub::GenerateNewNonStrictSlow(MacroAssembler* masm) {
292080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // esp[0] : return address
292180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // esp[4] : number of parameters
292280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // esp[8] : receiver displacement
29233fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // esp[12] : function
29243fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
29253fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // Check if the calling frame is an arguments adaptor frame.
29263fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  Label runtime;
29273fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ mov(edx, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
29283fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ mov(ecx, Operand(edx, StandardFrameConstants::kContextOffset));
29293fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ cmp(Operand(ecx), Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
29303fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ j(not_equal, &runtime, Label::kNear);
29313fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
29323fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // Patch the arguments.length and the parameters pointer.
29333fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ mov(ecx, Operand(edx, ArgumentsAdaptorFrameConstants::kLengthOffset));
29343fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ mov(Operand(esp, 1 * kPointerSize), ecx);
29353fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ lea(edx, Operand(edx, ecx, times_2,
29363fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch              StandardFrameConstants::kCallerSPOffset));
29373fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ mov(Operand(esp, 2 * kPointerSize), edx);
29383fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
29393fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ bind(&runtime);
29403fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ TailCallRuntime(Runtime::kNewArgumentsFast, 3, 1);
29413fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch}
29423fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
29433fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
29443fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdochvoid ArgumentsAccessStub::GenerateNewNonStrictFast(MacroAssembler* masm) {
29453fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // esp[0] : return address
29463fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // esp[4] : number of parameters (tagged)
29473fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // esp[8] : receiver displacement
29483fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // esp[12] : function
29493fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
29503fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // ebx = parameter count (tagged)
29513fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ mov(ebx, Operand(esp, 1 * kPointerSize));
29523fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
29533fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // Check if the calling frame is an arguments adaptor frame.
29543fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // TODO(rossberg): Factor out some of the bits that are shared with the other
29553fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // Generate* functions.
29563fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  Label runtime;
29573fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  Label adaptor_frame, try_allocate;
29583fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ mov(edx, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
29593fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ mov(ecx, Operand(edx, StandardFrameConstants::kContextOffset));
29603fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ cmp(Operand(ecx), Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
29613fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ j(equal, &adaptor_frame, Label::kNear);
29623fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
29633fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // No adaptor, parameter count = argument count.
29643fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ mov(ecx, ebx);
29653fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ jmp(&try_allocate, Label::kNear);
29663fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
29673fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // We have an adaptor frame. Patch the parameters pointer.
29683fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ bind(&adaptor_frame);
29693fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ mov(ecx, Operand(edx, ArgumentsAdaptorFrameConstants::kLengthOffset));
29703fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ lea(edx, Operand(edx, ecx, times_2,
29713fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch                      StandardFrameConstants::kCallerSPOffset));
29723fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ mov(Operand(esp, 2 * kPointerSize), edx);
29733fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
29743fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // ebx = parameter count (tagged)
29753fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // ecx = argument count (tagged)
29763fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // esp[4] = parameter count (tagged)
29773fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // esp[8] = address of receiver argument
29783fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // Compute the mapped parameter count = min(ebx, ecx) in ebx.
29793fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ cmp(ebx, Operand(ecx));
29803fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ j(less_equal, &try_allocate, Label::kNear);
29813fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ mov(ebx, ecx);
29823fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
29833fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ bind(&try_allocate);
29843fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
29853fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // Save mapped parameter count.
29863fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ push(ebx);
29873fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
29883fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // Compute the sizes of backing store, parameter map, and arguments object.
29893fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // 1. Parameter map, has 2 extra words containing context and backing store.
29903fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  const int kParameterMapHeaderSize =
29913fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch      FixedArray::kHeaderSize + 2 * kPointerSize;
29923fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  Label no_parameter_map;
29933fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ test(ebx, Operand(ebx));
29943fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ j(zero, &no_parameter_map, Label::kNear);
29953fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ lea(ebx, Operand(ebx, times_2, kParameterMapHeaderSize));
29963fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ bind(&no_parameter_map);
29973fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
29983fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // 2. Backing store.
29993fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ lea(ebx, Operand(ebx, ecx, times_2, FixedArray::kHeaderSize));
30003fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
30013fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // 3. Arguments object.
30023fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ add(Operand(ebx), Immediate(Heap::kArgumentsObjectSize));
30033fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
30043fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // Do the allocation of all three objects in one go.
30053fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ AllocateInNewSpace(ebx, eax, edx, edi, &runtime, TAG_OBJECT);
30063fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
30073fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // eax = address of new object(s) (tagged)
30083fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // ecx = argument count (tagged)
30093fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // esp[0] = mapped parameter count (tagged)
30103fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // esp[8] = parameter count (tagged)
30113fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // esp[12] = address of receiver argument
30123fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // Get the arguments boilerplate from the current (global) context into edi.
30133fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  Label has_mapped_parameters, copy;
30143fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ mov(edi, Operand(esi, Context::SlotOffset(Context::GLOBAL_INDEX)));
30153fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ mov(edi, FieldOperand(edi, GlobalObject::kGlobalContextOffset));
30163fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ mov(ebx, Operand(esp, 0 * kPointerSize));
30173fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ test(ebx, Operand(ebx));
30183fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ j(not_zero, &has_mapped_parameters, Label::kNear);
30193fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ mov(edi, Operand(edi,
30203fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch         Context::SlotOffset(Context::ARGUMENTS_BOILERPLATE_INDEX)));
30213fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ jmp(&copy, Label::kNear);
30223fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
30233fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ bind(&has_mapped_parameters);
30243fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ mov(edi, Operand(edi,
30253fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch            Context::SlotOffset(Context::ALIASED_ARGUMENTS_BOILERPLATE_INDEX)));
30263fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ bind(&copy);
30273fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
30283fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // eax = address of new object (tagged)
30293fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // ebx = mapped parameter count (tagged)
30303fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // ecx = argument count (tagged)
30313fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // edi = address of boilerplate object (tagged)
30323fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // esp[0] = mapped parameter count (tagged)
30333fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // esp[8] = parameter count (tagged)
30343fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // esp[12] = address of receiver argument
30353fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // Copy the JS object part.
30363fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  for (int i = 0; i < JSObject::kHeaderSize; i += kPointerSize) {
30373fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    __ mov(edx, FieldOperand(edi, i));
30383fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    __ mov(FieldOperand(eax, i), edx);
30393fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  }
30403fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
30413fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // Setup the callee in-object property.
30423fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  STATIC_ASSERT(Heap::kArgumentsCalleeIndex == 1);
30433fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ mov(edx, Operand(esp, 4 * kPointerSize));
30443fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ mov(FieldOperand(eax, JSObject::kHeaderSize +
30453fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch                      Heap::kArgumentsCalleeIndex * kPointerSize),
30463fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch         edx);
30473fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
30483fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // Use the length (smi tagged) and set that as an in-object property too.
30493fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  STATIC_ASSERT(Heap::kArgumentsLengthIndex == 0);
30503fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ mov(FieldOperand(eax, JSObject::kHeaderSize +
30513fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch                      Heap::kArgumentsLengthIndex * kPointerSize),
30523fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch         ecx);
30533fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
30543fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // Setup the elements pointer in the allocated arguments object.
30553fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // If we allocated a parameter map, edi will point there, otherwise to the
30563fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // backing store.
30573fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ lea(edi, Operand(eax, Heap::kArgumentsObjectSize));
30583fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ mov(FieldOperand(eax, JSObject::kElementsOffset), edi);
30593fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
30603fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // eax = address of new object (tagged)
30613fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // ebx = mapped parameter count (tagged)
30623fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // ecx = argument count (tagged)
30633fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // edi = address of parameter map or backing store (tagged)
30643fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // esp[0] = mapped parameter count (tagged)
30653fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // esp[8] = parameter count (tagged)
30663fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // esp[12] = address of receiver argument
30673fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // Free a register.
30683fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ push(eax);
30693fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
30703fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // Initialize parameter map. If there are no mapped arguments, we're done.
30713fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  Label skip_parameter_map;
30723fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ test(ebx, Operand(ebx));
30733fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ j(zero, &skip_parameter_map);
307480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
30753fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ mov(FieldOperand(edi, FixedArray::kMapOffset),
30763fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch         Immediate(FACTORY->non_strict_arguments_elements_map()));
30773fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ lea(eax, Operand(ebx, reinterpret_cast<intptr_t>(Smi::FromInt(2))));
30783fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ mov(FieldOperand(edi, FixedArray::kLengthOffset), eax);
30793fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ mov(FieldOperand(edi, FixedArray::kHeaderSize + 0 * kPointerSize), esi);
30803fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ lea(eax, Operand(edi, ebx, times_2, kParameterMapHeaderSize));
30813fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ mov(FieldOperand(edi, FixedArray::kHeaderSize + 1 * kPointerSize), eax);
30823fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
30833fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // Copy the parameter slots and the holes in the arguments.
30843fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // We need to fill in mapped_parameter_count slots. They index the context,
30853fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // where parameters are stored in reverse order, at
30863fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  //   MIN_CONTEXT_SLOTS .. MIN_CONTEXT_SLOTS+parameter_count-1
30873fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // The mapped parameter thus need to get indices
30883fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  //   MIN_CONTEXT_SLOTS+parameter_count-1 ..
30893fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  //       MIN_CONTEXT_SLOTS+parameter_count-mapped_parameter_count
30903fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // We loop from right to left.
30913fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  Label parameters_loop, parameters_test;
30923fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ push(ecx);
30933fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ mov(eax, Operand(esp, 2 * kPointerSize));
30943fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ mov(ebx, Immediate(Smi::FromInt(Context::MIN_CONTEXT_SLOTS)));
30953fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ add(ebx, Operand(esp, 4 * kPointerSize));
30963fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ sub(ebx, Operand(eax));
30973fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ mov(ecx, FACTORY->the_hole_value());
30983fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ mov(edx, edi);
30993fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ lea(edi, Operand(edi, eax, times_2, kParameterMapHeaderSize));
31003fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // eax = loop variable (tagged)
31013fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // ebx = mapping index (tagged)
31023fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // ecx = the hole value
31033fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // edx = address of parameter map (tagged)
31043fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // edi = address of backing store (tagged)
31053fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // esp[0] = argument count (tagged)
31063fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // esp[4] = address of new object (tagged)
31073fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // esp[8] = mapped parameter count (tagged)
31083fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // esp[16] = parameter count (tagged)
31093fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // esp[20] = address of receiver argument
31103fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ jmp(&parameters_test, Label::kNear);
31113fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
31123fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ bind(&parameters_loop);
31133fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ sub(Operand(eax), Immediate(Smi::FromInt(1)));
31143fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ mov(FieldOperand(edx, eax, times_2, kParameterMapHeaderSize), ebx);
31153fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ mov(FieldOperand(edi, eax, times_2, FixedArray::kHeaderSize), ecx);
31163fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ add(Operand(ebx), Immediate(Smi::FromInt(1)));
31173fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ bind(&parameters_test);
31183fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ test(eax, Operand(eax));
31193fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ j(not_zero, &parameters_loop, Label::kNear);
31203fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ pop(ecx);
31213fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
31223fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ bind(&skip_parameter_map);
31233fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
31243fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // ecx = argument count (tagged)
31253fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // edi = address of backing store (tagged)
31263fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // esp[0] = address of new object (tagged)
31273fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // esp[4] = mapped parameter count (tagged)
31283fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // esp[12] = parameter count (tagged)
31293fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // esp[16] = address of receiver argument
31303fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // Copy arguments header and remaining slots (if there are any).
31313fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ mov(FieldOperand(edi, FixedArray::kMapOffset),
31323fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch         Immediate(FACTORY->fixed_array_map()));
31333fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ mov(FieldOperand(edi, FixedArray::kLengthOffset), ecx);
31343fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
31353fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  Label arguments_loop, arguments_test;
31363fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ mov(ebx, Operand(esp, 1 * kPointerSize));
31373fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ mov(edx, Operand(esp, 4 * kPointerSize));
31383fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ sub(Operand(edx), ebx);  // Is there a smarter way to do negative scaling?
31393fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ sub(Operand(edx), ebx);
31403fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ jmp(&arguments_test, Label::kNear);
31413fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
31423fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ bind(&arguments_loop);
31433fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ sub(Operand(edx), Immediate(kPointerSize));
31443fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ mov(eax, Operand(edx, 0));
31453fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ mov(FieldOperand(edi, ebx, times_2, FixedArray::kHeaderSize), eax);
31463fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ add(Operand(ebx), Immediate(Smi::FromInt(1)));
31473fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
31483fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ bind(&arguments_test);
31493fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ cmp(ebx, Operand(ecx));
31503fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ j(less, &arguments_loop, Label::kNear);
31513fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
31523fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // Restore.
31533fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ pop(eax);  // Address of arguments object.
31543fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ pop(ebx);  // Parameter count.
31553fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
31563fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // Return and remove the on-stack parameters.
31573fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ ret(3 * kPointerSize);
31583fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
31593fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // Do the runtime call to allocate the arguments object.
31603fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ bind(&runtime);
31613fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ pop(eax);  // Remove saved parameter count.
31623fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ mov(Operand(esp, 1 * kPointerSize), ecx);  // Patch argument count.
31633fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ TailCallRuntime(Runtime::kNewStrictArgumentsFast, 3, 1);
31643fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch}
31653fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
31663fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
31673fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdochvoid ArgumentsAccessStub::GenerateNewStrict(MacroAssembler* masm) {
31683fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // esp[0] : return address
31693fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // esp[4] : number of parameters
31703fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // esp[8] : receiver displacement
31713fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // esp[12] : function
317280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
317380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check if the calling frame is an arguments adaptor frame.
317480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label adaptor_frame, try_allocate, runtime;
317580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(edx, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
317680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(ecx, Operand(edx, StandardFrameConstants::kContextOffset));
317780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cmp(Operand(ecx), Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
317869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ j(equal, &adaptor_frame, Label::kNear);
317980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
318080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Get the length from the frame.
318180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(ecx, Operand(esp, 1 * kPointerSize));
318269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ jmp(&try_allocate, Label::kNear);
318380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
318480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Patch the arguments.length and the parameters pointer.
318580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&adaptor_frame);
318680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(ecx, Operand(edx, ArgumentsAdaptorFrameConstants::kLengthOffset));
318780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(Operand(esp, 1 * kPointerSize), ecx);
31883fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ lea(edx, Operand(edx, ecx, times_2,
31893fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch                      StandardFrameConstants::kCallerSPOffset));
319080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(Operand(esp, 2 * kPointerSize), edx);
319180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
319280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Try the new space allocation. Start out with computing the size of
319380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // the arguments object and the elements array.
3194257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label add_arguments_object;
319580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&try_allocate);
319680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ test(ecx, Operand(ecx));
3197257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(zero, &add_arguments_object, Label::kNear);
319880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ lea(ecx, Operand(ecx, times_2, FixedArray::kHeaderSize));
319980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&add_arguments_object);
32003fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ add(Operand(ecx), Immediate(Heap::kArgumentsObjectSizeStrict));
320180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
320280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Do the allocation of both objects in one go.
320380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ AllocateInNewSpace(ecx, eax, edx, ebx, &runtime, TAG_OBJECT);
320480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
320580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Get the arguments boilerplate from the current (global) context.
320680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(edi, Operand(esi, Context::SlotOffset(Context::GLOBAL_INDEX)));
320780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(edi, FieldOperand(edi, GlobalObject::kGlobalContextOffset));
32083fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  const int offset =
32093fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch      Context::SlotOffset(Context::STRICT_MODE_ARGUMENTS_BOILERPLATE_INDEX);
32103fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ mov(edi, Operand(edi, offset));
321180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
321280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Copy the JS object part.
321380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  for (int i = 0; i < JSObject::kHeaderSize; i += kPointerSize) {
321480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ mov(ebx, FieldOperand(edi, i));
321580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ mov(FieldOperand(eax, i), ebx);
321680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
321780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
321880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Get the length (smi tagged) and set that as an in-object property too.
321944f0eee88ff00398ff7f715fab053374d808c90dSteve Block  STATIC_ASSERT(Heap::kArgumentsLengthIndex == 0);
322080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(ecx, Operand(esp, 1 * kPointerSize));
322144f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ mov(FieldOperand(eax, JSObject::kHeaderSize +
32223fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch                      Heap::kArgumentsLengthIndex * kPointerSize),
322344f0eee88ff00398ff7f715fab053374d808c90dSteve Block         ecx);
322480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
322580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // If there are no actual arguments, we're done.
322680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label done;
322780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ test(ecx, Operand(ecx));
322869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ j(zero, &done, Label::kNear);
322980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
323080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Get the parameters pointer from the stack.
323180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(edx, Operand(esp, 2 * kPointerSize));
323280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
323380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Setup the elements pointer in the allocated arguments object and
323480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // initialize the header in the elements fixed array.
32353fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ lea(edi, Operand(eax, Heap::kArgumentsObjectSizeStrict));
323680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(FieldOperand(eax, JSObject::kElementsOffset), edi);
323780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(FieldOperand(edi, FixedArray::kMapOffset),
32383fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch         Immediate(FACTORY->fixed_array_map()));
323944f0eee88ff00398ff7f715fab053374d808c90dSteve Block
324080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(FieldOperand(edi, FixedArray::kLengthOffset), ecx);
324180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Untag the length for the loop below.
324280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiUntag(ecx);
324380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
324480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Copy the fixed array slots.
3245257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label loop;
324680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&loop);
324780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(ebx, Operand(edx, -1 * kPointerSize));  // Skip receiver.
324880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(FieldOperand(edi, FixedArray::kHeaderSize), ebx);
324980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ add(Operand(edi), Immediate(kPointerSize));
325080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ sub(Operand(edx), Immediate(kPointerSize));
325180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ dec(ecx);
325280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(not_zero, &loop);
325380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
325480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Return and remove the on-stack parameters.
325580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&done);
325680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ ret(3 * kPointerSize);
325780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
325880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Do the runtime call to allocate the arguments object.
325980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&runtime);
32603fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ TailCallRuntime(Runtime::kNewStrictArgumentsFast, 3, 1);
326180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
326280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
326380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
326480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid RegExpExecStub::Generate(MacroAssembler* masm) {
326580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Just jump directly to runtime if native RegExp is not selected at compile
326680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // time or if regexp entry in generated code is turned off runtime switch or
326780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // at compilation.
326880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#ifdef V8_INTERPRETED_REGEXP
326980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ TailCallRuntime(Runtime::kRegExpExec, 4, 1);
327080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#else  // V8_INTERPRETED_REGEXP
327180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  if (!FLAG_regexp_entry_native) {
327280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ TailCallRuntime(Runtime::kRegExpExec, 4, 1);
327380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    return;
327480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
327580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
327680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Stack frame on entry.
327780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  //  esp[0]: return address
327880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  //  esp[4]: last_match_info (expected JSArray)
327980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  //  esp[8]: previous index
328080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  //  esp[12]: subject string
328180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  //  esp[16]: JSRegExp object
328280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
328380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  static const int kLastMatchInfoOffset = 1 * kPointerSize;
328480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  static const int kPreviousIndexOffset = 2 * kPointerSize;
328580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  static const int kSubjectOffset = 3 * kPointerSize;
328680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  static const int kJSRegExpOffset = 4 * kPointerSize;
328780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
328880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label runtime, invoke_regexp;
328980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
329080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Ensure that a RegExp stack is allocated.
329180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  ExternalReference address_of_regexp_stack_memory_address =
329244f0eee88ff00398ff7f715fab053374d808c90dSteve Block      ExternalReference::address_of_regexp_stack_memory_address(
329344f0eee88ff00398ff7f715fab053374d808c90dSteve Block          masm->isolate());
329480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  ExternalReference address_of_regexp_stack_memory_size =
329544f0eee88ff00398ff7f715fab053374d808c90dSteve Block      ExternalReference::address_of_regexp_stack_memory_size(masm->isolate());
329680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(ebx, Operand::StaticVariable(address_of_regexp_stack_memory_size));
329780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ test(ebx, Operand(ebx));
3298257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(zero, &runtime);
329980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
330080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check that the first argument is a JSRegExp object.
330180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(eax, Operand(esp, kJSRegExpOffset));
330280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  STATIC_ASSERT(kSmiTag == 0);
33033fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ JumpIfSmi(eax, &runtime);
330480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ CmpObjectType(eax, JS_REGEXP_TYPE, ecx);
330580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(not_equal, &runtime);
330680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check that the RegExp has been compiled (data contains a fixed array).
330780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(ecx, FieldOperand(eax, JSRegExp::kDataOffset));
330880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  if (FLAG_debug_code) {
330980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ test(ecx, Immediate(kSmiTagMask));
331080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ Check(not_zero, "Unexpected type for RegExp data, FixedArray expected");
331180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ CmpObjectType(ecx, FIXED_ARRAY_TYPE, ebx);
331280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ Check(equal, "Unexpected type for RegExp data, FixedArray expected");
331380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
331480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
331580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // ecx: RegExp data (FixedArray)
331680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check the type of the RegExp. Only continue if type is JSRegExp::IRREGEXP.
331780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(ebx, FieldOperand(ecx, JSRegExp::kDataTagOffset));
331880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cmp(Operand(ebx), Immediate(Smi::FromInt(JSRegExp::IRREGEXP)));
331980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(not_equal, &runtime);
332080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
332180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // ecx: RegExp data (FixedArray)
332280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check that the number of captures fit in the static offsets vector buffer.
332380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(edx, FieldOperand(ecx, JSRegExp::kIrregexpCaptureCountOffset));
332480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Calculate number of capture registers (number_of_captures + 1) * 2. This
332580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // uses the asumption that smis are 2 * their untagged value.
332680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  STATIC_ASSERT(kSmiTag == 0);
332780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  STATIC_ASSERT(kSmiTagSize + kSmiShiftSize == 1);
332880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ add(Operand(edx), Immediate(2));  // edx was a smi.
332980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check that the static offsets vector buffer is large enough.
333080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cmp(edx, OffsetsVector::kStaticOffsetsVectorSize);
333180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(above, &runtime);
333280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
333380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // ecx: RegExp data (FixedArray)
333480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // edx: Number of capture registers
333580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check that the second argument is a string.
333680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(eax, Operand(esp, kSubjectOffset));
33373fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ JumpIfSmi(eax, &runtime);
333880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Condition is_string = masm->IsObjectStringType(eax, ebx, ebx);
333980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(NegateCondition(is_string), &runtime);
334080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Get the length of the string to ebx.
334180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(ebx, FieldOperand(eax, String::kLengthOffset));
334280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
334380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // ebx: Length of subject string as a smi
334480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // ecx: RegExp data (FixedArray)
334580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // edx: Number of capture registers
334680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check that the third argument is a positive smi less than the subject
334780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // string length. A negative value will be greater (unsigned comparison).
334880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(eax, Operand(esp, kPreviousIndexOffset));
33493fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ JumpIfNotSmi(eax, &runtime);
335080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cmp(eax, Operand(ebx));
335180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(above_equal, &runtime);
335280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
335380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // ecx: RegExp data (FixedArray)
335480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // edx: Number of capture registers
335580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check that the fourth object is a JSArray object.
335680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(eax, Operand(esp, kLastMatchInfoOffset));
33573fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ JumpIfSmi(eax, &runtime);
335880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ CmpObjectType(eax, JS_ARRAY_TYPE, ebx);
335980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(not_equal, &runtime);
336080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check that the JSArray is in fast case.
336180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(ebx, FieldOperand(eax, JSArray::kElementsOffset));
336280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(eax, FieldOperand(ebx, HeapObject::kMapOffset));
336344f0eee88ff00398ff7f715fab053374d808c90dSteve Block  Factory* factory = masm->isolate()->factory();
336444f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ cmp(eax, factory->fixed_array_map());
336580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(not_equal, &runtime);
336680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check that the last match info has space for the capture registers and the
336780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // additional information.
336880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(eax, FieldOperand(ebx, FixedArray::kLengthOffset));
336980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiUntag(eax);
337080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ add(Operand(edx), Immediate(RegExpImpl::kLastMatchOverhead));
337180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cmp(edx, Operand(eax));
337280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(greater, &runtime);
337380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
337469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  // Reset offset for possibly sliced string.
337569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ Set(edi, Immediate(0));
337680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // ecx: RegExp data (FixedArray)
337780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check the representation and encoding of the subject string.
337880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label seq_ascii_string, seq_two_byte_string, check_code;
337980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(eax, Operand(esp, kSubjectOffset));
338080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset));
338180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movzx_b(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset));
338280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // First check for flat two byte string.
338380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ and_(ebx,
338480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen          kIsNotStringMask | kStringRepresentationMask | kStringEncodingMask);
338580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  STATIC_ASSERT((kStringTag | kSeqStringTag | kTwoByteStringTag) == 0);
338669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ j(zero, &seq_two_byte_string, Label::kNear);
338780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Any other flat string must be a flat ascii string.
338869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ and_(Operand(ebx),
338980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen          Immediate(kIsNotStringMask | kStringRepresentationMask));
339069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ j(zero, &seq_ascii_string, Label::kNear);
339180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
339269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  // Check for flat cons string or sliced string.
339380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // A flat cons string is a cons string where the second part is the empty
339480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // string. In that case the subject string is just the first part of the cons
339580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // string. Also in this case the first part of the cons string is known to be
339680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // a sequential string or an external string.
339769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  // In the case of a sliced string its offset has to be taken into account.
339869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  Label cons_string, check_encoding;
339969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  STATIC_ASSERT(kConsStringTag < kExternalStringTag);
340069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  STATIC_ASSERT(kSlicedStringTag > kExternalStringTag);
340169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ cmp(Operand(ebx), Immediate(kExternalStringTag));
340269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ j(less, &cons_string);
340369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ j(equal, &runtime);
340469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch
340569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  // String is sliced.
340669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ mov(edi, FieldOperand(eax, SlicedString::kOffsetOffset));
340769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ mov(eax, FieldOperand(eax, SlicedString::kParentOffset));
340869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  // edi: offset of sliced string, smi-tagged.
340969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  // eax: parent string.
341069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ jmp(&check_encoding, Label::kNear);
341169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  // String is a cons string, check whether it is flat.
341269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ bind(&cons_string);
341369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ cmp(FieldOperand(eax, ConsString::kSecondOffset), factory->empty_string());
341480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(not_equal, &runtime);
341580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(eax, FieldOperand(eax, ConsString::kFirstOffset));
341669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ bind(&check_encoding);
341780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset));
341869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  // eax: first part of cons string or parent of sliced string.
341969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  // ebx: map of first part of cons string or map of parent of sliced string.
342069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  // Is first part of cons or parent of slice a flat two byte string?
342180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ test_b(FieldOperand(ebx, Map::kInstanceTypeOffset),
342280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen            kStringRepresentationMask | kStringEncodingMask);
342380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  STATIC_ASSERT((kSeqStringTag | kTwoByteStringTag) == 0);
342469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ j(zero, &seq_two_byte_string, Label::kNear);
342580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Any other flat string must be ascii.
342680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ test_b(FieldOperand(ebx, Map::kInstanceTypeOffset),
342780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen            kStringRepresentationMask);
342880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(not_zero, &runtime);
342980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
343080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&seq_ascii_string);
343180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // eax: subject string (flat ascii)
343280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // ecx: RegExp data (FixedArray)
343380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(edx, FieldOperand(ecx, JSRegExp::kDataAsciiCodeOffset));
343469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ Set(ecx, Immediate(1));  // Type is ascii.
343569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ jmp(&check_code, Label::kNear);
343680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
343780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&seq_two_byte_string);
343880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // eax: subject string (flat two byte)
343980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // ecx: RegExp data (FixedArray)
344080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(edx, FieldOperand(ecx, JSRegExp::kDataUC16CodeOffset));
344169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ Set(ecx, Immediate(0));  // Type is two byte.
344280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
344380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&check_code);
344480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check that the irregexp code has been generated for the actual string
344580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // encoding. If it has, the field contains a code object otherwise it contains
3446257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // a smi (code flushing support).
3447257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ JumpIfSmi(edx, &runtime);
344880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
344980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // eax: subject string
345080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // edx: code
345169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  // ecx: encoding of subject string (1 if ascii, 0 if two_byte);
345280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Load used arguments before starting to push arguments for call to native
345380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // RegExp code to avoid handling changing stack height.
345480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(ebx, Operand(esp, kPreviousIndexOffset));
345580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiUntag(ebx);  // Previous index from smi.
345680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
345780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // eax: subject string
345880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // ebx: previous index
345980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // edx: code
346069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  // ecx: encoding of subject string (1 if ascii 0 if two_byte);
346180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // All checks done. Now push arguments for native regexp code.
346244f0eee88ff00398ff7f715fab053374d808c90dSteve Block  Counters* counters = masm->isolate()->counters();
346344f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ IncrementCounter(counters->regexp_entry_native(), 1);
346480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
346544f0eee88ff00398ff7f715fab053374d808c90dSteve Block  // Isolates: note we add an additional parameter here (isolate pointer).
346644f0eee88ff00398ff7f715fab053374d808c90dSteve Block  static const int kRegExpExecuteArguments = 8;
3467e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ EnterApiExitFrame(kRegExpExecuteArguments);
346880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
346944f0eee88ff00398ff7f715fab053374d808c90dSteve Block  // Argument 8: Pass current isolate address.
347044f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ mov(Operand(esp, 7 * kPointerSize),
347144f0eee88ff00398ff7f715fab053374d808c90dSteve Block      Immediate(ExternalReference::isolate_address()));
347244f0eee88ff00398ff7f715fab053374d808c90dSteve Block
347380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Argument 7: Indicate that this is a direct call from JavaScript.
347480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(Operand(esp, 6 * kPointerSize), Immediate(1));
347580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
347680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Argument 6: Start (high end) of backtracking stack memory area.
347769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ mov(esi, Operand::StaticVariable(address_of_regexp_stack_memory_address));
347869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ add(esi, Operand::StaticVariable(address_of_regexp_stack_memory_size));
347969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ mov(Operand(esp, 5 * kPointerSize), esi);
348080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
348180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Argument 5: static offsets vector buffer.
348280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(Operand(esp, 4 * kPointerSize),
348344f0eee88ff00398ff7f715fab053374d808c90dSteve Block         Immediate(ExternalReference::address_of_static_offsets_vector(
348444f0eee88ff00398ff7f715fab053374d808c90dSteve Block             masm->isolate())));
348580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
348669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  // Argument 2: Previous index.
348769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ mov(Operand(esp, 1 * kPointerSize), ebx);
348869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch
348969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  // Argument 1: Original subject string.
349069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  // The original subject is in the previous stack frame. Therefore we have to
349169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  // use ebp, which points exactly to one pointer size below the previous esp.
349269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  // (Because creating a new stack frame pushes the previous ebp onto the stack
349369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  // and thereby moves up esp by one kPointerSize.)
349469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ mov(esi, Operand(ebp, kSubjectOffset + kPointerSize));
349569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ mov(Operand(esp, 0 * kPointerSize), esi);
349669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch
349769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  // esi: original subject string
349869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  // eax: underlying subject string
349969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  // ebx: previous index
350069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  // ecx: encoding of subject string (1 if ascii 0 if two_byte);
350169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  // edx: code
350280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Argument 4: End of string data
350380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Argument 3: Start of string data
350469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  // Prepare start and end index of the input.
350569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  // Load the length from the original sliced string if that is the case.
350669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ mov(esi, FieldOperand(esi, String::kLengthOffset));
350769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ add(esi, Operand(edi));  // Calculate input end wrt offset.
350869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ SmiUntag(edi);
350969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ add(ebx, Operand(edi));  // Calculate input start wrt offset.
351069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch
351169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  // ebx: start index of the input string
351269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  // esi: end index of the input string
3513257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label setup_two_byte, setup_rest;
351469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ test(ecx, Operand(ecx));
3515257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(zero, &setup_two_byte, Label::kNear);
351669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ SmiUntag(esi);
351769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ lea(ecx, FieldOperand(eax, esi, times_1, SeqAsciiString::kHeaderSize));
351880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(Operand(esp, 3 * kPointerSize), ecx);  // Argument 4.
351980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ lea(ecx, FieldOperand(eax, ebx, times_1, SeqAsciiString::kHeaderSize));
352080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(Operand(esp, 2 * kPointerSize), ecx);  // Argument 3.
3521257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ jmp(&setup_rest, Label::kNear);
352280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
352380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&setup_two_byte);
352480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  STATIC_ASSERT(kSmiTag == 0);
352569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  STATIC_ASSERT(kSmiTagSize == 1);  // esi is smi (powered by 2).
352669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ lea(ecx, FieldOperand(eax, esi, times_1, SeqTwoByteString::kHeaderSize));
352780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(Operand(esp, 3 * kPointerSize), ecx);  // Argument 4.
352880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ lea(ecx, FieldOperand(eax, ebx, times_2, SeqTwoByteString::kHeaderSize));
352980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(Operand(esp, 2 * kPointerSize), ecx);  // Argument 3.
353080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
353180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&setup_rest);
353280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
353380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Locate the code entry and call it.
353480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ add(Operand(edx), Immediate(Code::kHeaderSize - kHeapObjectTag));
3535e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ call(Operand(edx));
3536e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
3537e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  // Drop arguments and come back to JS mode.
3538e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ LeaveApiExitFrame();
353980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
354080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check the result.
354180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label success;
354280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cmp(eax, NativeRegExpMacroAssembler::SUCCESS);
3543257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(equal, &success);
354480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label failure;
354580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cmp(eax, NativeRegExpMacroAssembler::FAILURE);
3546257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(equal, &failure);
354780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cmp(eax, NativeRegExpMacroAssembler::EXCEPTION);
354880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // If not exception it can only be retry. Handle that in the runtime system.
354980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(not_equal, &runtime);
355080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Result must now be exception. If there is no pending exception already a
355180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // stack overflow (on the backtrack stack) was detected in RegExp code but
355280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // haven't created the exception yet. Handle that in the runtime system.
355380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // TODO(592): Rerunning the RegExp to get the stack overflow exception.
3554589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch  ExternalReference pending_exception(Isolate::kPendingExceptionAddress,
355544f0eee88ff00398ff7f715fab053374d808c90dSteve Block                                      masm->isolate());
3556e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ mov(edx,
355744f0eee88ff00398ff7f715fab053374d808c90dSteve Block         Operand::StaticVariable(ExternalReference::the_hole_value_location(
355844f0eee88ff00398ff7f715fab053374d808c90dSteve Block             masm->isolate())));
3559e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ mov(eax, Operand::StaticVariable(pending_exception));
3560e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ cmp(edx, Operand(eax));
356180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(equal, &runtime);
3562e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  // For exception, throw the exception again.
3563e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
3564e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  // Clear the pending exception variable.
3565e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ mov(Operand::StaticVariable(pending_exception), edx);
3566e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
3567e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  // Special handling of termination exceptions which are uncatchable
3568e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  // by javascript code.
356944f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ cmp(eax, factory->termination_exception());
3570e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  Label throw_termination_exception;
357169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ j(equal, &throw_termination_exception, Label::kNear);
3572e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
3573e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  // Handle normal exception by following handler chain.
3574e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ Throw(eax);
3575e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
3576e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ bind(&throw_termination_exception);
3577e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ ThrowUncatchable(TERMINATION, eax);
3578e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
357980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&failure);
3580e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  // For failure to match, return null.
358144f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ mov(Operand(eax), factory->null_value());
358280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ ret(4 * kPointerSize);
358380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
358480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Load RegExp data.
358580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&success);
358680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(eax, Operand(esp, kJSRegExpOffset));
358780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(ecx, FieldOperand(eax, JSRegExp::kDataOffset));
358880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(edx, FieldOperand(ecx, JSRegExp::kIrregexpCaptureCountOffset));
358980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Calculate number of capture registers (number_of_captures + 1) * 2.
359080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  STATIC_ASSERT(kSmiTag == 0);
359180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  STATIC_ASSERT(kSmiTagSize + kSmiShiftSize == 1);
359280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ add(Operand(edx), Immediate(2));  // edx was a smi.
359380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
359480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // edx: Number of capture registers
359580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Load last_match_info which is still known to be a fast case JSArray.
359680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(eax, Operand(esp, kLastMatchInfoOffset));
359780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(ebx, FieldOperand(eax, JSArray::kElementsOffset));
359880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
359980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // ebx: last_match_info backing store (FixedArray)
360080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // edx: number of capture registers
360180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Store the capture count.
360280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiTag(edx);  // Number of capture registers to smi.
360380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(FieldOperand(ebx, RegExpImpl::kLastCaptureCountOffset), edx);
360480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiUntag(edx);  // Number of capture registers back from smi.
360580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Store last subject and last input.
360680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(eax, Operand(esp, kSubjectOffset));
360780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(FieldOperand(ebx, RegExpImpl::kLastSubjectOffset), eax);
360880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(ecx, ebx);
360980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ RecordWrite(ecx, RegExpImpl::kLastSubjectOffset, eax, edi);
361080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(eax, Operand(esp, kSubjectOffset));
361180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(FieldOperand(ebx, RegExpImpl::kLastInputOffset), eax);
361280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(ecx, ebx);
361380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ RecordWrite(ecx, RegExpImpl::kLastInputOffset, eax, edi);
361480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
361580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Get the static offsets vector filled by the native regexp code.
361680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  ExternalReference address_of_static_offsets_vector =
361744f0eee88ff00398ff7f715fab053374d808c90dSteve Block      ExternalReference::address_of_static_offsets_vector(masm->isolate());
361880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(ecx, Immediate(address_of_static_offsets_vector));
361980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
362080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // ebx: last_match_info backing store (FixedArray)
362180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // ecx: offsets vector
362280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // edx: number of capture registers
3623257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label next_capture, done;
362480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Capture register counter starts from number of capture registers and
362580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // counts down until wraping after zero.
362680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&next_capture);
362780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ sub(Operand(edx), Immediate(1));
3628257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(negative, &done, Label::kNear);
362980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Read the value from the static offsets vector buffer.
363080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(edi, Operand(ecx, edx, times_int_size, 0));
363180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiTag(edi);
363280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Store the smi value in the last match info.
363380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(FieldOperand(ebx,
363480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                      edx,
363580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                      times_pointer_size,
363680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                      RegExpImpl::kFirstCaptureOffset),
363780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                      edi);
363880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ jmp(&next_capture);
363980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&done);
364080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
364180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Return last match info.
364280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(eax, Operand(esp, kLastMatchInfoOffset));
364380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ ret(4 * kPointerSize);
364480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
364580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Do the runtime call to execute the regexp.
364680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&runtime);
364780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ TailCallRuntime(Runtime::kRegExpExec, 4, 1);
364880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#endif  // V8_INTERPRETED_REGEXP
364980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
365080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
365180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
3652b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdochvoid RegExpConstructResultStub::Generate(MacroAssembler* masm) {
3653b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  const int kMaxInlineLength = 100;
3654b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  Label slowcase;
3655257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label done;
3656b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ mov(ebx, Operand(esp, kPointerSize * 3));
36573fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ JumpIfNotSmi(ebx, &slowcase);
3658b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ cmp(Operand(ebx), Immediate(Smi::FromInt(kMaxInlineLength)));
3659b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ j(above, &slowcase);
3660b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Smi-tagging is equivalent to multiplying by 2.
3661b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  STATIC_ASSERT(kSmiTag == 0);
3662b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  STATIC_ASSERT(kSmiTagSize == 1);
3663b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Allocate RegExpResult followed by FixedArray with size in ebx.
3664b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // JSArray:   [Map][empty properties][Elements][Length-smi][index][input]
3665b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Elements:  [Map][Length][..elements..]
3666b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ AllocateInNewSpace(JSRegExpResult::kSize + FixedArray::kHeaderSize,
3667b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                        times_half_pointer_size,
3668b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                        ebx,  // In: Number of elements (times 2, being a smi)
3669b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                        eax,  // Out: Start of allocation (tagged).
3670b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                        ecx,  // Out: End of allocation.
3671b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                        edx,  // Scratch register
3672b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                        &slowcase,
3673b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                        TAG_OBJECT);
3674b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // eax: Start of allocated area, object-tagged.
3675b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
3676b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Set JSArray map to global.regexp_result_map().
3677b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Set empty properties FixedArray.
3678b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Set elements to point to FixedArray allocated right after the JSArray.
3679b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Interleave operations for better latency.
3680b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ mov(edx, ContextOperand(esi, Context::GLOBAL_INDEX));
368144f0eee88ff00398ff7f715fab053374d808c90dSteve Block  Factory* factory = masm->isolate()->factory();
368244f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ mov(ecx, Immediate(factory->empty_fixed_array()));
3683b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ lea(ebx, Operand(eax, JSRegExpResult::kSize));
3684b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalContextOffset));
3685b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ mov(FieldOperand(eax, JSObject::kElementsOffset), ebx);
3686b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ mov(FieldOperand(eax, JSObject::kPropertiesOffset), ecx);
3687b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ mov(edx, ContextOperand(edx, Context::REGEXP_RESULT_MAP_INDEX));
3688b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ mov(FieldOperand(eax, HeapObject::kMapOffset), edx);
3689b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
3690b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Set input, index and length fields from arguments.
3691b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ mov(ecx, Operand(esp, kPointerSize * 1));
3692b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ mov(FieldOperand(eax, JSRegExpResult::kInputOffset), ecx);
3693b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ mov(ecx, Operand(esp, kPointerSize * 2));
3694b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ mov(FieldOperand(eax, JSRegExpResult::kIndexOffset), ecx);
3695b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ mov(ecx, Operand(esp, kPointerSize * 3));
3696b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ mov(FieldOperand(eax, JSArray::kLengthOffset), ecx);
3697b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
3698b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Fill out the elements FixedArray.
3699b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // eax: JSArray.
3700b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // ebx: FixedArray.
3701b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // ecx: Number of elements in array, as smi.
3702b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
3703b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Set map.
3704b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ mov(FieldOperand(ebx, HeapObject::kMapOffset),
370544f0eee88ff00398ff7f715fab053374d808c90dSteve Block         Immediate(factory->fixed_array_map()));
3706b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Set length.
3707b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ mov(FieldOperand(ebx, FixedArray::kLengthOffset), ecx);
3708b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Fill contents of fixed-array with the-hole.
3709b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ SmiUntag(ecx);
371044f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ mov(edx, Immediate(factory->the_hole_value()));
3711b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ lea(ebx, FieldOperand(ebx, FixedArray::kHeaderSize));
3712b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Fill fixed array elements with hole.
3713b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // eax: JSArray.
3714b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // ecx: Number of elements to fill.
3715b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // ebx: Start of elements in FixedArray.
3716b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // edx: the hole.
3717b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  Label loop;
3718b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ test(ecx, Operand(ecx));
3719b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ bind(&loop);
3720257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(less_equal, &done, Label::kNear);  // Jump if ecx is negative or zero.
3721b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ sub(Operand(ecx), Immediate(1));
3722b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ mov(Operand(ebx, ecx, times_pointer_size, 0), edx);
3723b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ jmp(&loop);
3724b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
3725b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ bind(&done);
3726b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ ret(3 * kPointerSize);
3727b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
3728b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ bind(&slowcase);
3729b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ TailCallRuntime(Runtime::kRegExpConstructResult, 3, 1);
3730b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch}
3731b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
3732b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
373380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid NumberToStringStub::GenerateLookupNumberStringCache(MacroAssembler* masm,
373480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                                         Register object,
373580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                                         Register result,
373680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                                         Register scratch1,
373780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                                         Register scratch2,
373880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                                         bool object_is_smi,
373980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                                         Label* not_found) {
374080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Use of registers. Register result is used as a temporary.
374180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Register number_string_cache = result;
374280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Register mask = scratch1;
374380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Register scratch = scratch2;
374480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
374580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Load the number string cache.
374644f0eee88ff00398ff7f715fab053374d808c90dSteve Block  ExternalReference roots_address =
374744f0eee88ff00398ff7f715fab053374d808c90dSteve Block      ExternalReference::roots_address(masm->isolate());
374880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(scratch, Immediate(Heap::kNumberStringCacheRootIndex));
374980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(number_string_cache,
375080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen         Operand::StaticArray(scratch, times_pointer_size, roots_address));
375180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Make the hash mask from the length of the number string cache. It
375280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // contains two elements (number and string) for each cache entry.
375380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(mask, FieldOperand(number_string_cache, FixedArray::kLengthOffset));
375480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ shr(mask, kSmiTagSize + 1);  // Untag length and divide it by two.
375580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ sub(Operand(mask), Immediate(1));  // Make mask.
375680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
375780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Calculate the entry in the number string cache. The hash value in the
375880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // number string cache for smis is just the smi value, and the hash for
375980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // doubles is the xor of the upper and lower words. See
376080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Heap::GetNumberStringCache.
3761257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label smi_hash_calculated;
3762257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label load_result_from_cache;
376380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  if (object_is_smi) {
376480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ mov(scratch, object);
376580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ SmiUntag(scratch);
376680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  } else {
3767257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Label not_smi;
376880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    STATIC_ASSERT(kSmiTag == 0);
37693fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    __ JumpIfNotSmi(object, &not_smi, Label::kNear);
377080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ mov(scratch, object);
377180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ SmiUntag(scratch);
3772257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ jmp(&smi_hash_calculated, Label::kNear);
377380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ bind(&not_smi);
377480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ cmp(FieldOperand(object, HeapObject::kMapOffset),
377544f0eee88ff00398ff7f715fab053374d808c90dSteve Block           masm->isolate()->factory()->heap_number_map());
377680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ j(not_equal, not_found);
377780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    STATIC_ASSERT(8 == kDoubleSize);
377880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ mov(scratch, FieldOperand(object, HeapNumber::kValueOffset));
377980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ xor_(scratch, FieldOperand(object, HeapNumber::kValueOffset + 4));
378080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // Object is heap number and hash is now in scratch. Calculate cache index.
378180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ and_(scratch, Operand(mask));
378280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    Register index = scratch;
378380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    Register probe = mask;
378480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ mov(probe,
378580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen           FieldOperand(number_string_cache,
378680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                        index,
378780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                        times_twice_pointer_size,
378880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                        FixedArray::kHeaderSize));
37893fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    __ JumpIfSmi(probe, not_found);
37908b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch    if (CpuFeatures::IsSupported(SSE2)) {
379180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      CpuFeatures::Scope fscope(SSE2);
379280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ movdbl(xmm0, FieldOperand(object, HeapNumber::kValueOffset));
379380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ movdbl(xmm1, FieldOperand(probe, HeapNumber::kValueOffset));
379480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ ucomisd(xmm0, xmm1);
379580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    } else {
379680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ fld_d(FieldOperand(object, HeapNumber::kValueOffset));
379780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ fld_d(FieldOperand(probe, HeapNumber::kValueOffset));
379880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ FCmp();
379980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    }
380080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ j(parity_even, not_found);  // Bail out if NaN is involved.
380180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ j(not_equal, not_found);  // The cache did not contain this value.
3802257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ jmp(&load_result_from_cache, Label::kNear);
380380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
380480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
380580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&smi_hash_calculated);
380680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Object is smi and hash is now in scratch. Calculate cache index.
380780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ and_(scratch, Operand(mask));
380880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Register index = scratch;
380980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check if the entry is the smi we are looking for.
381080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cmp(object,
381180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen         FieldOperand(number_string_cache,
381280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                      index,
381380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                      times_twice_pointer_size,
381480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                      FixedArray::kHeaderSize));
381580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(not_equal, not_found);
381680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
381780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Get the result from the cache.
381880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&load_result_from_cache);
381980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(result,
382080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen         FieldOperand(number_string_cache,
382180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                      index,
382280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                      times_twice_pointer_size,
382380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                      FixedArray::kHeaderSize + kPointerSize));
382444f0eee88ff00398ff7f715fab053374d808c90dSteve Block  Counters* counters = masm->isolate()->counters();
382544f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ IncrementCounter(counters->number_to_string_native(), 1);
382680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
382780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
382880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
382980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid NumberToStringStub::Generate(MacroAssembler* masm) {
383080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label runtime;
383180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
383280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(ebx, Operand(esp, kPointerSize));
383380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
383480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Generate code to lookup number in the number string cache.
383580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  GenerateLookupNumberStringCache(masm, ebx, eax, ecx, edx, false, &runtime);
383680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ ret(1 * kPointerSize);
383780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
383880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&runtime);
383980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Handle number to string in the runtime system if not found in the cache.
384080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ TailCallRuntime(Runtime::kNumberToStringSkipCache, 1, 1);
384180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
384280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
384380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
384480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenstatic int NegativeComparisonResult(Condition cc) {
384580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  ASSERT(cc != equal);
384680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  ASSERT((cc == less) || (cc == less_equal)
384780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      || (cc == greater) || (cc == greater_equal));
384880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  return (cc == greater || cc == greater_equal) ? LESS : GREATER;
384980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
385080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
385180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid CompareStub::Generate(MacroAssembler* masm) {
385280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  ASSERT(lhs_.is(no_reg) && rhs_.is(no_reg));
385380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
385469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  Label check_unequal_objects;
385580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
38560d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  // Compare two smis if required.
38570d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  if (include_smi_compare_) {
38580d5e116f6aee03185f237311a943491bb079a768Kristian Monsen    Label non_smi, smi_done;
38590d5e116f6aee03185f237311a943491bb079a768Kristian Monsen    __ mov(ecx, Operand(edx));
38600d5e116f6aee03185f237311a943491bb079a768Kristian Monsen    __ or_(ecx, Operand(eax));
386169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    __ JumpIfNotSmi(ecx, &non_smi, Label::kNear);
38620d5e116f6aee03185f237311a943491bb079a768Kristian Monsen    __ sub(edx, Operand(eax));  // Return on the result of the subtraction.
386369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    __ j(no_overflow, &smi_done, Label::kNear);
3864f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    __ not_(edx);  // Correct sign in case of overflow. edx is never 0 here.
38650d5e116f6aee03185f237311a943491bb079a768Kristian Monsen    __ bind(&smi_done);
38660d5e116f6aee03185f237311a943491bb079a768Kristian Monsen    __ mov(eax, edx);
38670d5e116f6aee03185f237311a943491bb079a768Kristian Monsen    __ ret(0);
38680d5e116f6aee03185f237311a943491bb079a768Kristian Monsen    __ bind(&non_smi);
38690d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  } else if (FLAG_debug_code) {
38700d5e116f6aee03185f237311a943491bb079a768Kristian Monsen    __ mov(ecx, Operand(edx));
38710d5e116f6aee03185f237311a943491bb079a768Kristian Monsen    __ or_(ecx, Operand(eax));
38720d5e116f6aee03185f237311a943491bb079a768Kristian Monsen    __ test(ecx, Immediate(kSmiTagMask));
38730d5e116f6aee03185f237311a943491bb079a768Kristian Monsen    __ Assert(not_zero, "Unexpected smi operands.");
38740d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  }
38750d5e116f6aee03185f237311a943491bb079a768Kristian Monsen
387680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // NOTICE! This code is only reached after a smi-fast-case check, so
387780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // it is certain that at least one operand isn't a smi.
387880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
387980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Identical objects can be compared fast, but there are some tricky cases
388080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // for NaN and undefined.
388180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  {
388280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    Label not_identical;
388380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ cmp(eax, Operand(edx));
388480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ j(not_equal, &not_identical);
388580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
388680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    if (cc_ != equal) {
388780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      // Check for undefined.  undefined OP undefined is false even though
388880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      // undefined == undefined.
3889257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      Label check_for_nan;
389044f0eee88ff00398ff7f715fab053374d808c90dSteve Block      __ cmp(edx, masm->isolate()->factory()->undefined_value());
3891257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ j(not_equal, &check_for_nan, Label::kNear);
389280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ Set(eax, Immediate(Smi::FromInt(NegativeComparisonResult(cc_))));
389380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ ret(0);
389480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ bind(&check_for_nan);
389580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    }
389680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
389744f0eee88ff00398ff7f715fab053374d808c90dSteve Block    // Test for NaN. Sadly, we can't just compare to factory->nan_value(),
389880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // so we do the second best thing - test it ourselves.
389980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // Note: if cc_ != equal, never_nan_nan_ is not used.
390080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    if (never_nan_nan_ && (cc_ == equal)) {
390180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ Set(eax, Immediate(Smi::FromInt(EQUAL)));
390280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ ret(0);
390380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    } else {
3904257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      Label heap_number;
390580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ cmp(FieldOperand(edx, HeapObject::kMapOffset),
390644f0eee88ff00398ff7f715fab053374d808c90dSteve Block             Immediate(masm->isolate()->factory()->heap_number_map()));
3907257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ j(equal, &heap_number, Label::kNear);
390880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      if (cc_ != equal) {
390980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen        // Call runtime on identical JSObjects.  Otherwise return equal.
39103fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch        __ CmpObjectType(eax, FIRST_SPEC_OBJECT_TYPE, ecx);
391180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen        __ j(above_equal, &not_identical);
391280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      }
391380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ Set(eax, Immediate(Smi::FromInt(EQUAL)));
391480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ ret(0);
391580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
391680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ bind(&heap_number);
391780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      // It is a heap number, so return non-equal if it's NaN and equal if
391880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      // it's not NaN.
391980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      // The representation of NaN values has all exponent bits (52..62) set,
392080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      // and not all mantissa bits (0..51) clear.
392180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      // We only accept QNaNs, which have bit 51 set.
392280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      // Read top bits of double representation (second word of value).
392380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
392480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      // Value is a QNaN if value & kQuietNaNMask == kQuietNaNMask, i.e.,
392580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      // all bits in the mask are set. We only need to check the word
392680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      // that contains the exponent and high bit of the mantissa.
392780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      STATIC_ASSERT(((kQuietNaNHighBitsMask << 1) & 0x80000000u) != 0);
392880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ mov(edx, FieldOperand(edx, HeapNumber::kExponentOffset));
39299fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block      __ Set(eax, Immediate(0));
393080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      // Shift value and mask so kQuietNaNHighBitsMask applies to topmost
393180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      // bits.
393280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ add(edx, Operand(edx));
393380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ cmp(edx, kQuietNaNHighBitsMask << 1);
393480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      if (cc_ == equal) {
393580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen        STATIC_ASSERT(EQUAL != 1);
393680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen        __ setcc(above_equal, eax);
393780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen        __ ret(0);
393880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      } else {
3939257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        Label nan;
3940257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        __ j(above_equal, &nan, Label::kNear);
394180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen        __ Set(eax, Immediate(Smi::FromInt(EQUAL)));
394280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen        __ ret(0);
394380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen        __ bind(&nan);
394480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen        __ Set(eax, Immediate(Smi::FromInt(NegativeComparisonResult(cc_))));
394580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen        __ ret(0);
394680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      }
394780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    }
394880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
394980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ bind(&not_identical);
395080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
395180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
395280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Strict equality can quickly decide whether objects are equal.
395380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Non-strict object equality is slower, so it is handled later in the stub.
395480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  if (cc_ == equal && strict_) {
395580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    Label slow;  // Fallthrough label.
3956257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Label not_smis;
395780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // If we're doing a strict equality comparison, we don't have to do
395880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // type conversion, so we generate code to do fast comparison for objects
395980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // and oddballs. Non-smi numbers and strings still go through the usual
396080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // slow-case code.
396180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // If either is a Smi (we know that not both are), then they can only
396280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // be equal if the other is a HeapNumber. If so, use the slow case.
396380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    STATIC_ASSERT(kSmiTag == 0);
396480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    ASSERT_EQ(0, Smi::FromInt(0));
396580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ mov(ecx, Immediate(kSmiTagMask));
396680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ and_(ecx, Operand(eax));
396780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ test(ecx, Operand(edx));
3968257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ j(not_zero, &not_smis, Label::kNear);
396980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // One operand is a smi.
397080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
397180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // Check whether the non-smi is a heap number.
397280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    STATIC_ASSERT(kSmiTagMask == 1);
397380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // ecx still holds eax & kSmiTag, which is either zero or one.
397480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ sub(Operand(ecx), Immediate(0x01));
397580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ mov(ebx, edx);
397680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ xor_(ebx, Operand(eax));
397780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ and_(ebx, Operand(ecx));  // ebx holds either 0 or eax ^ edx.
397880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ xor_(ebx, Operand(eax));
397980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // if eax was smi, ebx is now edx, else eax.
398080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
398180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // Check if the non-smi operand is a heap number.
398280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ cmp(FieldOperand(ebx, HeapObject::kMapOffset),
398344f0eee88ff00398ff7f715fab053374d808c90dSteve Block           Immediate(masm->isolate()->factory()->heap_number_map()));
398480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // If heap number, handle it in the slow case.
398569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    __ j(equal, &slow, Label::kNear);
398680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // Return non-equal (ebx is not zero)
398780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ mov(eax, ebx);
398880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ ret(0);
398980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
399080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ bind(&not_smis);
399180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // If either operand is a JSObject or an oddball value, then they are not
399280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // equal since their pointers are different
399380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // There is no test for undetectability in strict equality.
399480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
399580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // Get the type of the first operand.
399680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // If the first object is a JS object, we have done pointer comparison.
3997257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Label first_non_object;
39983fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    STATIC_ASSERT(LAST_TYPE == LAST_SPEC_OBJECT_TYPE);
39993fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    __ CmpObjectType(eax, FIRST_SPEC_OBJECT_TYPE, ecx);
4000257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ j(below, &first_non_object, Label::kNear);
400180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
400280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // Return non-zero (eax is not zero)
4003257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Label return_not_equal;
400480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    STATIC_ASSERT(kHeapObjectTag != 0);
400580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ bind(&return_not_equal);
400680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ ret(0);
400780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
400880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ bind(&first_non_object);
400980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // Check for oddballs: true, false, null, undefined.
401080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ CmpInstanceType(ecx, ODDBALL_TYPE);
401180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ j(equal, &return_not_equal);
401280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
40133fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    __ CmpObjectType(edx, FIRST_SPEC_OBJECT_TYPE, ecx);
401480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ j(above_equal, &return_not_equal);
401580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
401680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // Check for oddballs: true, false, null, undefined.
401780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ CmpInstanceType(ecx, ODDBALL_TYPE);
401880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ j(equal, &return_not_equal);
401980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
402080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // Fall through to the general case.
402180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ bind(&slow);
402280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
402380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
402480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Generate the number comparison code.
402580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  if (include_number_compare_) {
402680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    Label non_number_comparison;
402780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    Label unordered;
40288b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch    if (CpuFeatures::IsSupported(SSE2)) {
402980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      CpuFeatures::Scope use_sse2(SSE2);
403080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      CpuFeatures::Scope use_cmov(CMOV);
403180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
403280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      FloatingPointHelper::LoadSSE2Operands(masm, &non_number_comparison);
403380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ ucomisd(xmm0, xmm1);
403480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
403580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      // Don't base result on EFLAGS when a NaN is involved.
403669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch      __ j(parity_even, &unordered, Label::kNear);
403780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      // Return a result of -1, 0, or 1, based on EFLAGS.
403880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ mov(eax, 0);  // equal
403980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ mov(ecx, Immediate(Smi::FromInt(1)));
404080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ cmov(above, eax, Operand(ecx));
404180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ mov(ecx, Immediate(Smi::FromInt(-1)));
404280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ cmov(below, eax, Operand(ecx));
404380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ ret(0);
404480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    } else {
404580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      FloatingPointHelper::CheckFloatOperands(
404680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen          masm, &non_number_comparison, ebx);
404780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      FloatingPointHelper::LoadFloatOperand(masm, eax);
404880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      FloatingPointHelper::LoadFloatOperand(masm, edx);
404980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ FCmp();
405080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
405180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      // Don't base result on EFLAGS when a NaN is involved.
405269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch      __ j(parity_even, &unordered, Label::kNear);
405380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
4054257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      Label below_label, above_label;
405580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      // Return a result of -1, 0, or 1, based on EFLAGS.
405669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch      __ j(below, &below_label, Label::kNear);
405769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch      __ j(above, &above_label, Label::kNear);
405880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
40599fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block      __ Set(eax, Immediate(0));
406080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ ret(0);
406180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
406280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ bind(&below_label);
406380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ mov(eax, Immediate(Smi::FromInt(-1)));
406480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ ret(0);
406580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
406680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ bind(&above_label);
406780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ mov(eax, Immediate(Smi::FromInt(1)));
406880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ ret(0);
406980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    }
407080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
407180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // If one of the numbers was NaN, then the result is always false.
407280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // The cc is never not-equal.
407380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ bind(&unordered);
407480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    ASSERT(cc_ != not_equal);
407580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    if (cc_ == less || cc_ == less_equal) {
407680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ mov(eax, Immediate(Smi::FromInt(1)));
407780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    } else {
407880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ mov(eax, Immediate(Smi::FromInt(-1)));
407980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    }
408080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ ret(0);
408180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
408280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // The number comparison code did not provide a valid result.
408380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ bind(&non_number_comparison);
408480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
408580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
408680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Fast negative check for symbol-to-symbol equality.
408780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label check_for_strings;
408880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  if (cc_ == equal) {
408980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    BranchIfNonSymbol(masm, &check_for_strings, eax, ecx);
409080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    BranchIfNonSymbol(masm, &check_for_strings, edx, ecx);
409180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
409280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // We've already checked for object identity, so if both operands
409380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // are symbols they aren't equal. Register eax already holds a
409480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // non-zero value, which indicates not equal, so just return.
409580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ ret(0);
409680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
409780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
409880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&check_for_strings);
409980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
410080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ JumpIfNotBothSequentialAsciiStrings(edx, eax, ecx, ebx,
410180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                         &check_unequal_objects);
410280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
410380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Inline comparison of ascii strings.
4104257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  if (cc_ == equal) {
4105257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    StringCompareStub::GenerateFlatAsciiStringEquals(masm,
410680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                                     edx,
410780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                                     eax,
410880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                                     ecx,
4109257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                                     ebx);
4110257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  } else {
4111257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    StringCompareStub::GenerateCompareFlatAsciiStrings(masm,
4112257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                                       edx,
4113257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                                       eax,
4114257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                                       ecx,
4115257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                                       ebx,
4116257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                                       edi);
4117257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
411880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#ifdef DEBUG
411980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ Abort("Unexpected fall-through from string comparison");
412080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#endif
412180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
412280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&check_unequal_objects);
412380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  if (cc_ == equal && !strict_) {
412480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // Non-strict equality.  Objects are unequal if
412580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // they are both JSObjects and not undetectable,
412680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // and their pointers are different.
4127257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Label not_both_objects;
4128257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Label return_unequal;
412980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // At most one is a smi, so we can test for smi by adding the two.
413080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // A smi plus a heap object has the low bit set, a heap object plus
413180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // a heap object has the low bit clear.
413280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    STATIC_ASSERT(kSmiTag == 0);
413380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    STATIC_ASSERT(kSmiTagMask == 1);
413480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ lea(ecx, Operand(eax, edx, times_1, 0));
413580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ test(ecx, Immediate(kSmiTagMask));
4136257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ j(not_zero, &not_both_objects, Label::kNear);
41373fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    __ CmpObjectType(eax, FIRST_SPEC_OBJECT_TYPE, ecx);
4138257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ j(below, &not_both_objects, Label::kNear);
41393fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    __ CmpObjectType(edx, FIRST_SPEC_OBJECT_TYPE, ebx);
4140257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ j(below, &not_both_objects, Label::kNear);
414180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // We do not bail out after this point.  Both are JSObjects, and
414280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // they are equal if and only if both are undetectable.
414380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // The and of the undetectable flags is 1 if and only if they are equal.
414480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ test_b(FieldOperand(ecx, Map::kBitFieldOffset),
414580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen              1 << Map::kIsUndetectable);
4146257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ j(zero, &return_unequal, Label::kNear);
414780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ test_b(FieldOperand(ebx, Map::kBitFieldOffset),
414880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen              1 << Map::kIsUndetectable);
4149257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ j(zero, &return_unequal, Label::kNear);
415080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // The objects are both undetectable, so they both compare as the value
415180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // undefined, and are equal.
415280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ Set(eax, Immediate(EQUAL));
415380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ bind(&return_unequal);
415480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // Return non-equal by returning the non-zero object pointer in eax,
415580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // or return equal if we fell through to here.
415680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ ret(0);  // rax, rdx were pushed
415780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ bind(&not_both_objects);
415880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
415980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
416080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Push arguments below the return address.
416180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ pop(ecx);
416280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ push(edx);
416380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ push(eax);
416480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
416580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Figure out which native to call and setup the arguments.
416680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Builtins::JavaScript builtin;
416780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  if (cc_ == equal) {
416880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    builtin = strict_ ? Builtins::STRICT_EQUALS : Builtins::EQUALS;
416980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  } else {
417080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    builtin = Builtins::COMPARE;
417180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ push(Immediate(Smi::FromInt(NegativeComparisonResult(cc_))));
417280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
417380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
417480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Restore return address on the stack.
417580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ push(ecx);
417680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
417780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Call the native; it returns -1 (less), 0 (equal), or 1 (greater)
417880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // tagged as a small integer.
417980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ InvokeBuiltin(builtin, JUMP_FUNCTION);
418080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
418180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
418280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
418380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid CompareStub::BranchIfNonSymbol(MacroAssembler* masm,
418480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                    Label* label,
418580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                    Register object,
418680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                    Register scratch) {
41873fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ JumpIfSmi(object, label);
418880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(scratch, FieldOperand(object, HeapObject::kMapOffset));
418980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movzx_b(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset));
419080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ and_(scratch, kIsSymbolMask | kIsNotStringMask);
419180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cmp(scratch, kSymbolTag | kStringTag);
419280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(not_equal, label);
419380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
419480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
419580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
419680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StackCheckStub::Generate(MacroAssembler* masm) {
4197f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  __ TailCallRuntime(Runtime::kStackGuard, 0, 1);
419880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
419980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
420080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
420180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid CallFunctionStub::Generate(MacroAssembler* masm) {
4202589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch  Label slow, non_function;
420380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
4204257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // The receiver might implicitly be the global object. This is
4205257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // indicated by passing the hole as the receiver to the call
4206257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // function stub.
4207257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  if (ReceiverMightBeImplicit()) {
4208257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Label call;
420980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // Get the receiver from the stack.
421080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // +1 ~ return address
421180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ mov(eax, Operand(esp, (argc_ + 1) * kPointerSize));
4212257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Call as function is indicated with the hole.
4213257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ cmp(eax, masm->isolate()->factory()->the_hole_value());
4214257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ j(not_equal, &call, Label::kNear);
4215257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Patch the receiver on the stack with the global receiver object.
4216257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ mov(ebx, GlobalObjectOperand());
4217257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ mov(ebx, FieldOperand(ebx, GlobalObject::kGlobalReceiverOffset));
4218257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ mov(Operand(esp, (argc_ + 1) * kPointerSize), ebx);
4219257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ bind(&call);
422080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
422180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
422280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Get the function to call from the stack.
422380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // +2 ~ receiver, return address
422480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(edi, Operand(esp, (argc_ + 2) * kPointerSize));
422580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
422680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check that the function really is a JavaScript function.
4227589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch  __ JumpIfSmi(edi, &non_function);
422880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Goto slow case if we do not have a function.
422980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx);
4230257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(not_equal, &slow);
423180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
423280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Fast-case: Just invoke the function.
423380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  ParameterCount actual(argc_);
4234257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
4235257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  if (ReceiverMightBeImplicit()) {
4236257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Label call_as_function;
4237257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ cmp(eax, masm->isolate()->factory()->the_hole_value());
4238257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ j(equal, &call_as_function);
4239257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ InvokeFunction(edi,
4240257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                      actual,
4241257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                      JUMP_FUNCTION,
4242257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                      NullCallWrapper(),
4243257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                      CALL_AS_METHOD);
4244257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ bind(&call_as_function);
4245257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
4246257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ InvokeFunction(edi,
4247257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                    actual,
4248257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                    JUMP_FUNCTION,
4249257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                    NullCallWrapper(),
4250257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                    CALL_AS_FUNCTION);
425180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
425280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Slow-case: Non-function called.
425380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&slow);
4254589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch  // Check for function proxy.
4255589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch  __ CmpInstanceType(ecx, JS_FUNCTION_PROXY_TYPE);
4256589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch  __ j(not_equal, &non_function);
4257589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch  __ pop(ecx);
4258589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch  __ push(edi);  // put proxy as additional argument under return address
4259589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch  __ push(ecx);
4260589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch  __ Set(eax, Immediate(argc_ + 1));
4261589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch  __ Set(ebx, Immediate(0));
4262589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch  __ SetCallKind(ecx, CALL_AS_FUNCTION);
4263589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch  __ GetBuiltinEntry(edx, Builtins::CALL_FUNCTION_PROXY);
4264589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch  {
4265589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch    Handle<Code> adaptor =
4266589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch      masm->isolate()->builtins()->ArgumentsAdaptorTrampoline();
4267589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch    __ jmp(adaptor, RelocInfo::CODE_TARGET);
4268589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch  }
4269589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch
427080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // CALL_NON_FUNCTION expects the non-function callee as receiver (instead
427180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // of the original receiver from the call site).
4272589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch  __ bind(&non_function);
427380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(Operand(esp, (argc_ + 1) * kPointerSize), edi);
427480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ Set(eax, Immediate(argc_));
427580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ Set(ebx, Immediate(0));
4276589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch  __ SetCallKind(ecx, CALL_AS_METHOD);
427780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ GetBuiltinEntry(edx, Builtins::CALL_NON_FUNCTION);
427844f0eee88ff00398ff7f715fab053374d808c90dSteve Block  Handle<Code> adaptor =
427944f0eee88ff00398ff7f715fab053374d808c90dSteve Block      masm->isolate()->builtins()->ArgumentsAdaptorTrampoline();
428080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ jmp(adaptor, RelocInfo::CODE_TARGET);
428180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
428280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
428380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
428444f0eee88ff00398ff7f715fab053374d808c90dSteve Blockbool CEntryStub::NeedsImmovableCode() {
428544f0eee88ff00398ff7f715fab053374d808c90dSteve Block  return false;
428644f0eee88ff00398ff7f715fab053374d808c90dSteve Block}
428744f0eee88ff00398ff7f715fab053374d808c90dSteve Block
428844f0eee88ff00398ff7f715fab053374d808c90dSteve Block
428980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid CEntryStub::GenerateThrowTOS(MacroAssembler* masm) {
4290e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ Throw(eax);
429180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
429280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
429380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
429480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid CEntryStub::GenerateCore(MacroAssembler* masm,
429580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                              Label* throw_normal_exception,
429680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                              Label* throw_termination_exception,
429780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                              Label* throw_out_of_memory_exception,
429880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                              bool do_gc,
42991e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block                              bool always_allocate_scope) {
430080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // eax: result parameter for PerformGC, if any
430180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // ebx: pointer to C function  (C callee-saved)
430280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // ebp: frame pointer  (restored after C call)
430380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // esp: stack pointer  (restored after C call)
430480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // edi: number of arguments including receiver  (C callee-saved)
430580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // esi: pointer to the first argument (C callee-saved)
430680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
430780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Result returned in eax, or eax+edx if result_size_ is 2.
430880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
430980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check stack alignment.
431080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  if (FLAG_debug_code) {
431180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ CheckStackAlignment();
431280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
431380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
431480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  if (do_gc) {
431580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // Pass failure code returned from last attempt as first argument to
431680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // PerformGC. No need to use PrepareCallCFunction/CallCFunction here as the
431780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // stack alignment is known to be correct. This function takes one argument
431880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // which is passed on the stack, and we know that the stack has been
431980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // prepared to pass at least one argument.
432080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ mov(Operand(esp, 0 * kPointerSize), eax);  // Result.
432180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ call(FUNCTION_ADDR(Runtime::PerformGC), RelocInfo::RUNTIME_ENTRY);
432280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
432380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
432480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  ExternalReference scope_depth =
432544f0eee88ff00398ff7f715fab053374d808c90dSteve Block      ExternalReference::heap_always_allocate_scope_depth(masm->isolate());
432680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  if (always_allocate_scope) {
432780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ inc(Operand::StaticVariable(scope_depth));
432880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
432980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
433080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Call C function.
433180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(Operand(esp, 0 * kPointerSize), edi);  // argc.
433280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(Operand(esp, 1 * kPointerSize), esi);  // argv.
433344f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ mov(Operand(esp, 2 * kPointerSize),
433444f0eee88ff00398ff7f715fab053374d808c90dSteve Block         Immediate(ExternalReference::isolate_address()));
433580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ call(Operand(ebx));
433680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Result is in eax or edx:eax - do not destroy these registers!
433780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
433880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  if (always_allocate_scope) {
433980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ dec(Operand::StaticVariable(scope_depth));
434080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
434180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
434280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Make sure we're not trying to return 'the hole' from the runtime
434380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // call as this may lead to crashes in the IC code later.
434480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  if (FLAG_debug_code) {
4345257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Label okay;
434644f0eee88ff00398ff7f715fab053374d808c90dSteve Block    __ cmp(eax, masm->isolate()->factory()->the_hole_value());
4347257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ j(not_equal, &okay, Label::kNear);
434880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ int3();
434980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ bind(&okay);
435080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
435180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
435280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check for failure result.
435380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label failure_returned;
435480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  STATIC_ASSERT(((kFailureTag + 1) & kFailureTagMask) == 0);
435580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ lea(ecx, Operand(eax, 1));
435680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Lower 2 bits of ecx are 0 iff eax has failure tag.
435780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ test(ecx, Immediate(kFailureTagMask));
4358257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(zero, &failure_returned);
435980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
436044f0eee88ff00398ff7f715fab053374d808c90dSteve Block  ExternalReference pending_exception_address(
4361589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch      Isolate::kPendingExceptionAddress, masm->isolate());
43621e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
43631e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  // Check that there is no pending exception, otherwise we
43641e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  // should have returned some failure value.
43651e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  if (FLAG_debug_code) {
43661e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    __ push(edx);
43671e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    __ mov(edx, Operand::StaticVariable(
436844f0eee88ff00398ff7f715fab053374d808c90dSteve Block        ExternalReference::the_hole_value_location(masm->isolate())));
4369257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Label okay;
43701e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    __ cmp(edx, Operand::StaticVariable(pending_exception_address));
43711e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    // Cannot use check here as it attempts to generate call into runtime.
4372257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ j(equal, &okay, Label::kNear);
43731e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    __ int3();
43741e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    __ bind(&okay);
43751e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    __ pop(edx);
43761e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  }
43771e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
437880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Exit the JavaScript to C++ exit frame.
4379b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ LeaveExitFrame(save_doubles_);
438080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ ret(0);
438180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
438280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Handling of failure.
438380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&failure_returned);
438480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
438580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label retry;
438680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // If the returned exception is RETRY_AFTER_GC continue at retry label
438780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  STATIC_ASSERT(Failure::RETRY_AFTER_GC == 0);
438880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ test(eax, Immediate(((1 << kFailureTypeTagSize) - 1) << kFailureTagSize));
438969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ j(zero, &retry, Label::kNear);
439080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
439180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Special handling of out of memory exceptions.
439280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cmp(eax, reinterpret_cast<int32_t>(Failure::OutOfMemoryException()));
439380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(equal, throw_out_of_memory_exception);
439480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
439580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Retrieve the pending exception and clear the variable.
439644f0eee88ff00398ff7f715fab053374d808c90dSteve Block  ExternalReference the_hole_location =
439744f0eee88ff00398ff7f715fab053374d808c90dSteve Block      ExternalReference::the_hole_value_location(masm->isolate());
439880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(eax, Operand::StaticVariable(pending_exception_address));
439944f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ mov(edx, Operand::StaticVariable(the_hole_location));
440080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(Operand::StaticVariable(pending_exception_address), edx);
440180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
440280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Special handling of termination exceptions which are uncatchable
440380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // by javascript code.
440444f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ cmp(eax, masm->isolate()->factory()->termination_exception());
440580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(equal, throw_termination_exception);
440680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
440780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Handle normal exception.
440880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ jmp(throw_normal_exception);
440980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
441080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Retry.
441180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&retry);
441280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
441380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
441480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
441580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid CEntryStub::GenerateThrowUncatchable(MacroAssembler* masm,
441680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                          UncatchableExceptionType type) {
4417e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ ThrowUncatchable(type, eax);
441880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
441980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
442080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
442180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid CEntryStub::Generate(MacroAssembler* masm) {
442280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // eax: number of arguments including receiver
442380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // ebx: pointer to C function  (C callee-saved)
442480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // ebp: frame pointer  (restored after C call)
442580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // esp: stack pointer  (restored after C call)
442680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // esi: current context (C callee-saved)
442780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // edi: JS function of the caller (C callee-saved)
442880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
442980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // NOTE: Invocations of builtins may return failure objects instead
443080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // of a proper result. The builtin entry handles this by performing
443180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // a garbage collection and retrying the builtin (twice).
443280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
443380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Enter the exit frame that transitions from JavaScript to C++.
4434b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ EnterExitFrame(save_doubles_);
443580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
443680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // eax: result parameter for PerformGC, if any (setup below)
443780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // ebx: pointer to builtin function  (C callee-saved)
443880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // ebp: frame pointer  (restored after C call)
443980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // esp: stack pointer  (restored after C call)
444080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // edi: number of arguments including receiver (C callee-saved)
444180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // esi: argv pointer (C callee-saved)
444280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
444380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label throw_normal_exception;
444480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label throw_termination_exception;
444580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label throw_out_of_memory_exception;
444680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
444780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Call into the runtime system.
444880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  GenerateCore(masm,
444980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen               &throw_normal_exception,
445080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen               &throw_termination_exception,
445180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen               &throw_out_of_memory_exception,
445280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen               false,
445380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen               false);
445480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
445580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Do space-specific GC and retry runtime call.
445680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  GenerateCore(masm,
445780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen               &throw_normal_exception,
445880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen               &throw_termination_exception,
445980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen               &throw_out_of_memory_exception,
446080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen               true,
446180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen               false);
446280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
446380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Do full GC and retry runtime call one final time.
446480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Failure* failure = Failure::InternalError();
446580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(eax, Immediate(reinterpret_cast<int32_t>(failure)));
446680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  GenerateCore(masm,
446780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen               &throw_normal_exception,
446880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen               &throw_termination_exception,
446980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen               &throw_out_of_memory_exception,
447080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen               true,
447180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen               true);
447280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
447380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&throw_out_of_memory_exception);
447480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  GenerateThrowUncatchable(masm, OUT_OF_MEMORY);
447580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
447680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&throw_termination_exception);
447780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  GenerateThrowUncatchable(masm, TERMINATION);
447880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
447980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&throw_normal_exception);
448080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  GenerateThrowTOS(masm);
448180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
448280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
448380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
448480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid JSEntryStub::GenerateBody(MacroAssembler* masm, bool is_construct) {
448580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label invoke, exit;
448680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label not_outermost_js, not_outermost_js_2;
448780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
448880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Setup frame.
448980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ push(ebp);
449080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(ebp, Operand(esp));
449180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
449280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Push marker in two places.
449380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  int marker = is_construct ? StackFrame::ENTRY_CONSTRUCT : StackFrame::ENTRY;
449480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ push(Immediate(Smi::FromInt(marker)));  // context slot
449580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ push(Immediate(Smi::FromInt(marker)));  // function slot
449680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Save callee-saved registers (C calling conventions).
449780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ push(edi);
449880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ push(esi);
449980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ push(ebx);
450080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
450180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Save copies of the top frame descriptor on the stack.
4502589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch  ExternalReference c_entry_fp(Isolate::kCEntryFPAddress, masm->isolate());
450380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ push(Operand::StaticVariable(c_entry_fp));
450480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
450580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // If this is the outermost JS call, set js_entry_sp value.
4506589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch  ExternalReference js_entry_sp(Isolate::kJSEntrySPAddress,
450744f0eee88ff00398ff7f715fab053374d808c90dSteve Block                                masm->isolate());
450880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cmp(Operand::StaticVariable(js_entry_sp), Immediate(0));
450969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ j(not_equal, &not_outermost_js, Label::kNear);
451080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(Operand::StaticVariable(js_entry_sp), ebp);
4511053d10c438f14580aaf4ab1b2aad93a5a4fe8b82Steve Block  __ push(Immediate(Smi::FromInt(StackFrame::OUTERMOST_JSENTRY_FRAME)));
4512053d10c438f14580aaf4ab1b2aad93a5a4fe8b82Steve Block  Label cont;
451369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ jmp(&cont, Label::kNear);
451480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&not_outermost_js);
4515053d10c438f14580aaf4ab1b2aad93a5a4fe8b82Steve Block  __ push(Immediate(Smi::FromInt(StackFrame::INNER_JSENTRY_FRAME)));
4516053d10c438f14580aaf4ab1b2aad93a5a4fe8b82Steve Block  __ bind(&cont);
451780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
451880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Call a faked try-block that does the invoke.
451980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ call(&invoke);
452080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
452180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Caught exception: Store result (exception) in the pending
452280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // exception field in the JSEnv and return a failure sentinel.
4523589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch  ExternalReference pending_exception(Isolate::kPendingExceptionAddress,
452444f0eee88ff00398ff7f715fab053374d808c90dSteve Block                                      masm->isolate());
452580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(Operand::StaticVariable(pending_exception), eax);
452680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(eax, reinterpret_cast<int32_t>(Failure::Exception()));
452780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ jmp(&exit);
452880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
452980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Invoke: Link this frame into the handler chain.
453080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&invoke);
453180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ PushTryHandler(IN_JS_ENTRY, JS_ENTRY_HANDLER);
453280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
453380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Clear any pending exceptions.
453444f0eee88ff00398ff7f715fab053374d808c90dSteve Block  ExternalReference the_hole_location =
453544f0eee88ff00398ff7f715fab053374d808c90dSteve Block      ExternalReference::the_hole_value_location(masm->isolate());
453644f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ mov(edx, Operand::StaticVariable(the_hole_location));
453780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(Operand::StaticVariable(pending_exception), edx);
453880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
453980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Fake a receiver (NULL).
454080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ push(Immediate(0));  // receiver
454180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
454280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Invoke the function by calling through JS entry trampoline
454380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // builtin and pop the faked function when we return. Notice that we
454480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // cannot store a reference to the trampoline code directly in this
454580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // stub, because the builtin stubs may not have been generated yet.
454680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  if (is_construct) {
454744f0eee88ff00398ff7f715fab053374d808c90dSteve Block    ExternalReference construct_entry(
454844f0eee88ff00398ff7f715fab053374d808c90dSteve Block        Builtins::kJSConstructEntryTrampoline,
454944f0eee88ff00398ff7f715fab053374d808c90dSteve Block        masm->isolate());
455080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ mov(edx, Immediate(construct_entry));
455180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  } else {
455244f0eee88ff00398ff7f715fab053374d808c90dSteve Block    ExternalReference entry(Builtins::kJSEntryTrampoline,
455344f0eee88ff00398ff7f715fab053374d808c90dSteve Block                            masm->isolate());
455480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ mov(edx, Immediate(entry));
455580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
455680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(edx, Operand(edx, 0));  // deref address
455780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ lea(edx, FieldOperand(edx, Code::kHeaderSize));
455880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ call(Operand(edx));
455980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
456080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Unlink this frame from the handler chain.
4561053d10c438f14580aaf4ab1b2aad93a5a4fe8b82Steve Block  __ PopTryHandler();
456280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
4563053d10c438f14580aaf4ab1b2aad93a5a4fe8b82Steve Block  __ bind(&exit);
4564053d10c438f14580aaf4ab1b2aad93a5a4fe8b82Steve Block  // Check if the current stack frame is marked as the outermost JS frame.
4565053d10c438f14580aaf4ab1b2aad93a5a4fe8b82Steve Block  __ pop(ebx);
4566053d10c438f14580aaf4ab1b2aad93a5a4fe8b82Steve Block  __ cmp(Operand(ebx),
4567053d10c438f14580aaf4ab1b2aad93a5a4fe8b82Steve Block         Immediate(Smi::FromInt(StackFrame::OUTERMOST_JSENTRY_FRAME)));
456880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(not_equal, &not_outermost_js_2);
456980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(Operand::StaticVariable(js_entry_sp), Immediate(0));
457080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&not_outermost_js_2);
457180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
457280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Restore the top frame descriptor from the stack.
457344f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ pop(Operand::StaticVariable(ExternalReference(
4574589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch      Isolate::kCEntryFPAddress,
457544f0eee88ff00398ff7f715fab053374d808c90dSteve Block      masm->isolate())));
457680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
457780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Restore callee-saved registers (C calling conventions).
457880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ pop(ebx);
457980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ pop(esi);
458080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ pop(edi);
458180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ add(Operand(esp), Immediate(2 * kPointerSize));  // remove markers
458280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
458380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Restore frame pointer and return.
458480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ pop(ebp);
458580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ ret(0);
458680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
458780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
458880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
4589086aeeaae12517475c22695a200be45495516549Ben Murdoch// Generate stub code for instanceof.
4590086aeeaae12517475c22695a200be45495516549Ben Murdoch// This code can patch a call site inlined cache of the instance of check,
4591086aeeaae12517475c22695a200be45495516549Ben Murdoch// which looks like this.
4592086aeeaae12517475c22695a200be45495516549Ben Murdoch//
4593086aeeaae12517475c22695a200be45495516549Ben Murdoch//   81 ff XX XX XX XX   cmp    edi, <the hole, patched to a map>
4594086aeeaae12517475c22695a200be45495516549Ben Murdoch//   75 0a               jne    <some near label>
4595086aeeaae12517475c22695a200be45495516549Ben Murdoch//   b8 XX XX XX XX      mov    eax, <the hole, patched to either true or false>
4596086aeeaae12517475c22695a200be45495516549Ben Murdoch//
4597086aeeaae12517475c22695a200be45495516549Ben Murdoch// If call site patching is requested the stack will have the delta from the
4598086aeeaae12517475c22695a200be45495516549Ben Murdoch// return address to the cmp instruction just below the return address. This
4599086aeeaae12517475c22695a200be45495516549Ben Murdoch// also means that call site patching can only take place with arguments in
4600086aeeaae12517475c22695a200be45495516549Ben Murdoch// registers. TOS looks like this when call site patching is requested
4601086aeeaae12517475c22695a200be45495516549Ben Murdoch//
4602086aeeaae12517475c22695a200be45495516549Ben Murdoch//   esp[0] : return address
4603086aeeaae12517475c22695a200be45495516549Ben Murdoch//   esp[4] : delta from return address to cmp instruction
4604086aeeaae12517475c22695a200be45495516549Ben Murdoch//
460580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid InstanceofStub::Generate(MacroAssembler* masm) {
4606086aeeaae12517475c22695a200be45495516549Ben Murdoch  // Call site inlining and patching implies arguments in registers.
4607086aeeaae12517475c22695a200be45495516549Ben Murdoch  ASSERT(HasArgsInRegisters() || !HasCallSiteInlineCheck());
4608086aeeaae12517475c22695a200be45495516549Ben Murdoch
4609b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Fixed register usage throughout the stub.
4610b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  Register object = eax;  // Object (lhs).
4611b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  Register map = ebx;  // Map of the object.
4612b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  Register function = edx;  // Function (rhs).
4613b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  Register prototype = edi;  // Prototype of the function.
4614b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  Register scratch = ecx;
4615b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
4616086aeeaae12517475c22695a200be45495516549Ben Murdoch  // Constants describing the call site code to patch.
4617086aeeaae12517475c22695a200be45495516549Ben Murdoch  static const int kDeltaToCmpImmediate = 2;
4618086aeeaae12517475c22695a200be45495516549Ben Murdoch  static const int kDeltaToMov = 8;
4619086aeeaae12517475c22695a200be45495516549Ben Murdoch  static const int kDeltaToMovImmediate = 9;
4620086aeeaae12517475c22695a200be45495516549Ben Murdoch  static const int8_t kCmpEdiImmediateByte1 = BitCast<int8_t, uint8_t>(0x81);
4621086aeeaae12517475c22695a200be45495516549Ben Murdoch  static const int8_t kCmpEdiImmediateByte2 = BitCast<int8_t, uint8_t>(0xff);
4622086aeeaae12517475c22695a200be45495516549Ben Murdoch  static const int8_t kMovEaxImmediateByte = BitCast<int8_t, uint8_t>(0xb8);
4623086aeeaae12517475c22695a200be45495516549Ben Murdoch
462444f0eee88ff00398ff7f715fab053374d808c90dSteve Block  ExternalReference roots_address =
462544f0eee88ff00398ff7f715fab053374d808c90dSteve Block      ExternalReference::roots_address(masm->isolate());
4626086aeeaae12517475c22695a200be45495516549Ben Murdoch
4627086aeeaae12517475c22695a200be45495516549Ben Murdoch  ASSERT_EQ(object.code(), InstanceofStub::left().code());
4628086aeeaae12517475c22695a200be45495516549Ben Murdoch  ASSERT_EQ(function.code(), InstanceofStub::right().code());
4629086aeeaae12517475c22695a200be45495516549Ben Murdoch
4630b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Get the object and function - they are always both needed.
4631b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  Label slow, not_js_object;
4632086aeeaae12517475c22695a200be45495516549Ben Murdoch  if (!HasArgsInRegisters()) {
4633b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ mov(object, Operand(esp, 2 * kPointerSize));
4634b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ mov(function, Operand(esp, 1 * kPointerSize));
4635b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  }
463680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
463780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check that the left hand is a JS object.
46383fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ JumpIfSmi(object, &not_js_object);
4639b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ IsObjectJSObjectType(object, map, scratch, &not_js_object);
464080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
4641086aeeaae12517475c22695a200be45495516549Ben Murdoch  // If there is a call site cache don't look in the global cache, but do the
4642086aeeaae12517475c22695a200be45495516549Ben Murdoch  // real lookup and update the call site cache.
4643086aeeaae12517475c22695a200be45495516549Ben Murdoch  if (!HasCallSiteInlineCheck()) {
4644086aeeaae12517475c22695a200be45495516549Ben Murdoch    // Look up the function and the map in the instanceof cache.
4645257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Label miss;
4646086aeeaae12517475c22695a200be45495516549Ben Murdoch    __ mov(scratch, Immediate(Heap::kInstanceofCacheFunctionRootIndex));
4647086aeeaae12517475c22695a200be45495516549Ben Murdoch    __ cmp(function,
4648086aeeaae12517475c22695a200be45495516549Ben Murdoch           Operand::StaticArray(scratch, times_pointer_size, roots_address));
4649257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ j(not_equal, &miss, Label::kNear);
4650086aeeaae12517475c22695a200be45495516549Ben Murdoch    __ mov(scratch, Immediate(Heap::kInstanceofCacheMapRootIndex));
4651086aeeaae12517475c22695a200be45495516549Ben Murdoch    __ cmp(map, Operand::StaticArray(
4652086aeeaae12517475c22695a200be45495516549Ben Murdoch        scratch, times_pointer_size, roots_address));
4653257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ j(not_equal, &miss, Label::kNear);
4654086aeeaae12517475c22695a200be45495516549Ben Murdoch    __ mov(scratch, Immediate(Heap::kInstanceofCacheAnswerRootIndex));
4655086aeeaae12517475c22695a200be45495516549Ben Murdoch    __ mov(eax, Operand::StaticArray(
4656086aeeaae12517475c22695a200be45495516549Ben Murdoch        scratch, times_pointer_size, roots_address));
4657086aeeaae12517475c22695a200be45495516549Ben Murdoch    __ ret((HasArgsInRegisters() ? 0 : 2) * kPointerSize);
4658086aeeaae12517475c22695a200be45495516549Ben Murdoch    __ bind(&miss);
4659086aeeaae12517475c22695a200be45495516549Ben Murdoch  }
4660086aeeaae12517475c22695a200be45495516549Ben Murdoch
4661b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Get the prototype of the function.
4662b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ TryGetFunctionPrototype(function, prototype, scratch, &slow);
466380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
466480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check that the function prototype is a JS object.
46653fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ JumpIfSmi(prototype, &slow);
4666b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ IsObjectJSObjectType(prototype, scratch, scratch, &slow);
4667b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
4668086aeeaae12517475c22695a200be45495516549Ben Murdoch  // Update the global instanceof or call site inlined cache with the current
4669086aeeaae12517475c22695a200be45495516549Ben Murdoch  // map and function. The cached answer will be set when it is known below.
4670086aeeaae12517475c22695a200be45495516549Ben Murdoch  if (!HasCallSiteInlineCheck()) {
4671b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ mov(scratch, Immediate(Heap::kInstanceofCacheMapRootIndex));
4672b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ mov(Operand::StaticArray(scratch, times_pointer_size, roots_address), map);
4673b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ mov(scratch, Immediate(Heap::kInstanceofCacheFunctionRootIndex));
4674b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ mov(Operand::StaticArray(scratch, times_pointer_size, roots_address),
4675b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch         function);
4676086aeeaae12517475c22695a200be45495516549Ben Murdoch  } else {
4677086aeeaae12517475c22695a200be45495516549Ben Murdoch    // The constants for the code patching are based on no push instructions
4678086aeeaae12517475c22695a200be45495516549Ben Murdoch    // at the call site.
4679086aeeaae12517475c22695a200be45495516549Ben Murdoch    ASSERT(HasArgsInRegisters());
4680086aeeaae12517475c22695a200be45495516549Ben Murdoch    // Get return address and delta to inlined map check.
4681086aeeaae12517475c22695a200be45495516549Ben Murdoch    __ mov(scratch, Operand(esp, 0 * kPointerSize));
4682086aeeaae12517475c22695a200be45495516549Ben Murdoch    __ sub(scratch, Operand(esp, 1 * kPointerSize));
4683086aeeaae12517475c22695a200be45495516549Ben Murdoch    if (FLAG_debug_code) {
4684086aeeaae12517475c22695a200be45495516549Ben Murdoch      __ cmpb(Operand(scratch, 0), kCmpEdiImmediateByte1);
4685086aeeaae12517475c22695a200be45495516549Ben Murdoch      __ Assert(equal, "InstanceofStub unexpected call site cache (cmp 1)");
4686086aeeaae12517475c22695a200be45495516549Ben Murdoch      __ cmpb(Operand(scratch, 1), kCmpEdiImmediateByte2);
4687086aeeaae12517475c22695a200be45495516549Ben Murdoch      __ Assert(equal, "InstanceofStub unexpected call site cache (cmp 2)");
4688086aeeaae12517475c22695a200be45495516549Ben Murdoch    }
4689086aeeaae12517475c22695a200be45495516549Ben Murdoch    __ mov(Operand(scratch, kDeltaToCmpImmediate), map);
4690086aeeaae12517475c22695a200be45495516549Ben Murdoch  }
4691b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
4692b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Loop through the prototype chain of the object looking for the function
4693b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // prototype.
4694b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ mov(scratch, FieldOperand(map, Map::kPrototypeOffset));
4695257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label loop, is_instance, is_not_instance;
469680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&loop);
4697b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ cmp(scratch, Operand(prototype));
4698257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(equal, &is_instance, Label::kNear);
469944f0eee88ff00398ff7f715fab053374d808c90dSteve Block  Factory* factory = masm->isolate()->factory();
470044f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ cmp(Operand(scratch), Immediate(factory->null_value()));
4701257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(equal, &is_not_instance, Label::kNear);
4702b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ mov(scratch, FieldOperand(scratch, HeapObject::kMapOffset));
4703b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ mov(scratch, FieldOperand(scratch, Map::kPrototypeOffset));
470480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ jmp(&loop);
470580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
470680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&is_instance);
4707086aeeaae12517475c22695a200be45495516549Ben Murdoch  if (!HasCallSiteInlineCheck()) {
4708086aeeaae12517475c22695a200be45495516549Ben Murdoch    __ Set(eax, Immediate(0));
4709086aeeaae12517475c22695a200be45495516549Ben Murdoch    __ mov(scratch, Immediate(Heap::kInstanceofCacheAnswerRootIndex));
4710086aeeaae12517475c22695a200be45495516549Ben Murdoch    __ mov(Operand::StaticArray(scratch,
4711086aeeaae12517475c22695a200be45495516549Ben Murdoch                                times_pointer_size, roots_address), eax);
4712086aeeaae12517475c22695a200be45495516549Ben Murdoch  } else {
4713086aeeaae12517475c22695a200be45495516549Ben Murdoch    // Get return address and delta to inlined map check.
471444f0eee88ff00398ff7f715fab053374d808c90dSteve Block    __ mov(eax, factory->true_value());
4715086aeeaae12517475c22695a200be45495516549Ben Murdoch    __ mov(scratch, Operand(esp, 0 * kPointerSize));
4716086aeeaae12517475c22695a200be45495516549Ben Murdoch    __ sub(scratch, Operand(esp, 1 * kPointerSize));
4717086aeeaae12517475c22695a200be45495516549Ben Murdoch    if (FLAG_debug_code) {
4718086aeeaae12517475c22695a200be45495516549Ben Murdoch      __ cmpb(Operand(scratch, kDeltaToMov), kMovEaxImmediateByte);
4719086aeeaae12517475c22695a200be45495516549Ben Murdoch      __ Assert(equal, "InstanceofStub unexpected call site cache (mov)");
4720086aeeaae12517475c22695a200be45495516549Ben Murdoch    }
4721086aeeaae12517475c22695a200be45495516549Ben Murdoch    __ mov(Operand(scratch, kDeltaToMovImmediate), eax);
4722086aeeaae12517475c22695a200be45495516549Ben Murdoch    if (!ReturnTrueFalseObject()) {
4723086aeeaae12517475c22695a200be45495516549Ben Murdoch      __ Set(eax, Immediate(0));
4724086aeeaae12517475c22695a200be45495516549Ben Murdoch    }
4725086aeeaae12517475c22695a200be45495516549Ben Murdoch  }
4726086aeeaae12517475c22695a200be45495516549Ben Murdoch  __ ret((HasArgsInRegisters() ? 0 : 2) * kPointerSize);
472780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
472880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&is_not_instance);
4729086aeeaae12517475c22695a200be45495516549Ben Murdoch  if (!HasCallSiteInlineCheck()) {
4730086aeeaae12517475c22695a200be45495516549Ben Murdoch    __ Set(eax, Immediate(Smi::FromInt(1)));
4731086aeeaae12517475c22695a200be45495516549Ben Murdoch    __ mov(scratch, Immediate(Heap::kInstanceofCacheAnswerRootIndex));
4732086aeeaae12517475c22695a200be45495516549Ben Murdoch    __ mov(Operand::StaticArray(
4733086aeeaae12517475c22695a200be45495516549Ben Murdoch        scratch, times_pointer_size, roots_address), eax);
4734086aeeaae12517475c22695a200be45495516549Ben Murdoch  } else {
4735086aeeaae12517475c22695a200be45495516549Ben Murdoch    // Get return address and delta to inlined map check.
473644f0eee88ff00398ff7f715fab053374d808c90dSteve Block    __ mov(eax, factory->false_value());
4737086aeeaae12517475c22695a200be45495516549Ben Murdoch    __ mov(scratch, Operand(esp, 0 * kPointerSize));
4738086aeeaae12517475c22695a200be45495516549Ben Murdoch    __ sub(scratch, Operand(esp, 1 * kPointerSize));
4739086aeeaae12517475c22695a200be45495516549Ben Murdoch    if (FLAG_debug_code) {
4740086aeeaae12517475c22695a200be45495516549Ben Murdoch      __ cmpb(Operand(scratch, kDeltaToMov), kMovEaxImmediateByte);
4741086aeeaae12517475c22695a200be45495516549Ben Murdoch      __ Assert(equal, "InstanceofStub unexpected call site cache (mov)");
4742086aeeaae12517475c22695a200be45495516549Ben Murdoch    }
4743086aeeaae12517475c22695a200be45495516549Ben Murdoch    __ mov(Operand(scratch, kDeltaToMovImmediate), eax);
4744086aeeaae12517475c22695a200be45495516549Ben Murdoch    if (!ReturnTrueFalseObject()) {
4745086aeeaae12517475c22695a200be45495516549Ben Murdoch      __ Set(eax, Immediate(Smi::FromInt(1)));
4746086aeeaae12517475c22695a200be45495516549Ben Murdoch    }
4747086aeeaae12517475c22695a200be45495516549Ben Murdoch  }
4748086aeeaae12517475c22695a200be45495516549Ben Murdoch  __ ret((HasArgsInRegisters() ? 0 : 2) * kPointerSize);
4749b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
4750b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  Label object_not_null, object_not_null_or_smi;
4751b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ bind(&not_js_object);
4752b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Before null, smi and string value checks, check that the rhs is a function
4753b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // as for a non-function rhs an exception needs to be thrown.
475469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ JumpIfSmi(function, &slow, Label::kNear);
4755b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ CmpObjectType(function, JS_FUNCTION_TYPE, scratch);
475669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ j(not_equal, &slow, Label::kNear);
4757b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
4758b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Null is not instance of anything.
475944f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ cmp(object, factory->null_value());
476069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ j(not_equal, &object_not_null, Label::kNear);
4761b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ Set(eax, Immediate(Smi::FromInt(1)));
4762086aeeaae12517475c22695a200be45495516549Ben Murdoch  __ ret((HasArgsInRegisters() ? 0 : 2) * kPointerSize);
4763b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
4764b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ bind(&object_not_null);
4765b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Smi values is not instance of anything.
476669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ JumpIfNotSmi(object, &object_not_null_or_smi, Label::kNear);
4767b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ Set(eax, Immediate(Smi::FromInt(1)));
4768086aeeaae12517475c22695a200be45495516549Ben Murdoch  __ ret((HasArgsInRegisters() ? 0 : 2) * kPointerSize);
4769b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
4770b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ bind(&object_not_null_or_smi);
4771b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // String values is not instance of anything.
4772b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  Condition is_string = masm->IsObjectStringType(object, scratch, scratch);
477369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ j(NegateCondition(is_string), &slow, Label::kNear);
4774b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ Set(eax, Immediate(Smi::FromInt(1)));
4775086aeeaae12517475c22695a200be45495516549Ben Murdoch  __ ret((HasArgsInRegisters() ? 0 : 2) * kPointerSize);
477680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
477780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Slow-case: Go through the JavaScript implementation.
477880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&slow);
4779086aeeaae12517475c22695a200be45495516549Ben Murdoch  if (!ReturnTrueFalseObject()) {
4780086aeeaae12517475c22695a200be45495516549Ben Murdoch    // Tail call the builtin which returns 0 or 1.
4781086aeeaae12517475c22695a200be45495516549Ben Murdoch    if (HasArgsInRegisters()) {
4782086aeeaae12517475c22695a200be45495516549Ben Murdoch      // Push arguments below return address.
4783086aeeaae12517475c22695a200be45495516549Ben Murdoch      __ pop(scratch);
4784086aeeaae12517475c22695a200be45495516549Ben Murdoch      __ push(object);
4785086aeeaae12517475c22695a200be45495516549Ben Murdoch      __ push(function);
4786086aeeaae12517475c22695a200be45495516549Ben Murdoch      __ push(scratch);
4787086aeeaae12517475c22695a200be45495516549Ben Murdoch    }
4788086aeeaae12517475c22695a200be45495516549Ben Murdoch    __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION);
4789086aeeaae12517475c22695a200be45495516549Ben Murdoch  } else {
4790086aeeaae12517475c22695a200be45495516549Ben Murdoch    // Call the builtin and convert 0/1 to true/false.
4791086aeeaae12517475c22695a200be45495516549Ben Murdoch    __ EnterInternalFrame();
4792b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ push(object);
4793b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ push(function);
4794086aeeaae12517475c22695a200be45495516549Ben Murdoch    __ InvokeBuiltin(Builtins::INSTANCE_OF, CALL_FUNCTION);
4795086aeeaae12517475c22695a200be45495516549Ben Murdoch    __ LeaveInternalFrame();
4796257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Label true_value, done;
4797086aeeaae12517475c22695a200be45495516549Ben Murdoch    __ test(eax, Operand(eax));
4798257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ j(zero, &true_value, Label::kNear);
479944f0eee88ff00398ff7f715fab053374d808c90dSteve Block    __ mov(eax, factory->false_value());
4800257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ jmp(&done, Label::kNear);
4801086aeeaae12517475c22695a200be45495516549Ben Murdoch    __ bind(&true_value);
480244f0eee88ff00398ff7f715fab053374d808c90dSteve Block    __ mov(eax, factory->true_value());
4803086aeeaae12517475c22695a200be45495516549Ben Murdoch    __ bind(&done);
4804086aeeaae12517475c22695a200be45495516549Ben Murdoch    __ ret((HasArgsInRegisters() ? 0 : 2) * kPointerSize);
4805b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  }
480680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
480780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
480880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
4809086aeeaae12517475c22695a200be45495516549Ben MurdochRegister InstanceofStub::left() { return eax; }
4810086aeeaae12517475c22695a200be45495516549Ben Murdoch
4811086aeeaae12517475c22695a200be45495516549Ben Murdoch
4812086aeeaae12517475c22695a200be45495516549Ben MurdochRegister InstanceofStub::right() { return edx; }
4813086aeeaae12517475c22695a200be45495516549Ben Murdoch
4814086aeeaae12517475c22695a200be45495516549Ben Murdoch
481580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenint CompareStub::MinorKey() {
481680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Encode the three parameters in a unique 16 bit value. To avoid duplicate
481780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // stubs the never NaN NaN condition is only taken into account if the
481880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // condition is equals.
481980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  ASSERT(static_cast<unsigned>(cc_) < (1 << 12));
482080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  ASSERT(lhs_.is(no_reg) && rhs_.is(no_reg));
482180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  return ConditionField::encode(static_cast<unsigned>(cc_))
482280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen         | RegisterField::encode(false)   // lhs_ and rhs_ are not used
482380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen         | StrictField::encode(strict_)
482480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen         | NeverNanNanField::encode(cc_ == equal ? never_nan_nan_ : false)
48250d5e116f6aee03185f237311a943491bb079a768Kristian Monsen         | IncludeNumberCompareField::encode(include_number_compare_)
48260d5e116f6aee03185f237311a943491bb079a768Kristian Monsen         | IncludeSmiCompareField::encode(include_smi_compare_);
482780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
482880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
482980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
483080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// Unfortunately you have to run without snapshots to see most of these
483180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// names in the profile since most compare stubs end up in the snapshot.
48323fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdochvoid CompareStub::PrintName(StringStream* stream) {
483380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  ASSERT(lhs_.is(no_reg) && rhs_.is(no_reg));
483480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  const char* cc_name;
483580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  switch (cc_) {
483680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    case less: cc_name = "LT"; break;
483780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    case greater: cc_name = "GT"; break;
483880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    case less_equal: cc_name = "LE"; break;
483980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    case greater_equal: cc_name = "GE"; break;
484080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    case equal: cc_name = "EQ"; break;
484180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    case not_equal: cc_name = "NE"; break;
484280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    default: cc_name = "UnknownCondition"; break;
484380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
48443fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  bool is_equality = cc_ == equal || cc_ == not_equal;
48453fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  stream->Add("CompareStub_%s", cc_name);
48463fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  if (strict_ && is_equality) stream->Add("_STRICT");
48473fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  if (never_nan_nan_ && is_equality) stream->Add("_NO_NAN");
48483fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  if (!include_number_compare_) stream->Add("_NO_NUMBER");
48493fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  if (!include_smi_compare_) stream->Add("_NO_SMI");
485080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
485180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
485280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
485380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// -------------------------------------------------------------------------
485480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// StringCharCodeAtGenerator
485580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
485680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StringCharCodeAtGenerator::GenerateFast(MacroAssembler* masm) {
485780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label flat_string;
485880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label ascii_string;
485980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label got_char_code;
486069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  Label sliced_string;
486180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
486280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // If the receiver is a smi trigger the non-string case.
486380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  STATIC_ASSERT(kSmiTag == 0);
48643fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ JumpIfSmi(object_, receiver_not_string_);
486580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
486680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Fetch the instance type of the receiver into result register.
486780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(result_, FieldOperand(object_, HeapObject::kMapOffset));
486880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movzx_b(result_, FieldOperand(result_, Map::kInstanceTypeOffset));
486980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // If the receiver is not a string trigger the non-string case.
487080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ test(result_, Immediate(kIsNotStringMask));
487180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(not_zero, receiver_not_string_);
487280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
487380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // If the index is non-smi trigger the non-smi case.
487480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  STATIC_ASSERT(kSmiTag == 0);
48753fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ JumpIfNotSmi(index_, &index_not_smi_);
487680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
487780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Put smi-tagged index into scratch register.
487880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(scratch_, index_);
487980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&got_smi_index_);
488080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
488180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check for index out of range.
488280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cmp(scratch_, FieldOperand(object_, String::kLengthOffset));
488380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(above_equal, index_out_of_range_);
488480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
488580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // We need special handling for non-flat strings.
488680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  STATIC_ASSERT(kSeqStringTag == 0);
488780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ test(result_, Immediate(kStringRepresentationMask));
488880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(zero, &flat_string);
488980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
489080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Handle non-flat strings.
489169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ and_(result_, kStringRepresentationMask);
489269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  STATIC_ASSERT(kConsStringTag < kExternalStringTag);
489369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  STATIC_ASSERT(kSlicedStringTag > kExternalStringTag);
489469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ cmp(result_, kExternalStringTag);
489569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ j(greater, &sliced_string, Label::kNear);
489669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ j(equal, &call_runtime_);
489780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
489880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // ConsString.
489980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check whether the right hand side is the empty string (i.e. if
490080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // this is really a flat string in a cons string). If that is not
490180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // the case we would rather go to the runtime system now to flatten
490280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // the string.
490369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  Label assure_seq_string;
490480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cmp(FieldOperand(object_, ConsString::kSecondOffset),
490544f0eee88ff00398ff7f715fab053374d808c90dSteve Block         Immediate(masm->isolate()->factory()->empty_string()));
490680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(not_equal, &call_runtime_);
490780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Get the first of the two strings and load its instance type.
490880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(object_, FieldOperand(object_, ConsString::kFirstOffset));
490969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ jmp(&assure_seq_string, Label::kNear);
491069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch
491169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  // SlicedString, unpack and add offset.
491269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ bind(&sliced_string);
491369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ add(scratch_, FieldOperand(object_, SlicedString::kOffsetOffset));
491469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ mov(object_, FieldOperand(object_, SlicedString::kParentOffset));
491569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch
491669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  // Assure that we are dealing with a sequential string. Go to runtime if not.
491769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ bind(&assure_seq_string);
491880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(result_, FieldOperand(object_, HeapObject::kMapOffset));
491980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movzx_b(result_, FieldOperand(result_, Map::kInstanceTypeOffset));
492080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  STATIC_ASSERT(kSeqStringTag == 0);
492180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ test(result_, Immediate(kStringRepresentationMask));
492280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(not_zero, &call_runtime_);
492369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ jmp(&flat_string, Label::kNear);
492480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
492580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check for 1-byte or 2-byte string.
492680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&flat_string);
4927589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch  STATIC_ASSERT((kStringEncodingMask & kAsciiStringTag) != 0);
4928589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch  STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0);
492980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ test(result_, Immediate(kStringEncodingMask));
493069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ j(not_zero, &ascii_string, Label::kNear);
493180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
493280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // 2-byte string.
493380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Load the 2-byte character code into the result register.
493480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize == 1);
493580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movzx_w(result_, FieldOperand(object_,
493680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                   scratch_, times_1,  // Scratch is smi-tagged.
493780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                   SeqTwoByteString::kHeaderSize));
493869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ jmp(&got_char_code, Label::kNear);
493980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
494080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // ASCII string.
494180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Load the byte into the result register.
494280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&ascii_string);
494380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiUntag(scratch_);
494480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movzx_b(result_, FieldOperand(object_,
494580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                   scratch_, times_1,
494680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                   SeqAsciiString::kHeaderSize));
494780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&got_char_code);
494880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiTag(result_);
494980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&exit_);
495080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
495180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
495280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
495380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StringCharCodeAtGenerator::GenerateSlow(
495480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    MacroAssembler* masm, const RuntimeCallHelper& call_helper) {
495580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ Abort("Unexpected fallthrough to CharCodeAt slow case");
495680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
495780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Index is not a smi.
495880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&index_not_smi_);
495980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // If index is a heap number, try converting it to an integer.
496044f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ CheckMap(index_,
496144f0eee88ff00398ff7f715fab053374d808c90dSteve Block              masm->isolate()->factory()->heap_number_map(),
496244f0eee88ff00398ff7f715fab053374d808c90dSteve Block              index_not_number_,
4963257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch              DONT_DO_SMI_CHECK);
496480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  call_helper.BeforeCall(masm);
496580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ push(object_);
496680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ push(index_);
496780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ push(index_);  // Consumed by runtime conversion function.
496880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  if (index_flags_ == STRING_INDEX_IS_NUMBER) {
496980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ CallRuntime(Runtime::kNumberToIntegerMapMinusZero, 1);
497080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  } else {
497180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    ASSERT(index_flags_ == STRING_INDEX_IS_ARRAY_INDEX);
497280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // NumberToSmi discards numbers that are not exact integers.
497380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ CallRuntime(Runtime::kNumberToSmi, 1);
497480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
497580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  if (!scratch_.is(eax)) {
497680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // Save the conversion result before the pop instructions below
497780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // have a chance to overwrite it.
497880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ mov(scratch_, eax);
497980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
498080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ pop(index_);
498180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ pop(object_);
498280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Reload the instance type.
498380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(result_, FieldOperand(object_, HeapObject::kMapOffset));
498480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movzx_b(result_, FieldOperand(result_, Map::kInstanceTypeOffset));
498580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  call_helper.AfterCall(masm);
498680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // If index is still not a smi, it must be out of range.
498780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  STATIC_ASSERT(kSmiTag == 0);
49883fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ JumpIfNotSmi(scratch_, index_out_of_range_);
498980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Otherwise, return to the fast path.
499080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ jmp(&got_smi_index_);
499180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
499280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Call runtime. We get here when the receiver is a string and the
499380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // index is a number, but the code of getting the actual character
499480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // is too complex (e.g., when the string needs to be flattened).
499580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&call_runtime_);
499680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  call_helper.BeforeCall(masm);
499780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ push(object_);
499880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ push(index_);
499980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ CallRuntime(Runtime::kStringCharCodeAt, 2);
500080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  if (!result_.is(eax)) {
500180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ mov(result_, eax);
500280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
500380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  call_helper.AfterCall(masm);
500480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ jmp(&exit_);
500580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
500680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ Abort("Unexpected fallthrough from CharCodeAt slow case");
500780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
500880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
500980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
501080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// -------------------------------------------------------------------------
501180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// StringCharFromCodeGenerator
501280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
501380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StringCharFromCodeGenerator::GenerateFast(MacroAssembler* masm) {
501480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Fast case of Heap::LookupSingleCharacterStringFromCode.
501580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  STATIC_ASSERT(kSmiTag == 0);
501680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  STATIC_ASSERT(kSmiShiftSize == 0);
501780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  ASSERT(IsPowerOf2(String::kMaxAsciiCharCode + 1));
501880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ test(code_,
501980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen          Immediate(kSmiTagMask |
502080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                    ((~String::kMaxAsciiCharCode) << kSmiTagSize)));
5021257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(not_zero, &slow_case_);
502280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
502344f0eee88ff00398ff7f715fab053374d808c90dSteve Block  Factory* factory = masm->isolate()->factory();
502444f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ Set(result_, Immediate(factory->single_character_string_cache()));
502580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  STATIC_ASSERT(kSmiTag == 0);
502680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  STATIC_ASSERT(kSmiTagSize == 1);
502780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  STATIC_ASSERT(kSmiShiftSize == 0);
502880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // At this point code register contains smi tagged ascii char code.
502980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(result_, FieldOperand(result_,
503080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                               code_, times_half_pointer_size,
503180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                               FixedArray::kHeaderSize));
503244f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ cmp(result_, factory->undefined_value());
5033257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(equal, &slow_case_);
503480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&exit_);
503580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
503680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
503780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
503880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StringCharFromCodeGenerator::GenerateSlow(
503980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    MacroAssembler* masm, const RuntimeCallHelper& call_helper) {
504080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ Abort("Unexpected fallthrough to CharFromCode slow case");
504180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
504280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&slow_case_);
504380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  call_helper.BeforeCall(masm);
504480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ push(code_);
504580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ CallRuntime(Runtime::kCharFromCode, 1);
504680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  if (!result_.is(eax)) {
504780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ mov(result_, eax);
504880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
504980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  call_helper.AfterCall(masm);
505080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ jmp(&exit_);
505180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
505280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ Abort("Unexpected fallthrough from CharFromCode slow case");
505380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
505480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
505580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
505680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// -------------------------------------------------------------------------
505780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// StringCharAtGenerator
505880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
505980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StringCharAtGenerator::GenerateFast(MacroAssembler* masm) {
506080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  char_code_at_generator_.GenerateFast(masm);
506180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  char_from_code_generator_.GenerateFast(masm);
506280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
506380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
506480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
506580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StringCharAtGenerator::GenerateSlow(
506680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    MacroAssembler* masm, const RuntimeCallHelper& call_helper) {
506780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  char_code_at_generator_.GenerateSlow(masm, call_helper);
506880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  char_from_code_generator_.GenerateSlow(masm, call_helper);
506980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
507080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
507180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
507280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StringAddStub::Generate(MacroAssembler* masm) {
50739ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick  Label string_add_runtime, call_builtin;
50749ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick  Builtins::JavaScript builtin_id = Builtins::ADD;
507580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
507680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Load the two arguments.
507780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(eax, Operand(esp, 2 * kPointerSize));  // First argument.
507880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(edx, Operand(esp, 1 * kPointerSize));  // Second argument.
507980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
508080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Make sure that both arguments are strings if not known in advance.
50819ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick  if (flags_ == NO_STRING_ADD_FLAGS) {
50823fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    __ JumpIfSmi(eax, &string_add_runtime);
508380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ CmpObjectType(eax, FIRST_NONSTRING_TYPE, ebx);
508480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ j(above_equal, &string_add_runtime);
508580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
508680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // First argument is a a string, test second.
50873fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    __ JumpIfSmi(edx, &string_add_runtime);
508880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ CmpObjectType(edx, FIRST_NONSTRING_TYPE, ebx);
508980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ j(above_equal, &string_add_runtime);
50909ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick  } else {
50919ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick    // Here at least one of the arguments is definitely a string.
50929ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick    // We convert the one that is not known to be a string.
50939ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick    if ((flags_ & NO_STRING_CHECK_LEFT_IN_STUB) == 0) {
50949ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick      ASSERT((flags_ & NO_STRING_CHECK_RIGHT_IN_STUB) != 0);
50959ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick      GenerateConvertArgument(masm, 2 * kPointerSize, eax, ebx, ecx, edi,
50969ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick                              &call_builtin);
50979ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick      builtin_id = Builtins::STRING_ADD_RIGHT;
50989ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick    } else if ((flags_ & NO_STRING_CHECK_RIGHT_IN_STUB) == 0) {
50999ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick      ASSERT((flags_ & NO_STRING_CHECK_LEFT_IN_STUB) != 0);
51009ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick      GenerateConvertArgument(masm, 1 * kPointerSize, edx, ebx, ecx, edi,
51019ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick                              &call_builtin);
51029ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick      builtin_id = Builtins::STRING_ADD_LEFT;
51039ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick    }
510480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
510580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
510680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Both arguments are strings.
510780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // eax: first string
510880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // edx: second string
510980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check if either of the strings are empty. In that case return the other.
5110257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label second_not_zero_length, both_not_zero_length;
511180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(ecx, FieldOperand(edx, String::kLengthOffset));
511280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  STATIC_ASSERT(kSmiTag == 0);
511380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ test(ecx, Operand(ecx));
5114257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(not_zero, &second_not_zero_length, Label::kNear);
511580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Second string is empty, result is first string which is already in eax.
511644f0eee88ff00398ff7f715fab053374d808c90dSteve Block  Counters* counters = masm->isolate()->counters();
511744f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ IncrementCounter(counters->string_add_native(), 1);
511880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ ret(2 * kPointerSize);
511980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&second_not_zero_length);
512080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(ebx, FieldOperand(eax, String::kLengthOffset));
512180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  STATIC_ASSERT(kSmiTag == 0);
512280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ test(ebx, Operand(ebx));
5123257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(not_zero, &both_not_zero_length, Label::kNear);
512480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // First string is empty, result is second string which is in edx.
512580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(eax, edx);
512644f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ IncrementCounter(counters->string_add_native(), 1);
512780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ ret(2 * kPointerSize);
512880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
512980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Both strings are non-empty.
513080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // eax: first string
513180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // ebx: length of first string as a smi
513280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // ecx: length of second string as a smi
513380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // edx: second string
513480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Look at the length of the result of adding the two strings.
513580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label string_add_flat_result, longer_than_two;
513680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&both_not_zero_length);
513780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ add(ebx, Operand(ecx));
513880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  STATIC_ASSERT(Smi::kMaxValue == String::kMaxLength);
513980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Handle exceptionally long strings in the runtime system.
514080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(overflow, &string_add_runtime);
514144f0eee88ff00398ff7f715fab053374d808c90dSteve Block  // Use the symbol table when adding two one character strings, as it
514244f0eee88ff00398ff7f715fab053374d808c90dSteve Block  // helps later optimizations to return a symbol here.
514380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cmp(Operand(ebx), Immediate(Smi::FromInt(2)));
514480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(not_equal, &longer_than_two);
514580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
514680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check that both strings are non-external ascii strings.
514780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ JumpIfNotBothSequentialAsciiStrings(eax, edx, ebx, ecx,
514880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                         &string_add_runtime);
514980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
51509ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick  // Get the two characters forming the new string.
515180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movzx_b(ebx, FieldOperand(eax, SeqAsciiString::kHeaderSize));
515280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movzx_b(ecx, FieldOperand(edx, SeqAsciiString::kHeaderSize));
515380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
515480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Try to lookup two character string in symbol table. If it is not found
515580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // just allocate a new one.
51569ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick  Label make_two_character_string, make_two_character_string_no_reload;
515780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  StringHelper::GenerateTwoCharacterSymbolTableProbe(
51589ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick      masm, ebx, ecx, eax, edx, edi,
51599ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick      &make_two_character_string_no_reload, &make_two_character_string);
516044f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ IncrementCounter(counters->string_add_native(), 1);
516180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ ret(2 * kPointerSize);
516280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
51639ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick  // Allocate a two character string.
516480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&make_two_character_string);
51659ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick  // Reload the arguments.
51669ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick  __ mov(eax, Operand(esp, 2 * kPointerSize));  // First argument.
51679ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick  __ mov(edx, Operand(esp, 1 * kPointerSize));  // Second argument.
51689ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick  // Get the two characters forming the new string.
51699ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick  __ movzx_b(ebx, FieldOperand(eax, SeqAsciiString::kHeaderSize));
51709ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick  __ movzx_b(ecx, FieldOperand(edx, SeqAsciiString::kHeaderSize));
51719ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick  __ bind(&make_two_character_string_no_reload);
517244f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ IncrementCounter(counters->string_add_make_two_char(), 1);
51739ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick  __ AllocateAsciiString(eax,  // Result.
51749ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick                         2,    // Length.
51759ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick                         edi,  // Scratch 1.
51769ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick                         edx,  // Scratch 2.
51779ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick                         &string_add_runtime);
51789ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick  // Pack both characters in ebx.
51799ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick  __ shl(ecx, kBitsPerByte);
51809ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick  __ or_(ebx, Operand(ecx));
51819ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick  // Set the characters in the new string.
51829ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick  __ mov_w(FieldOperand(eax, SeqAsciiString::kHeaderSize), ebx);
518344f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ IncrementCounter(counters->string_add_native(), 1);
51849ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick  __ ret(2 * kPointerSize);
518580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
518680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&longer_than_two);
518780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check if resulting string will be flat.
518880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cmp(Operand(ebx), Immediate(Smi::FromInt(String::kMinNonFlatLength)));
518980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(below, &string_add_flat_result);
519080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
519180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // If result is not supposed to be flat allocate a cons string object. If both
519280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // strings are ascii the result is an ascii cons string.
519380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label non_ascii, allocated, ascii_data;
519480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(edi, FieldOperand(eax, HeapObject::kMapOffset));
519580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movzx_b(ecx, FieldOperand(edi, Map::kInstanceTypeOffset));
519680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(edi, FieldOperand(edx, HeapObject::kMapOffset));
519780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movzx_b(edi, FieldOperand(edi, Map::kInstanceTypeOffset));
519880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ and_(ecx, Operand(edi));
5199589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch  STATIC_ASSERT((kStringEncodingMask & kAsciiStringTag) != 0);
5200589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch  STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0);
5201589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch  __ test(ecx, Immediate(kStringEncodingMask));
520280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(zero, &non_ascii);
520380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&ascii_data);
520480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Allocate an acsii cons string.
520580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ AllocateAsciiConsString(ecx, edi, no_reg, &string_add_runtime);
520680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&allocated);
520780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Fill the fields of the cons string.
520880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  if (FLAG_debug_code) __ AbortIfNotSmi(ebx);
520980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(FieldOperand(ecx, ConsString::kLengthOffset), ebx);
521080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(FieldOperand(ecx, ConsString::kHashFieldOffset),
521180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen         Immediate(String::kEmptyHashField));
521280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(FieldOperand(ecx, ConsString::kFirstOffset), eax);
521380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(FieldOperand(ecx, ConsString::kSecondOffset), edx);
521480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(eax, ecx);
521544f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ IncrementCounter(counters->string_add_native(), 1);
521680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ ret(2 * kPointerSize);
521780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&non_ascii);
521880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // At least one of the strings is two-byte. Check whether it happens
521980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // to contain only ascii characters.
522080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // ecx: first instance type AND second instance type.
522180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // edi: second instance type.
522280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ test(ecx, Immediate(kAsciiDataHintMask));
522380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(not_zero, &ascii_data);
522480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(ecx, FieldOperand(eax, HeapObject::kMapOffset));
522580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset));
522680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ xor_(edi, Operand(ecx));
522780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  STATIC_ASSERT(kAsciiStringTag != 0 && kAsciiDataHintTag != 0);
522880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ and_(edi, kAsciiStringTag | kAsciiDataHintTag);
522980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cmp(edi, kAsciiStringTag | kAsciiDataHintTag);
523080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(equal, &ascii_data);
523180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Allocate a two byte cons string.
5232589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch  __ AllocateTwoByteConsString(ecx, edi, no_reg, &string_add_runtime);
523380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ jmp(&allocated);
523480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
523580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Handle creating a flat result. First check that both strings are not
523680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // external strings.
523780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // eax: first string
523880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // ebx: length of resulting flat string as a smi
523980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // edx: second string
524080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&string_add_flat_result);
524180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(ecx, FieldOperand(eax, HeapObject::kMapOffset));
524280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset));
524380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ and_(ecx, kStringRepresentationMask);
524480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cmp(ecx, kExternalStringTag);
524580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(equal, &string_add_runtime);
524680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset));
524780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset));
524880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ and_(ecx, kStringRepresentationMask);
524980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cmp(ecx, kExternalStringTag);
525080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(equal, &string_add_runtime);
525169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  // We cannot encounter sliced strings here since:
525269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  STATIC_ASSERT(SlicedString::kMinLength >= String::kMinNonFlatLength);
525380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Now check if both strings are ascii strings.
525480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // eax: first string
525580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // ebx: length of resulting flat string as a smi
525680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // edx: second string
525780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label non_ascii_string_add_flat_result;
5258589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch  STATIC_ASSERT((kStringEncodingMask & kAsciiStringTag) != 0);
5259589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch  STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0);
526080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(ecx, FieldOperand(eax, HeapObject::kMapOffset));
5261589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch  __ test_b(FieldOperand(ecx, Map::kInstanceTypeOffset), kStringEncodingMask);
526280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(zero, &non_ascii_string_add_flat_result);
526380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset));
5264589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch  __ test_b(FieldOperand(ecx, Map::kInstanceTypeOffset), kStringEncodingMask);
526580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(zero, &string_add_runtime);
526680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
526780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Both strings are ascii strings.  As they are short they are both flat.
526880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // ebx: length of resulting flat string as a smi
526980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiUntag(ebx);
527080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ AllocateAsciiString(eax, ebx, ecx, edx, edi, &string_add_runtime);
527180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // eax: result string
527280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(ecx, eax);
527380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Locate first character of result.
527480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ add(Operand(ecx), Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag));
527580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Load first argument and locate first character.
527680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(edx, Operand(esp, 2 * kPointerSize));
527780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(edi, FieldOperand(edx, String::kLengthOffset));
527880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiUntag(edi);
527980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ add(Operand(edx), Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag));
528080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // eax: result string
528180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // ecx: first character of result
528280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // edx: first char of first argument
528380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // edi: length of first argument
528480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  StringHelper::GenerateCopyCharacters(masm, ecx, edx, edi, ebx, true);
528580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Load second argument and locate first character.
528680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(edx, Operand(esp, 1 * kPointerSize));
528780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(edi, FieldOperand(edx, String::kLengthOffset));
528880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiUntag(edi);
528980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ add(Operand(edx), Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag));
529080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // eax: result string
529180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // ecx: next character of result
529280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // edx: first char of second argument
529380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // edi: length of second argument
529480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  StringHelper::GenerateCopyCharacters(masm, ecx, edx, edi, ebx, true);
529544f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ IncrementCounter(counters->string_add_native(), 1);
529680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ ret(2 * kPointerSize);
529780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
529880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Handle creating a flat two byte result.
529980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // eax: first string - known to be two byte
530080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // ebx: length of resulting flat string as a smi
530180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // edx: second string
530280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&non_ascii_string_add_flat_result);
530380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset));
5304589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch  __ test_b(FieldOperand(ecx, Map::kInstanceTypeOffset), kStringEncodingMask);
530580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(not_zero, &string_add_runtime);
530680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Both strings are two byte strings. As they are short they are both
530780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // flat.
530880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiUntag(ebx);
530980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ AllocateTwoByteString(eax, ebx, ecx, edx, edi, &string_add_runtime);
531080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // eax: result string
531180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(ecx, eax);
531280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Locate first character of result.
531380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ add(Operand(ecx),
531480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen         Immediate(SeqTwoByteString::kHeaderSize - kHeapObjectTag));
531580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Load first argument and locate first character.
531680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(edx, Operand(esp, 2 * kPointerSize));
531780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(edi, FieldOperand(edx, String::kLengthOffset));
531880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiUntag(edi);
531980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ add(Operand(edx),
532080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen         Immediate(SeqTwoByteString::kHeaderSize - kHeapObjectTag));
532180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // eax: result string
532280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // ecx: first character of result
532380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // edx: first char of first argument
532480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // edi: length of first argument
532580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  StringHelper::GenerateCopyCharacters(masm, ecx, edx, edi, ebx, false);
532680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Load second argument and locate first character.
532780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(edx, Operand(esp, 1 * kPointerSize));
532880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(edi, FieldOperand(edx, String::kLengthOffset));
532980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiUntag(edi);
533080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ add(Operand(edx), Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag));
533180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // eax: result string
533280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // ecx: next character of result
533380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // edx: first char of second argument
533480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // edi: length of second argument
533580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  StringHelper::GenerateCopyCharacters(masm, ecx, edx, edi, ebx, false);
533644f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ IncrementCounter(counters->string_add_native(), 1);
533780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ ret(2 * kPointerSize);
533880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
533980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Just jump to runtime to add the two strings.
534080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&string_add_runtime);
534180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ TailCallRuntime(Runtime::kStringAdd, 2, 1);
53429ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick
53439ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick  if (call_builtin.is_linked()) {
53449ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick    __ bind(&call_builtin);
53459ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick    __ InvokeBuiltin(builtin_id, JUMP_FUNCTION);
53469ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick  }
53479ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick}
53489ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick
53499ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick
53509ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrickvoid StringAddStub::GenerateConvertArgument(MacroAssembler* masm,
53519ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick                                            int stack_offset,
53529ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick                                            Register arg,
53539ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick                                            Register scratch1,
53549ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick                                            Register scratch2,
53559ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick                                            Register scratch3,
53569ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick                                            Label* slow) {
53579ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick  // First check if the argument is already a string.
53589ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick  Label not_string, done;
53593fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ JumpIfSmi(arg, &not_string);
53609ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick  __ CmpObjectType(arg, FIRST_NONSTRING_TYPE, scratch1);
53619ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick  __ j(below, &done);
53629ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick
53639ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick  // Check the number to string cache.
53649ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick  Label not_cached;
53659ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick  __ bind(&not_string);
53669ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick  // Puts the cached result into scratch1.
53679ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick  NumberToStringStub::GenerateLookupNumberStringCache(masm,
53689ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick                                                      arg,
53699ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick                                                      scratch1,
53709ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick                                                      scratch2,
53719ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick                                                      scratch3,
53729ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick                                                      false,
53739ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick                                                      &not_cached);
53749ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick  __ mov(arg, scratch1);
53759ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick  __ mov(Operand(esp, stack_offset), arg);
53769ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick  __ jmp(&done);
53779ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick
53789ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick  // Check if the argument is a safe string wrapper.
53799ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick  __ bind(&not_cached);
53803fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ JumpIfSmi(arg, slow);
53819ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick  __ CmpObjectType(arg, JS_VALUE_TYPE, scratch1);  // map -> scratch1.
53829ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick  __ j(not_equal, slow);
53839ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick  __ test_b(FieldOperand(scratch1, Map::kBitField2Offset),
53849ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick            1 << Map::kStringWrapperSafeForDefaultValueOf);
53859ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick  __ j(zero, slow);
53869ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick  __ mov(arg, FieldOperand(arg, JSValue::kValueOffset));
53879ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick  __ mov(Operand(esp, stack_offset), arg);
53889ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick
53899ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick  __ bind(&done);
539080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
539180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
539280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
539380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StringHelper::GenerateCopyCharacters(MacroAssembler* masm,
539480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                          Register dest,
539580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                          Register src,
539680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                          Register count,
539780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                          Register scratch,
539880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                          bool ascii) {
5399257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label loop;
540080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&loop);
540180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // This loop just copies one character at a time, as it is only used for very
540280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // short strings.
540380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  if (ascii) {
540480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ mov_b(scratch, Operand(src, 0));
540580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ mov_b(Operand(dest, 0), scratch);
540680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ add(Operand(src), Immediate(1));
540780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ add(Operand(dest), Immediate(1));
540880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  } else {
540980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ mov_w(scratch, Operand(src, 0));
541080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ mov_w(Operand(dest, 0), scratch);
541180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ add(Operand(src), Immediate(2));
541280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ add(Operand(dest), Immediate(2));
541380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
541480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ sub(Operand(count), Immediate(1));
541580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(not_zero, &loop);
541680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
541780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
541880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
541980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StringHelper::GenerateCopyCharactersREP(MacroAssembler* masm,
542080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                             Register dest,
542180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                             Register src,
542280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                             Register count,
542380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                             Register scratch,
542480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                             bool ascii) {
542580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Copy characters using rep movs of doublewords.
542680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // The destination is aligned on a 4 byte boundary because we are
542780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // copying to the beginning of a newly allocated string.
542880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  ASSERT(dest.is(edi));  // rep movs destination
542980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  ASSERT(src.is(esi));  // rep movs source
543080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  ASSERT(count.is(ecx));  // rep movs count
543180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  ASSERT(!scratch.is(dest));
543280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  ASSERT(!scratch.is(src));
543380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  ASSERT(!scratch.is(count));
543480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
543580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Nothing to do for zero characters.
543680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label done;
543780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ test(count, Operand(count));
543880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(zero, &done);
543980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
544080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Make count the number of bytes to copy.
544180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  if (!ascii) {
544280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ shl(count, 1);
544380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
544480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
544580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Don't enter the rep movs if there are less than 4 bytes to copy.
5446257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label last_bytes;
544780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ test(count, Immediate(~3));
5448257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(zero, &last_bytes, Label::kNear);
544980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
545080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Copy from edi to esi using rep movs instruction.
545180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(scratch, count);
545280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ sar(count, 2);  // Number of doublewords to copy.
545380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cld();
545480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ rep_movs();
545580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
545680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Find number of bytes left.
545780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(count, scratch);
545880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ and_(count, 3);
545980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
546080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check if there are more bytes to copy.
546180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&last_bytes);
546280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ test(count, Operand(count));
546380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(zero, &done);
546480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
546580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Copy remaining characters.
5466257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label loop;
546780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&loop);
546880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov_b(scratch, Operand(src, 0));
546980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov_b(Operand(dest, 0), scratch);
547080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ add(Operand(src), Immediate(1));
547180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ add(Operand(dest), Immediate(1));
547280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ sub(Operand(count), Immediate(1));
547380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(not_zero, &loop);
547480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
547580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&done);
547680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
547780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
547880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
547980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StringHelper::GenerateTwoCharacterSymbolTableProbe(MacroAssembler* masm,
548080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                                        Register c1,
548180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                                        Register c2,
548280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                                        Register scratch1,
548380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                                        Register scratch2,
548480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                                        Register scratch3,
54859ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick                                                        Label* not_probed,
548680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                                        Label* not_found) {
548780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Register scratch3 is the general scratch register in this function.
548880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Register scratch = scratch3;
548980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
549080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Make sure that both characters are not digits as such strings has a
549180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // different hash algorithm. Don't try to look for these in the symbol table.
5492257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label not_array_index;
549380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(scratch, c1);
549480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ sub(Operand(scratch), Immediate(static_cast<int>('0')));
549580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cmp(Operand(scratch), Immediate(static_cast<int>('9' - '0')));
5496257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(above, &not_array_index, Label::kNear);
549780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(scratch, c2);
549880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ sub(Operand(scratch), Immediate(static_cast<int>('0')));
549980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cmp(Operand(scratch), Immediate(static_cast<int>('9' - '0')));
55009ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick  __ j(below_equal, not_probed);
550180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
550280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&not_array_index);
550380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Calculate the two character string hash.
550480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Register hash = scratch1;
550580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  GenerateHashInit(masm, hash, c1, scratch);
550680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  GenerateHashAddCharacter(masm, hash, c2, scratch);
550780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  GenerateHashGetHash(masm, hash, scratch);
550880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
550980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Collect the two characters in a register.
551080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Register chars = c1;
551180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ shl(c2, kBitsPerByte);
551280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ or_(chars, Operand(c2));
551380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
551480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // chars: two character string, char 1 in byte 0 and char 2 in byte 1.
551580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // hash:  hash of two character string.
551680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
551780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Load the symbol table.
551880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Register symbol_table = c2;
551944f0eee88ff00398ff7f715fab053374d808c90dSteve Block  ExternalReference roots_address =
552044f0eee88ff00398ff7f715fab053374d808c90dSteve Block      ExternalReference::roots_address(masm->isolate());
552180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(scratch, Immediate(Heap::kSymbolTableRootIndex));
552280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(symbol_table,
552380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen         Operand::StaticArray(scratch, times_pointer_size, roots_address));
552480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
552580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Calculate capacity mask from the symbol table capacity.
552680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Register mask = scratch2;
552780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(mask, FieldOperand(symbol_table, SymbolTable::kCapacityOffset));
552880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiUntag(mask);
552980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ sub(Operand(mask), Immediate(1));
553080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
553180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Registers
553280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // chars:        two character string, char 1 in byte 0 and char 2 in byte 1.
553380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // hash:         hash of two character string
553480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // symbol_table: symbol table
553580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // mask:         capacity mask
553680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // scratch:      -
553780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
553880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Perform a number of probes in the symbol table.
553980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  static const int kProbes = 4;
554080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label found_in_symbol_table;
554180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label next_probe[kProbes], next_probe_pop_mask[kProbes];
5542692be65d6b06edd9ff4cfc4c308555b7c99c1191Ben Murdoch  Register candidate = scratch;  // Scratch register contains candidate.
554380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  for (int i = 0; i < kProbes; i++) {
554480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // Calculate entry in symbol table.
554580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ mov(scratch, hash);
554680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    if (i > 0) {
554780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ add(Operand(scratch), Immediate(SymbolTable::GetProbeOffset(i)));
554880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    }
554980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ and_(scratch, Operand(mask));
555080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
555180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // Load the entry from the symbol table.
555280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    STATIC_ASSERT(SymbolTable::kEntrySize == 1);
555380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ mov(candidate,
555480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen           FieldOperand(symbol_table,
555580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                        scratch,
555680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                        times_pointer_size,
555780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                        SymbolTable::kElementsStartOffset));
555880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
555980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // If entry is undefined no string with this hash can be found.
556044f0eee88ff00398ff7f715fab053374d808c90dSteve Block    Factory* factory = masm->isolate()->factory();
556144f0eee88ff00398ff7f715fab053374d808c90dSteve Block    __ cmp(candidate, factory->undefined_value());
556280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ j(equal, not_found);
556344f0eee88ff00398ff7f715fab053374d808c90dSteve Block    __ cmp(candidate, factory->null_value());
556444f0eee88ff00398ff7f715fab053374d808c90dSteve Block    __ j(equal, &next_probe[i]);
556580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
556680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // If length is not 2 the string is not a candidate.
556780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ cmp(FieldOperand(candidate, String::kLengthOffset),
556880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen           Immediate(Smi::FromInt(2)));
556980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ j(not_equal, &next_probe[i]);
557080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
557180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // As we are out of registers save the mask on the stack and use that
557280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // register as a temporary.
557380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ push(mask);
557480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    Register temp = mask;
557580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
557680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // Check that the candidate is a non-external ascii string.
557780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ mov(temp, FieldOperand(candidate, HeapObject::kMapOffset));
557880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ movzx_b(temp, FieldOperand(temp, Map::kInstanceTypeOffset));
557980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ JumpIfInstanceTypeIsNotSequentialAscii(
558080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen        temp, temp, &next_probe_pop_mask[i]);
558180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
558280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // Check if the two characters match.
558380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ mov(temp, FieldOperand(candidate, SeqAsciiString::kHeaderSize));
558480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ and_(temp, 0x0000ffff);
558580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ cmp(chars, Operand(temp));
558680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ j(equal, &found_in_symbol_table);
558780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ bind(&next_probe_pop_mask[i]);
558880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ pop(mask);
558980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ bind(&next_probe[i]);
559080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
559180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
559280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // No matching 2 character string found by probing.
559380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ jmp(not_found);
559480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
559580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Scratch register contains result when we fall through to here.
5596692be65d6b06edd9ff4cfc4c308555b7c99c1191Ben Murdoch  Register result = candidate;
559780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&found_in_symbol_table);
559880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ pop(mask);  // Pop saved mask from the stack.
559980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  if (!result.is(eax)) {
560080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ mov(eax, result);
560180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
560280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
560380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
560480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
560580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StringHelper::GenerateHashInit(MacroAssembler* masm,
560680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                    Register hash,
560780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                    Register character,
560880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                    Register scratch) {
5609692be65d6b06edd9ff4cfc4c308555b7c99c1191Ben Murdoch  // hash = (seed + character) + ((seed + character) << 10);
5610692be65d6b06edd9ff4cfc4c308555b7c99c1191Ben Murdoch  if (Serializer::enabled()) {
5611692be65d6b06edd9ff4cfc4c308555b7c99c1191Ben Murdoch    ExternalReference roots_address =
5612692be65d6b06edd9ff4cfc4c308555b7c99c1191Ben Murdoch        ExternalReference::roots_address(masm->isolate());
5613692be65d6b06edd9ff4cfc4c308555b7c99c1191Ben Murdoch    __ mov(scratch, Immediate(Heap::kStringHashSeedRootIndex));
5614692be65d6b06edd9ff4cfc4c308555b7c99c1191Ben Murdoch    __ mov(scratch, Operand::StaticArray(scratch,
5615692be65d6b06edd9ff4cfc4c308555b7c99c1191Ben Murdoch                                         times_pointer_size,
5616692be65d6b06edd9ff4cfc4c308555b7c99c1191Ben Murdoch                                         roots_address));
5617692be65d6b06edd9ff4cfc4c308555b7c99c1191Ben Murdoch    __ add(scratch, Operand(character));
5618692be65d6b06edd9ff4cfc4c308555b7c99c1191Ben Murdoch    __ mov(hash, scratch);
5619692be65d6b06edd9ff4cfc4c308555b7c99c1191Ben Murdoch    __ shl(scratch, 10);
5620692be65d6b06edd9ff4cfc4c308555b7c99c1191Ben Murdoch    __ add(hash, Operand(scratch));
5621692be65d6b06edd9ff4cfc4c308555b7c99c1191Ben Murdoch  } else {
5622692be65d6b06edd9ff4cfc4c308555b7c99c1191Ben Murdoch    int32_t seed = masm->isolate()->heap()->StringHashSeed();
5623692be65d6b06edd9ff4cfc4c308555b7c99c1191Ben Murdoch    __ lea(scratch, Operand(character, seed));
5624692be65d6b06edd9ff4cfc4c308555b7c99c1191Ben Murdoch    __ shl(scratch, 10);
5625692be65d6b06edd9ff4cfc4c308555b7c99c1191Ben Murdoch    __ lea(hash, Operand(scratch, character, times_1, seed));
5626692be65d6b06edd9ff4cfc4c308555b7c99c1191Ben Murdoch  }
562780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // hash ^= hash >> 6;
562880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(scratch, hash);
5629692be65d6b06edd9ff4cfc4c308555b7c99c1191Ben Murdoch  __ shr(scratch, 6);
563080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ xor_(hash, Operand(scratch));
563180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
563280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
563380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
563480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StringHelper::GenerateHashAddCharacter(MacroAssembler* masm,
563580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                            Register hash,
563680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                            Register character,
563780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                            Register scratch) {
563880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // hash += character;
563980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ add(hash, Operand(character));
564080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // hash += hash << 10;
564180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(scratch, hash);
564280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ shl(scratch, 10);
564380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ add(hash, Operand(scratch));
564480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // hash ^= hash >> 6;
564580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(scratch, hash);
5646692be65d6b06edd9ff4cfc4c308555b7c99c1191Ben Murdoch  __ shr(scratch, 6);
564780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ xor_(hash, Operand(scratch));
564880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
564980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
565080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
565180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StringHelper::GenerateHashGetHash(MacroAssembler* masm,
565280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                       Register hash,
565380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                       Register scratch) {
565480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // hash += hash << 3;
565580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(scratch, hash);
565680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ shl(scratch, 3);
565780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ add(hash, Operand(scratch));
565880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // hash ^= hash >> 11;
565980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(scratch, hash);
5660692be65d6b06edd9ff4cfc4c308555b7c99c1191Ben Murdoch  __ shr(scratch, 11);
566180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ xor_(hash, Operand(scratch));
566280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // hash += hash << 15;
566380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(scratch, hash);
566480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ shl(scratch, 15);
566580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ add(hash, Operand(scratch));
566680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
5667692be65d6b06edd9ff4cfc4c308555b7c99c1191Ben Murdoch  __ and_(hash, String::kHashBitMask);
5668692be65d6b06edd9ff4cfc4c308555b7c99c1191Ben Murdoch
566980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // if (hash == 0) hash = 27;
5670257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label hash_not_zero;
5671257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(not_zero, &hash_not_zero, Label::kNear);
5672692be65d6b06edd9ff4cfc4c308555b7c99c1191Ben Murdoch  __ mov(hash, Immediate(StringHasher::kZeroHash));
567380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&hash_not_zero);
567480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
567580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
567680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
567780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid SubStringStub::Generate(MacroAssembler* masm) {
567880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label runtime;
567980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
568080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Stack frame on entry.
568180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  //  esp[0]: return address
568280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  //  esp[4]: to
568380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  //  esp[8]: from
568480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  //  esp[12]: string
568580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
568680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Make sure first argument is a string.
568780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(eax, Operand(esp, 3 * kPointerSize));
568880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  STATIC_ASSERT(kSmiTag == 0);
56893fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ JumpIfSmi(eax, &runtime);
569080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Condition is_string = masm->IsObjectStringType(eax, ebx, ebx);
569180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(NegateCondition(is_string), &runtime);
569280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
569380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // eax: string
569480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // ebx: instance type
569580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
569680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Calculate length of sub string using the smi values.
569780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label result_longer_than_two;
569880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(ecx, Operand(esp, 1 * kPointerSize));  // To index.
56993fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ JumpIfNotSmi(ecx, &runtime);
570080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(edx, Operand(esp, 2 * kPointerSize));  // From index.
57013fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ JumpIfNotSmi(edx, &runtime);
570280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ sub(ecx, Operand(edx));
570380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cmp(ecx, FieldOperand(eax, String::kLengthOffset));
570480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label return_eax;
570580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(equal, &return_eax);
570680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Special handling of sub-strings of length 1 and 2. One character strings
570780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // are handled in the runtime system (looked up in the single character
570880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // cache). Two character strings are looked for in the symbol cache.
570980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiUntag(ecx);  // Result length is no longer smi.
571080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cmp(ecx, 2);
571180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(greater, &result_longer_than_two);
571280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(less, &runtime);
571380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
571480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Sub string of length 2 requested.
571580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // eax: string
571680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // ebx: instance type
571780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // ecx: sub string length (value is 2)
571880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // edx: from index (smi)
571980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ JumpIfInstanceTypeIsNotSequentialAscii(ebx, ebx, &runtime);
572080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
572180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Get the two characters forming the sub string.
572280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiUntag(edx);  // From index is no longer smi.
572380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movzx_b(ebx, FieldOperand(eax, edx, times_1, SeqAsciiString::kHeaderSize));
572480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movzx_b(ecx,
572580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen             FieldOperand(eax, edx, times_1, SeqAsciiString::kHeaderSize + 1));
572680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
572780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Try to lookup two character string in symbol table.
572880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label make_two_character_string;
572980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  StringHelper::GenerateTwoCharacterSymbolTableProbe(
57309ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick      masm, ebx, ecx, eax, edx, edi,
57319ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick      &make_two_character_string, &make_two_character_string);
573280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ ret(3 * kPointerSize);
573380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
573480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&make_two_character_string);
573580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Setup registers for allocating the two character string.
573680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(eax, Operand(esp, 3 * kPointerSize));
573780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset));
573880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movzx_b(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset));
573980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ Set(ecx, Immediate(2));
574080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
574169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  if (FLAG_string_slices) {
574269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    Label copy_routine;
574369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    // If coming from the make_two_character_string path, the string
574469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    // is too short to be sliced anyways.
574569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    STATIC_ASSERT(2 < SlicedString::kMinLength);
574669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    __ jmp(&copy_routine);
574769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    __ bind(&result_longer_than_two);
574869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch
574969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    // eax: string
575069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    // ebx: instance type
575169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    // ecx: sub string length
575269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    // edx: from index (smi)
575369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    Label allocate_slice, sliced_string, seq_string;
575469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    __ cmp(ecx, SlicedString::kMinLength);
575569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    // Short slice.  Copy instead of slicing.
575669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    __ j(less, &copy_routine);
575769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    STATIC_ASSERT(kSeqStringTag == 0);
575869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    __ test(ebx, Immediate(kStringRepresentationMask));
575969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    __ j(zero, &seq_string, Label::kNear);
576069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    STATIC_ASSERT(kIsIndirectStringMask == (kSlicedStringTag & kConsStringTag));
576169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    STATIC_ASSERT(kIsIndirectStringMask != 0);
576269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    __ test(ebx, Immediate(kIsIndirectStringMask));
576369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    // External string.  Jump to runtime.
576469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    __ j(zero, &runtime);
576569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch
576669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    Factory* factory = masm->isolate()->factory();
576769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    __ test(ebx, Immediate(kSlicedNotConsMask));
576869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    __ j(not_zero, &sliced_string, Label::kNear);
576969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    // Cons string.  Check whether it is flat, then fetch first part.
577069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    __ cmp(FieldOperand(eax, ConsString::kSecondOffset),
577169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch           factory->empty_string());
577269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    __ j(not_equal, &runtime);
577369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    __ mov(edi, FieldOperand(eax, ConsString::kFirstOffset));
577469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    __ jmp(&allocate_slice, Label::kNear);
577569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch
577669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    __ bind(&sliced_string);
577769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    // Sliced string.  Fetch parent and correct start index by offset.
577869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    __ add(edx, FieldOperand(eax, SlicedString::kOffsetOffset));
577969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    __ mov(edi, FieldOperand(eax, SlicedString::kParentOffset));
578069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    __ jmp(&allocate_slice, Label::kNear);
578169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch
578269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    __ bind(&seq_string);
578369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    // Sequential string.  Just move string to the right register.
578469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    __ mov(edi, eax);
578569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch
578669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    __ bind(&allocate_slice);
578769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    // edi: underlying subject string
578869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    // ebx: instance type of original subject string
578969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    // edx: offset
579069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    // ecx: length
579169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    // Allocate new sliced string.  At this point we do not reload the instance
579269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    // type including the string encoding because we simply rely on the info
579369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    // provided by the original string.  It does not matter if the original
579469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    // string's encoding is wrong because we always have to recheck encoding of
579569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    // the newly created string's parent anyways due to externalized strings.
579669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    Label two_byte_slice, set_slice_header;
5797589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch    STATIC_ASSERT((kStringEncodingMask & kAsciiStringTag) != 0);
5798589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch    STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0);
5799589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch    __ test(ebx, Immediate(kStringEncodingMask));
580069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    __ j(zero, &two_byte_slice, Label::kNear);
580169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    __ AllocateAsciiSlicedString(eax, ebx, no_reg, &runtime);
580269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    __ jmp(&set_slice_header, Label::kNear);
580369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    __ bind(&two_byte_slice);
5804589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch    __ AllocateTwoByteSlicedString(eax, ebx, no_reg, &runtime);
580569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    __ bind(&set_slice_header);
580669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    __ mov(FieldOperand(eax, SlicedString::kOffsetOffset), edx);
580769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    __ SmiTag(ecx);
580869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    __ mov(FieldOperand(eax, SlicedString::kLengthOffset), ecx);
580969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    __ mov(FieldOperand(eax, SlicedString::kParentOffset), edi);
581069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    __ mov(FieldOperand(eax, SlicedString::kHashFieldOffset),
581169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch           Immediate(String::kEmptyHashField));
581269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    __ jmp(&return_eax);
581369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch
581469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    __ bind(&copy_routine);
581569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  } else {
581669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    __ bind(&result_longer_than_two);
581769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  }
581869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch
581980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // eax: string
582080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // ebx: instance type
582180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // ecx: result string length
582280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check for flat ascii string
582380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label non_ascii_flat;
582480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ JumpIfInstanceTypeIsNotSequentialAscii(ebx, ebx, &non_ascii_flat);
582580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
582680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Allocate the result.
582780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ AllocateAsciiString(eax, ecx, ebx, edx, edi, &runtime);
582880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
582980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // eax: result string
583080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // ecx: result string length
583180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(edx, esi);  // esi used by following code.
583280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Locate first character of result.
583380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(edi, eax);
583480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ add(Operand(edi), Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag));
583580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Load string argument and locate character of sub string start.
583680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(esi, Operand(esp, 3 * kPointerSize));
583780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ add(Operand(esi), Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag));
583880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(ebx, Operand(esp, 2 * kPointerSize));  // from
583980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiUntag(ebx);
584080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ add(esi, Operand(ebx));
584180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
584280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // eax: result string
584380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // ecx: result length
584480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // edx: original value of esi
584580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // edi: first character of result
584680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // esi: character of sub string start
584780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  StringHelper::GenerateCopyCharactersREP(masm, edi, esi, ecx, ebx, true);
584880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(esi, edx);  // Restore esi.
584944f0eee88ff00398ff7f715fab053374d808c90dSteve Block  Counters* counters = masm->isolate()->counters();
585044f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ IncrementCounter(counters->sub_string_native(), 1);
585180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ ret(3 * kPointerSize);
585280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
585380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&non_ascii_flat);
585480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // eax: string
585580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // ebx: instance type & kStringRepresentationMask | kStringEncodingMask
585680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // ecx: result string length
585780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check for flat two byte string
585880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cmp(ebx, kSeqStringTag | kTwoByteStringTag);
585980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(not_equal, &runtime);
586080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
586180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Allocate the result.
586280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ AllocateTwoByteString(eax, ecx, ebx, edx, edi, &runtime);
586380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
586480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // eax: result string
586580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // ecx: result string length
586680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(edx, esi);  // esi used by following code.
586780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Locate first character of result.
586880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(edi, eax);
586980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ add(Operand(edi),
587080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen         Immediate(SeqTwoByteString::kHeaderSize - kHeapObjectTag));
587180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Load string argument and locate character of sub string start.
587280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(esi, Operand(esp, 3 * kPointerSize));
587380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ add(Operand(esi),
587480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen         Immediate(SeqTwoByteString::kHeaderSize - kHeapObjectTag));
587580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(ebx, Operand(esp, 2 * kPointerSize));  // from
587680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // As from is a smi it is 2 times the value which matches the size of a two
587780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // byte character.
587880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  STATIC_ASSERT(kSmiTag == 0);
587980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  STATIC_ASSERT(kSmiTagSize + kSmiShiftSize == 1);
588080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ add(esi, Operand(ebx));
588180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
588280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // eax: result string
588380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // ecx: result length
588480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // edx: original value of esi
588580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // edi: first character of result
588680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // esi: character of sub string start
588780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  StringHelper::GenerateCopyCharactersREP(masm, edi, esi, ecx, ebx, false);
588880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(esi, edx);  // Restore esi.
588980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
589080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&return_eax);
589144f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ IncrementCounter(counters->sub_string_native(), 1);
589280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ ret(3 * kPointerSize);
589380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
589480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Just jump to runtime to create the sub string.
589580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&runtime);
589680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ TailCallRuntime(Runtime::kSubString, 3, 1);
589780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
589880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
589980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
5900257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid StringCompareStub::GenerateFlatAsciiStringEquals(MacroAssembler* masm,
5901257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                                      Register left,
5902257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                                      Register right,
5903257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                                      Register scratch1,
5904257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                                      Register scratch2) {
5905257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Register length = scratch1;
5906257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5907257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Compare lengths.
5908257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label strings_not_equal, check_zero_length;
5909257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ mov(length, FieldOperand(left, String::kLengthOffset));
5910257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ cmp(length, FieldOperand(right, String::kLengthOffset));
5911257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(equal, &check_zero_length, Label::kNear);
5912257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&strings_not_equal);
5913257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Set(eax, Immediate(Smi::FromInt(NOT_EQUAL)));
5914257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ ret(0);
5915257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5916257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Check if the length is zero.
5917257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label compare_chars;
5918257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&check_zero_length);
5919257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  STATIC_ASSERT(kSmiTag == 0);
5920257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ test(length, Operand(length));
5921257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(not_zero, &compare_chars, Label::kNear);
5922257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Set(eax, Immediate(Smi::FromInt(EQUAL)));
5923257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ ret(0);
5924257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5925257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Compare characters.
5926257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&compare_chars);
5927257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  GenerateAsciiCharsCompareLoop(masm, left, right, length, scratch2,
5928257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                &strings_not_equal, Label::kNear);
5929257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5930257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Characters are equal.
5931257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Set(eax, Immediate(Smi::FromInt(EQUAL)));
5932257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ ret(0);
5933257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch}
5934257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5935257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
593680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StringCompareStub::GenerateCompareFlatAsciiStrings(MacroAssembler* masm,
593780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                                        Register left,
593880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                                        Register right,
593980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                                        Register scratch1,
594080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                                        Register scratch2,
594180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                                        Register scratch3) {
594244f0eee88ff00398ff7f715fab053374d808c90dSteve Block  Counters* counters = masm->isolate()->counters();
594344f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ IncrementCounter(counters->string_compare_native(), 1);
594480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
594580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Find minimum length.
5946257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label left_shorter;
594780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(scratch1, FieldOperand(left, String::kLengthOffset));
594880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(scratch3, scratch1);
594980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ sub(scratch3, FieldOperand(right, String::kLengthOffset));
595080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
595180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Register length_delta = scratch3;
595280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
5953257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(less_equal, &left_shorter, Label::kNear);
595480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Right string is shorter. Change scratch1 to be length of right string.
595580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ sub(scratch1, Operand(length_delta));
595680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&left_shorter);
595780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
595880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Register min_length = scratch1;
595980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
596080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // If either length is zero, just compare lengths.
5961257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label compare_lengths;
596280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ test(min_length, Operand(min_length));
5963257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(zero, &compare_lengths, Label::kNear);
596480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
5965257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Compare characters.
5966257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label result_not_equal;
5967257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  GenerateAsciiCharsCompareLoop(masm, left, right, min_length, scratch2,
5968257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                &result_not_equal, Label::kNear);
596980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
597080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Compare lengths -  strings up to min-length are equal.
597180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&compare_lengths);
597280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ test(length_delta, Operand(length_delta));
5973257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(not_zero, &result_not_equal, Label::kNear);
597480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
597580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Result is EQUAL.
597680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  STATIC_ASSERT(EQUAL == 0);
597780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  STATIC_ASSERT(kSmiTag == 0);
597880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ Set(eax, Immediate(Smi::FromInt(EQUAL)));
597980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ ret(0);
598080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
5981257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label result_greater;
598280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&result_not_equal);
5983257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(greater, &result_greater, Label::kNear);
598480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
598580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Result is LESS.
598680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ Set(eax, Immediate(Smi::FromInt(LESS)));
598780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ ret(0);
598880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
598980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Result is GREATER.
599080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&result_greater);
599180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ Set(eax, Immediate(Smi::FromInt(GREATER)));
599280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ ret(0);
599380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
599480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
599580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
5996257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid StringCompareStub::GenerateAsciiCharsCompareLoop(
5997257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    MacroAssembler* masm,
5998257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Register left,
5999257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Register right,
6000257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Register length,
6001257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Register scratch,
6002257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Label* chars_not_equal,
6003257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Label::Distance chars_not_equal_near) {
6004257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Change index to run from -length to -1 by adding length to string
6005257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // start. This means that loop ends when index reaches zero, which
6006257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // doesn't need an additional compare.
6007257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ SmiUntag(length);
6008257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ lea(left,
6009257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch         FieldOperand(left, length, times_1, SeqAsciiString::kHeaderSize));
6010257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ lea(right,
6011257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch         FieldOperand(right, length, times_1, SeqAsciiString::kHeaderSize));
6012257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ neg(length);
6013257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Register index = length;  // index = -length;
6014257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6015257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Compare loop.
6016257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label loop;
6017257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&loop);
6018257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ mov_b(scratch, Operand(left, index, times_1, 0));
6019257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ cmpb(scratch, Operand(right, index, times_1, 0));
6020257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(not_equal, chars_not_equal, chars_not_equal_near);
6021257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ add(Operand(index), Immediate(1));
6022257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(not_zero, &loop);
6023257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch}
6024257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6025257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
602680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StringCompareStub::Generate(MacroAssembler* masm) {
602780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label runtime;
602880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
602980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Stack frame on entry.
603080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  //  esp[0]: return address
603180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  //  esp[4]: right string
603280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  //  esp[8]: left string
603380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
603480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(edx, Operand(esp, 2 * kPointerSize));  // left
603580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(eax, Operand(esp, 1 * kPointerSize));  // right
603680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
6037257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label not_same;
603880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cmp(edx, Operand(eax));
6039257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(not_equal, &not_same, Label::kNear);
604080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  STATIC_ASSERT(EQUAL == 0);
604180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  STATIC_ASSERT(kSmiTag == 0);
604280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ Set(eax, Immediate(Smi::FromInt(EQUAL)));
604344f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ IncrementCounter(masm->isolate()->counters()->string_compare_native(), 1);
604480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ ret(2 * kPointerSize);
604580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
604680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&not_same);
604780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
604880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check that both objects are sequential ascii strings.
604980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ JumpIfNotBothSequentialAsciiStrings(edx, eax, ecx, ebx, &runtime);
605080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
605180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Compare flat ascii strings.
605280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Drop arguments from the stack.
605380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ pop(ecx);
605480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ add(Operand(esp), Immediate(2 * kPointerSize));
605580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ push(ecx);
605680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  GenerateCompareFlatAsciiStrings(masm, edx, eax, ecx, ebx, edi);
605780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
605880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Call the runtime; it returns -1 (less), 0 (equal), or 1 (greater)
605980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // tagged as a small integer.
606080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&runtime);
606180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ TailCallRuntime(Runtime::kStringCompare, 2, 1);
606280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
606380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
6064b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
6065b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdochvoid ICCompareStub::GenerateSmis(MacroAssembler* masm) {
6066b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  ASSERT(state_ == CompareIC::SMIS);
6067257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label miss;
6068b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ mov(ecx, Operand(edx));
6069b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ or_(ecx, Operand(eax));
60703fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ JumpIfNotSmi(ecx, &miss, Label::kNear);
6071b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
6072b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  if (GetCondition() == equal) {
6073b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    // For equality we do not care about the sign of the result.
6074b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ sub(eax, Operand(edx));
6075b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  } else {
6076257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Label done;
6077b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ sub(edx, Operand(eax));
6078257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ j(no_overflow, &done, Label::kNear);
6079b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    // Correct sign of result in case of overflow.
6080b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ not_(edx);
6081b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ bind(&done);
6082b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ mov(eax, edx);
6083b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  }
6084b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ ret(0);
6085b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
6086b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ bind(&miss);
6087b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  GenerateMiss(masm);
6088b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch}
6089b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
6090b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
6091b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdochvoid ICCompareStub::GenerateHeapNumbers(MacroAssembler* masm) {
6092b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  ASSERT(state_ == CompareIC::HEAP_NUMBERS);
6093b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
6094257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label generic_stub;
6095257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label unordered;
6096257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label miss;
6097b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ mov(ecx, Operand(edx));
6098b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ and_(ecx, Operand(eax));
60993fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ JumpIfSmi(ecx, &generic_stub, Label::kNear);
6100b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
6101b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ CmpObjectType(eax, HEAP_NUMBER_TYPE, ecx);
6102257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(not_equal, &miss, Label::kNear);
6103b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ CmpObjectType(edx, HEAP_NUMBER_TYPE, ecx);
6104257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(not_equal, &miss, Label::kNear);
6105b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
6106b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Inlining the double comparison and falling back to the general compare
6107b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // stub if NaN is involved or SS2 or CMOV is unsupported.
61088b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  if (CpuFeatures::IsSupported(SSE2) && CpuFeatures::IsSupported(CMOV)) {
6109b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    CpuFeatures::Scope scope1(SSE2);
6110b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    CpuFeatures::Scope scope2(CMOV);
6111b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
6112b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    // Load left and right operand
6113b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ movdbl(xmm0, FieldOperand(edx, HeapNumber::kValueOffset));
6114b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ movdbl(xmm1, FieldOperand(eax, HeapNumber::kValueOffset));
6115b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
6116b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    // Compare operands
6117b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ ucomisd(xmm0, xmm1);
6118b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
6119b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    // Don't base result on EFLAGS when a NaN is involved.
6120257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ j(parity_even, &unordered, Label::kNear);
6121b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
6122b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    // Return a result of -1, 0, or 1, based on EFLAGS.
6123b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    // Performing mov, because xor would destroy the flag register.
6124b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ mov(eax, 0);  // equal
6125b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ mov(ecx, Immediate(Smi::FromInt(1)));
6126b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ cmov(above, eax, Operand(ecx));
6127b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ mov(ecx, Immediate(Smi::FromInt(-1)));
6128b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ cmov(below, eax, Operand(ecx));
6129b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ ret(0);
6130b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
6131b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ bind(&unordered);
6132b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  }
6133b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
6134b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  CompareStub stub(GetCondition(), strict(), NO_COMPARE_FLAGS);
6135b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ bind(&generic_stub);
6136b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ jmp(stub.GetCode(), RelocInfo::CODE_TARGET);
6137b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
6138b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ bind(&miss);
6139b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  GenerateMiss(masm);
6140b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch}
6141b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
6142b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
6143257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid ICCompareStub::GenerateSymbols(MacroAssembler* masm) {
6144257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  ASSERT(state_ == CompareIC::SYMBOLS);
6145257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  ASSERT(GetCondition() == equal);
6146257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6147257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Registers containing left and right operands respectively.
6148257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Register left = edx;
6149257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Register right = eax;
6150257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Register tmp1 = ecx;
6151257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Register tmp2 = ebx;
6152257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6153257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Check that both operands are heap objects.
6154257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label miss;
6155257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ mov(tmp1, Operand(left));
6156257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  STATIC_ASSERT(kSmiTag == 0);
6157257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ and_(tmp1, Operand(right));
61583fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ JumpIfSmi(tmp1, &miss, Label::kNear);
6159257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6160257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Check that both operands are symbols.
6161257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ mov(tmp1, FieldOperand(left, HeapObject::kMapOffset));
6162257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ mov(tmp2, FieldOperand(right, HeapObject::kMapOffset));
6163257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ movzx_b(tmp1, FieldOperand(tmp1, Map::kInstanceTypeOffset));
6164257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ movzx_b(tmp2, FieldOperand(tmp2, Map::kInstanceTypeOffset));
6165257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  STATIC_ASSERT(kSymbolTag != 0);
6166257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ and_(tmp1, Operand(tmp2));
6167257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ test(tmp1, Immediate(kIsSymbolMask));
6168257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(zero, &miss, Label::kNear);
6169257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6170257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Symbols are compared by identity.
6171257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label done;
6172257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ cmp(left, Operand(right));
6173257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Make sure eax is non-zero. At this point input operands are
6174257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // guaranteed to be non-zero.
6175257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  ASSERT(right.is(eax));
6176257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(not_equal, &done, Label::kNear);
6177257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  STATIC_ASSERT(EQUAL == 0);
6178257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  STATIC_ASSERT(kSmiTag == 0);
6179257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Set(eax, Immediate(Smi::FromInt(EQUAL)));
6180257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&done);
6181257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ ret(0);
6182257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6183257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&miss);
6184257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  GenerateMiss(masm);
6185257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch}
6186257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6187257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6188257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid ICCompareStub::GenerateStrings(MacroAssembler* masm) {
6189257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  ASSERT(state_ == CompareIC::STRINGS);
6190257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  ASSERT(GetCondition() == equal);
6191257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label miss;
6192257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6193257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Registers containing left and right operands respectively.
6194257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Register left = edx;
6195257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Register right = eax;
6196257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Register tmp1 = ecx;
6197257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Register tmp2 = ebx;
6198257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Register tmp3 = edi;
6199257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6200257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Check that both operands are heap objects.
6201257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ mov(tmp1, Operand(left));
6202257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  STATIC_ASSERT(kSmiTag == 0);
6203257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ and_(tmp1, Operand(right));
62043fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ JumpIfSmi(tmp1, &miss);
6205257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6206257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Check that both operands are strings. This leaves the instance
6207257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // types loaded in tmp1 and tmp2.
6208257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ mov(tmp1, FieldOperand(left, HeapObject::kMapOffset));
6209257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ mov(tmp2, FieldOperand(right, HeapObject::kMapOffset));
6210257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ movzx_b(tmp1, FieldOperand(tmp1, Map::kInstanceTypeOffset));
6211257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ movzx_b(tmp2, FieldOperand(tmp2, Map::kInstanceTypeOffset));
6212257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ mov(tmp3, tmp1);
6213257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  STATIC_ASSERT(kNotStringTag != 0);
6214257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ or_(tmp3, Operand(tmp2));
6215257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ test(tmp3, Immediate(kIsNotStringMask));
6216257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(not_zero, &miss);
6217257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6218257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Fast check for identical strings.
6219257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label not_same;
6220257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ cmp(left, Operand(right));
6221257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(not_equal, &not_same, Label::kNear);
6222257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  STATIC_ASSERT(EQUAL == 0);
6223257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  STATIC_ASSERT(kSmiTag == 0);
6224257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Set(eax, Immediate(Smi::FromInt(EQUAL)));
6225257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ ret(0);
6226257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6227257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Handle not identical strings.
6228257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&not_same);
6229257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6230257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Check that both strings are symbols. If they are, we're done
6231257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // because we already know they are not identical.
6232257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label do_compare;
6233257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  STATIC_ASSERT(kSymbolTag != 0);
6234257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ and_(tmp1, Operand(tmp2));
6235257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ test(tmp1, Immediate(kIsSymbolMask));
6236257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(zero, &do_compare, Label::kNear);
6237257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Make sure eax is non-zero. At this point input operands are
6238257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // guaranteed to be non-zero.
6239257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  ASSERT(right.is(eax));
6240257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ ret(0);
6241257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6242257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Check that both strings are sequential ASCII.
6243257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label runtime;
6244257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&do_compare);
6245257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ JumpIfNotBothSequentialAsciiStrings(left, right, tmp1, tmp2, &runtime);
6246257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6247257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Compare flat ASCII strings. Returns when done.
6248257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  StringCompareStub::GenerateFlatAsciiStringEquals(
6249257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      masm, left, right, tmp1, tmp2);
6250257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6251257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Handle more complex cases in runtime.
6252257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&runtime);
6253257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ pop(tmp1);  // Return address.
6254257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ push(left);
6255257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ push(right);
6256257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ push(tmp1);
6257257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ TailCallRuntime(Runtime::kStringEquals, 2, 1);
6258257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6259257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&miss);
6260257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  GenerateMiss(masm);
6261257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch}
6262257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6263257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6264b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdochvoid ICCompareStub::GenerateObjects(MacroAssembler* masm) {
6265b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  ASSERT(state_ == CompareIC::OBJECTS);
6266257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label miss;
6267b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ mov(ecx, Operand(edx));
6268b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ and_(ecx, Operand(eax));
62693fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ JumpIfSmi(ecx, &miss, Label::kNear);
6270b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
6271b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ CmpObjectType(eax, JS_OBJECT_TYPE, ecx);
6272257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(not_equal, &miss, Label::kNear);
6273b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ CmpObjectType(edx, JS_OBJECT_TYPE, ecx);
6274257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(not_equal, &miss, Label::kNear);
6275b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
6276b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  ASSERT(GetCondition() == equal);
6277b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ sub(eax, Operand(edx));
6278b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ ret(0);
6279b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
6280b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ bind(&miss);
6281b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  GenerateMiss(masm);
6282b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch}
6283b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
6284b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
6285b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdochvoid ICCompareStub::GenerateMiss(MacroAssembler* masm) {
6286b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Save the registers.
6287b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ pop(ecx);
6288b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ push(edx);
6289b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ push(eax);
6290b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ push(ecx);
6291b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
6292b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Call the runtime system in a fresh internal frame.
629344f0eee88ff00398ff7f715fab053374d808c90dSteve Block  ExternalReference miss = ExternalReference(IC_Utility(IC::kCompareIC_Miss),
629444f0eee88ff00398ff7f715fab053374d808c90dSteve Block                                             masm->isolate());
6295b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ EnterInternalFrame();
6296b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ push(edx);
6297b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ push(eax);
6298b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ push(Immediate(Smi::FromInt(op_)));
6299b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ CallExternalReference(miss, 3);
6300b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ LeaveInternalFrame();
6301b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
6302b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Compute the entry point of the rewritten stub.
6303b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ lea(edi, FieldOperand(eax, Code::kHeaderSize));
6304b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
6305b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Restore registers.
6306b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ pop(ecx);
6307b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ pop(eax);
6308b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ pop(edx);
6309b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ push(ecx);
6310b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
6311b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Do a tail call to the rewritten stub.
6312b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ jmp(Operand(edi));
6313b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch}
6314b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
6315b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
6316257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// Helper function used to check that the dictionary doesn't contain
6317257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// the property. This function may return false negatives, so miss_label
6318257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// must always call a backup property check that is complete.
6319257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// This function is safe to call if the receiver has fast properties.
6320257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// Name must be a symbol and receiver must be a heap object.
6321257744e915dfc84d6d07a6b2accf8402d9ffc708Ben MurdochMaybeObject* StringDictionaryLookupStub::GenerateNegativeLookup(
6322257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    MacroAssembler* masm,
6323257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Label* miss,
6324257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Label* done,
6325257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Register properties,
6326257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    String* name,
6327257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Register r0) {
6328257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  ASSERT(name->IsSymbol());
6329257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6330257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // If names of slots in range from 1 to kProbes - 1 for the hash value are
6331257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // not equal to the name and kProbes-th slot is not used (its name is the
6332257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // undefined value), it guarantees the hash table doesn't contain the
6333257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // property. It's true even if some slots represent deleted properties
6334257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // (their names are the null value).
6335257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  for (int i = 0; i < kInlinedProbes; i++) {
6336257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Compute the masked index: (hash + i + i * i) & mask.
6337257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Register index = r0;
6338257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Capacity is smi 2^n.
6339257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ mov(index, FieldOperand(properties, kCapacityOffset));
6340257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ dec(index);
6341257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ and_(Operand(index),
6342257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch           Immediate(Smi::FromInt(name->Hash() +
6343257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                   StringDictionary::GetProbeOffset(i))));
6344257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6345257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Scale the index by multiplying by the entry size.
6346257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    ASSERT(StringDictionary::kEntrySize == 3);
6347257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ lea(index, Operand(index, index, times_2, 0));  // index *= 3.
6348257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Register entity_name = r0;
6349257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Having undefined at this place means the name is not contained.
6350257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    ASSERT_EQ(kSmiTagSize, 1);
6351257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ mov(entity_name, Operand(properties, index, times_half_pointer_size,
6352257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                kElementsStartOffset - kHeapObjectTag));
6353257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ cmp(entity_name, masm->isolate()->factory()->undefined_value());
6354257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ j(equal, done);
6355257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6356257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Stop if found the property.
6357257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ cmp(entity_name, Handle<String>(name));
6358257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ j(equal, miss);
6359257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6360257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Check if the entry name is not a symbol.
6361257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ mov(entity_name, FieldOperand(entity_name, HeapObject::kMapOffset));
6362257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ test_b(FieldOperand(entity_name, Map::kInstanceTypeOffset),
6363257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch              kIsSymbolMask);
6364257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ j(zero, miss);
6365257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
6366257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6367257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  StringDictionaryLookupStub stub(properties,
6368257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                  r0,
6369257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                  r0,
6370257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                  StringDictionaryLookupStub::NEGATIVE_LOOKUP);
6371257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ push(Immediate(Handle<Object>(name)));
6372257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ push(Immediate(name->Hash()));
6373257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  MaybeObject* result = masm->TryCallStub(&stub);
6374257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  if (result->IsFailure()) return result;
6375257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ test(r0, Operand(r0));
6376257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(not_zero, miss);
6377257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ jmp(done);
6378257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  return result;
6379257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch}
6380257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6381257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6382257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// Probe the string dictionary in the |elements| register. Jump to the
6383257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// |done| label if a property with the given name is found leaving the
6384257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// index into the dictionary in |r0|. Jump to the |miss| label
6385257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// otherwise.
6386257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid StringDictionaryLookupStub::GeneratePositiveLookup(MacroAssembler* masm,
6387257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                                        Label* miss,
6388257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                                        Label* done,
6389257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                                        Register elements,
6390257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                                        Register name,
6391257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                                        Register r0,
6392257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                                        Register r1) {
6393257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Assert that name contains a string.
6394257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  if (FLAG_debug_code) __ AbortIfNotString(name);
6395257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6396257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ mov(r1, FieldOperand(elements, kCapacityOffset));
6397257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ shr(r1, kSmiTagSize);  // convert smi to int
6398257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ dec(r1);
6399257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6400257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Generate an unrolled loop that performs a few probes before
6401257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // giving up. Measurements done on Gmail indicate that 2 probes
6402257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // cover ~93% of loads from dictionaries.
6403257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  for (int i = 0; i < kInlinedProbes; i++) {
6404257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Compute the masked index: (hash + i + i * i) & mask.
6405257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ mov(r0, FieldOperand(name, String::kHashFieldOffset));
6406257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ shr(r0, String::kHashShift);
6407257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    if (i > 0) {
6408257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ add(Operand(r0), Immediate(StringDictionary::GetProbeOffset(i)));
6409257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    }
6410257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ and_(r0, Operand(r1));
6411257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6412257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Scale the index by multiplying by the entry size.
6413257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    ASSERT(StringDictionary::kEntrySize == 3);
6414257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ lea(r0, Operand(r0, r0, times_2, 0));  // r0 = r0 * 3
6415257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6416257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Check if the key is identical to the name.
6417257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ cmp(name, Operand(elements,
6418257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                         r0,
6419257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                         times_4,
6420257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                         kElementsStartOffset - kHeapObjectTag));
6421257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ j(equal, done);
6422257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
6423257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6424257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  StringDictionaryLookupStub stub(elements,
6425257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                  r1,
6426257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                  r0,
6427257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                  POSITIVE_LOOKUP);
6428257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ push(name);
6429257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ mov(r0, FieldOperand(name, String::kHashFieldOffset));
6430257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ shr(r0, String::kHashShift);
6431257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ push(r0);
6432257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ CallStub(&stub);
6433257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6434257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ test(r1, Operand(r1));
6435257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(zero, miss);
6436257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ jmp(done);
6437257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch}
6438257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6439257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6440257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid StringDictionaryLookupStub::Generate(MacroAssembler* masm) {
6441257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Stack frame on entry:
6442257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  //  esp[0 * kPointerSize]: return address.
6443257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  //  esp[1 * kPointerSize]: key's hash.
6444257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  //  esp[2 * kPointerSize]: key.
6445257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Registers:
6446257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  //  dictionary_: StringDictionary to probe.
6447257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  //  result_: used as scratch.
6448257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  //  index_: will hold an index of entry if lookup is successful.
6449257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  //          might alias with result_.
6450257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Returns:
6451257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  //  result_ is zero if lookup failed, non zero otherwise.
6452257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6453257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label in_dictionary, maybe_in_dictionary, not_in_dictionary;
6454257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6455257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Register scratch = result_;
6456257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6457257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ mov(scratch, FieldOperand(dictionary_, kCapacityOffset));
6458257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ dec(scratch);
6459257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ SmiUntag(scratch);
6460257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ push(scratch);
6461257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6462257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // If names of slots in range from 1 to kProbes - 1 for the hash value are
6463257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // not equal to the name and kProbes-th slot is not used (its name is the
6464257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // undefined value), it guarantees the hash table doesn't contain the
6465257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // property. It's true even if some slots represent deleted properties
6466257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // (their names are the null value).
6467257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  for (int i = kInlinedProbes; i < kTotalProbes; i++) {
6468257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Compute the masked index: (hash + i + i * i) & mask.
6469257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ mov(scratch, Operand(esp, 2 * kPointerSize));
6470257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    if (i > 0) {
6471257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ add(Operand(scratch),
6472257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch             Immediate(StringDictionary::GetProbeOffset(i)));
6473257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    }
6474257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ and_(scratch, Operand(esp, 0));
6475257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6476257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Scale the index by multiplying by the entry size.
6477257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    ASSERT(StringDictionary::kEntrySize == 3);
6478257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ lea(index_, Operand(scratch, scratch, times_2, 0));  // index *= 3.
6479257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6480257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Having undefined at this place means the name is not contained.
6481257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    ASSERT_EQ(kSmiTagSize, 1);
6482257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ mov(scratch, Operand(dictionary_,
6483257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                            index_,
6484257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                            times_pointer_size,
6485257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                            kElementsStartOffset - kHeapObjectTag));
6486257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ cmp(scratch, masm->isolate()->factory()->undefined_value());
6487257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ j(equal, &not_in_dictionary);
6488257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6489257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Stop if found the property.
6490257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ cmp(scratch, Operand(esp, 3 * kPointerSize));
6491257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ j(equal, &in_dictionary);
6492257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6493257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    if (i != kTotalProbes - 1 && mode_ == NEGATIVE_LOOKUP) {
6494257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // If we hit a non symbol key during negative lookup
6495257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // we have to bailout as this key might be equal to the
6496257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // key we are looking for.
6497257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6498257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // Check if the entry name is not a symbol.
6499257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ mov(scratch, FieldOperand(scratch, HeapObject::kMapOffset));
6500257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ test_b(FieldOperand(scratch, Map::kInstanceTypeOffset),
6501257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                kIsSymbolMask);
6502257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ j(zero, &maybe_in_dictionary);
6503257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    }
6504257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
6505257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6506257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&maybe_in_dictionary);
6507257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // If we are doing negative lookup then probing failure should be
6508257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // treated as a lookup success. For positive lookup probing failure
6509257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // should be treated as lookup failure.
6510257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  if (mode_ == POSITIVE_LOOKUP) {
6511257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ mov(result_, Immediate(0));
6512257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ Drop(1);
6513257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ ret(2 * kPointerSize);
6514257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
6515257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6516257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&in_dictionary);
6517257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ mov(result_, Immediate(1));
6518257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Drop(1);
6519257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ ret(2 * kPointerSize);
6520257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6521257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&not_in_dictionary);
6522257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ mov(result_, Immediate(0));
6523257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Drop(1);
6524257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ ret(2 * kPointerSize);
6525257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch}
6526257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6527257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
652880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#undef __
652980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
653080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} }  // namespace v8::internal
653180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
653280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#endif  // V8_TARGET_ARCH_IA32
6533