code-stubs-ia32.cc revision 3fb3ca8c7ca439d408449a395897395c0faae8d1
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
2393fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch// The stub returns zero for false, and a non-zero value for true.
24080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid ToBooleanStub::Generate(MacroAssembler* masm) {
241257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label false_result, true_result, not_string;
242257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Factory* factory = masm->isolate()->factory();
2433fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  const Register map = edx;
2443fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
2453fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ mov(eax, Operand(esp, 1 * kPointerSize));
246257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
247257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // undefined -> false
248257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ cmp(eax, factory->undefined_value());
249257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(equal, &false_result);
250257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
251257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Boolean -> its value
252257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ cmp(eax, factory->false_value());
253257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(equal, &false_result);
2543fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ cmp(eax, factory->true_value());
2553fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ j(equal, &true_result);
256257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
257257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Smis: 0 -> false, all other -> true
258257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ test(eax, Operand(eax));
259257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(zero, &false_result);
2603fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ JumpIfSmi(eax, &true_result);
26180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
2623fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // 'null' -> false.
26344f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ cmp(eax, factory->null_value());
264257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(equal, &false_result, Label::kNear);
26580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
2663fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // Get the map of the heap object.
2673fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ mov(map, FieldOperand(eax, HeapObject::kMapOffset));
26880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
2693fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // Undetectable -> false.
2703fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ test_b(FieldOperand(map, Map::kBitFieldOffset),
27180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen            1 << Map::kIsUndetectable);
272257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(not_zero, &false_result, Label::kNear);
27380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
2743fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // JavaScript object -> true.
2753fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ CmpInstanceType(map, FIRST_SPEC_OBJECT_TYPE);
276257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(above_equal, &true_result, Label::kNear);
27780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
2783fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // String value -> false iff empty.
2793fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ CmpInstanceType(map, FIRST_NONSTRING_TYPE);
280257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(above_equal, &not_string, Label::kNear);
28180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cmp(FieldOperand(eax, String::kLengthOffset), Immediate(0));
282257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(zero, &false_result, Label::kNear);
283257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ jmp(&true_result, Label::kNear);
28480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
28580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&not_string);
2863fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // HeapNumber -> false iff +0, -0, or NaN.
2873fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ cmp(map, factory->heap_number_map());
288257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(not_equal, &true_result, Label::kNear);
28980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ fldz();
29080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ fld_d(FieldOperand(eax, HeapNumber::kValueOffset));
29180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ FCmp();
292257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(zero, &false_result, Label::kNear);
29380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Fall through to |true_result|.
29480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
2953fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // Return 1/0 for true/false in tos_.
29680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&true_result);
2973fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ mov(tos_, 1);
29880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ ret(1 * kPointerSize);
29980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&false_result);
3003fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ mov(tos_, 0);
30180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ ret(1 * kPointerSize);
30280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
30380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
30480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
3058b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdochclass FloatingPointHelper : public AllStatic {
3068b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch public:
3078b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  enum ArgLocation {
3088b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch    ARGS_ON_STACK,
3098b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch    ARGS_IN_REGISTERS
3108b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  };
31180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
3128b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  // Code pattern for loading a floating point value. Input value must
3138b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  // be either a smi or a heap number object (fp value). Requirements:
3148b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  // operand in register number. Returns operand as floating point number
3158b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  // on FPU stack.
3168b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  static void LoadFloatOperand(MacroAssembler* masm, Register number);
31780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
3188b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  // Code pattern for loading floating point values. Input values must
3198b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  // be either smi or heap number objects (fp values). Requirements:
3208b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  // operand_1 on TOS+1 or in edx, operand_2 on TOS+2 or in eax.
3218b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  // Returns operands as floating point numbers on FPU stack.
3228b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  static void LoadFloatOperands(MacroAssembler* masm,
3238b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch                                Register scratch,
3248b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch                                ArgLocation arg_location = ARGS_ON_STACK);
32580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
3268b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  // Similar to LoadFloatOperand but assumes that both operands are smis.
3278b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  // Expects operands in edx, eax.
3288b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  static void LoadFloatSmis(MacroAssembler* masm, Register scratch);
329b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
3308b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  // Test if operands are smi or number objects (fp). Requirements:
3318b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  // operand_1 in eax, operand_2 in edx; falls through on float
3328b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  // operands, jumps to the non_float label otherwise.
3338b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  static void CheckFloatOperands(MacroAssembler* masm,
3348b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch                                 Label* non_float,
3358b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch                                 Register scratch);
336b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
3378b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  // Checks that the two floating point numbers on top of the FPU stack
3388b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  // have int32 values.
3398b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  static void CheckFloatOperandsAreInt32(MacroAssembler* masm,
3408b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch                                         Label* non_int32);
341b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
3428b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  // Takes the operands in edx and eax and loads them as integers in eax
3438b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  // and ecx.
3448b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  static void LoadUnknownsAsIntegers(MacroAssembler* masm,
3458b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch                                     bool use_sse3,
3468b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch                                     Label* operand_conversion_failure);
347b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
3488b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  // Must only be called after LoadUnknownsAsIntegers.  Assumes that the
3498b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  // operands are pushed on the stack, and that their conversions to int32
3508b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  // are in eax and ecx.  Checks that the original numbers were in the int32
3518b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  // range.
3528b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  static void CheckLoadedIntegersWereInt32(MacroAssembler* masm,
3538b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch                                           bool use_sse3,
3548b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch                                           Label* not_int32);
355b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
3568b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  // Assumes that operands are smis or heap numbers and loads them
3578b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  // into xmm0 and xmm1. Operands are in edx and eax.
3588b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  // Leaves operands unchanged.
3598b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  static void LoadSSE2Operands(MacroAssembler* masm);
360b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
3618b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  // Test if operands are numbers (smi or HeapNumber objects), and load
3628b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  // them into xmm0 and xmm1 if they are.  Jump to label not_numbers if
3638b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  // either operand is not a number.  Operands are in edx and eax.
3648b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  // Leaves operands unchanged.
3658b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  static void LoadSSE2Operands(MacroAssembler* masm, Label* not_numbers);
366b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
3678b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  // Similar to LoadSSE2Operands but assumes that both operands are smis.
3688b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  // Expects operands in edx, eax.
3698b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  static void LoadSSE2Smis(MacroAssembler* masm, Register scratch);
370b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
371257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Checks that the two floating point numbers loaded into xmm0 and xmm1
372257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // have int32 values.
373257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  static void CheckSSE2OperandsAreInt32(MacroAssembler* masm,
374257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                        Label* non_int32,
375257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                        Register scratch);
376257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch};
377257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
378257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
379257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// Get the integer part of a heap number.  Surprisingly, all this bit twiddling
380257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// is faster than using the built-in instructions on floating point registers.
381257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// Trashes edi and ebx.  Dest is ecx.  Source cannot be ecx or one of the
382257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// trashed registers.
383257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochstatic void IntegerConvert(MacroAssembler* masm,
384257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                           Register source,
385257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                           bool use_sse3,
386257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                           Label* conversion_failure) {
387257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  ASSERT(!source.is(ecx) && !source.is(edi) && !source.is(ebx));
388257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label done, right_exponent, normal_exponent;
389257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Register scratch = ebx;
390257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Register scratch2 = edi;
391257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Get exponent word.
392257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ mov(scratch, FieldOperand(source, HeapNumber::kExponentOffset));
393257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Get exponent alone in scratch2.
394257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ mov(scratch2, scratch);
395257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ and_(scratch2, HeapNumber::kExponentMask);
396257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  if (use_sse3) {
397257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    CpuFeatures::Scope scope(SSE3);
398257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Check whether the exponent is too big for a 64 bit signed integer.
399257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    static const uint32_t kTooBigExponent =
400257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        (HeapNumber::kExponentBias + 63) << HeapNumber::kExponentShift;
401257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ cmp(Operand(scratch2), Immediate(kTooBigExponent));
402257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ j(greater_equal, conversion_failure);
403257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Load x87 register with heap number.
404257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ fld_d(FieldOperand(source, HeapNumber::kValueOffset));
405257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Reserve space for 64 bit answer.
406257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ sub(Operand(esp), Immediate(sizeof(uint64_t)));  // Nolint.
407257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Do conversion, which cannot fail because we checked the exponent.
408257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ fisttp_d(Operand(esp, 0));
409257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ mov(ecx, Operand(esp, 0));  // Load low word of answer into ecx.
410257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ add(Operand(esp), Immediate(sizeof(uint64_t)));  // Nolint.
411257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  } else {
412257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Load ecx with zero.  We use this either for the final shift or
413257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // for the answer.
414257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ xor_(ecx, Operand(ecx));
415257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Check whether the exponent matches a 32 bit signed int that cannot be
416257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // represented by a Smi.  A non-smi 32 bit integer is 1.xxx * 2^30 so the
417257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // exponent is 30 (biased).  This is the exponent that we are fastest at and
418257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // also the highest exponent we can handle here.
419257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    const uint32_t non_smi_exponent =
420257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        (HeapNumber::kExponentBias + 30) << HeapNumber::kExponentShift;
421257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ cmp(Operand(scratch2), Immediate(non_smi_exponent));
422257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // If we have a match of the int32-but-not-Smi exponent then skip some
423257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // logic.
424257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ j(equal, &right_exponent);
425257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // If the exponent is higher than that then go to slow case.  This catches
426257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // numbers that don't fit in a signed int32, infinities and NaNs.
427257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ j(less, &normal_exponent);
428257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
429257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    {
430257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // Handle a big exponent.  The only reason we have this code is that the
431257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // >>> operator has a tendency to generate numbers with an exponent of 31.
432257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      const uint32_t big_non_smi_exponent =
433257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          (HeapNumber::kExponentBias + 31) << HeapNumber::kExponentShift;
434257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ cmp(Operand(scratch2), Immediate(big_non_smi_exponent));
435257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ j(not_equal, conversion_failure);
436257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // We have the big exponent, typically from >>>.  This means the number is
437257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // in the range 2^31 to 2^32 - 1.  Get the top bits of the mantissa.
438257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ mov(scratch2, scratch);
439257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ and_(scratch2, HeapNumber::kMantissaMask);
440257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // Put back the implicit 1.
441257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ or_(scratch2, 1 << HeapNumber::kExponentShift);
442257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // Shift up the mantissa bits to take up the space the exponent used to
443257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // take. We just orred in the implicit bit so that took care of one and
444257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // we want to use the full unsigned range so we subtract 1 bit from the
445257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // shift distance.
446257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      const int big_shift_distance = HeapNumber::kNonMantissaBitsInTopWord - 1;
447257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ shl(scratch2, big_shift_distance);
448257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // Get the second half of the double.
449257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ mov(ecx, FieldOperand(source, HeapNumber::kMantissaOffset));
450257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // Shift down 21 bits to get the most significant 11 bits or the low
451257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // mantissa word.
452257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ shr(ecx, 32 - big_shift_distance);
453257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ or_(ecx, Operand(scratch2));
454257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // We have the answer in ecx, but we may need to negate it.
455257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ test(scratch, Operand(scratch));
456257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ j(positive, &done);
457257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ neg(ecx);
458257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ jmp(&done);
459257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    }
460257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
461257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ bind(&normal_exponent);
462257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Exponent word in scratch, exponent part of exponent word in scratch2.
463257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Zero in ecx.
464257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // We know the exponent is smaller than 30 (biased).  If it is less than
465257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // 0 (biased) then the number is smaller in magnitude than 1.0 * 2^0, ie
466257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // it rounds to zero.
467257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    const uint32_t zero_exponent =
468257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        (HeapNumber::kExponentBias + 0) << HeapNumber::kExponentShift;
469257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ sub(Operand(scratch2), Immediate(zero_exponent));
470257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // ecx already has a Smi zero.
471257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ j(less, &done);
472257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
473257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // We have a shifted exponent between 0 and 30 in scratch2.
474257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ shr(scratch2, HeapNumber::kExponentShift);
475257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ mov(ecx, Immediate(30));
476257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ sub(ecx, Operand(scratch2));
477257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
478257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ bind(&right_exponent);
479257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Here ecx is the shift, scratch is the exponent word.
480257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Get the top bits of the mantissa.
481257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ and_(scratch, HeapNumber::kMantissaMask);
482257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Put back the implicit 1.
483257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ or_(scratch, 1 << HeapNumber::kExponentShift);
484257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Shift up the mantissa bits to take up the space the exponent used to
485257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // take. We have kExponentShift + 1 significant bits int he low end of the
486257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // word.  Shift them to the top bits.
487257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    const int shift_distance = HeapNumber::kNonMantissaBitsInTopWord - 2;
488257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ shl(scratch, shift_distance);
489257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Get the second half of the double. For some exponents we don't
490257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // actually need this because the bits get shifted out again, but
491257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // it's probably slower to test than just to do it.
492257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ mov(scratch2, FieldOperand(source, HeapNumber::kMantissaOffset));
493257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Shift down 22 bits to get the most significant 10 bits or the low
494257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // mantissa word.
495257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ shr(scratch2, 32 - shift_distance);
496257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ or_(scratch2, Operand(scratch));
497257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Move down according to the exponent.
498257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ shr_cl(scratch2);
499257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Now the unsigned answer is in scratch2.  We need to move it to ecx and
500257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // we may need to fix the sign.
501257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Label negative;
502257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ xor_(ecx, Operand(ecx));
503257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ cmp(ecx, FieldOperand(source, HeapNumber::kExponentOffset));
504257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ j(greater, &negative, Label::kNear);
505257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ mov(ecx, scratch2);
506257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ jmp(&done, Label::kNear);
507257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ bind(&negative);
508257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ sub(ecx, Operand(scratch2));
509257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ bind(&done);
510257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
511257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch}
512257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
513257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5143fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdochvoid UnaryOpStub::PrintName(StringStream* stream) {
515257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  const char* op_name = Token::Name(op_);
516257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  const char* overwrite_name = NULL;  // Make g++ happy.
517257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  switch (mode_) {
518257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case UNARY_NO_OVERWRITE: overwrite_name = "Alloc"; break;
519257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case UNARY_OVERWRITE: overwrite_name = "Overwrite"; break;
520257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
5213fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  stream->Add("UnaryOpStub_%s_%s_%s",
5223fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch              op_name,
5233fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch              overwrite_name,
5243fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch              UnaryOpIC::GetName(operand_type_));
525257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch}
526257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
527257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
528257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// TODO(svenpanne): Use virtual functions instead of switch.
529257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::Generate(MacroAssembler* masm) {
530257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  switch (operand_type_) {
531257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case UnaryOpIC::UNINITIALIZED:
532257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      GenerateTypeTransition(masm);
533257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      break;
534257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case UnaryOpIC::SMI:
535257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      GenerateSmiStub(masm);
536257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      break;
537257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case UnaryOpIC::HEAP_NUMBER:
538257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      GenerateHeapNumberStub(masm);
539257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      break;
540257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case UnaryOpIC::GENERIC:
541257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      GenerateGenericStub(masm);
542257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      break;
543257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
544257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch}
545257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
546257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
547257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::GenerateTypeTransition(MacroAssembler* masm) {
548257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ pop(ecx);  // Save return address.
5493fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
5503fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ push(eax);  // the operand
551257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ push(Immediate(Smi::FromInt(op_)));
5523fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ push(Immediate(Smi::FromInt(mode_)));
553257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ push(Immediate(Smi::FromInt(operand_type_)));
554257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
555257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ push(ecx);  // Push return address.
556257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
557257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Patch the caller to an appropriate specialized stub and return the
558257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // operation result to the caller of the stub.
559257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ TailCallExternalReference(
5603fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch      ExternalReference(IC_Utility(IC::kUnaryOp_Patch), masm->isolate()), 4, 1);
561257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch}
562257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
563257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
564257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// TODO(svenpanne): Use virtual functions instead of switch.
565257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::GenerateSmiStub(MacroAssembler* masm) {
566257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  switch (op_) {
567257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case Token::SUB:
568257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      GenerateSmiStubSub(masm);
569257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      break;
570257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case Token::BIT_NOT:
571257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      GenerateSmiStubBitNot(masm);
572257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      break;
573257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    default:
574257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      UNREACHABLE();
575257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
576257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch}
577257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
578257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
579257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::GenerateSmiStubSub(MacroAssembler* masm) {
580257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label non_smi, undo, slow;
581257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  GenerateSmiCodeSub(masm, &non_smi, &undo, &slow,
582257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                     Label::kNear, Label::kNear, Label::kNear);
583257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&undo);
584257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  GenerateSmiCodeUndo(masm);
585257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&non_smi);
586257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&slow);
587257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  GenerateTypeTransition(masm);
588257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch}
589257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
590257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
591257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::GenerateSmiStubBitNot(MacroAssembler* masm) {
592257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label non_smi;
593257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  GenerateSmiCodeBitNot(masm, &non_smi);
594257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&non_smi);
595257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  GenerateTypeTransition(masm);
596257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch}
597257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
598257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
599257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::GenerateSmiCodeSub(MacroAssembler* masm,
600257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                     Label* non_smi,
601257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                     Label* undo,
602257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                     Label* slow,
603257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                     Label::Distance non_smi_near,
604257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                     Label::Distance undo_near,
605257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                     Label::Distance slow_near) {
606257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Check whether the value is a smi.
6073fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ JumpIfNotSmi(eax, non_smi, non_smi_near);
608257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
609257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // We can't handle -0 with smis, so use a type transition for that case.
610257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ test(eax, Operand(eax));
611257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(zero, slow, slow_near);
612257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
613257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Try optimistic subtraction '0 - value', saving operand in eax for undo.
614257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ mov(edx, Operand(eax));
615257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Set(eax, Immediate(0));
616257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ sub(eax, Operand(edx));
617257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(overflow, undo, undo_near);
618257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ ret(0);
619257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch}
620257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
621257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
622257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::GenerateSmiCodeBitNot(
623257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    MacroAssembler* masm,
624257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Label* non_smi,
625257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Label::Distance non_smi_near) {
626257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Check whether the value is a smi.
6273fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ JumpIfNotSmi(eax, non_smi, non_smi_near);
628257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
629257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Flip bits and revert inverted smi-tag.
630257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ not_(eax);
631257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ and_(eax, ~kSmiTagMask);
632257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ ret(0);
633257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch}
634257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
635257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
636257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::GenerateSmiCodeUndo(MacroAssembler* masm) {
637257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ mov(eax, Operand(edx));
638257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch}
639257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
640257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
641257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// TODO(svenpanne): Use virtual functions instead of switch.
642257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::GenerateHeapNumberStub(MacroAssembler* masm) {
643257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  switch (op_) {
644257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case Token::SUB:
645257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      GenerateHeapNumberStubSub(masm);
646257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      break;
647257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case Token::BIT_NOT:
648257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      GenerateHeapNumberStubBitNot(masm);
649257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      break;
650257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    default:
651257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      UNREACHABLE();
652257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
653257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch}
654257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
655257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
656257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::GenerateHeapNumberStubSub(MacroAssembler* masm) {
657257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label non_smi, undo, slow, call_builtin;
658257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  GenerateSmiCodeSub(masm, &non_smi, &undo, &call_builtin, Label::kNear);
659257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&non_smi);
660257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  GenerateHeapNumberCodeSub(masm, &slow);
661257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&undo);
662257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  GenerateSmiCodeUndo(masm);
663257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&slow);
664257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  GenerateTypeTransition(masm);
665257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&call_builtin);
666257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  GenerateGenericCodeFallback(masm);
667257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch}
668257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
669257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
670257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::GenerateHeapNumberStubBitNot(
671257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    MacroAssembler* masm) {
672257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label non_smi, slow;
673257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  GenerateSmiCodeBitNot(masm, &non_smi, Label::kNear);
674257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&non_smi);
675257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  GenerateHeapNumberCodeBitNot(masm, &slow);
676257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&slow);
677257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  GenerateTypeTransition(masm);
678257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch}
679257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
680257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
681257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::GenerateHeapNumberCodeSub(MacroAssembler* masm,
682257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                            Label* slow) {
683257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ mov(edx, FieldOperand(eax, HeapObject::kMapOffset));
684257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ cmp(edx, masm->isolate()->factory()->heap_number_map());
685257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(not_equal, slow);
686257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
687257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  if (mode_ == UNARY_OVERWRITE) {
688257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ xor_(FieldOperand(eax, HeapNumber::kExponentOffset),
689257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch            Immediate(HeapNumber::kSignMask));  // Flip sign.
690257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  } else {
691257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ mov(edx, Operand(eax));
692257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // edx: operand
693257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
694257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Label slow_allocate_heapnumber, heapnumber_allocated;
695257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ AllocateHeapNumber(eax, ebx, ecx, &slow_allocate_heapnumber);
696257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ jmp(&heapnumber_allocated);
697257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
698257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ bind(&slow_allocate_heapnumber);
699257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ EnterInternalFrame();
700257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ push(edx);
701257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ CallRuntime(Runtime::kNumberAlloc, 0);
702257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ pop(edx);
703257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ LeaveInternalFrame();
704257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
705257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ bind(&heapnumber_allocated);
706257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // eax: allocated 'empty' number
707257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ mov(ecx, FieldOperand(edx, HeapNumber::kExponentOffset));
708257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ xor_(ecx, HeapNumber::kSignMask);  // Flip sign.
709257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ mov(FieldOperand(eax, HeapNumber::kExponentOffset), ecx);
710257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ mov(ecx, FieldOperand(edx, HeapNumber::kMantissaOffset));
711257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ mov(FieldOperand(eax, HeapNumber::kMantissaOffset), ecx);
712257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
713257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ ret(0);
714257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch}
715257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
716257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
717257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::GenerateHeapNumberCodeBitNot(MacroAssembler* masm,
718257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                               Label* slow) {
719257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ mov(edx, FieldOperand(eax, HeapObject::kMapOffset));
720257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ cmp(edx, masm->isolate()->factory()->heap_number_map());
721257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(not_equal, slow);
722257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
723257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Convert the heap number in eax to an untagged integer in ecx.
724257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  IntegerConvert(masm, eax, CpuFeatures::IsSupported(SSE3), slow);
725257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
726257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Do the bitwise operation and check if the result fits in a smi.
727257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label try_float;
728257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ not_(ecx);
729257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ cmp(ecx, 0xc0000000);
730257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(sign, &try_float, Label::kNear);
731257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
732257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Tag the result as a smi and we're done.
733257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  STATIC_ASSERT(kSmiTagSize == 1);
734257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ lea(eax, Operand(ecx, times_2, kSmiTag));
735257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ ret(0);
736257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
737257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Try to store the result in a heap number.
738257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&try_float);
739257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  if (mode_ == UNARY_NO_OVERWRITE) {
740257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Label slow_allocate_heapnumber, heapnumber_allocated;
741257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ mov(ebx, eax);
742257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ AllocateHeapNumber(eax, edx, edi, &slow_allocate_heapnumber);
743257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ jmp(&heapnumber_allocated);
744257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
745257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ bind(&slow_allocate_heapnumber);
746257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ EnterInternalFrame();
747257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Push the original HeapNumber on the stack. The integer value can't
748257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // be stored since it's untagged and not in the smi range (so we can't
749257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // smi-tag it). We'll recalculate the value after the GC instead.
750257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ push(ebx);
751257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ CallRuntime(Runtime::kNumberAlloc, 0);
752257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // New HeapNumber is in eax.
753257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ pop(edx);
754257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ LeaveInternalFrame();
755257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // IntegerConvert uses ebx and edi as scratch registers.
756257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // This conversion won't go slow-case.
757257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    IntegerConvert(masm, edx, CpuFeatures::IsSupported(SSE3), slow);
758257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ not_(ecx);
759257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
760257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ bind(&heapnumber_allocated);
761257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
762257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  if (CpuFeatures::IsSupported(SSE2)) {
763257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    CpuFeatures::Scope use_sse2(SSE2);
764257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ cvtsi2sd(xmm0, Operand(ecx));
765257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0);
766257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  } else {
767257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ push(ecx);
768257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ fild_s(Operand(esp, 0));
769257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ pop(ecx);
770257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset));
771257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
772257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ ret(0);
773257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch}
774257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
775257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
776257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// TODO(svenpanne): Use virtual functions instead of switch.
777257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::GenerateGenericStub(MacroAssembler* masm) {
778257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  switch (op_) {
779257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case Token::SUB:
780257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      GenerateGenericStubSub(masm);
781257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      break;
782257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case Token::BIT_NOT:
783257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      GenerateGenericStubBitNot(masm);
784257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      break;
785257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    default:
786257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      UNREACHABLE();
787257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
788257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch}
789257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
790257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
791257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::GenerateGenericStubSub(MacroAssembler* masm)  {
792257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label non_smi, undo, slow;
793257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  GenerateSmiCodeSub(masm, &non_smi, &undo, &slow, Label::kNear);
794257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&non_smi);
795257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  GenerateHeapNumberCodeSub(masm, &slow);
796257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&undo);
797257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  GenerateSmiCodeUndo(masm);
798257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&slow);
799257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  GenerateGenericCodeFallback(masm);
800257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch}
801257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
802257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
803257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::GenerateGenericStubBitNot(MacroAssembler* masm) {
804257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label non_smi, slow;
805257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  GenerateSmiCodeBitNot(masm, &non_smi, Label::kNear);
806257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&non_smi);
807257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  GenerateHeapNumberCodeBitNot(masm, &slow);
808257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&slow);
809257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  GenerateGenericCodeFallback(masm);
810257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch}
811257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
812257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
813257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::GenerateGenericCodeFallback(MacroAssembler* masm) {
814257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Handle the slow case by jumping to the corresponding JavaScript builtin.
815257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ pop(ecx);  // pop return address.
816257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ push(eax);
817257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ push(ecx);  // push return address
818257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  switch (op_) {
819257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case Token::SUB:
820257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ InvokeBuiltin(Builtins::UNARY_MINUS, JUMP_FUNCTION);
821257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      break;
822257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case Token::BIT_NOT:
823257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ InvokeBuiltin(Builtins::BIT_NOT, JUMP_FUNCTION);
824257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      break;
825257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    default:
826257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      UNREACHABLE();
827257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
828257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch}
829b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
830b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
831257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid BinaryOpStub::GenerateTypeTransition(MacroAssembler* masm) {
832b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ pop(ecx);  // Save return address.
833b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ push(edx);
834b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ push(eax);
835b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Left and right arguments are now on top.
836b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Push this stub's key. Although the operation and the type info are
837b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // encoded into the key, the encoding is opaque, so push them too.
838b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ push(Immediate(Smi::FromInt(MinorKey())));
839b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ push(Immediate(Smi::FromInt(op_)));
840b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ push(Immediate(Smi::FromInt(operands_type_)));
841b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
842b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ push(ecx);  // Push return address.
843b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
844b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Patch the caller to an appropriate specialized stub and return the
845b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // operation result to the caller of the stub.
846b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ TailCallExternalReference(
847257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      ExternalReference(IC_Utility(IC::kBinaryOp_Patch),
84844f0eee88ff00398ff7f715fab053374d808c90dSteve Block                        masm->isolate()),
849b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      5,
850b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      1);
851b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch}
852b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
853b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
854b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch// Prepare for a type transition runtime call when the args are already on
855b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch// the stack, under the return address.
856257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid BinaryOpStub::GenerateTypeTransitionWithSavedArgs(MacroAssembler* masm) {
857b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ pop(ecx);  // Save return address.
858b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Left and right arguments are already on top of the stack.
859b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Push this stub's key. Although the operation and the type info are
860b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // encoded into the key, the encoding is opaque, so push them too.
861b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ push(Immediate(Smi::FromInt(MinorKey())));
862b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ push(Immediate(Smi::FromInt(op_)));
863b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ push(Immediate(Smi::FromInt(operands_type_)));
864b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
865b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ push(ecx);  // Push return address.
866b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
867b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Patch the caller to an appropriate specialized stub and return the
868b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // operation result to the caller of the stub.
869b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ TailCallExternalReference(
870257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      ExternalReference(IC_Utility(IC::kBinaryOp_Patch),
87144f0eee88ff00398ff7f715fab053374d808c90dSteve Block                        masm->isolate()),
872b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      5,
873b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      1);
874b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch}
875b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
876b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
877257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid BinaryOpStub::Generate(MacroAssembler* masm) {
878b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  switch (operands_type_) {
879257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case BinaryOpIC::UNINITIALIZED:
880b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      GenerateTypeTransition(masm);
881b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
882257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case BinaryOpIC::SMI:
883b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      GenerateSmiStub(masm);
884b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
885257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case BinaryOpIC::INT32:
886b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      GenerateInt32Stub(masm);
887b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
888257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case BinaryOpIC::HEAP_NUMBER:
889b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      GenerateHeapNumberStub(masm);
890b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
891257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case BinaryOpIC::ODDBALL:
89244f0eee88ff00398ff7f715fab053374d808c90dSteve Block      GenerateOddballStub(masm);
89344f0eee88ff00398ff7f715fab053374d808c90dSteve Block      break;
894257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case BinaryOpIC::BOTH_STRING:
895257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      GenerateBothStringStub(masm);
896257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      break;
897257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case BinaryOpIC::STRING:
898b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      GenerateStringStub(masm);
899b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
900257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case BinaryOpIC::GENERIC:
901b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      GenerateGeneric(masm);
902b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
903b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    default:
904b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      UNREACHABLE();
905b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  }
906b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch}
907b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
908b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
9093fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdochvoid BinaryOpStub::PrintName(StringStream* stream) {
910b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  const char* op_name = Token::Name(op_);
911b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  const char* overwrite_name;
912b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  switch (mode_) {
913b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case NO_OVERWRITE: overwrite_name = "Alloc"; break;
914b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case OVERWRITE_RIGHT: overwrite_name = "OverwriteRight"; break;
915b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case OVERWRITE_LEFT: overwrite_name = "OverwriteLeft"; break;
916b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    default: overwrite_name = "UnknownOverwrite"; break;
917b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  }
9183fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  stream->Add("BinaryOpStub_%s_%s_%s",
9193fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch              op_name,
9203fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch              overwrite_name,
9213fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch              BinaryOpIC::GetName(operands_type_));
922b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch}
923b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
924b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
925257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid BinaryOpStub::GenerateSmiCode(
926257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    MacroAssembler* masm,
927b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    Label* slow,
928b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    SmiCodeGenerateHeapNumberResults allow_heapnumber_results) {
929b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // 1. Move arguments into edx, eax except for DIV and MOD, which need the
930b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // dividend in eax and edx free for the division.  Use eax, ebx for those.
931b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  Comment load_comment(masm, "-- Load arguments");
932b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  Register left = edx;
933b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  Register right = eax;
934b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  if (op_ == Token::DIV || op_ == Token::MOD) {
935b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    left = eax;
936b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    right = ebx;
937b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ mov(ebx, eax);
938b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ mov(eax, edx);
939b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  }
940b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
941b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
942b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // 2. Prepare the smi check of both operands by oring them together.
943b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  Comment smi_check_comment(masm, "-- Smi check arguments");
944b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  Label not_smis;
945b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  Register combined = ecx;
946b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  ASSERT(!left.is(combined) && !right.is(combined));
947b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  switch (op_) {
948b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::BIT_OR:
949b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // Perform the operation into eax and smi check the result.  Preserve
950b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // eax in case the result is not a smi.
951b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      ASSERT(!left.is(ecx) && !right.is(ecx));
952b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ mov(ecx, right);
953b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ or_(right, Operand(left));  // Bitwise or is commutative.
954b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      combined = right;
955b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
956b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
957b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::BIT_XOR:
958b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::BIT_AND:
959b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::ADD:
960b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::SUB:
961b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::MUL:
962b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::DIV:
963b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::MOD:
964b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ mov(combined, right);
965b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ or_(combined, Operand(left));
966b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
967b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
968b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::SHL:
969b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::SAR:
970b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::SHR:
971b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // Move the right operand into ecx for the shift operation, use eax
972b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // for the smi check register.
973b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      ASSERT(!left.is(ecx) && !right.is(ecx));
974b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ mov(ecx, right);
975b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ or_(right, Operand(left));
976b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      combined = right;
977b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
978b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
979b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    default:
980b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
981b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  }
982b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
983b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // 3. Perform the smi check of the operands.
984b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  STATIC_ASSERT(kSmiTag == 0);  // Adjust zero check if not the case.
9853fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ JumpIfNotSmi(combined, &not_smis);
986b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
987b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // 4. Operands are both smis, perform the operation leaving the result in
988b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // eax and check the result if necessary.
989b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  Comment perform_smi(masm, "-- Perform smi operation");
990b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  Label use_fp_on_smis;
991b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  switch (op_) {
992b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::BIT_OR:
993b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // Nothing to do.
994b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
995b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
996b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::BIT_XOR:
997b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      ASSERT(right.is(eax));
998b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ xor_(right, Operand(left));  // Bitwise xor is commutative.
999b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1000b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1001b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::BIT_AND:
1002b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      ASSERT(right.is(eax));
1003b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ and_(right, Operand(left));  // Bitwise and is commutative.
1004b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1005b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1006b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::SHL:
1007b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // Remove tags from operands (but keep sign).
1008b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ SmiUntag(left);
1009b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ SmiUntag(ecx);
1010b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // Perform the operation.
1011b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ shl_cl(left);
1012b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // Check that the *signed* result fits in a smi.
1013b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ cmp(left, 0xc0000000);
1014257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ j(sign, &use_fp_on_smis);
1015b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // Tag the result and store it in register eax.
1016b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ SmiTag(left);
1017b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ mov(eax, left);
1018b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1019b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1020b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::SAR:
1021b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // Remove tags from operands (but keep sign).
1022b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ SmiUntag(left);
1023b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ SmiUntag(ecx);
1024b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // Perform the operation.
1025b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ sar_cl(left);
1026b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // Tag the result and store it in register eax.
1027b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ SmiTag(left);
1028b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ mov(eax, left);
1029b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1030b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1031b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::SHR:
1032b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // Remove tags from operands (but keep sign).
1033b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ SmiUntag(left);
1034b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ SmiUntag(ecx);
1035b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // Perform the operation.
1036b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ shr_cl(left);
1037b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // Check that the *unsigned* result fits in a smi.
1038b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // Neither of the two high-order bits can be set:
1039b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // - 0x80000000: high bit would be lost when smi tagging.
1040b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // - 0x40000000: this number would convert to negative when
1041b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // Smi tagging these two cases can only happen with shifts
1042b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // by 0 or 1 when handed a valid smi.
1043b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ test(left, Immediate(0xc0000000));
1044257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ j(not_zero, &use_fp_on_smis);
1045b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // Tag the result and store it in register eax.
1046b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ SmiTag(left);
1047b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ mov(eax, left);
1048b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1049b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1050b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::ADD:
1051b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      ASSERT(right.is(eax));
1052b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ add(right, Operand(left));  // Addition is commutative.
1053257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ j(overflow, &use_fp_on_smis);
1054b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1055b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1056b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::SUB:
1057b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ sub(left, Operand(right));
1058257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ j(overflow, &use_fp_on_smis);
1059b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ mov(eax, left);
1060b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1061b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1062b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::MUL:
1063b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // If the smi tag is 0 we can just leave the tag on one operand.
1064b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      STATIC_ASSERT(kSmiTag == 0);  // Adjust code below if not the case.
1065b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // We can't revert the multiplication if the result is not a smi
1066b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // so save the right operand.
1067b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ mov(ebx, right);
1068b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // Remove tag from one of the operands (but keep sign).
1069b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ SmiUntag(right);
1070b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // Do multiplication.
1071b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ imul(right, Operand(left));  // Multiplication is commutative.
1072257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ j(overflow, &use_fp_on_smis);
1073b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // Check for negative zero result.  Use combined = left | right.
1074b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ NegativeZeroTest(right, combined, &use_fp_on_smis);
1075b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1076b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1077b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::DIV:
1078b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // We can't revert the division if the result is not a smi so
1079b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // save the left operand.
1080b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ mov(edi, left);
1081b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // Check for 0 divisor.
1082b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ test(right, Operand(right));
1083257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ j(zero, &use_fp_on_smis);
1084b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // Sign extend left into edx:eax.
1085b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      ASSERT(left.is(eax));
1086b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ cdq();
1087b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // Divide edx:eax by right.
1088b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ idiv(right);
1089b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // Check for the corner case of dividing the most negative smi by
1090b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // -1. We cannot use the overflow flag, since it is not set by idiv
1091b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // instruction.
1092b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize == 1);
1093b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ cmp(eax, 0x40000000);
1094b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ j(equal, &use_fp_on_smis);
1095b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // Check for negative zero result.  Use combined = left | right.
1096b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ NegativeZeroTest(eax, combined, &use_fp_on_smis);
1097b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // Check that the remainder is zero.
1098b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ test(edx, Operand(edx));
1099b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ j(not_zero, &use_fp_on_smis);
1100b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // Tag the result and store it in register eax.
1101b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ SmiTag(eax);
1102b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1103b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1104b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::MOD:
1105b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // Check for 0 divisor.
1106b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ test(right, Operand(right));
1107257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ j(zero, &not_smis);
1108b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1109b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // Sign extend left into edx:eax.
1110b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      ASSERT(left.is(eax));
1111b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ cdq();
1112b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // Divide edx:eax by right.
1113b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ idiv(right);
1114b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // Check for negative zero result.  Use combined = left | right.
1115b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ NegativeZeroTest(edx, combined, slow);
1116b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // Move remainder to register eax.
1117b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ mov(eax, edx);
1118b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1119b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1120b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    default:
1121b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      UNREACHABLE();
1122b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  }
1123b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1124b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // 5. Emit return of result in eax.  Some operations have registers pushed.
1125b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  switch (op_) {
1126b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::ADD:
1127b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::SUB:
1128b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::MUL:
1129b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::DIV:
1130b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ ret(0);
1131b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1132b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::MOD:
1133b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::BIT_OR:
1134b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::BIT_AND:
1135b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::BIT_XOR:
1136b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::SAR:
1137b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::SHL:
1138b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::SHR:
1139b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ ret(2 * kPointerSize);
1140b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1141b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    default:
1142b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      UNREACHABLE();
1143b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  }
1144b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1145b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // 6. For some operations emit inline code to perform floating point
1146b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // operations on known smis (e.g., if the result of the operation
1147b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // overflowed the smi range).
1148b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  if (allow_heapnumber_results == NO_HEAPNUMBER_RESULTS) {
1149b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ bind(&use_fp_on_smis);
1150b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    switch (op_) {
1151b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // Undo the effects of some operations, and some register moves.
1152b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      case Token::SHL:
1153b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        // The arguments are saved on the stack, and only used from there.
1154b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        break;
1155b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      case Token::ADD:
1156b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        // Revert right = right + left.
1157b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        __ sub(right, Operand(left));
1158b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        break;
1159b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      case Token::SUB:
1160b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        // Revert left = left - right.
1161b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        __ add(left, Operand(right));
1162b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        break;
1163b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      case Token::MUL:
1164b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        // Right was clobbered but a copy is in ebx.
1165b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        __ mov(right, ebx);
1166b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        break;
1167b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      case Token::DIV:
1168b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        // Left was clobbered but a copy is in edi.  Right is in ebx for
1169b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        // division.  They should be in eax, ebx for jump to not_smi.
1170b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        __ mov(eax, edi);
1171b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        break;
1172b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      default:
1173b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        // No other operators jump to use_fp_on_smis.
1174b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        break;
1175b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    }
1176b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ jmp(&not_smis);
1177b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  } else {
1178b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    ASSERT(allow_heapnumber_results == ALLOW_HEAPNUMBER_RESULTS);
1179b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    switch (op_) {
1180257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      case Token::SHL:
1181257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      case Token::SHR: {
1182b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        Comment perform_float(masm, "-- Perform float operation on smis");
1183b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        __ bind(&use_fp_on_smis);
1184b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        // Result we want is in left == edx, so we can put the allocated heap
1185b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        // number in eax.
1186b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        __ AllocateHeapNumber(eax, ecx, ebx, slow);
1187b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        // Store the result in the HeapNumber and return.
1188257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        // It's OK to overwrite the arguments on the stack because we
1189257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        // are about to return.
1190257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        if (op_ == Token::SHR) {
1191b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          __ mov(Operand(esp, 1 * kPointerSize), left);
1192257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          __ mov(Operand(esp, 2 * kPointerSize), Immediate(0));
1193257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          __ fild_d(Operand(esp, 1 * kPointerSize));
1194b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset));
1195257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        } else {
1196257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          ASSERT_EQ(Token::SHL, op_);
1197257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          if (CpuFeatures::IsSupported(SSE2)) {
1198257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch            CpuFeatures::Scope use_sse2(SSE2);
1199257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch            __ cvtsi2sd(xmm0, Operand(left));
1200257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch            __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0);
1201257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          } else {
1202257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch            __ mov(Operand(esp, 1 * kPointerSize), left);
1203257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch            __ fild_s(Operand(esp, 1 * kPointerSize));
1204257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch            __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset));
1205257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          }
1206b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        }
1207257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        __ ret(2 * kPointerSize);
1208257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        break;
1209b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      }
1210b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1211b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      case Token::ADD:
1212b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      case Token::SUB:
1213b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      case Token::MUL:
1214b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      case Token::DIV: {
1215b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        Comment perform_float(masm, "-- Perform float operation on smis");
1216b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        __ bind(&use_fp_on_smis);
1217b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        // Restore arguments to edx, eax.
1218b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        switch (op_) {
1219b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          case Token::ADD:
1220b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            // Revert right = right + left.
1221b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            __ sub(right, Operand(left));
1222b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            break;
1223b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          case Token::SUB:
1224b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            // Revert left = left - right.
1225b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            __ add(left, Operand(right));
1226b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            break;
1227b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          case Token::MUL:
1228b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            // Right was clobbered but a copy is in ebx.
1229b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            __ mov(right, ebx);
1230b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            break;
1231b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          case Token::DIV:
1232b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            // Left was clobbered but a copy is in edi.  Right is in ebx for
1233b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            // division.
1234b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            __ mov(edx, edi);
1235b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            __ mov(eax, right);
1236b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            break;
1237b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          default: UNREACHABLE();
1238b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            break;
1239b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        }
1240b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        __ AllocateHeapNumber(ecx, ebx, no_reg, slow);
12418b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch        if (CpuFeatures::IsSupported(SSE2)) {
1242b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          CpuFeatures::Scope use_sse2(SSE2);
1243b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          FloatingPointHelper::LoadSSE2Smis(masm, ebx);
1244b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          switch (op_) {
1245b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            case Token::ADD: __ addsd(xmm0, xmm1); break;
1246b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            case Token::SUB: __ subsd(xmm0, xmm1); break;
1247b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            case Token::MUL: __ mulsd(xmm0, xmm1); break;
1248b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            case Token::DIV: __ divsd(xmm0, xmm1); break;
1249b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            default: UNREACHABLE();
1250b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          }
1251b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          __ movdbl(FieldOperand(ecx, HeapNumber::kValueOffset), xmm0);
1252b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        } else {  // SSE2 not available, use FPU.
1253b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          FloatingPointHelper::LoadFloatSmis(masm, ebx);
1254b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          switch (op_) {
1255b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            case Token::ADD: __ faddp(1); break;
1256b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            case Token::SUB: __ fsubp(1); break;
1257b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            case Token::MUL: __ fmulp(1); break;
1258b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            case Token::DIV: __ fdivp(1); break;
1259b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            default: UNREACHABLE();
1260b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          }
1261b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          __ fstp_d(FieldOperand(ecx, HeapNumber::kValueOffset));
1262b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        }
1263b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        __ mov(eax, ecx);
1264b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        __ ret(0);
1265b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        break;
1266b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      }
1267b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1268b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      default:
1269b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        break;
1270b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    }
1271b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  }
1272b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1273b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // 7. Non-smi operands, fall out to the non-smi code with the operands in
1274b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // edx and eax.
1275b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  Comment done_comment(masm, "-- Enter non-smi code");
1276b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ bind(&not_smis);
1277b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  switch (op_) {
1278b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::BIT_OR:
1279b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::SHL:
1280b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::SAR:
1281b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::SHR:
1282b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // Right operand is saved in ecx and eax was destroyed by the smi
1283b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // check.
1284b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ mov(eax, ecx);
1285b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1286b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1287b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::DIV:
1288b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::MOD:
1289b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // Operands are in eax, ebx at this point.
1290b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ mov(edx, eax);
1291b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ mov(eax, ebx);
1292b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1293b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1294b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    default:
1295b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1296b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  }
1297b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch}
1298b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1299b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1300257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid BinaryOpStub::GenerateSmiStub(MacroAssembler* masm) {
1301b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  Label call_runtime;
1302b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1303b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  switch (op_) {
1304b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::ADD:
1305b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::SUB:
1306b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::MUL:
1307b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::DIV:
1308b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1309b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::MOD:
1310b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::BIT_OR:
1311b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::BIT_AND:
1312b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::BIT_XOR:
1313b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::SAR:
1314b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::SHL:
1315b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::SHR:
1316b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      GenerateRegisterArgsPush(masm);
1317b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1318b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    default:
1319b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      UNREACHABLE();
1320b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  }
1321b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1322257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  if (result_type_ == BinaryOpIC::UNINITIALIZED ||
1323257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      result_type_ == BinaryOpIC::SMI) {
1324b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    GenerateSmiCode(masm, &call_runtime, NO_HEAPNUMBER_RESULTS);
1325b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  } else {
1326b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    GenerateSmiCode(masm, &call_runtime, ALLOW_HEAPNUMBER_RESULTS);
1327b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  }
1328b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ bind(&call_runtime);
1329b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  switch (op_) {
1330b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::ADD:
1331b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::SUB:
1332b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::MUL:
1333b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::DIV:
1334b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      GenerateTypeTransition(masm);
1335b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1336b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::MOD:
1337b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::BIT_OR:
1338b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::BIT_AND:
1339b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::BIT_XOR:
1340b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::SAR:
1341b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::SHL:
1342b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::SHR:
1343b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      GenerateTypeTransitionWithSavedArgs(masm);
1344b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1345b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    default:
1346b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      UNREACHABLE();
1347b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  }
1348b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch}
1349b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1350b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1351257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid BinaryOpStub::GenerateStringStub(MacroAssembler* masm) {
1352257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  ASSERT(operands_type_ == BinaryOpIC::STRING);
1353b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  ASSERT(op_ == Token::ADD);
13541e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  // Try to add arguments as strings, otherwise, transition to the generic
1355257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // BinaryOpIC type.
13561e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  GenerateAddStrings(masm);
1357b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  GenerateTypeTransition(masm);
1358b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch}
1359b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1360b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1361257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid BinaryOpStub::GenerateBothStringStub(MacroAssembler* masm) {
1362257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label call_runtime;
1363257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  ASSERT(operands_type_ == BinaryOpIC::BOTH_STRING);
1364257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  ASSERT(op_ == Token::ADD);
1365257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // If both arguments are strings, call the string add stub.
1366257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Otherwise, do a transition.
1367257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1368257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Registers containing left and right operands respectively.
1369257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Register left = edx;
1370257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Register right = eax;
1371257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1372257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Test if left operand is a string.
13733fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ JumpIfSmi(left, &call_runtime);
1374257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ CmpObjectType(left, FIRST_NONSTRING_TYPE, ecx);
1375257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(above_equal, &call_runtime);
1376257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1377257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Test if right operand is a string.
13783fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ JumpIfSmi(right, &call_runtime);
1379257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ CmpObjectType(right, FIRST_NONSTRING_TYPE, ecx);
1380257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(above_equal, &call_runtime);
1381257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1382257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  StringAddStub string_add_stub(NO_STRING_CHECK_IN_STUB);
1383257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  GenerateRegisterArgsPush(masm);
1384257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ TailCallStub(&string_add_stub);
1385257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1386257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&call_runtime);
1387257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  GenerateTypeTransition(masm);
1388257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch}
1389257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1390257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1391257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid BinaryOpStub::GenerateInt32Stub(MacroAssembler* masm) {
1392b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  Label call_runtime;
1393257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  ASSERT(operands_type_ == BinaryOpIC::INT32);
1394b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1395b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Floating point case.
1396b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  switch (op_) {
1397b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::ADD:
1398b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::SUB:
1399b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::MUL:
1400b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::DIV: {
1401b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      Label not_floats;
1402b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      Label not_int32;
14038b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch      if (CpuFeatures::IsSupported(SSE2)) {
1404b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        CpuFeatures::Scope use_sse2(SSE2);
1405b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        FloatingPointHelper::LoadSSE2Operands(masm, &not_floats);
1406b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        FloatingPointHelper::CheckSSE2OperandsAreInt32(masm, &not_int32, ecx);
1407b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        switch (op_) {
1408b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          case Token::ADD: __ addsd(xmm0, xmm1); break;
1409b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          case Token::SUB: __ subsd(xmm0, xmm1); break;
1410b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          case Token::MUL: __ mulsd(xmm0, xmm1); break;
1411b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          case Token::DIV: __ divsd(xmm0, xmm1); break;
1412b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          default: UNREACHABLE();
1413b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        }
1414b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        // Check result type if it is currently Int32.
1415257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        if (result_type_ <= BinaryOpIC::INT32) {
1416b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          __ cvttsd2si(ecx, Operand(xmm0));
1417b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          __ cvtsi2sd(xmm2, Operand(ecx));
1418b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          __ ucomisd(xmm0, xmm2);
1419b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          __ j(not_zero, &not_int32);
1420b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          __ j(carry, &not_int32);
1421b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        }
1422b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        GenerateHeapResultAllocation(masm, &call_runtime);
1423b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0);
1424b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        __ ret(0);
1425b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      } else {  // SSE2 not available, use FPU.
1426b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        FloatingPointHelper::CheckFloatOperands(masm, &not_floats, ebx);
1427b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        FloatingPointHelper::LoadFloatOperands(
1428b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            masm,
1429b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            ecx,
1430b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            FloatingPointHelper::ARGS_IN_REGISTERS);
1431b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        FloatingPointHelper::CheckFloatOperandsAreInt32(masm, &not_int32);
1432b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        switch (op_) {
1433b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          case Token::ADD: __ faddp(1); break;
1434b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          case Token::SUB: __ fsubp(1); break;
1435b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          case Token::MUL: __ fmulp(1); break;
1436b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          case Token::DIV: __ fdivp(1); break;
1437b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          default: UNREACHABLE();
1438b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        }
1439b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        Label after_alloc_failure;
1440b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        GenerateHeapResultAllocation(masm, &after_alloc_failure);
1441b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset));
1442b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        __ ret(0);
1443b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        __ bind(&after_alloc_failure);
1444b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        __ ffree();
1445b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        __ jmp(&call_runtime);
1446b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      }
1447b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1448b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ bind(&not_floats);
1449b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ bind(&not_int32);
1450b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      GenerateTypeTransition(masm);
1451b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1452b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    }
1453b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1454b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::MOD: {
1455b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // For MOD we go directly to runtime in the non-smi case.
1456b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1457b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    }
1458b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::BIT_OR:
1459b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::BIT_AND:
1460b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::BIT_XOR:
1461b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::SAR:
1462b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::SHL:
1463b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::SHR: {
1464b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      GenerateRegisterArgsPush(masm);
1465b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      Label not_floats;
1466b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      Label not_int32;
1467b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      Label non_smi_result;
1468b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      /*  {
1469b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        CpuFeatures::Scope use_sse2(SSE2);
1470b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        FloatingPointHelper::LoadSSE2Operands(masm, &not_floats);
1471b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        FloatingPointHelper::CheckSSE2OperandsAreInt32(masm, &not_int32, ecx);
1472b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        }*/
1473b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      FloatingPointHelper::LoadUnknownsAsIntegers(masm,
1474b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                                                  use_sse3_,
1475b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                                                  &not_floats);
1476b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      FloatingPointHelper::CheckLoadedIntegersWereInt32(masm, use_sse3_,
1477b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                                                        &not_int32);
1478b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      switch (op_) {
1479b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        case Token::BIT_OR:  __ or_(eax, Operand(ecx)); break;
1480b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        case Token::BIT_AND: __ and_(eax, Operand(ecx)); break;
1481b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        case Token::BIT_XOR: __ xor_(eax, Operand(ecx)); break;
1482b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        case Token::SAR: __ sar_cl(eax); break;
1483b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        case Token::SHL: __ shl_cl(eax); break;
1484b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        case Token::SHR: __ shr_cl(eax); break;
1485b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        default: UNREACHABLE();
1486b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      }
1487b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      if (op_ == Token::SHR) {
1488b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        // Check if result is non-negative and fits in a smi.
1489b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        __ test(eax, Immediate(0xc0000000));
1490b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        __ j(not_zero, &call_runtime);
1491b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      } else {
1492b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        // Check if result fits in a smi.
1493b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        __ cmp(eax, 0xc0000000);
1494b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        __ j(negative, &non_smi_result);
1495b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      }
1496b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // Tag smi result and return.
1497b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ SmiTag(eax);
1498b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ ret(2 * kPointerSize);  // Drop two pushed arguments from the stack.
1499b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1500b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // All ops except SHR return a signed int32 that we load in
1501b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // a HeapNumber.
1502b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      if (op_ != Token::SHR) {
1503b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        __ bind(&non_smi_result);
1504b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        // Allocate a heap number if needed.
1505b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        __ mov(ebx, Operand(eax));  // ebx: result
1506257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        Label skip_allocation;
1507b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        switch (mode_) {
1508b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          case OVERWRITE_LEFT:
1509b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          case OVERWRITE_RIGHT:
1510b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            // If the operand was an object, we skip the
1511b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            // allocation of a heap number.
1512b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            __ mov(eax, Operand(esp, mode_ == OVERWRITE_RIGHT ?
1513b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                                1 * kPointerSize : 2 * kPointerSize));
15143fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch            __ JumpIfNotSmi(eax, &skip_allocation, Label::kNear);
1515b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            // Fall through!
1516b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          case NO_OVERWRITE:
1517b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            __ AllocateHeapNumber(eax, ecx, edx, &call_runtime);
1518b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            __ bind(&skip_allocation);
1519b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            break;
1520b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          default: UNREACHABLE();
1521b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        }
1522b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        // Store the result in the HeapNumber and return.
15238b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch        if (CpuFeatures::IsSupported(SSE2)) {
1524b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          CpuFeatures::Scope use_sse2(SSE2);
1525b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          __ cvtsi2sd(xmm0, Operand(ebx));
1526b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0);
1527b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        } else {
1528b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          __ mov(Operand(esp, 1 * kPointerSize), ebx);
1529b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          __ fild_s(Operand(esp, 1 * kPointerSize));
1530b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset));
1531b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        }
1532b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        __ ret(2 * kPointerSize);  // Drop two pushed arguments from the stack.
1533b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      }
1534b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1535b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ bind(&not_floats);
1536b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ bind(&not_int32);
1537b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      GenerateTypeTransitionWithSavedArgs(masm);
1538b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1539b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    }
1540b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    default: UNREACHABLE(); break;
1541b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  }
1542b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1543b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // If an allocation fails, or SHR or MOD hit a hard case,
1544b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // use the runtime system to get the correct result.
1545b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ bind(&call_runtime);
1546b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1547b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  switch (op_) {
1548b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::ADD:
1549b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      GenerateRegisterArgsPush(masm);
1550b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ InvokeBuiltin(Builtins::ADD, JUMP_FUNCTION);
1551b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1552b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::SUB:
1553b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      GenerateRegisterArgsPush(masm);
1554b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ InvokeBuiltin(Builtins::SUB, JUMP_FUNCTION);
1555b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1556b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::MUL:
1557b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      GenerateRegisterArgsPush(masm);
1558b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ InvokeBuiltin(Builtins::MUL, JUMP_FUNCTION);
1559b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1560b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::DIV:
1561b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      GenerateRegisterArgsPush(masm);
1562b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ InvokeBuiltin(Builtins::DIV, JUMP_FUNCTION);
1563b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1564b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::MOD:
1565b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      GenerateRegisterArgsPush(masm);
1566b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ InvokeBuiltin(Builtins::MOD, JUMP_FUNCTION);
1567b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1568b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::BIT_OR:
1569b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ InvokeBuiltin(Builtins::BIT_OR, JUMP_FUNCTION);
1570b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1571b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::BIT_AND:
1572b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ InvokeBuiltin(Builtins::BIT_AND, JUMP_FUNCTION);
1573b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1574b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::BIT_XOR:
1575b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ InvokeBuiltin(Builtins::BIT_XOR, JUMP_FUNCTION);
1576b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1577b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::SAR:
1578b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ InvokeBuiltin(Builtins::SAR, JUMP_FUNCTION);
1579b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1580b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::SHL:
1581b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ InvokeBuiltin(Builtins::SHL, JUMP_FUNCTION);
1582b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1583b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::SHR:
1584b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ InvokeBuiltin(Builtins::SHR, JUMP_FUNCTION);
1585b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1586b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    default:
1587b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      UNREACHABLE();
1588b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  }
1589b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch}
1590b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1591b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1592257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid BinaryOpStub::GenerateOddballStub(MacroAssembler* masm) {
159344f0eee88ff00398ff7f715fab053374d808c90dSteve Block  if (op_ == Token::ADD) {
159444f0eee88ff00398ff7f715fab053374d808c90dSteve Block    // Handle string addition here, because it is the only operation
159544f0eee88ff00398ff7f715fab053374d808c90dSteve Block    // that does not do a ToNumber conversion on the operands.
159644f0eee88ff00398ff7f715fab053374d808c90dSteve Block    GenerateAddStrings(masm);
159744f0eee88ff00398ff7f715fab053374d808c90dSteve Block  }
159844f0eee88ff00398ff7f715fab053374d808c90dSteve Block
1599257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Factory* factory = masm->isolate()->factory();
1600257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
160144f0eee88ff00398ff7f715fab053374d808c90dSteve Block  // Convert odd ball arguments to numbers.
1602257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label check, done;
1603257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ cmp(edx, factory->undefined_value());
1604257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(not_equal, &check, Label::kNear);
160544f0eee88ff00398ff7f715fab053374d808c90dSteve Block  if (Token::IsBitOp(op_)) {
160644f0eee88ff00398ff7f715fab053374d808c90dSteve Block    __ xor_(edx, Operand(edx));
160744f0eee88ff00398ff7f715fab053374d808c90dSteve Block  } else {
1608257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ mov(edx, Immediate(factory->nan_value()));
160944f0eee88ff00398ff7f715fab053374d808c90dSteve Block  }
1610257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ jmp(&done, Label::kNear);
161144f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ bind(&check);
1612257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ cmp(eax, factory->undefined_value());
1613257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(not_equal, &done, Label::kNear);
161444f0eee88ff00398ff7f715fab053374d808c90dSteve Block  if (Token::IsBitOp(op_)) {
161544f0eee88ff00398ff7f715fab053374d808c90dSteve Block    __ xor_(eax, Operand(eax));
161644f0eee88ff00398ff7f715fab053374d808c90dSteve Block  } else {
1617257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ mov(eax, Immediate(factory->nan_value()));
161844f0eee88ff00398ff7f715fab053374d808c90dSteve Block  }
161944f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ bind(&done);
162044f0eee88ff00398ff7f715fab053374d808c90dSteve Block
162144f0eee88ff00398ff7f715fab053374d808c90dSteve Block  GenerateHeapNumberStub(masm);
162244f0eee88ff00398ff7f715fab053374d808c90dSteve Block}
162344f0eee88ff00398ff7f715fab053374d808c90dSteve Block
162444f0eee88ff00398ff7f715fab053374d808c90dSteve Block
1625257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid BinaryOpStub::GenerateHeapNumberStub(MacroAssembler* masm) {
1626b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  Label call_runtime;
1627b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1628b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Floating point case.
1629b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  switch (op_) {
1630b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::ADD:
1631b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::SUB:
1632b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::MUL:
1633b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::DIV: {
1634b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      Label not_floats;
16358b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch      if (CpuFeatures::IsSupported(SSE2)) {
1636b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        CpuFeatures::Scope use_sse2(SSE2);
1637b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        FloatingPointHelper::LoadSSE2Operands(masm, &not_floats);
1638b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1639b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        switch (op_) {
1640b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          case Token::ADD: __ addsd(xmm0, xmm1); break;
1641b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          case Token::SUB: __ subsd(xmm0, xmm1); break;
1642b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          case Token::MUL: __ mulsd(xmm0, xmm1); break;
1643b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          case Token::DIV: __ divsd(xmm0, xmm1); break;
1644b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          default: UNREACHABLE();
1645b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        }
1646b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        GenerateHeapResultAllocation(masm, &call_runtime);
1647b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0);
1648b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        __ ret(0);
1649b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      } else {  // SSE2 not available, use FPU.
1650b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        FloatingPointHelper::CheckFloatOperands(masm, &not_floats, ebx);
1651b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        FloatingPointHelper::LoadFloatOperands(
1652b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            masm,
1653b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            ecx,
1654b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            FloatingPointHelper::ARGS_IN_REGISTERS);
1655b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        switch (op_) {
1656b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          case Token::ADD: __ faddp(1); break;
1657b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          case Token::SUB: __ fsubp(1); break;
1658b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          case Token::MUL: __ fmulp(1); break;
1659b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          case Token::DIV: __ fdivp(1); break;
1660b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          default: UNREACHABLE();
1661b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        }
1662b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        Label after_alloc_failure;
1663b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        GenerateHeapResultAllocation(masm, &after_alloc_failure);
1664b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset));
1665b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        __ ret(0);
1666b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        __ bind(&after_alloc_failure);
1667b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        __ ffree();
1668b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        __ jmp(&call_runtime);
1669b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      }
1670b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1671b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ bind(&not_floats);
1672b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      GenerateTypeTransition(masm);
1673b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1674b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    }
1675b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1676b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::MOD: {
1677b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // For MOD we go directly to runtime in the non-smi case.
1678b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1679b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    }
1680b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::BIT_OR:
1681b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::BIT_AND:
1682b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::BIT_XOR:
1683b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::SAR:
1684b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::SHL:
1685b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::SHR: {
1686b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      GenerateRegisterArgsPush(masm);
1687b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      Label not_floats;
1688b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      Label non_smi_result;
1689b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      FloatingPointHelper::LoadUnknownsAsIntegers(masm,
1690b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                                                  use_sse3_,
1691b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                                                  &not_floats);
1692b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      switch (op_) {
1693b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        case Token::BIT_OR:  __ or_(eax, Operand(ecx)); break;
1694b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        case Token::BIT_AND: __ and_(eax, Operand(ecx)); break;
1695b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        case Token::BIT_XOR: __ xor_(eax, Operand(ecx)); break;
1696b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        case Token::SAR: __ sar_cl(eax); break;
1697b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        case Token::SHL: __ shl_cl(eax); break;
1698b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        case Token::SHR: __ shr_cl(eax); break;
1699b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        default: UNREACHABLE();
1700b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      }
1701b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      if (op_ == Token::SHR) {
1702b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        // Check if result is non-negative and fits in a smi.
1703b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        __ test(eax, Immediate(0xc0000000));
1704b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        __ j(not_zero, &call_runtime);
1705b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      } else {
1706b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        // Check if result fits in a smi.
1707b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        __ cmp(eax, 0xc0000000);
1708b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        __ j(negative, &non_smi_result);
1709b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      }
1710b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // Tag smi result and return.
1711b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ SmiTag(eax);
1712b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ ret(2 * kPointerSize);  // Drop two pushed arguments from the stack.
1713b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1714b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // All ops except SHR return a signed int32 that we load in
1715b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // a HeapNumber.
1716b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      if (op_ != Token::SHR) {
1717b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        __ bind(&non_smi_result);
1718b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        // Allocate a heap number if needed.
1719b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        __ mov(ebx, Operand(eax));  // ebx: result
1720257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        Label skip_allocation;
1721b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        switch (mode_) {
1722b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          case OVERWRITE_LEFT:
1723b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          case OVERWRITE_RIGHT:
1724b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            // If the operand was an object, we skip the
1725b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            // allocation of a heap number.
1726b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            __ mov(eax, Operand(esp, mode_ == OVERWRITE_RIGHT ?
1727b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                                1 * kPointerSize : 2 * kPointerSize));
17283fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch            __ JumpIfNotSmi(eax, &skip_allocation, Label::kNear);
1729b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            // Fall through!
1730b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          case NO_OVERWRITE:
1731b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            __ AllocateHeapNumber(eax, ecx, edx, &call_runtime);
1732b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            __ bind(&skip_allocation);
1733b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            break;
1734b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          default: UNREACHABLE();
1735b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        }
1736b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        // Store the result in the HeapNumber and return.
17378b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch        if (CpuFeatures::IsSupported(SSE2)) {
1738b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          CpuFeatures::Scope use_sse2(SSE2);
1739b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          __ cvtsi2sd(xmm0, Operand(ebx));
1740b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0);
1741b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        } else {
1742b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          __ mov(Operand(esp, 1 * kPointerSize), ebx);
1743b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          __ fild_s(Operand(esp, 1 * kPointerSize));
1744b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset));
1745b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        }
1746b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        __ ret(2 * kPointerSize);  // Drop two pushed arguments from the stack.
1747b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      }
1748b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1749b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ bind(&not_floats);
1750b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      GenerateTypeTransitionWithSavedArgs(masm);
1751b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1752b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    }
1753b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    default: UNREACHABLE(); break;
1754b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  }
1755b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1756b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // If an allocation fails, or SHR or MOD hit a hard case,
1757b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // use the runtime system to get the correct result.
1758b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ bind(&call_runtime);
1759b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1760b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  switch (op_) {
1761b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::ADD:
1762b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      GenerateRegisterArgsPush(masm);
1763b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ InvokeBuiltin(Builtins::ADD, JUMP_FUNCTION);
1764b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1765b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::SUB:
1766b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      GenerateRegisterArgsPush(masm);
1767b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ InvokeBuiltin(Builtins::SUB, JUMP_FUNCTION);
1768b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1769b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::MUL:
1770b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      GenerateRegisterArgsPush(masm);
1771b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ InvokeBuiltin(Builtins::MUL, JUMP_FUNCTION);
1772b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1773b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::DIV:
1774b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      GenerateRegisterArgsPush(masm);
1775b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ InvokeBuiltin(Builtins::DIV, JUMP_FUNCTION);
1776b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1777b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::MOD:
1778b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      GenerateRegisterArgsPush(masm);
1779b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ InvokeBuiltin(Builtins::MOD, JUMP_FUNCTION);
1780b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1781b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::BIT_OR:
1782b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ InvokeBuiltin(Builtins::BIT_OR, JUMP_FUNCTION);
1783b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1784b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::BIT_AND:
1785b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ InvokeBuiltin(Builtins::BIT_AND, JUMP_FUNCTION);
1786b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1787b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::BIT_XOR:
1788b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ InvokeBuiltin(Builtins::BIT_XOR, JUMP_FUNCTION);
1789b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1790b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::SAR:
1791b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ InvokeBuiltin(Builtins::SAR, JUMP_FUNCTION);
1792b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1793b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::SHL:
1794b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ InvokeBuiltin(Builtins::SHL, JUMP_FUNCTION);
1795b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1796b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::SHR:
1797b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ InvokeBuiltin(Builtins::SHR, JUMP_FUNCTION);
1798b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1799b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    default:
1800b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      UNREACHABLE();
1801b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  }
1802b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch}
1803b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1804b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1805257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid BinaryOpStub::GenerateGeneric(MacroAssembler* masm) {
1806b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  Label call_runtime;
1807b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
180844f0eee88ff00398ff7f715fab053374d808c90dSteve Block  Counters* counters = masm->isolate()->counters();
180944f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ IncrementCounter(counters->generic_binary_stub_calls(), 1);
1810b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1811b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  switch (op_) {
1812b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::ADD:
1813b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::SUB:
1814b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::MUL:
1815b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::DIV:
1816b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1817b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::MOD:
1818b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::BIT_OR:
1819b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::BIT_AND:
1820b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::BIT_XOR:
1821b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::SAR:
1822b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::SHL:
1823b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::SHR:
1824b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      GenerateRegisterArgsPush(masm);
1825b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1826b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    default:
1827b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      UNREACHABLE();
1828b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  }
1829b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1830b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  GenerateSmiCode(masm, &call_runtime, ALLOW_HEAPNUMBER_RESULTS);
1831b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1832b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Floating point case.
1833b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  switch (op_) {
1834b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::ADD:
1835b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::SUB:
1836b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::MUL:
1837b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::DIV: {
1838b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      Label not_floats;
18398b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch      if (CpuFeatures::IsSupported(SSE2)) {
1840b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        CpuFeatures::Scope use_sse2(SSE2);
1841b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        FloatingPointHelper::LoadSSE2Operands(masm, &not_floats);
1842b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1843b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        switch (op_) {
1844b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          case Token::ADD: __ addsd(xmm0, xmm1); break;
1845b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          case Token::SUB: __ subsd(xmm0, xmm1); break;
1846b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          case Token::MUL: __ mulsd(xmm0, xmm1); break;
1847b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          case Token::DIV: __ divsd(xmm0, xmm1); break;
1848b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          default: UNREACHABLE();
1849b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        }
1850b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        GenerateHeapResultAllocation(masm, &call_runtime);
1851b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0);
1852b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        __ ret(0);
1853b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      } else {  // SSE2 not available, use FPU.
1854b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        FloatingPointHelper::CheckFloatOperands(masm, &not_floats, ebx);
1855b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        FloatingPointHelper::LoadFloatOperands(
1856b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            masm,
1857b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            ecx,
1858b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            FloatingPointHelper::ARGS_IN_REGISTERS);
1859b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        switch (op_) {
1860b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          case Token::ADD: __ faddp(1); break;
1861b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          case Token::SUB: __ fsubp(1); break;
1862b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          case Token::MUL: __ fmulp(1); break;
1863b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          case Token::DIV: __ fdivp(1); break;
1864b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          default: UNREACHABLE();
1865b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        }
1866b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        Label after_alloc_failure;
1867b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        GenerateHeapResultAllocation(masm, &after_alloc_failure);
1868b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset));
1869b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        __ ret(0);
1870b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        __ bind(&after_alloc_failure);
1871b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          __ ffree();
1872b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          __ jmp(&call_runtime);
1873b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      }
1874b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        __ bind(&not_floats);
1875b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        break;
1876b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      }
1877b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::MOD: {
1878b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // For MOD we go directly to runtime in the non-smi case.
1879b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1880b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    }
1881b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::BIT_OR:
1882b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::BIT_AND:
1883b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      case Token::BIT_XOR:
1884b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::SAR:
1885b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::SHL:
1886b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::SHR: {
1887b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      Label non_smi_result;
1888b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      FloatingPointHelper::LoadUnknownsAsIntegers(masm,
1889b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                                                  use_sse3_,
1890b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                                                  &call_runtime);
1891b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      switch (op_) {
1892b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        case Token::BIT_OR:  __ or_(eax, Operand(ecx)); break;
1893b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        case Token::BIT_AND: __ and_(eax, Operand(ecx)); break;
1894b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        case Token::BIT_XOR: __ xor_(eax, Operand(ecx)); break;
1895b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        case Token::SAR: __ sar_cl(eax); break;
1896b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        case Token::SHL: __ shl_cl(eax); break;
1897b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        case Token::SHR: __ shr_cl(eax); break;
1898b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        default: UNREACHABLE();
1899b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      }
1900b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      if (op_ == Token::SHR) {
1901b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        // Check if result is non-negative and fits in a smi.
1902b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        __ test(eax, Immediate(0xc0000000));
1903b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        __ j(not_zero, &call_runtime);
1904b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      } else {
1905b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        // Check if result fits in a smi.
1906b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        __ cmp(eax, 0xc0000000);
1907b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        __ j(negative, &non_smi_result);
1908b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      }
1909b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // Tag smi result and return.
1910b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ SmiTag(eax);
1911b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ ret(2 * kPointerSize);  // Drop the arguments from the stack.
1912b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1913b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // All ops except SHR return a signed int32 that we load in
1914b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // a HeapNumber.
1915b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      if (op_ != Token::SHR) {
1916b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        __ bind(&non_smi_result);
1917b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        // Allocate a heap number if needed.
1918b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        __ mov(ebx, Operand(eax));  // ebx: result
1919257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        Label skip_allocation;
1920b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        switch (mode_) {
1921b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          case OVERWRITE_LEFT:
1922b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          case OVERWRITE_RIGHT:
1923b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            // If the operand was an object, we skip the
1924b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch              // allocation of a heap number.
1925b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            __ mov(eax, Operand(esp, mode_ == OVERWRITE_RIGHT ?
1926b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                                1 * kPointerSize : 2 * kPointerSize));
19273fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch            __ JumpIfNotSmi(eax, &skip_allocation, Label::kNear);
1928b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            // Fall through!
1929b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          case NO_OVERWRITE:
1930b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            __ AllocateHeapNumber(eax, ecx, edx, &call_runtime);
1931b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            __ bind(&skip_allocation);
1932b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            break;
1933b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          default: UNREACHABLE();
1934b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        }
1935b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        // Store the result in the HeapNumber and return.
19368b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch        if (CpuFeatures::IsSupported(SSE2)) {
1937b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          CpuFeatures::Scope use_sse2(SSE2);
1938b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          __ cvtsi2sd(xmm0, Operand(ebx));
1939b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0);
1940b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        } else {
1941b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          __ mov(Operand(esp, 1 * kPointerSize), ebx);
1942b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          __ fild_s(Operand(esp, 1 * kPointerSize));
1943b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset));
1944b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        }
1945b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        __ ret(2 * kPointerSize);
1946b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      }
1947b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1948b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    }
1949b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    default: UNREACHABLE(); break;
1950b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  }
1951b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1952b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // If all else fails, use the runtime system to get the correct
1953b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // result.
1954b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ bind(&call_runtime);
1955b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  switch (op_) {
1956b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::ADD: {
19571e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      GenerateAddStrings(masm);
1958b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      GenerateRegisterArgsPush(masm);
1959b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ InvokeBuiltin(Builtins::ADD, JUMP_FUNCTION);
1960b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1961b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    }
1962b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::SUB:
1963b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      GenerateRegisterArgsPush(masm);
1964b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ InvokeBuiltin(Builtins::SUB, JUMP_FUNCTION);
1965b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1966b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::MUL:
1967b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      GenerateRegisterArgsPush(masm);
1968b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ InvokeBuiltin(Builtins::MUL, JUMP_FUNCTION);
1969b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1970b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::DIV:
1971b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      GenerateRegisterArgsPush(masm);
1972b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ InvokeBuiltin(Builtins::DIV, JUMP_FUNCTION);
1973b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1974b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::MOD:
1975b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ InvokeBuiltin(Builtins::MOD, JUMP_FUNCTION);
1976b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1977b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::BIT_OR:
1978b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ InvokeBuiltin(Builtins::BIT_OR, JUMP_FUNCTION);
1979b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1980b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::BIT_AND:
1981b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ InvokeBuiltin(Builtins::BIT_AND, JUMP_FUNCTION);
1982b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1983b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::BIT_XOR:
1984b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ InvokeBuiltin(Builtins::BIT_XOR, JUMP_FUNCTION);
1985b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1986b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::SAR:
1987b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ InvokeBuiltin(Builtins::SAR, JUMP_FUNCTION);
1988b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1989b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::SHL:
1990b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ InvokeBuiltin(Builtins::SHL, JUMP_FUNCTION);
1991b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1992b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::SHR:
1993b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ InvokeBuiltin(Builtins::SHR, JUMP_FUNCTION);
1994b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
1995b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    default:
1996b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      UNREACHABLE();
1997b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  }
1998b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch}
1999b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
2000b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
2001257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid BinaryOpStub::GenerateAddStrings(MacroAssembler* masm) {
2002e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  ASSERT(op_ == Token::ADD);
2003257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label left_not_string, call_runtime;
20041e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
20051e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  // Registers containing left and right operands respectively.
20061e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  Register left = edx;
20071e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  Register right = eax;
20081e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
20091e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  // Test if left operand is a string.
20103fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ JumpIfSmi(left, &left_not_string, Label::kNear);
20111e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  __ CmpObjectType(left, FIRST_NONSTRING_TYPE, ecx);
2012257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(above_equal, &left_not_string, Label::kNear);
20131e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
20141e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  StringAddStub string_add_left_stub(NO_STRING_CHECK_LEFT_IN_STUB);
20151e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  GenerateRegisterArgsPush(masm);
20161e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  __ TailCallStub(&string_add_left_stub);
20171e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
20181e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  // Left operand is not a string, test right.
20191e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  __ bind(&left_not_string);
20203fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ JumpIfSmi(right, &call_runtime, Label::kNear);
20211e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  __ CmpObjectType(right, FIRST_NONSTRING_TYPE, ecx);
2022257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(above_equal, &call_runtime, Label::kNear);
20231e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
20241e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  StringAddStub string_add_right_stub(NO_STRING_CHECK_RIGHT_IN_STUB);
20251e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  GenerateRegisterArgsPush(masm);
20261e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  __ TailCallStub(&string_add_right_stub);
20271e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
20281e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  // Neither argument is a string.
20291e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  __ bind(&call_runtime);
20301e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block}
20311e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
20321e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
2033257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid BinaryOpStub::GenerateHeapResultAllocation(
2034b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    MacroAssembler* masm,
2035b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    Label* alloc_failure) {
2036b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  Label skip_allocation;
2037b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  OverwriteMode mode = mode_;
2038b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  switch (mode) {
2039b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case OVERWRITE_LEFT: {
2040b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // If the argument in edx is already an object, we skip the
2041b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // allocation of a heap number.
20423fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch      __ JumpIfNotSmi(edx, &skip_allocation, Label::kNear);
2043b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // Allocate a heap number for the result. Keep eax and edx intact
2044b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // for the possible runtime call.
2045b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ AllocateHeapNumber(ebx, ecx, no_reg, alloc_failure);
2046b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // Now edx can be overwritten losing one of the arguments as we are
2047b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // now done and will not need it any more.
2048b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ mov(edx, Operand(ebx));
2049b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ bind(&skip_allocation);
2050b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // Use object in edx as a result holder
2051b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ mov(eax, Operand(edx));
2052b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
2053b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    }
2054b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case OVERWRITE_RIGHT:
2055b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // If the argument in eax is already an object, we skip the
2056b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // allocation of a heap number.
20573fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch      __ JumpIfNotSmi(eax, &skip_allocation, Label::kNear);
2058b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // Fall through!
2059b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case NO_OVERWRITE:
2060b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // Allocate a heap number for the result. Keep eax and edx intact
2061b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // for the possible runtime call.
2062b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ AllocateHeapNumber(ebx, ecx, no_reg, alloc_failure);
2063b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // Now eax can be overwritten losing one of the arguments as we are
2064b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // now done and will not need it any more.
2065b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ mov(eax, ebx);
2066b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ bind(&skip_allocation);
2067b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      break;
2068b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    default: UNREACHABLE();
2069b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  }
2070b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch}
2071b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
2072b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
2073257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid BinaryOpStub::GenerateRegisterArgsPush(MacroAssembler* masm) {
207480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ pop(ecx);
2075b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ push(edx);
2076b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ push(eax);
207780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ push(ecx);
207880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
207980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
208080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
208180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid TranscendentalCacheStub::Generate(MacroAssembler* masm) {
2082b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // TAGGED case:
2083b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  //   Input:
2084b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  //     esp[4]: tagged number input argument (should be number).
2085b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  //     esp[0]: return address.
2086b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  //   Output:
2087b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  //     eax: tagged double result.
2088b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // UNTAGGED case:
2089b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  //   Input::
2090b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  //     esp[0]: return address.
2091b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  //     xmm1: untagged double input argument
2092b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  //   Output:
2093b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  //     xmm1: untagged double result.
2094b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
209580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label runtime_call;
209680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label runtime_call_clear_stack;
2097b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  Label skip_cache;
2098b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  const bool tagged = (argument_type_ == TAGGED);
2099b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  if (tagged) {
2100b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    // Test that eax is a number.
2101257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Label input_not_smi;
2102257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Label loaded;
2103b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ mov(eax, Operand(esp, kPointerSize));
21043fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    __ JumpIfNotSmi(eax, &input_not_smi, Label::kNear);
2105b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    // Input is a smi. Untag and load it onto the FPU stack.
2106b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    // Then load the low and high words of the double into ebx, edx.
2107b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    STATIC_ASSERT(kSmiTagSize == 1);
2108b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ sar(eax, 1);
2109b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ sub(Operand(esp), Immediate(2 * kPointerSize));
2110b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ mov(Operand(esp, 0), eax);
2111b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ fild_s(Operand(esp, 0));
2112b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ fst_d(Operand(esp, 0));
2113b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ pop(edx);
2114b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ pop(ebx);
2115257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ jmp(&loaded, Label::kNear);
2116b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ bind(&input_not_smi);
2117b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    // Check if input is a HeapNumber.
2118b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset));
211944f0eee88ff00398ff7f715fab053374d808c90dSteve Block    Factory* factory = masm->isolate()->factory();
212044f0eee88ff00398ff7f715fab053374d808c90dSteve Block    __ cmp(Operand(ebx), Immediate(factory->heap_number_map()));
2121b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ j(not_equal, &runtime_call);
2122b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    // Input is a HeapNumber. Push it on the FPU stack and load its
2123b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    // low and high words into ebx, edx.
2124b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ fld_d(FieldOperand(eax, HeapNumber::kValueOffset));
2125b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ mov(edx, FieldOperand(eax, HeapNumber::kExponentOffset));
2126b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ mov(ebx, FieldOperand(eax, HeapNumber::kMantissaOffset));
2127b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
2128b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ bind(&loaded);
2129b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  } else {  // UNTAGGED.
21308b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch    if (CpuFeatures::IsSupported(SSE4_1)) {
2131b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      CpuFeatures::Scope sse4_scope(SSE4_1);
2132b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ pextrd(Operand(edx), xmm1, 0x1);  // copy xmm1[63..32] to edx.
2133b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    } else {
2134b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ pshufd(xmm0, xmm1, 0x1);
2135b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ movd(Operand(edx), xmm0);
2136b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    }
2137b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ movd(Operand(ebx), xmm1);
2138b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  }
213980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
2140b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // ST[0] or xmm1  == double value
214180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // ebx = low 32 bits of double value
214280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // edx = high 32 bits of double value
214380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Compute hash (the shifts are arithmetic):
214480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  //   h = (low ^ high); h ^= h >> 16; h ^= h >> 8; h = h & (cacheSize - 1);
214580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(ecx, ebx);
214680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ xor_(ecx, Operand(edx));
214780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(eax, ecx);
214880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ sar(eax, 16);
214980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ xor_(ecx, Operand(eax));
215080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(eax, ecx);
215180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ sar(eax, 8);
215280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ xor_(ecx, Operand(eax));
215344f0eee88ff00398ff7f715fab053374d808c90dSteve Block  ASSERT(IsPowerOf2(TranscendentalCache::SubCache::kCacheSize));
215444f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ and_(Operand(ecx),
215544f0eee88ff00398ff7f715fab053374d808c90dSteve Block          Immediate(TranscendentalCache::SubCache::kCacheSize - 1));
215680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
2157b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // ST[0] or xmm1 == double value.
215880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // ebx = low 32 bits of double value.
215980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // edx = high 32 bits of double value.
216080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // ecx = TranscendentalCache::hash(double value).
216144f0eee88ff00398ff7f715fab053374d808c90dSteve Block  ExternalReference cache_array =
216244f0eee88ff00398ff7f715fab053374d808c90dSteve Block      ExternalReference::transcendental_cache_array_address(masm->isolate());
216344f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ mov(eax, Immediate(cache_array));
216444f0eee88ff00398ff7f715fab053374d808c90dSteve Block  int cache_array_index =
216544f0eee88ff00398ff7f715fab053374d808c90dSteve Block      type_ * sizeof(masm->isolate()->transcendental_cache()->caches_[0]);
216644f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ mov(eax, Operand(eax, cache_array_index));
216780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Eax points to the cache for the type type_.
216880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // If NULL, the cache hasn't been initialized yet, so go through runtime.
216980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ test(eax, Operand(eax));
217080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(zero, &runtime_call_clear_stack);
217180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#ifdef DEBUG
217280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check that the layout of cache elements match expectations.
217344f0eee88ff00398ff7f715fab053374d808c90dSteve Block  { TranscendentalCache::SubCache::Element test_elem[2];
217480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    char* elem_start = reinterpret_cast<char*>(&test_elem[0]);
217580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    char* elem2_start = reinterpret_cast<char*>(&test_elem[1]);
217680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    char* elem_in0  = reinterpret_cast<char*>(&(test_elem[0].in[0]));
217780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    char* elem_in1  = reinterpret_cast<char*>(&(test_elem[0].in[1]));
217880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    char* elem_out = reinterpret_cast<char*>(&(test_elem[0].output));
217980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    CHECK_EQ(12, elem2_start - elem_start);  // Two uint_32's and a pointer.
218080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    CHECK_EQ(0, elem_in0 - elem_start);
218180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    CHECK_EQ(kIntSize, elem_in1 - elem_start);
218280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    CHECK_EQ(2 * kIntSize, elem_out - elem_start);
218380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
218480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#endif
218580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Find the address of the ecx'th entry in the cache, i.e., &eax[ecx*12].
218680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ lea(ecx, Operand(ecx, ecx, times_2, 0));
218780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ lea(ecx, Operand(eax, ecx, times_4, 0));
218880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check if cache matches: Double value is stored in uint32_t[2] array.
2189257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label cache_miss;
219080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cmp(ebx, Operand(ecx, 0));
2191257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(not_equal, &cache_miss, Label::kNear);
219280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cmp(edx, Operand(ecx, kIntSize));
2193257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(not_equal, &cache_miss, Label::kNear);
219480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Cache hit!
219580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(eax, Operand(ecx, 2 * kIntSize));
2196b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  if (tagged) {
2197b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ fstp(0);
2198b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ ret(kPointerSize);
2199b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  } else {  // UNTAGGED.
2200b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ movdbl(xmm1, FieldOperand(eax, HeapNumber::kValueOffset));
2201b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ Ret();
2202b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  }
220380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
220480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&cache_miss);
220580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Update cache with new value.
220680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // We are short on registers, so use no_reg as scratch.
220780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // This gives slightly larger code.
2208b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  if (tagged) {
2209b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ AllocateHeapNumber(eax, edi, no_reg, &runtime_call_clear_stack);
2210b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  } else {  // UNTAGGED.
2211b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ AllocateHeapNumber(eax, edi, no_reg, &skip_cache);
2212b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ sub(Operand(esp), Immediate(kDoubleSize));
2213b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ movdbl(Operand(esp, 0), xmm1);
2214b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ fld_d(Operand(esp, 0));
2215b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ add(Operand(esp), Immediate(kDoubleSize));
2216b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  }
221780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  GenerateOperation(masm);
221880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(Operand(ecx, 0), ebx);
221980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(Operand(ecx, kIntSize), edx);
222080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(Operand(ecx, 2 * kIntSize), eax);
222180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset));
2222b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  if (tagged) {
2223b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ ret(kPointerSize);
2224b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  } else {  // UNTAGGED.
2225b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ movdbl(xmm1, FieldOperand(eax, HeapNumber::kValueOffset));
2226b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ Ret();
2227b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
2228b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    // Skip cache and return answer directly, only in untagged case.
2229b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ bind(&skip_cache);
2230b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ sub(Operand(esp), Immediate(kDoubleSize));
2231b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ movdbl(Operand(esp, 0), xmm1);
2232b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ fld_d(Operand(esp, 0));
2233b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    GenerateOperation(masm);
2234b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ fstp_d(Operand(esp, 0));
2235b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ movdbl(xmm1, Operand(esp, 0));
2236b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ add(Operand(esp), Immediate(kDoubleSize));
2237b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    // We return the value in xmm1 without adding it to the cache, but
2238b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    // we cause a scavenging GC so that future allocations will succeed.
2239b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ EnterInternalFrame();
2240b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    // Allocate an unused object bigger than a HeapNumber.
2241b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ push(Immediate(Smi::FromInt(2 * kDoubleSize)));
2242b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ CallRuntimeSaveDoubles(Runtime::kAllocateInNewSpace);
2243b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ LeaveInternalFrame();
2244b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ Ret();
2245b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  }
224680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
2247b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Call runtime, doing whatever allocation and cleanup is necessary.
2248b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  if (tagged) {
2249b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ bind(&runtime_call_clear_stack);
2250b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ fstp(0);
2251b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ bind(&runtime_call);
225244f0eee88ff00398ff7f715fab053374d808c90dSteve Block    ExternalReference runtime =
225344f0eee88ff00398ff7f715fab053374d808c90dSteve Block        ExternalReference(RuntimeFunction(), masm->isolate());
225444f0eee88ff00398ff7f715fab053374d808c90dSteve Block    __ TailCallExternalReference(runtime, 1, 1);
2255b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  } else {  // UNTAGGED.
2256b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ bind(&runtime_call_clear_stack);
2257b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ bind(&runtime_call);
2258b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ AllocateHeapNumber(eax, edi, no_reg, &skip_cache);
2259b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm1);
2260b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ EnterInternalFrame();
2261b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ push(eax);
2262b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ CallRuntime(RuntimeFunction(), 1);
2263b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ LeaveInternalFrame();
2264b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ movdbl(xmm1, FieldOperand(eax, HeapNumber::kValueOffset));
2265b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ Ret();
2266b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  }
226780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
226880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
226980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
227080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian MonsenRuntime::FunctionId TranscendentalCacheStub::RuntimeFunction() {
227180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  switch (type_) {
227280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    case TranscendentalCache::SIN: return Runtime::kMath_sin;
227380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    case TranscendentalCache::COS: return Runtime::kMath_cos;
2274b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case TranscendentalCache::LOG: return Runtime::kMath_log;
227580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    default:
227680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      UNIMPLEMENTED();
227780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      return Runtime::kAbort;
227880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
227980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
228080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
228180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
228280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid TranscendentalCacheStub::GenerateOperation(MacroAssembler* masm) {
228380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Only free register is edi.
2284b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Input value is on FP stack, and also in ebx/edx.
2285b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Input value is possibly in xmm1.
2286b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Address of result (a newly allocated HeapNumber) may be in eax.
2287b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  if (type_ == TranscendentalCache::SIN || type_ == TranscendentalCache::COS) {
2288b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    // Both fsin and fcos require arguments in the range +/-2^63 and
2289b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    // return NaN for infinities and NaN. They can share all code except
2290b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    // the actual fsin/fcos operation.
2291257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Label in_range, done;
2292b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    // If argument is outside the range -2^63..2^63, fsin/cos doesn't
2293b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    // work. We must reduce it to the appropriate range.
2294b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ mov(edi, edx);
2295b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ and_(Operand(edi), Immediate(0x7ff00000));  // Exponent only.
2296b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    int supported_exponent_limit =
2297b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        (63 + HeapNumber::kExponentBias) << HeapNumber::kExponentShift;
2298b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ cmp(Operand(edi), Immediate(supported_exponent_limit));
2299257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ j(below, &in_range, Label::kNear);
2300b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    // Check for infinity and NaN. Both return NaN for sin.
2301b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ cmp(Operand(edi), Immediate(0x7ff00000));
2302257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Label non_nan_result;
2303257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ j(not_equal, &non_nan_result, Label::kNear);
2304b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    // Input is +/-Infinity or NaN. Result is NaN.
2305b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ fstp(0);
2306b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    // NaN is represented by 0x7ff8000000000000.
2307b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ push(Immediate(0x7ff80000));
2308b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ push(Immediate(0));
2309b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ fld_d(Operand(esp, 0));
2310b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ add(Operand(esp), Immediate(2 * kPointerSize));
2311257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ jmp(&done, Label::kNear);
231280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
2313257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ bind(&non_nan_result);
231480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
2315257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Use fpmod to restrict argument to the range +/-2*PI.
2316257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ mov(edi, eax);  // Save eax before using fnstsw_ax.
2317257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ fldpi();
2318257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ fadd(0);
2319257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ fld(1);
2320257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // FPU Stack: input, 2*pi, input.
2321257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    {
2322257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      Label no_exceptions;
2323257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ fwait();
2324257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ fnstsw_ax();
2325257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // Clear if Illegal Operand or Zero Division exceptions are set.
2326257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ test(Operand(eax), Immediate(5));
2327257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ j(zero, &no_exceptions, Label::kNear);
2328257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ fnclex();
2329257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ bind(&no_exceptions);
2330257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    }
233180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
2332257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Compute st(0) % st(1)
2333257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    {
2334257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      Label partial_remainder_loop;
2335257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ bind(&partial_remainder_loop);
2336257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ fprem1();
2337257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ fwait();
2338257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ fnstsw_ax();
2339257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ test(Operand(eax), Immediate(0x400 /* C2 */));
2340257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // If C2 is set, computation only has partial result. Loop to
2341257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // continue computation.
2342257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ j(not_zero, &partial_remainder_loop);
2343257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    }
2344257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // FPU Stack: input, 2*pi, input % 2*pi
2345257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ fstp(2);
2346257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ fstp(0);
2347257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ mov(eax, edi);  // Restore eax (allocated HeapNumber pointer).
234880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
2349257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // FPU Stack: input % 2*pi
2350257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ bind(&in_range);
2351257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    switch (type_) {
2352257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      case TranscendentalCache::SIN:
2353257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        __ fsin();
2354257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        break;
2355257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      case TranscendentalCache::COS:
2356257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        __ fcos();
2357257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        break;
2358257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      default:
2359257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        UNREACHABLE();
236080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    }
2361257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ bind(&done);
2362257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  } else {
2363257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    ASSERT(type_ == TranscendentalCache::LOG);
2364257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ fldln2();
2365257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ fxch();
2366257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ fyl2x();
236780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
236880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
236980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
237080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
237180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// Input: edx, eax are the left and right objects of a bit op.
237280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// Output: eax, ecx are left and right integers for a bit op.
237380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid FloatingPointHelper::LoadUnknownsAsIntegers(MacroAssembler* masm,
237480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                                 bool use_sse3,
237580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                                 Label* conversion_failure) {
237680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check float operands.
237780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label arg1_is_object, check_undefined_arg1;
237880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label arg2_is_object, check_undefined_arg2;
237980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label load_arg2, done;
238080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
238180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Test if arg1 is a Smi.
23823fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ JumpIfNotSmi(edx, &arg1_is_object);
238380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
238480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiUntag(edx);
238580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ jmp(&load_arg2);
238680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
238780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // If the argument is undefined it converts to zero (ECMA-262, section 9.5).
238880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&check_undefined_arg1);
238944f0eee88ff00398ff7f715fab053374d808c90dSteve Block  Factory* factory = masm->isolate()->factory();
239044f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ cmp(edx, factory->undefined_value());
239180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(not_equal, conversion_failure);
239280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(edx, Immediate(0));
239380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ jmp(&load_arg2);
239480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
239580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&arg1_is_object);
239680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(ebx, FieldOperand(edx, HeapObject::kMapOffset));
239744f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ cmp(ebx, factory->heap_number_map());
239880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(not_equal, &check_undefined_arg1);
239980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
240080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Get the untagged integer version of the edx heap number in ecx.
2401257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  IntegerConvert(masm, edx, use_sse3, conversion_failure);
240280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(edx, ecx);
240380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
240480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Here edx has the untagged integer, eax has a Smi or a heap number.
240580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&load_arg2);
240680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
240780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Test if arg2 is a Smi.
24083fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ JumpIfNotSmi(eax, &arg2_is_object);
240980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
241080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiUntag(eax);
241180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(ecx, eax);
241280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ jmp(&done);
241380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
241480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // If the argument is undefined it converts to zero (ECMA-262, section 9.5).
241580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&check_undefined_arg2);
241644f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ cmp(eax, factory->undefined_value());
241780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(not_equal, conversion_failure);
241880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(ecx, Immediate(0));
241980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ jmp(&done);
242080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
242180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&arg2_is_object);
242280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset));
242344f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ cmp(ebx, factory->heap_number_map());
242480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(not_equal, &check_undefined_arg2);
242580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
242680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Get the untagged integer version of the eax heap number in ecx.
2427257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  IntegerConvert(masm, eax, use_sse3, conversion_failure);
242880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&done);
242980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(eax, edx);
243080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
243180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
243280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
2433b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdochvoid FloatingPointHelper::CheckLoadedIntegersWereInt32(MacroAssembler* masm,
2434b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                                                       bool use_sse3,
2435b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                                                       Label* not_int32) {
2436b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  return;
2437b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch}
2438b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
2439b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
244080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid FloatingPointHelper::LoadFloatOperand(MacroAssembler* masm,
244180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                           Register number) {
2442257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label load_smi, done;
244380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
24443fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ JumpIfSmi(number, &load_smi, Label::kNear);
244580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ fld_d(FieldOperand(number, HeapNumber::kValueOffset));
2446257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ jmp(&done, Label::kNear);
244780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
244880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&load_smi);
244980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiUntag(number);
245080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ push(number);
245180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ fild_s(Operand(esp, 0));
245280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ pop(number);
245380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
245480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&done);
245580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
245680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
245780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
245880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid FloatingPointHelper::LoadSSE2Operands(MacroAssembler* masm) {
2459257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label load_smi_edx, load_eax, load_smi_eax, done;
246080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Load operand in edx into xmm0.
24613fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ JumpIfSmi(edx, &load_smi_edx, Label::kNear);
246280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movdbl(xmm0, FieldOperand(edx, HeapNumber::kValueOffset));
246380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
246480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&load_eax);
246580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Load operand in eax into xmm1.
24663fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ JumpIfSmi(eax, &load_smi_eax, Label::kNear);
246780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movdbl(xmm1, FieldOperand(eax, HeapNumber::kValueOffset));
2468257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ jmp(&done, Label::kNear);
246980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
247080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&load_smi_edx);
247180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiUntag(edx);  // Untag smi before converting to float.
247280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cvtsi2sd(xmm0, Operand(edx));
247380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiTag(edx);  // Retag smi for heap number overwriting test.
247480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ jmp(&load_eax);
247580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
247680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&load_smi_eax);
247780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiUntag(eax);  // Untag smi before converting to float.
247880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cvtsi2sd(xmm1, Operand(eax));
247980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiTag(eax);  // Retag smi for heap number overwriting test.
248080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
248180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&done);
248280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
248380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
248480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
248580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid FloatingPointHelper::LoadSSE2Operands(MacroAssembler* masm,
248680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                           Label* not_numbers) {
2487257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label load_smi_edx, load_eax, load_smi_eax, load_float_eax, done;
248880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Load operand in edx into xmm0, or branch to not_numbers.
24893fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ JumpIfSmi(edx, &load_smi_edx, Label::kNear);
249044f0eee88ff00398ff7f715fab053374d808c90dSteve Block  Factory* factory = masm->isolate()->factory();
249144f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ cmp(FieldOperand(edx, HeapObject::kMapOffset), factory->heap_number_map());
249280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(not_equal, not_numbers);  // Argument in edx is not a number.
249380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movdbl(xmm0, FieldOperand(edx, HeapNumber::kValueOffset));
249480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&load_eax);
249580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Load operand in eax into xmm1, or branch to not_numbers.
24963fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ JumpIfSmi(eax, &load_smi_eax, Label::kNear);
249744f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ cmp(FieldOperand(eax, HeapObject::kMapOffset), factory->heap_number_map());
2498257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(equal, &load_float_eax, Label::kNear);
249980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ jmp(not_numbers);  // Argument in eax is not a number.
250080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&load_smi_edx);
250180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiUntag(edx);  // Untag smi before converting to float.
250280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cvtsi2sd(xmm0, Operand(edx));
250380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiTag(edx);  // Retag smi for heap number overwriting test.
250480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ jmp(&load_eax);
250580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&load_smi_eax);
250680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiUntag(eax);  // Untag smi before converting to float.
250780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cvtsi2sd(xmm1, Operand(eax));
250880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiTag(eax);  // Retag smi for heap number overwriting test.
2509257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ jmp(&done, Label::kNear);
251080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&load_float_eax);
251180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movdbl(xmm1, FieldOperand(eax, HeapNumber::kValueOffset));
251280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&done);
251380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
251480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
251580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
251680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid FloatingPointHelper::LoadSSE2Smis(MacroAssembler* masm,
251780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                       Register scratch) {
251880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  const Register left = edx;
251980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  const Register right = eax;
252080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(scratch, left);
252180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  ASSERT(!scratch.is(right));  // We're about to clobber scratch.
252280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiUntag(scratch);
252380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cvtsi2sd(xmm0, Operand(scratch));
252480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
252580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(scratch, right);
252680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiUntag(scratch);
252780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cvtsi2sd(xmm1, Operand(scratch));
252880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
252980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
253080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
2531b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdochvoid FloatingPointHelper::CheckSSE2OperandsAreInt32(MacroAssembler* masm,
2532b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                                                    Label* non_int32,
2533b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                                                    Register scratch) {
2534b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ cvttsd2si(scratch, Operand(xmm0));
2535b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ cvtsi2sd(xmm2, Operand(scratch));
2536b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ ucomisd(xmm0, xmm2);
2537b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ j(not_zero, non_int32);
2538b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ j(carry, non_int32);
2539b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ cvttsd2si(scratch, Operand(xmm1));
2540b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ cvtsi2sd(xmm2, Operand(scratch));
2541b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ ucomisd(xmm1, xmm2);
2542b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ j(not_zero, non_int32);
2543b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ j(carry, non_int32);
2544b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch}
2545b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
2546b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
254780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid FloatingPointHelper::LoadFloatOperands(MacroAssembler* masm,
254880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                            Register scratch,
254980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                            ArgLocation arg_location) {
2550257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label load_smi_1, load_smi_2, done_load_1, done;
255180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  if (arg_location == ARGS_IN_REGISTERS) {
255280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ mov(scratch, edx);
255380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  } else {
255480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ mov(scratch, Operand(esp, 2 * kPointerSize));
255580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
25563fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ JumpIfSmi(scratch, &load_smi_1, Label::kNear);
255780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ fld_d(FieldOperand(scratch, HeapNumber::kValueOffset));
255880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&done_load_1);
255980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
256080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  if (arg_location == ARGS_IN_REGISTERS) {
256180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ mov(scratch, eax);
256280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  } else {
256380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ mov(scratch, Operand(esp, 1 * kPointerSize));
256480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
25653fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ JumpIfSmi(scratch, &load_smi_2, Label::kNear);
256680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ fld_d(FieldOperand(scratch, HeapNumber::kValueOffset));
2567257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ jmp(&done, Label::kNear);
256880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
256980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&load_smi_1);
257080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiUntag(scratch);
257180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ push(scratch);
257280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ fild_s(Operand(esp, 0));
257380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ pop(scratch);
257480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ jmp(&done_load_1);
257580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
257680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&load_smi_2);
257780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiUntag(scratch);
257880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ push(scratch);
257980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ fild_s(Operand(esp, 0));
258080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ pop(scratch);
258180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
258280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&done);
258380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
258480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
258580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
258680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid FloatingPointHelper::LoadFloatSmis(MacroAssembler* masm,
258780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                        Register scratch) {
258880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  const Register left = edx;
258980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  const Register right = eax;
259080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(scratch, left);
259180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  ASSERT(!scratch.is(right));  // We're about to clobber scratch.
259280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiUntag(scratch);
259380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ push(scratch);
259480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ fild_s(Operand(esp, 0));
259580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
259680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(scratch, right);
259780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiUntag(scratch);
259880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(Operand(esp, 0), scratch);
259980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ fild_s(Operand(esp, 0));
260080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ pop(scratch);
260180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
260280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
260380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
260480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid FloatingPointHelper::CheckFloatOperands(MacroAssembler* masm,
260580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                             Label* non_float,
260680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                             Register scratch) {
2607257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label test_other, done;
260880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Test if both operands are floats or smi -> scratch=k_is_float;
260980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Otherwise scratch = k_not_float.
26103fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ JumpIfSmi(edx, &test_other, Label::kNear);
261180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(scratch, FieldOperand(edx, HeapObject::kMapOffset));
261244f0eee88ff00398ff7f715fab053374d808c90dSteve Block  Factory* factory = masm->isolate()->factory();
261344f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ cmp(scratch, factory->heap_number_map());
261480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(not_equal, non_float);  // argument in edx is not a number -> NaN
261580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
261680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&test_other);
26173fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ JumpIfSmi(eax, &done, Label::kNear);
261880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(scratch, FieldOperand(eax, HeapObject::kMapOffset));
261944f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ cmp(scratch, factory->heap_number_map());
262080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(not_equal, non_float);  // argument in eax is not a number -> NaN
262180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
262280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Fall-through: Both operands are numbers.
262380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&done);
262480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
262580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
262680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
2627b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdochvoid FloatingPointHelper::CheckFloatOperandsAreInt32(MacroAssembler* masm,
2628b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                                                     Label* non_int32) {
2629b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  return;
2630b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch}
2631b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
2632b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
2633b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdochvoid MathPowStub::Generate(MacroAssembler* masm) {
2634b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Registers are used as follows:
2635b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // edx = base
2636b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // eax = exponent
2637b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // ecx = temporary, result
2638b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
2639b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  CpuFeatures::Scope use_sse2(SSE2);
2640b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  Label allocate_return, call_runtime;
2641b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
2642b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Load input parameters.
2643b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ mov(edx, Operand(esp, 2 * kPointerSize));
2644b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ mov(eax, Operand(esp, 1 * kPointerSize));
2645b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
2646b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Save 1 in xmm3 - we need this several times later on.
2647b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ mov(ecx, Immediate(1));
2648b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ cvtsi2sd(xmm3, Operand(ecx));
2649b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
2650b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  Label exponent_nonsmi;
2651b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  Label base_nonsmi;
2652b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // If the exponent is a heap number go to that specific case.
26533fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ JumpIfNotSmi(eax, &exponent_nonsmi);
26543fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ JumpIfNotSmi(edx, &base_nonsmi);
2655b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
2656e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  // Optimized version when both exponent and base are smis.
2657b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  Label powi;
2658b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ SmiUntag(edx);
2659b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ cvtsi2sd(xmm0, Operand(edx));
2660b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ jmp(&powi);
2661b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // exponent is smi and base is a heapnumber.
2662b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ bind(&base_nonsmi);
266344f0eee88ff00398ff7f715fab053374d808c90dSteve Block  Factory* factory = masm->isolate()->factory();
2664b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ cmp(FieldOperand(edx, HeapObject::kMapOffset),
266544f0eee88ff00398ff7f715fab053374d808c90dSteve Block         factory->heap_number_map());
2666b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ j(not_equal, &call_runtime);
2667b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
2668b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ movdbl(xmm0, FieldOperand(edx, HeapNumber::kValueOffset));
2669b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
2670b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Optimized version of pow if exponent is a smi.
2671b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // xmm0 contains the base.
2672b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ bind(&powi);
2673b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ SmiUntag(eax);
2674b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
2675b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Save exponent in base as we need to check if exponent is negative later.
2676b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // We know that base and exponent are in different registers.
2677b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ mov(edx, eax);
2678b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
2679b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Get absolute value of exponent.
2680257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label no_neg;
2681b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ cmp(eax, 0);
2682257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(greater_equal, &no_neg, Label::kNear);
2683b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ neg(eax);
2684b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ bind(&no_neg);
2685b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
2686b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Load xmm1 with 1.
2687b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ movsd(xmm1, xmm3);
2688257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label while_true;
2689257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label no_multiply;
2690b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
2691b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ bind(&while_true);
2692b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ shr(eax, 1);
2693257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(not_carry, &no_multiply, Label::kNear);
2694b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ mulsd(xmm1, xmm0);
2695b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ bind(&no_multiply);
2696b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ mulsd(xmm0, xmm0);
2697b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ j(not_zero, &while_true);
2698b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
2699b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // base has the original value of the exponent - if the exponent  is
2700b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // negative return 1/result.
2701b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ test(edx, Operand(edx));
2702b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ j(positive, &allocate_return);
2703b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Special case if xmm1 has reached infinity.
2704b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ mov(ecx, Immediate(0x7FB00000));
2705b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ movd(xmm0, Operand(ecx));
2706b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ cvtss2sd(xmm0, xmm0);
2707b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ ucomisd(xmm0, xmm1);
2708b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ j(equal, &call_runtime);
2709b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ divsd(xmm3, xmm1);
2710b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ movsd(xmm1, xmm3);
2711b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ jmp(&allocate_return);
2712b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
2713b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // exponent (or both) is a heapnumber - no matter what we should now work
2714b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // on doubles.
2715b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ bind(&exponent_nonsmi);
2716b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ cmp(FieldOperand(eax, HeapObject::kMapOffset),
271744f0eee88ff00398ff7f715fab053374d808c90dSteve Block         factory->heap_number_map());
2718b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ j(not_equal, &call_runtime);
2719b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ movdbl(xmm1, FieldOperand(eax, HeapNumber::kValueOffset));
2720b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Test if exponent is nan.
2721b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ ucomisd(xmm1, xmm1);
2722b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ j(parity_even, &call_runtime);
2723b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
2724257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label base_not_smi;
2725257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label handle_special_cases;
27263fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ JumpIfNotSmi(edx, &base_not_smi, Label::kNear);
2727b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ SmiUntag(edx);
2728b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ cvtsi2sd(xmm0, Operand(edx));
2729257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ jmp(&handle_special_cases, Label::kNear);
2730b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
2731b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ bind(&base_not_smi);
2732b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ cmp(FieldOperand(edx, HeapObject::kMapOffset),
273344f0eee88ff00398ff7f715fab053374d808c90dSteve Block         factory->heap_number_map());
2734b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ j(not_equal, &call_runtime);
2735b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ mov(ecx, FieldOperand(edx, HeapNumber::kExponentOffset));
2736b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ and_(ecx, HeapNumber::kExponentMask);
2737b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ cmp(Operand(ecx), Immediate(HeapNumber::kExponentMask));
2738b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // base is NaN or +/-Infinity
2739b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ j(greater_equal, &call_runtime);
2740b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ movdbl(xmm0, FieldOperand(edx, HeapNumber::kValueOffset));
2741b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
2742b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // base is in xmm0 and exponent is in xmm1.
2743b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ bind(&handle_special_cases);
2744257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label not_minus_half;
2745b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Test for -0.5.
2746b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Load xmm2 with -0.5.
2747b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ mov(ecx, Immediate(0xBF000000));
2748b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ movd(xmm2, Operand(ecx));
2749b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ cvtss2sd(xmm2, xmm2);
2750b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // xmm2 now has -0.5.
2751b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ ucomisd(xmm2, xmm1);
2752257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(not_equal, &not_minus_half, Label::kNear);
2753b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
2754b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Calculates reciprocal of square root.
27551e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  // sqrtsd returns -0 when input is -0.  ECMA spec requires +0.
2756257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ xorps(xmm1, xmm1);
27571e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  __ addsd(xmm1, xmm0);
2758b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ sqrtsd(xmm1, xmm1);
27591e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  __ divsd(xmm3, xmm1);
27601e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  __ movsd(xmm1, xmm3);
2761b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ jmp(&allocate_return);
2762b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
2763b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Test for 0.5.
2764b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ bind(&not_minus_half);
2765b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Load xmm2 with 0.5.
2766b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Since xmm3 is 1 and xmm2 is -0.5 this is simply xmm2 + xmm3.
2767b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ addsd(xmm2, xmm3);
2768b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // xmm2 now has 0.5.
2769b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ ucomisd(xmm2, xmm1);
2770b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ j(not_equal, &call_runtime);
2771b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Calculates square root.
27721e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  // sqrtsd returns -0 when input is -0.  ECMA spec requires +0.
2773257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ xorps(xmm1, xmm1);
27741e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  __ addsd(xmm1, xmm0);
2775b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ sqrtsd(xmm1, xmm1);
2776b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
2777b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ bind(&allocate_return);
2778b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ AllocateHeapNumber(ecx, eax, edx, &call_runtime);
2779b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ movdbl(FieldOperand(ecx, HeapNumber::kValueOffset), xmm1);
2780b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ mov(eax, ecx);
2781e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ ret(2 * kPointerSize);
2782b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
2783b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ bind(&call_runtime);
2784b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ TailCallRuntime(Runtime::kMath_pow_cfunction, 2, 1);
2785b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch}
2786b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
2787b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
278880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid ArgumentsAccessStub::GenerateReadElement(MacroAssembler* masm) {
278980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // The key is in edx and the parameter count is in eax.
279080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
279180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // The displacement is used for skipping the frame pointer on the
279280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // stack. It is the offset of the last parameter (if any) relative
279380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // to the frame pointer.
279480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  static const int kDisplacement = 1 * kPointerSize;
279580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
279680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check that the key is a smi.
279780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label slow;
27983fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ JumpIfNotSmi(edx, &slow);
279980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
280080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check if the calling frame is an arguments adaptor frame.
2801257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label adaptor;
280280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(ebx, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
280380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(ecx, Operand(ebx, StandardFrameConstants::kContextOffset));
280480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cmp(Operand(ecx), Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
2805257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(equal, &adaptor, Label::kNear);
280680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
280780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check index against formal parameters count limit passed in
280880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // through register eax. Use unsigned comparison to get negative
280980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // check for free.
281080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cmp(edx, Operand(eax));
2811257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(above_equal, &slow);
281280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
281380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Read the argument from the stack and return it.
281480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  STATIC_ASSERT(kSmiTagSize == 1);
281580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  STATIC_ASSERT(kSmiTag == 0);  // Shifting code depends on these.
281680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ lea(ebx, Operand(ebp, eax, times_2, 0));
281780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ neg(edx);
281880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(eax, Operand(ebx, edx, times_2, kDisplacement));
281980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ ret(0);
282080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
282180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Arguments adaptor case: Check index against actual arguments
282280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // limit found in the arguments adaptor frame. Use unsigned
282380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // comparison to get negative check for free.
282480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&adaptor);
282580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(ecx, Operand(ebx, ArgumentsAdaptorFrameConstants::kLengthOffset));
282680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cmp(edx, Operand(ecx));
2827257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(above_equal, &slow);
282880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
282980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Read the argument from the stack and return it.
283080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  STATIC_ASSERT(kSmiTagSize == 1);
283180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  STATIC_ASSERT(kSmiTag == 0);  // Shifting code depends on these.
283280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ lea(ebx, Operand(ebx, ecx, times_2, 0));
283380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ neg(edx);
283480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(eax, Operand(ebx, edx, times_2, kDisplacement));
283580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ ret(0);
283680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
283780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Slow-case: Handle non-smi or out-of-bounds access to arguments
283880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // by calling the runtime system.
283980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&slow);
284080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ pop(ebx);  // Return address.
284180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ push(edx);
284280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ push(ebx);
284380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ TailCallRuntime(Runtime::kGetArgumentsProperty, 1, 1);
284480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
284580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
284680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
28473fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdochvoid ArgumentsAccessStub::GenerateNewNonStrictSlow(MacroAssembler* masm) {
284880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // esp[0] : return address
284980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // esp[4] : number of parameters
285080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // esp[8] : receiver displacement
28513fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // esp[12] : function
28523fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
28533fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // Check if the calling frame is an arguments adaptor frame.
28543fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  Label runtime;
28553fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ mov(edx, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
28563fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ mov(ecx, Operand(edx, StandardFrameConstants::kContextOffset));
28573fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ cmp(Operand(ecx), Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
28583fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ j(not_equal, &runtime, Label::kNear);
28593fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
28603fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // Patch the arguments.length and the parameters pointer.
28613fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ mov(ecx, Operand(edx, ArgumentsAdaptorFrameConstants::kLengthOffset));
28623fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ mov(Operand(esp, 1 * kPointerSize), ecx);
28633fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ lea(edx, Operand(edx, ecx, times_2,
28643fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch              StandardFrameConstants::kCallerSPOffset));
28653fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ mov(Operand(esp, 2 * kPointerSize), edx);
28663fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
28673fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ bind(&runtime);
28683fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ TailCallRuntime(Runtime::kNewArgumentsFast, 3, 1);
28693fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch}
28703fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
28713fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
28723fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdochvoid ArgumentsAccessStub::GenerateNewNonStrictFast(MacroAssembler* masm) {
28733fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // esp[0] : return address
28743fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // esp[4] : number of parameters (tagged)
28753fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // esp[8] : receiver displacement
28763fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // esp[12] : function
28773fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
28783fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // ebx = parameter count (tagged)
28793fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ mov(ebx, Operand(esp, 1 * kPointerSize));
28803fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
28813fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // Check if the calling frame is an arguments adaptor frame.
28823fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // TODO(rossberg): Factor out some of the bits that are shared with the other
28833fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // Generate* functions.
28843fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  Label runtime;
28853fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  Label adaptor_frame, try_allocate;
28863fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ mov(edx, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
28873fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ mov(ecx, Operand(edx, StandardFrameConstants::kContextOffset));
28883fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ cmp(Operand(ecx), Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
28893fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ j(equal, &adaptor_frame, Label::kNear);
28903fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
28913fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // No adaptor, parameter count = argument count.
28923fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ mov(ecx, ebx);
28933fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ jmp(&try_allocate, Label::kNear);
28943fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
28953fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // We have an adaptor frame. Patch the parameters pointer.
28963fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ bind(&adaptor_frame);
28973fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ mov(ecx, Operand(edx, ArgumentsAdaptorFrameConstants::kLengthOffset));
28983fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ lea(edx, Operand(edx, ecx, times_2,
28993fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch                      StandardFrameConstants::kCallerSPOffset));
29003fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ mov(Operand(esp, 2 * kPointerSize), edx);
29013fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
29023fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // ebx = parameter count (tagged)
29033fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // ecx = argument count (tagged)
29043fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // esp[4] = parameter count (tagged)
29053fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // esp[8] = address of receiver argument
29063fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // Compute the mapped parameter count = min(ebx, ecx) in ebx.
29073fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ cmp(ebx, Operand(ecx));
29083fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ j(less_equal, &try_allocate, Label::kNear);
29093fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ mov(ebx, ecx);
29103fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
29113fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ bind(&try_allocate);
29123fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
29133fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // Save mapped parameter count.
29143fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ push(ebx);
29153fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
29163fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // Compute the sizes of backing store, parameter map, and arguments object.
29173fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // 1. Parameter map, has 2 extra words containing context and backing store.
29183fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  const int kParameterMapHeaderSize =
29193fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch      FixedArray::kHeaderSize + 2 * kPointerSize;
29203fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  Label no_parameter_map;
29213fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ test(ebx, Operand(ebx));
29223fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ j(zero, &no_parameter_map, Label::kNear);
29233fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ lea(ebx, Operand(ebx, times_2, kParameterMapHeaderSize));
29243fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ bind(&no_parameter_map);
29253fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
29263fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // 2. Backing store.
29273fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ lea(ebx, Operand(ebx, ecx, times_2, FixedArray::kHeaderSize));
29283fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
29293fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // 3. Arguments object.
29303fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ add(Operand(ebx), Immediate(Heap::kArgumentsObjectSize));
29313fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
29323fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // Do the allocation of all three objects in one go.
29333fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ AllocateInNewSpace(ebx, eax, edx, edi, &runtime, TAG_OBJECT);
29343fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
29353fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // eax = address of new object(s) (tagged)
29363fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // ecx = argument count (tagged)
29373fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // esp[0] = mapped parameter count (tagged)
29383fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // esp[8] = parameter count (tagged)
29393fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // esp[12] = address of receiver argument
29403fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // Get the arguments boilerplate from the current (global) context into edi.
29413fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  Label has_mapped_parameters, copy;
29423fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ mov(edi, Operand(esi, Context::SlotOffset(Context::GLOBAL_INDEX)));
29433fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ mov(edi, FieldOperand(edi, GlobalObject::kGlobalContextOffset));
29443fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ mov(ebx, Operand(esp, 0 * kPointerSize));
29453fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ test(ebx, Operand(ebx));
29463fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ j(not_zero, &has_mapped_parameters, Label::kNear);
29473fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ mov(edi, Operand(edi,
29483fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch         Context::SlotOffset(Context::ARGUMENTS_BOILERPLATE_INDEX)));
29493fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ jmp(&copy, Label::kNear);
29503fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
29513fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ bind(&has_mapped_parameters);
29523fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ mov(edi, Operand(edi,
29533fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch            Context::SlotOffset(Context::ALIASED_ARGUMENTS_BOILERPLATE_INDEX)));
29543fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ bind(&copy);
29553fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
29563fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // eax = address of new object (tagged)
29573fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // ebx = mapped parameter count (tagged)
29583fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // ecx = argument count (tagged)
29593fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // edi = address of boilerplate object (tagged)
29603fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // esp[0] = mapped parameter count (tagged)
29613fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // esp[8] = parameter count (tagged)
29623fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // esp[12] = address of receiver argument
29633fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // Copy the JS object part.
29643fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  for (int i = 0; i < JSObject::kHeaderSize; i += kPointerSize) {
29653fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    __ mov(edx, FieldOperand(edi, i));
29663fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    __ mov(FieldOperand(eax, i), edx);
29673fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  }
29683fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
29693fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // Setup the callee in-object property.
29703fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  STATIC_ASSERT(Heap::kArgumentsCalleeIndex == 1);
29713fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ mov(edx, Operand(esp, 4 * kPointerSize));
29723fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ mov(FieldOperand(eax, JSObject::kHeaderSize +
29733fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch                      Heap::kArgumentsCalleeIndex * kPointerSize),
29743fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch         edx);
29753fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
29763fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // Use the length (smi tagged) and set that as an in-object property too.
29773fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  STATIC_ASSERT(Heap::kArgumentsLengthIndex == 0);
29783fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ mov(FieldOperand(eax, JSObject::kHeaderSize +
29793fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch                      Heap::kArgumentsLengthIndex * kPointerSize),
29803fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch         ecx);
29813fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
29823fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // Setup the elements pointer in the allocated arguments object.
29833fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // If we allocated a parameter map, edi will point there, otherwise to the
29843fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // backing store.
29853fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ lea(edi, Operand(eax, Heap::kArgumentsObjectSize));
29863fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ mov(FieldOperand(eax, JSObject::kElementsOffset), edi);
29873fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
29883fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // eax = address of new object (tagged)
29893fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // ebx = mapped parameter count (tagged)
29903fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // ecx = argument count (tagged)
29913fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // edi = address of parameter map or backing store (tagged)
29923fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // esp[0] = mapped parameter count (tagged)
29933fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // esp[8] = parameter count (tagged)
29943fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // esp[12] = address of receiver argument
29953fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // Free a register.
29963fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ push(eax);
29973fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
29983fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // Initialize parameter map. If there are no mapped arguments, we're done.
29993fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  Label skip_parameter_map;
30003fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ test(ebx, Operand(ebx));
30013fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ j(zero, &skip_parameter_map);
300280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
30033fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ mov(FieldOperand(edi, FixedArray::kMapOffset),
30043fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch         Immediate(FACTORY->non_strict_arguments_elements_map()));
30053fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ lea(eax, Operand(ebx, reinterpret_cast<intptr_t>(Smi::FromInt(2))));
30063fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ mov(FieldOperand(edi, FixedArray::kLengthOffset), eax);
30073fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ mov(FieldOperand(edi, FixedArray::kHeaderSize + 0 * kPointerSize), esi);
30083fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ lea(eax, Operand(edi, ebx, times_2, kParameterMapHeaderSize));
30093fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ mov(FieldOperand(edi, FixedArray::kHeaderSize + 1 * kPointerSize), eax);
30103fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
30113fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // Copy the parameter slots and the holes in the arguments.
30123fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // We need to fill in mapped_parameter_count slots. They index the context,
30133fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // where parameters are stored in reverse order, at
30143fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  //   MIN_CONTEXT_SLOTS .. MIN_CONTEXT_SLOTS+parameter_count-1
30153fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // The mapped parameter thus need to get indices
30163fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  //   MIN_CONTEXT_SLOTS+parameter_count-1 ..
30173fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  //       MIN_CONTEXT_SLOTS+parameter_count-mapped_parameter_count
30183fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // We loop from right to left.
30193fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  Label parameters_loop, parameters_test;
30203fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ push(ecx);
30213fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ mov(eax, Operand(esp, 2 * kPointerSize));
30223fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ mov(ebx, Immediate(Smi::FromInt(Context::MIN_CONTEXT_SLOTS)));
30233fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ add(ebx, Operand(esp, 4 * kPointerSize));
30243fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ sub(ebx, Operand(eax));
30253fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ mov(ecx, FACTORY->the_hole_value());
30263fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ mov(edx, edi);
30273fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ lea(edi, Operand(edi, eax, times_2, kParameterMapHeaderSize));
30283fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // eax = loop variable (tagged)
30293fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // ebx = mapping index (tagged)
30303fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // ecx = the hole value
30313fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // edx = address of parameter map (tagged)
30323fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // edi = address of backing store (tagged)
30333fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // esp[0] = argument count (tagged)
30343fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // esp[4] = address of new object (tagged)
30353fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // esp[8] = mapped parameter count (tagged)
30363fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // esp[16] = parameter count (tagged)
30373fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // esp[20] = address of receiver argument
30383fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ jmp(&parameters_test, Label::kNear);
30393fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
30403fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ bind(&parameters_loop);
30413fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ sub(Operand(eax), Immediate(Smi::FromInt(1)));
30423fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ mov(FieldOperand(edx, eax, times_2, kParameterMapHeaderSize), ebx);
30433fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ mov(FieldOperand(edi, eax, times_2, FixedArray::kHeaderSize), ecx);
30443fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ add(Operand(ebx), Immediate(Smi::FromInt(1)));
30453fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ bind(&parameters_test);
30463fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ test(eax, Operand(eax));
30473fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ j(not_zero, &parameters_loop, Label::kNear);
30483fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ pop(ecx);
30493fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
30503fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ bind(&skip_parameter_map);
30513fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
30523fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // ecx = argument count (tagged)
30533fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // edi = address of backing store (tagged)
30543fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // esp[0] = address of new object (tagged)
30553fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // esp[4] = mapped parameter count (tagged)
30563fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // esp[12] = parameter count (tagged)
30573fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // esp[16] = address of receiver argument
30583fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // Copy arguments header and remaining slots (if there are any).
30593fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ mov(FieldOperand(edi, FixedArray::kMapOffset),
30603fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch         Immediate(FACTORY->fixed_array_map()));
30613fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ mov(FieldOperand(edi, FixedArray::kLengthOffset), ecx);
30623fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
30633fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  Label arguments_loop, arguments_test;
30643fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ mov(ebx, Operand(esp, 1 * kPointerSize));
30653fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ mov(edx, Operand(esp, 4 * kPointerSize));
30663fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ sub(Operand(edx), ebx);  // Is there a smarter way to do negative scaling?
30673fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ sub(Operand(edx), ebx);
30683fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ jmp(&arguments_test, Label::kNear);
30693fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
30703fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ bind(&arguments_loop);
30713fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ sub(Operand(edx), Immediate(kPointerSize));
30723fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ mov(eax, Operand(edx, 0));
30733fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ mov(FieldOperand(edi, ebx, times_2, FixedArray::kHeaderSize), eax);
30743fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ add(Operand(ebx), Immediate(Smi::FromInt(1)));
30753fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
30763fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ bind(&arguments_test);
30773fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ cmp(ebx, Operand(ecx));
30783fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ j(less, &arguments_loop, Label::kNear);
30793fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
30803fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // Restore.
30813fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ pop(eax);  // Address of arguments object.
30823fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ pop(ebx);  // Parameter count.
30833fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
30843fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // Return and remove the on-stack parameters.
30853fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ ret(3 * kPointerSize);
30863fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
30873fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // Do the runtime call to allocate the arguments object.
30883fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ bind(&runtime);
30893fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ pop(eax);  // Remove saved parameter count.
30903fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ mov(Operand(esp, 1 * kPointerSize), ecx);  // Patch argument count.
30913fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ TailCallRuntime(Runtime::kNewStrictArgumentsFast, 3, 1);
30923fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch}
30933fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
30943fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
30953fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdochvoid ArgumentsAccessStub::GenerateNewStrict(MacroAssembler* masm) {
30963fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // esp[0] : return address
30973fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // esp[4] : number of parameters
30983fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // esp[8] : receiver displacement
30993fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // esp[12] : function
310080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
310180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check if the calling frame is an arguments adaptor frame.
310280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label adaptor_frame, try_allocate, runtime;
310380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(edx, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
310480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(ecx, Operand(edx, StandardFrameConstants::kContextOffset));
310580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cmp(Operand(ecx), Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
310680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(equal, &adaptor_frame);
310780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
310880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Get the length from the frame.
310980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(ecx, Operand(esp, 1 * kPointerSize));
311080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ jmp(&try_allocate);
311180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
311280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Patch the arguments.length and the parameters pointer.
311380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&adaptor_frame);
311480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(ecx, Operand(edx, ArgumentsAdaptorFrameConstants::kLengthOffset));
311580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(Operand(esp, 1 * kPointerSize), ecx);
31163fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ lea(edx, Operand(edx, ecx, times_2,
31173fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch                      StandardFrameConstants::kCallerSPOffset));
311880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(Operand(esp, 2 * kPointerSize), edx);
311980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
312080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Try the new space allocation. Start out with computing the size of
312180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // the arguments object and the elements array.
3122257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label add_arguments_object;
312380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&try_allocate);
312480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ test(ecx, Operand(ecx));
3125257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(zero, &add_arguments_object, Label::kNear);
312680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ lea(ecx, Operand(ecx, times_2, FixedArray::kHeaderSize));
312780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&add_arguments_object);
31283fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ add(Operand(ecx), Immediate(Heap::kArgumentsObjectSizeStrict));
312980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
313080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Do the allocation of both objects in one go.
313180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ AllocateInNewSpace(ecx, eax, edx, ebx, &runtime, TAG_OBJECT);
313280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
313380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Get the arguments boilerplate from the current (global) context.
313480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(edi, Operand(esi, Context::SlotOffset(Context::GLOBAL_INDEX)));
313580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(edi, FieldOperand(edi, GlobalObject::kGlobalContextOffset));
31363fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  const int offset =
31373fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch      Context::SlotOffset(Context::STRICT_MODE_ARGUMENTS_BOILERPLATE_INDEX);
31383fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ mov(edi, Operand(edi, offset));
313980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
314080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Copy the JS object part.
314180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  for (int i = 0; i < JSObject::kHeaderSize; i += kPointerSize) {
314280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ mov(ebx, FieldOperand(edi, i));
314380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ mov(FieldOperand(eax, i), ebx);
314480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
314580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
314680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Get the length (smi tagged) and set that as an in-object property too.
314744f0eee88ff00398ff7f715fab053374d808c90dSteve Block  STATIC_ASSERT(Heap::kArgumentsLengthIndex == 0);
314880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(ecx, Operand(esp, 1 * kPointerSize));
314944f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ mov(FieldOperand(eax, JSObject::kHeaderSize +
31503fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch                      Heap::kArgumentsLengthIndex * kPointerSize),
315144f0eee88ff00398ff7f715fab053374d808c90dSteve Block         ecx);
315280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
315380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // If there are no actual arguments, we're done.
315480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label done;
315580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ test(ecx, Operand(ecx));
315680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(zero, &done);
315780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
315880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Get the parameters pointer from the stack.
315980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(edx, Operand(esp, 2 * kPointerSize));
316080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
316180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Setup the elements pointer in the allocated arguments object and
316280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // initialize the header in the elements fixed array.
31633fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ lea(edi, Operand(eax, Heap::kArgumentsObjectSizeStrict));
316480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(FieldOperand(eax, JSObject::kElementsOffset), edi);
316580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(FieldOperand(edi, FixedArray::kMapOffset),
31663fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch         Immediate(FACTORY->fixed_array_map()));
316744f0eee88ff00398ff7f715fab053374d808c90dSteve Block
316880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(FieldOperand(edi, FixedArray::kLengthOffset), ecx);
316980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Untag the length for the loop below.
317080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiUntag(ecx);
317180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
317280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Copy the fixed array slots.
3173257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label loop;
317480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&loop);
317580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(ebx, Operand(edx, -1 * kPointerSize));  // Skip receiver.
317680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(FieldOperand(edi, FixedArray::kHeaderSize), ebx);
317780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ add(Operand(edi), Immediate(kPointerSize));
317880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ sub(Operand(edx), Immediate(kPointerSize));
317980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ dec(ecx);
318080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(not_zero, &loop);
318180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
318280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Return and remove the on-stack parameters.
318380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&done);
318480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ ret(3 * kPointerSize);
318580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
318680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Do the runtime call to allocate the arguments object.
318780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&runtime);
31883fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ TailCallRuntime(Runtime::kNewStrictArgumentsFast, 3, 1);
318980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
319080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
319180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
319280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid RegExpExecStub::Generate(MacroAssembler* masm) {
319380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Just jump directly to runtime if native RegExp is not selected at compile
319480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // time or if regexp entry in generated code is turned off runtime switch or
319580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // at compilation.
319680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#ifdef V8_INTERPRETED_REGEXP
319780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ TailCallRuntime(Runtime::kRegExpExec, 4, 1);
319880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#else  // V8_INTERPRETED_REGEXP
319980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  if (!FLAG_regexp_entry_native) {
320080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ TailCallRuntime(Runtime::kRegExpExec, 4, 1);
320180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    return;
320280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
320380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
320480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Stack frame on entry.
320580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  //  esp[0]: return address
320680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  //  esp[4]: last_match_info (expected JSArray)
320780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  //  esp[8]: previous index
320880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  //  esp[12]: subject string
320980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  //  esp[16]: JSRegExp object
321080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
321180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  static const int kLastMatchInfoOffset = 1 * kPointerSize;
321280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  static const int kPreviousIndexOffset = 2 * kPointerSize;
321380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  static const int kSubjectOffset = 3 * kPointerSize;
321480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  static const int kJSRegExpOffset = 4 * kPointerSize;
321580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
321680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label runtime, invoke_regexp;
321780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
321880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Ensure that a RegExp stack is allocated.
321980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  ExternalReference address_of_regexp_stack_memory_address =
322044f0eee88ff00398ff7f715fab053374d808c90dSteve Block      ExternalReference::address_of_regexp_stack_memory_address(
322144f0eee88ff00398ff7f715fab053374d808c90dSteve Block          masm->isolate());
322280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  ExternalReference address_of_regexp_stack_memory_size =
322344f0eee88ff00398ff7f715fab053374d808c90dSteve Block      ExternalReference::address_of_regexp_stack_memory_size(masm->isolate());
322480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(ebx, Operand::StaticVariable(address_of_regexp_stack_memory_size));
322580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ test(ebx, Operand(ebx));
3226257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(zero, &runtime);
322780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
322880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check that the first argument is a JSRegExp object.
322980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(eax, Operand(esp, kJSRegExpOffset));
323080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  STATIC_ASSERT(kSmiTag == 0);
32313fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ JumpIfSmi(eax, &runtime);
323280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ CmpObjectType(eax, JS_REGEXP_TYPE, ecx);
323380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(not_equal, &runtime);
323480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check that the RegExp has been compiled (data contains a fixed array).
323580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(ecx, FieldOperand(eax, JSRegExp::kDataOffset));
323680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  if (FLAG_debug_code) {
323780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ test(ecx, Immediate(kSmiTagMask));
323880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ Check(not_zero, "Unexpected type for RegExp data, FixedArray expected");
323980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ CmpObjectType(ecx, FIXED_ARRAY_TYPE, ebx);
324080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ Check(equal, "Unexpected type for RegExp data, FixedArray expected");
324180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
324280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
324380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // ecx: RegExp data (FixedArray)
324480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check the type of the RegExp. Only continue if type is JSRegExp::IRREGEXP.
324580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(ebx, FieldOperand(ecx, JSRegExp::kDataTagOffset));
324680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cmp(Operand(ebx), Immediate(Smi::FromInt(JSRegExp::IRREGEXP)));
324780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(not_equal, &runtime);
324880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
324980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // ecx: RegExp data (FixedArray)
325080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check that the number of captures fit in the static offsets vector buffer.
325180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(edx, FieldOperand(ecx, JSRegExp::kIrregexpCaptureCountOffset));
325280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Calculate number of capture registers (number_of_captures + 1) * 2. This
325380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // uses the asumption that smis are 2 * their untagged value.
325480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  STATIC_ASSERT(kSmiTag == 0);
325580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  STATIC_ASSERT(kSmiTagSize + kSmiShiftSize == 1);
325680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ add(Operand(edx), Immediate(2));  // edx was a smi.
325780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check that the static offsets vector buffer is large enough.
325880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cmp(edx, OffsetsVector::kStaticOffsetsVectorSize);
325980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(above, &runtime);
326080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
326180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // ecx: RegExp data (FixedArray)
326280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // edx: Number of capture registers
326380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check that the second argument is a string.
326480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(eax, Operand(esp, kSubjectOffset));
32653fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ JumpIfSmi(eax, &runtime);
326680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Condition is_string = masm->IsObjectStringType(eax, ebx, ebx);
326780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(NegateCondition(is_string), &runtime);
326880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Get the length of the string to ebx.
326980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(ebx, FieldOperand(eax, String::kLengthOffset));
327080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
327180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // ebx: Length of subject string as a smi
327280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // ecx: RegExp data (FixedArray)
327380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // edx: Number of capture registers
327480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check that the third argument is a positive smi less than the subject
327580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // string length. A negative value will be greater (unsigned comparison).
327680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(eax, Operand(esp, kPreviousIndexOffset));
32773fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ JumpIfNotSmi(eax, &runtime);
327880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cmp(eax, Operand(ebx));
327980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(above_equal, &runtime);
328080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
328180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // ecx: RegExp data (FixedArray)
328280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // edx: Number of capture registers
328380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check that the fourth object is a JSArray object.
328480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(eax, Operand(esp, kLastMatchInfoOffset));
32853fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ JumpIfSmi(eax, &runtime);
328680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ CmpObjectType(eax, JS_ARRAY_TYPE, ebx);
328780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(not_equal, &runtime);
328880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check that the JSArray is in fast case.
328980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(ebx, FieldOperand(eax, JSArray::kElementsOffset));
329080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(eax, FieldOperand(ebx, HeapObject::kMapOffset));
329144f0eee88ff00398ff7f715fab053374d808c90dSteve Block  Factory* factory = masm->isolate()->factory();
329244f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ cmp(eax, factory->fixed_array_map());
329380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(not_equal, &runtime);
329480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check that the last match info has space for the capture registers and the
329580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // additional information.
329680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(eax, FieldOperand(ebx, FixedArray::kLengthOffset));
329780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiUntag(eax);
329880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ add(Operand(edx), Immediate(RegExpImpl::kLastMatchOverhead));
329980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cmp(edx, Operand(eax));
330080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(greater, &runtime);
330180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
330280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // ecx: RegExp data (FixedArray)
330380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check the representation and encoding of the subject string.
330480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label seq_ascii_string, seq_two_byte_string, check_code;
330580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(eax, Operand(esp, kSubjectOffset));
330680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset));
330780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movzx_b(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset));
330880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // First check for flat two byte string.
330980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ and_(ebx,
331080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen          kIsNotStringMask | kStringRepresentationMask | kStringEncodingMask);
331180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  STATIC_ASSERT((kStringTag | kSeqStringTag | kTwoByteStringTag) == 0);
331280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(zero, &seq_two_byte_string);
331380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Any other flat string must be a flat ascii string.
331480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ test(Operand(ebx),
331580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen          Immediate(kIsNotStringMask | kStringRepresentationMask));
331680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(zero, &seq_ascii_string);
331780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
331880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check for flat cons string.
331980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // A flat cons string is a cons string where the second part is the empty
332080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // string. In that case the subject string is just the first part of the cons
332180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // string. Also in this case the first part of the cons string is known to be
332280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // a sequential string or an external string.
332380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  STATIC_ASSERT(kExternalStringTag != 0);
332480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  STATIC_ASSERT((kConsStringTag & kExternalStringTag) == 0);
332580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ test(Operand(ebx),
332680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen          Immediate(kIsNotStringMask | kExternalStringTag));
332780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(not_zero, &runtime);
332880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // String is a cons string.
332980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(edx, FieldOperand(eax, ConsString::kSecondOffset));
333044f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ cmp(Operand(edx), factory->empty_string());
333180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(not_equal, &runtime);
333280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(eax, FieldOperand(eax, ConsString::kFirstOffset));
333380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset));
333480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // String is a cons string with empty second part.
333580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // eax: first part of cons string.
333680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // ebx: map of first part of cons string.
333780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Is first part a flat two byte string?
333880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ test_b(FieldOperand(ebx, Map::kInstanceTypeOffset),
333980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen            kStringRepresentationMask | kStringEncodingMask);
334080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  STATIC_ASSERT((kSeqStringTag | kTwoByteStringTag) == 0);
334180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(zero, &seq_two_byte_string);
334280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Any other flat string must be ascii.
334380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ test_b(FieldOperand(ebx, Map::kInstanceTypeOffset),
334480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen            kStringRepresentationMask);
334580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(not_zero, &runtime);
334680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
334780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&seq_ascii_string);
334880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // eax: subject string (flat ascii)
334980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // ecx: RegExp data (FixedArray)
335080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(edx, FieldOperand(ecx, JSRegExp::kDataAsciiCodeOffset));
335180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ Set(edi, Immediate(1));  // Type is ascii.
335280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ jmp(&check_code);
335380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
335480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&seq_two_byte_string);
335580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // eax: subject string (flat two byte)
335680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // ecx: RegExp data (FixedArray)
335780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(edx, FieldOperand(ecx, JSRegExp::kDataUC16CodeOffset));
335880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ Set(edi, Immediate(0));  // Type is two byte.
335980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
336080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&check_code);
336180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check that the irregexp code has been generated for the actual string
336280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // encoding. If it has, the field contains a code object otherwise it contains
3363257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // a smi (code flushing support).
3364257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ JumpIfSmi(edx, &runtime);
336580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
336680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // eax: subject string
336780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // edx: code
336880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // edi: encoding of subject string (1 if ascii, 0 if two_byte);
336980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Load used arguments before starting to push arguments for call to native
337080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // RegExp code to avoid handling changing stack height.
337180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(ebx, Operand(esp, kPreviousIndexOffset));
337280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiUntag(ebx);  // Previous index from smi.
337380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
337480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // eax: subject string
337580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // ebx: previous index
337680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // edx: code
337780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // edi: encoding of subject string (1 if ascii 0 if two_byte);
337880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // All checks done. Now push arguments for native regexp code.
337944f0eee88ff00398ff7f715fab053374d808c90dSteve Block  Counters* counters = masm->isolate()->counters();
338044f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ IncrementCounter(counters->regexp_entry_native(), 1);
338180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
338244f0eee88ff00398ff7f715fab053374d808c90dSteve Block  // Isolates: note we add an additional parameter here (isolate pointer).
338344f0eee88ff00398ff7f715fab053374d808c90dSteve Block  static const int kRegExpExecuteArguments = 8;
3384e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ EnterApiExitFrame(kRegExpExecuteArguments);
338580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
338644f0eee88ff00398ff7f715fab053374d808c90dSteve Block  // Argument 8: Pass current isolate address.
338744f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ mov(Operand(esp, 7 * kPointerSize),
338844f0eee88ff00398ff7f715fab053374d808c90dSteve Block      Immediate(ExternalReference::isolate_address()));
338944f0eee88ff00398ff7f715fab053374d808c90dSteve Block
339080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Argument 7: Indicate that this is a direct call from JavaScript.
339180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(Operand(esp, 6 * kPointerSize), Immediate(1));
339280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
339380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Argument 6: Start (high end) of backtracking stack memory area.
339480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(ecx, Operand::StaticVariable(address_of_regexp_stack_memory_address));
339580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ add(ecx, Operand::StaticVariable(address_of_regexp_stack_memory_size));
339680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(Operand(esp, 5 * kPointerSize), ecx);
339780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
339880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Argument 5: static offsets vector buffer.
339980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(Operand(esp, 4 * kPointerSize),
340044f0eee88ff00398ff7f715fab053374d808c90dSteve Block         Immediate(ExternalReference::address_of_static_offsets_vector(
340144f0eee88ff00398ff7f715fab053374d808c90dSteve Block             masm->isolate())));
340280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
340380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Argument 4: End of string data
340480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Argument 3: Start of string data
3405257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label setup_two_byte, setup_rest;
340680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ test(edi, Operand(edi));
340780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(edi, FieldOperand(eax, String::kLengthOffset));
3408257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(zero, &setup_two_byte, Label::kNear);
340980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiUntag(edi);
341080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ lea(ecx, FieldOperand(eax, edi, times_1, SeqAsciiString::kHeaderSize));
341180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(Operand(esp, 3 * kPointerSize), ecx);  // Argument 4.
341280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ lea(ecx, FieldOperand(eax, ebx, times_1, SeqAsciiString::kHeaderSize));
341380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(Operand(esp, 2 * kPointerSize), ecx);  // Argument 3.
3414257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ jmp(&setup_rest, Label::kNear);
341580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
341680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&setup_two_byte);
341780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  STATIC_ASSERT(kSmiTag == 0);
341880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  STATIC_ASSERT(kSmiTagSize == 1);  // edi is smi (powered by 2).
341980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ lea(ecx, FieldOperand(eax, edi, times_1, SeqTwoByteString::kHeaderSize));
342080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(Operand(esp, 3 * kPointerSize), ecx);  // Argument 4.
342180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ lea(ecx, FieldOperand(eax, ebx, times_2, SeqTwoByteString::kHeaderSize));
342280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(Operand(esp, 2 * kPointerSize), ecx);  // Argument 3.
342380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
342480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&setup_rest);
342580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
342680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Argument 2: Previous index.
342780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(Operand(esp, 1 * kPointerSize), ebx);
342880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
342980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Argument 1: Subject string.
343080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(Operand(esp, 0 * kPointerSize), eax);
343180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
343280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Locate the code entry and call it.
343380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ add(Operand(edx), Immediate(Code::kHeaderSize - kHeapObjectTag));
3434e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ call(Operand(edx));
3435e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
3436e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  // Drop arguments and come back to JS mode.
3437e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ LeaveApiExitFrame();
343880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
343980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check the result.
344080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label success;
344180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cmp(eax, NativeRegExpMacroAssembler::SUCCESS);
3442257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(equal, &success);
344380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label failure;
344480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cmp(eax, NativeRegExpMacroAssembler::FAILURE);
3445257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(equal, &failure);
344680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cmp(eax, NativeRegExpMacroAssembler::EXCEPTION);
344780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // If not exception it can only be retry. Handle that in the runtime system.
344880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(not_equal, &runtime);
344980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Result must now be exception. If there is no pending exception already a
345080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // stack overflow (on the backtrack stack) was detected in RegExp code but
345180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // haven't created the exception yet. Handle that in the runtime system.
345280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // TODO(592): Rerunning the RegExp to get the stack overflow exception.
345344f0eee88ff00398ff7f715fab053374d808c90dSteve Block  ExternalReference pending_exception(Isolate::k_pending_exception_address,
345444f0eee88ff00398ff7f715fab053374d808c90dSteve Block                                      masm->isolate());
3455e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ mov(edx,
345644f0eee88ff00398ff7f715fab053374d808c90dSteve Block         Operand::StaticVariable(ExternalReference::the_hole_value_location(
345744f0eee88ff00398ff7f715fab053374d808c90dSteve Block             masm->isolate())));
3458e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ mov(eax, Operand::StaticVariable(pending_exception));
3459e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ cmp(edx, Operand(eax));
346080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(equal, &runtime);
3461e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  // For exception, throw the exception again.
3462e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
3463e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  // Clear the pending exception variable.
3464e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ mov(Operand::StaticVariable(pending_exception), edx);
3465e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
3466e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  // Special handling of termination exceptions which are uncatchable
3467e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  // by javascript code.
346844f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ cmp(eax, factory->termination_exception());
3469e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  Label throw_termination_exception;
3470e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ j(equal, &throw_termination_exception);
3471e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
3472e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  // Handle normal exception by following handler chain.
3473e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ Throw(eax);
3474e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
3475e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ bind(&throw_termination_exception);
3476e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ ThrowUncatchable(TERMINATION, eax);
3477e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
347880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&failure);
3479e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  // For failure to match, return null.
348044f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ mov(Operand(eax), factory->null_value());
348180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ ret(4 * kPointerSize);
348280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
348380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Load RegExp data.
348480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&success);
348580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(eax, Operand(esp, kJSRegExpOffset));
348680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(ecx, FieldOperand(eax, JSRegExp::kDataOffset));
348780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(edx, FieldOperand(ecx, JSRegExp::kIrregexpCaptureCountOffset));
348880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Calculate number of capture registers (number_of_captures + 1) * 2.
348980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  STATIC_ASSERT(kSmiTag == 0);
349080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  STATIC_ASSERT(kSmiTagSize + kSmiShiftSize == 1);
349180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ add(Operand(edx), Immediate(2));  // edx was a smi.
349280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
349380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // edx: Number of capture registers
349480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Load last_match_info which is still known to be a fast case JSArray.
349580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(eax, Operand(esp, kLastMatchInfoOffset));
349680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(ebx, FieldOperand(eax, JSArray::kElementsOffset));
349780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
349880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // ebx: last_match_info backing store (FixedArray)
349980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // edx: number of capture registers
350080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Store the capture count.
350180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiTag(edx);  // Number of capture registers to smi.
350280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(FieldOperand(ebx, RegExpImpl::kLastCaptureCountOffset), edx);
350380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiUntag(edx);  // Number of capture registers back from smi.
350480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Store last subject and last input.
350580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(eax, Operand(esp, kSubjectOffset));
350680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(FieldOperand(ebx, RegExpImpl::kLastSubjectOffset), eax);
350780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(ecx, ebx);
350880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ RecordWrite(ecx, RegExpImpl::kLastSubjectOffset, eax, edi);
350980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(eax, Operand(esp, kSubjectOffset));
351080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(FieldOperand(ebx, RegExpImpl::kLastInputOffset), eax);
351180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(ecx, ebx);
351280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ RecordWrite(ecx, RegExpImpl::kLastInputOffset, eax, edi);
351380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
351480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Get the static offsets vector filled by the native regexp code.
351580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  ExternalReference address_of_static_offsets_vector =
351644f0eee88ff00398ff7f715fab053374d808c90dSteve Block      ExternalReference::address_of_static_offsets_vector(masm->isolate());
351780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(ecx, Immediate(address_of_static_offsets_vector));
351880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
351980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // ebx: last_match_info backing store (FixedArray)
352080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // ecx: offsets vector
352180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // edx: number of capture registers
3522257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label next_capture, done;
352380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Capture register counter starts from number of capture registers and
352480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // counts down until wraping after zero.
352580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&next_capture);
352680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ sub(Operand(edx), Immediate(1));
3527257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(negative, &done, Label::kNear);
352880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Read the value from the static offsets vector buffer.
352980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(edi, Operand(ecx, edx, times_int_size, 0));
353080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiTag(edi);
353180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Store the smi value in the last match info.
353280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(FieldOperand(ebx,
353380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                      edx,
353480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                      times_pointer_size,
353580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                      RegExpImpl::kFirstCaptureOffset),
353680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                      edi);
353780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ jmp(&next_capture);
353880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&done);
353980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
354080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Return last match info.
354180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(eax, Operand(esp, kLastMatchInfoOffset));
354280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ ret(4 * kPointerSize);
354380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
354480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Do the runtime call to execute the regexp.
354580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&runtime);
354680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ TailCallRuntime(Runtime::kRegExpExec, 4, 1);
354780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#endif  // V8_INTERPRETED_REGEXP
354880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
354980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
355080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
3551b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdochvoid RegExpConstructResultStub::Generate(MacroAssembler* masm) {
3552b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  const int kMaxInlineLength = 100;
3553b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  Label slowcase;
3554257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label done;
3555b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ mov(ebx, Operand(esp, kPointerSize * 3));
35563fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ JumpIfNotSmi(ebx, &slowcase);
3557b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ cmp(Operand(ebx), Immediate(Smi::FromInt(kMaxInlineLength)));
3558b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ j(above, &slowcase);
3559b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Smi-tagging is equivalent to multiplying by 2.
3560b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  STATIC_ASSERT(kSmiTag == 0);
3561b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  STATIC_ASSERT(kSmiTagSize == 1);
3562b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Allocate RegExpResult followed by FixedArray with size in ebx.
3563b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // JSArray:   [Map][empty properties][Elements][Length-smi][index][input]
3564b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Elements:  [Map][Length][..elements..]
3565b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ AllocateInNewSpace(JSRegExpResult::kSize + FixedArray::kHeaderSize,
3566b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                        times_half_pointer_size,
3567b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                        ebx,  // In: Number of elements (times 2, being a smi)
3568b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                        eax,  // Out: Start of allocation (tagged).
3569b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                        ecx,  // Out: End of allocation.
3570b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                        edx,  // Scratch register
3571b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                        &slowcase,
3572b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                        TAG_OBJECT);
3573b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // eax: Start of allocated area, object-tagged.
3574b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
3575b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Set JSArray map to global.regexp_result_map().
3576b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Set empty properties FixedArray.
3577b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Set elements to point to FixedArray allocated right after the JSArray.
3578b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Interleave operations for better latency.
3579b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ mov(edx, ContextOperand(esi, Context::GLOBAL_INDEX));
358044f0eee88ff00398ff7f715fab053374d808c90dSteve Block  Factory* factory = masm->isolate()->factory();
358144f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ mov(ecx, Immediate(factory->empty_fixed_array()));
3582b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ lea(ebx, Operand(eax, JSRegExpResult::kSize));
3583b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalContextOffset));
3584b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ mov(FieldOperand(eax, JSObject::kElementsOffset), ebx);
3585b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ mov(FieldOperand(eax, JSObject::kPropertiesOffset), ecx);
3586b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ mov(edx, ContextOperand(edx, Context::REGEXP_RESULT_MAP_INDEX));
3587b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ mov(FieldOperand(eax, HeapObject::kMapOffset), edx);
3588b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
3589b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Set input, index and length fields from arguments.
3590b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ mov(ecx, Operand(esp, kPointerSize * 1));
3591b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ mov(FieldOperand(eax, JSRegExpResult::kInputOffset), ecx);
3592b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ mov(ecx, Operand(esp, kPointerSize * 2));
3593b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ mov(FieldOperand(eax, JSRegExpResult::kIndexOffset), ecx);
3594b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ mov(ecx, Operand(esp, kPointerSize * 3));
3595b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ mov(FieldOperand(eax, JSArray::kLengthOffset), ecx);
3596b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
3597b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Fill out the elements FixedArray.
3598b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // eax: JSArray.
3599b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // ebx: FixedArray.
3600b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // ecx: Number of elements in array, as smi.
3601b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
3602b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Set map.
3603b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ mov(FieldOperand(ebx, HeapObject::kMapOffset),
360444f0eee88ff00398ff7f715fab053374d808c90dSteve Block         Immediate(factory->fixed_array_map()));
3605b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Set length.
3606b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ mov(FieldOperand(ebx, FixedArray::kLengthOffset), ecx);
3607b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Fill contents of fixed-array with the-hole.
3608b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ SmiUntag(ecx);
360944f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ mov(edx, Immediate(factory->the_hole_value()));
3610b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ lea(ebx, FieldOperand(ebx, FixedArray::kHeaderSize));
3611b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Fill fixed array elements with hole.
3612b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // eax: JSArray.
3613b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // ecx: Number of elements to fill.
3614b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // ebx: Start of elements in FixedArray.
3615b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // edx: the hole.
3616b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  Label loop;
3617b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ test(ecx, Operand(ecx));
3618b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ bind(&loop);
3619257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(less_equal, &done, Label::kNear);  // Jump if ecx is negative or zero.
3620b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ sub(Operand(ecx), Immediate(1));
3621b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ mov(Operand(ebx, ecx, times_pointer_size, 0), edx);
3622b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ jmp(&loop);
3623b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
3624b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ bind(&done);
3625b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ ret(3 * kPointerSize);
3626b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
3627b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ bind(&slowcase);
3628b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ TailCallRuntime(Runtime::kRegExpConstructResult, 3, 1);
3629b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch}
3630b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
3631b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
363280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid NumberToStringStub::GenerateLookupNumberStringCache(MacroAssembler* masm,
363380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                                         Register object,
363480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                                         Register result,
363580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                                         Register scratch1,
363680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                                         Register scratch2,
363780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                                         bool object_is_smi,
363880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                                         Label* not_found) {
363980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Use of registers. Register result is used as a temporary.
364080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Register number_string_cache = result;
364180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Register mask = scratch1;
364280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Register scratch = scratch2;
364380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
364480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Load the number string cache.
364544f0eee88ff00398ff7f715fab053374d808c90dSteve Block  ExternalReference roots_address =
364644f0eee88ff00398ff7f715fab053374d808c90dSteve Block      ExternalReference::roots_address(masm->isolate());
364780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(scratch, Immediate(Heap::kNumberStringCacheRootIndex));
364880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(number_string_cache,
364980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen         Operand::StaticArray(scratch, times_pointer_size, roots_address));
365080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Make the hash mask from the length of the number string cache. It
365180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // contains two elements (number and string) for each cache entry.
365280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(mask, FieldOperand(number_string_cache, FixedArray::kLengthOffset));
365380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ shr(mask, kSmiTagSize + 1);  // Untag length and divide it by two.
365480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ sub(Operand(mask), Immediate(1));  // Make mask.
365580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
365680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Calculate the entry in the number string cache. The hash value in the
365780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // number string cache for smis is just the smi value, and the hash for
365880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // doubles is the xor of the upper and lower words. See
365980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Heap::GetNumberStringCache.
3660257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label smi_hash_calculated;
3661257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label load_result_from_cache;
366280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  if (object_is_smi) {
366380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ mov(scratch, object);
366480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ SmiUntag(scratch);
366580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  } else {
3666257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Label not_smi;
366780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    STATIC_ASSERT(kSmiTag == 0);
36683fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    __ JumpIfNotSmi(object, &not_smi, Label::kNear);
366980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ mov(scratch, object);
367080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ SmiUntag(scratch);
3671257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ jmp(&smi_hash_calculated, Label::kNear);
367280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ bind(&not_smi);
367380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ cmp(FieldOperand(object, HeapObject::kMapOffset),
367444f0eee88ff00398ff7f715fab053374d808c90dSteve Block           masm->isolate()->factory()->heap_number_map());
367580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ j(not_equal, not_found);
367680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    STATIC_ASSERT(8 == kDoubleSize);
367780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ mov(scratch, FieldOperand(object, HeapNumber::kValueOffset));
367880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ xor_(scratch, FieldOperand(object, HeapNumber::kValueOffset + 4));
367980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // Object is heap number and hash is now in scratch. Calculate cache index.
368080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ and_(scratch, Operand(mask));
368180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    Register index = scratch;
368280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    Register probe = mask;
368380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ mov(probe,
368480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen           FieldOperand(number_string_cache,
368580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                        index,
368680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                        times_twice_pointer_size,
368780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                        FixedArray::kHeaderSize));
36883fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    __ JumpIfSmi(probe, not_found);
36898b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch    if (CpuFeatures::IsSupported(SSE2)) {
369080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      CpuFeatures::Scope fscope(SSE2);
369180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ movdbl(xmm0, FieldOperand(object, HeapNumber::kValueOffset));
369280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ movdbl(xmm1, FieldOperand(probe, HeapNumber::kValueOffset));
369380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ ucomisd(xmm0, xmm1);
369480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    } else {
369580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ fld_d(FieldOperand(object, HeapNumber::kValueOffset));
369680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ fld_d(FieldOperand(probe, HeapNumber::kValueOffset));
369780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ FCmp();
369880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    }
369980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ j(parity_even, not_found);  // Bail out if NaN is involved.
370080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ j(not_equal, not_found);  // The cache did not contain this value.
3701257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ jmp(&load_result_from_cache, Label::kNear);
370280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
370380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
370480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&smi_hash_calculated);
370580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Object is smi and hash is now in scratch. Calculate cache index.
370680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ and_(scratch, Operand(mask));
370780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Register index = scratch;
370880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check if the entry is the smi we are looking for.
370980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cmp(object,
371080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen         FieldOperand(number_string_cache,
371180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                      index,
371280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                      times_twice_pointer_size,
371380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                      FixedArray::kHeaderSize));
371480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(not_equal, not_found);
371580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
371680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Get the result from the cache.
371780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&load_result_from_cache);
371880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(result,
371980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen         FieldOperand(number_string_cache,
372080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                      index,
372180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                      times_twice_pointer_size,
372280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                      FixedArray::kHeaderSize + kPointerSize));
372344f0eee88ff00398ff7f715fab053374d808c90dSteve Block  Counters* counters = masm->isolate()->counters();
372444f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ IncrementCounter(counters->number_to_string_native(), 1);
372580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
372680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
372780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
372880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid NumberToStringStub::Generate(MacroAssembler* masm) {
372980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label runtime;
373080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
373180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(ebx, Operand(esp, kPointerSize));
373280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
373380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Generate code to lookup number in the number string cache.
373480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  GenerateLookupNumberStringCache(masm, ebx, eax, ecx, edx, false, &runtime);
373580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ ret(1 * kPointerSize);
373680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
373780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&runtime);
373880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Handle number to string in the runtime system if not found in the cache.
373980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ TailCallRuntime(Runtime::kNumberToStringSkipCache, 1, 1);
374080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
374180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
374280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
374380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenstatic int NegativeComparisonResult(Condition cc) {
374480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  ASSERT(cc != equal);
374580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  ASSERT((cc == less) || (cc == less_equal)
374680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      || (cc == greater) || (cc == greater_equal));
374780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  return (cc == greater || cc == greater_equal) ? LESS : GREATER;
374880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
374980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
375080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid CompareStub::Generate(MacroAssembler* masm) {
375180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  ASSERT(lhs_.is(no_reg) && rhs_.is(no_reg));
375280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
375380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label check_unequal_objects, done;
375480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
37550d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  // Compare two smis if required.
37560d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  if (include_smi_compare_) {
37570d5e116f6aee03185f237311a943491bb079a768Kristian Monsen    Label non_smi, smi_done;
37580d5e116f6aee03185f237311a943491bb079a768Kristian Monsen    __ mov(ecx, Operand(edx));
37590d5e116f6aee03185f237311a943491bb079a768Kristian Monsen    __ or_(ecx, Operand(eax));
37603fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    __ JumpIfNotSmi(ecx, &non_smi);
37610d5e116f6aee03185f237311a943491bb079a768Kristian Monsen    __ sub(edx, Operand(eax));  // Return on the result of the subtraction.
37620d5e116f6aee03185f237311a943491bb079a768Kristian Monsen    __ j(no_overflow, &smi_done);
3763f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    __ not_(edx);  // Correct sign in case of overflow. edx is never 0 here.
37640d5e116f6aee03185f237311a943491bb079a768Kristian Monsen    __ bind(&smi_done);
37650d5e116f6aee03185f237311a943491bb079a768Kristian Monsen    __ mov(eax, edx);
37660d5e116f6aee03185f237311a943491bb079a768Kristian Monsen    __ ret(0);
37670d5e116f6aee03185f237311a943491bb079a768Kristian Monsen    __ bind(&non_smi);
37680d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  } else if (FLAG_debug_code) {
37690d5e116f6aee03185f237311a943491bb079a768Kristian Monsen    __ mov(ecx, Operand(edx));
37700d5e116f6aee03185f237311a943491bb079a768Kristian Monsen    __ or_(ecx, Operand(eax));
37710d5e116f6aee03185f237311a943491bb079a768Kristian Monsen    __ test(ecx, Immediate(kSmiTagMask));
37720d5e116f6aee03185f237311a943491bb079a768Kristian Monsen    __ Assert(not_zero, "Unexpected smi operands.");
37730d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  }
37740d5e116f6aee03185f237311a943491bb079a768Kristian Monsen
377580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // NOTICE! This code is only reached after a smi-fast-case check, so
377680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // it is certain that at least one operand isn't a smi.
377780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
377880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Identical objects can be compared fast, but there are some tricky cases
377980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // for NaN and undefined.
378080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  {
378180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    Label not_identical;
378280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ cmp(eax, Operand(edx));
378380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ j(not_equal, &not_identical);
378480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
378580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    if (cc_ != equal) {
378680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      // Check for undefined.  undefined OP undefined is false even though
378780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      // undefined == undefined.
3788257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      Label check_for_nan;
378944f0eee88ff00398ff7f715fab053374d808c90dSteve Block      __ cmp(edx, masm->isolate()->factory()->undefined_value());
3790257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ j(not_equal, &check_for_nan, Label::kNear);
379180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ Set(eax, Immediate(Smi::FromInt(NegativeComparisonResult(cc_))));
379280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ ret(0);
379380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ bind(&check_for_nan);
379480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    }
379580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
379644f0eee88ff00398ff7f715fab053374d808c90dSteve Block    // Test for NaN. Sadly, we can't just compare to factory->nan_value(),
379780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // so we do the second best thing - test it ourselves.
379880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // Note: if cc_ != equal, never_nan_nan_ is not used.
379980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    if (never_nan_nan_ && (cc_ == equal)) {
380080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ Set(eax, Immediate(Smi::FromInt(EQUAL)));
380180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ ret(0);
380280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    } else {
3803257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      Label heap_number;
380480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ cmp(FieldOperand(edx, HeapObject::kMapOffset),
380544f0eee88ff00398ff7f715fab053374d808c90dSteve Block             Immediate(masm->isolate()->factory()->heap_number_map()));
3806257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ j(equal, &heap_number, Label::kNear);
380780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      if (cc_ != equal) {
380880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen        // Call runtime on identical JSObjects.  Otherwise return equal.
38093fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch        __ CmpObjectType(eax, FIRST_SPEC_OBJECT_TYPE, ecx);
381080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen        __ j(above_equal, &not_identical);
381180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      }
381280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ Set(eax, Immediate(Smi::FromInt(EQUAL)));
381380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ ret(0);
381480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
381580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ bind(&heap_number);
381680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      // It is a heap number, so return non-equal if it's NaN and equal if
381780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      // it's not NaN.
381880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      // The representation of NaN values has all exponent bits (52..62) set,
381980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      // and not all mantissa bits (0..51) clear.
382080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      // We only accept QNaNs, which have bit 51 set.
382180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      // Read top bits of double representation (second word of value).
382280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
382380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      // Value is a QNaN if value & kQuietNaNMask == kQuietNaNMask, i.e.,
382480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      // all bits in the mask are set. We only need to check the word
382580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      // that contains the exponent and high bit of the mantissa.
382680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      STATIC_ASSERT(((kQuietNaNHighBitsMask << 1) & 0x80000000u) != 0);
382780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ mov(edx, FieldOperand(edx, HeapNumber::kExponentOffset));
38289fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block      __ Set(eax, Immediate(0));
382980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      // Shift value and mask so kQuietNaNHighBitsMask applies to topmost
383080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      // bits.
383180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ add(edx, Operand(edx));
383280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ cmp(edx, kQuietNaNHighBitsMask << 1);
383380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      if (cc_ == equal) {
383480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen        STATIC_ASSERT(EQUAL != 1);
383580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen        __ setcc(above_equal, eax);
383680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen        __ ret(0);
383780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      } else {
3838257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        Label nan;
3839257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        __ j(above_equal, &nan, Label::kNear);
384080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen        __ Set(eax, Immediate(Smi::FromInt(EQUAL)));
384180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen        __ ret(0);
384280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen        __ bind(&nan);
384380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen        __ Set(eax, Immediate(Smi::FromInt(NegativeComparisonResult(cc_))));
384480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen        __ ret(0);
384580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      }
384680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    }
384780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
384880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ bind(&not_identical);
384980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
385080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
385180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Strict equality can quickly decide whether objects are equal.
385280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Non-strict object equality is slower, so it is handled later in the stub.
385380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  if (cc_ == equal && strict_) {
385480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    Label slow;  // Fallthrough label.
3855257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Label not_smis;
385680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // If we're doing a strict equality comparison, we don't have to do
385780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // type conversion, so we generate code to do fast comparison for objects
385880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // and oddballs. Non-smi numbers and strings still go through the usual
385980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // slow-case code.
386080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // If either is a Smi (we know that not both are), then they can only
386180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // be equal if the other is a HeapNumber. If so, use the slow case.
386280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    STATIC_ASSERT(kSmiTag == 0);
386380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    ASSERT_EQ(0, Smi::FromInt(0));
386480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ mov(ecx, Immediate(kSmiTagMask));
386580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ and_(ecx, Operand(eax));
386680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ test(ecx, Operand(edx));
3867257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ j(not_zero, &not_smis, Label::kNear);
386880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // One operand is a smi.
386980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
387080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // Check whether the non-smi is a heap number.
387180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    STATIC_ASSERT(kSmiTagMask == 1);
387280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // ecx still holds eax & kSmiTag, which is either zero or one.
387380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ sub(Operand(ecx), Immediate(0x01));
387480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ mov(ebx, edx);
387580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ xor_(ebx, Operand(eax));
387680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ and_(ebx, Operand(ecx));  // ebx holds either 0 or eax ^ edx.
387780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ xor_(ebx, Operand(eax));
387880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // if eax was smi, ebx is now edx, else eax.
387980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
388080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // Check if the non-smi operand is a heap number.
388180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ cmp(FieldOperand(ebx, HeapObject::kMapOffset),
388244f0eee88ff00398ff7f715fab053374d808c90dSteve Block           Immediate(masm->isolate()->factory()->heap_number_map()));
388380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // If heap number, handle it in the slow case.
388480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ j(equal, &slow);
388580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // Return non-equal (ebx is not zero)
388680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ mov(eax, ebx);
388780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ ret(0);
388880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
388980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ bind(&not_smis);
389080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // If either operand is a JSObject or an oddball value, then they are not
389180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // equal since their pointers are different
389280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // There is no test for undetectability in strict equality.
389380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
389480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // Get the type of the first operand.
389580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // If the first object is a JS object, we have done pointer comparison.
3896257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Label first_non_object;
38973fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    STATIC_ASSERT(LAST_TYPE == LAST_SPEC_OBJECT_TYPE);
38983fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    __ CmpObjectType(eax, FIRST_SPEC_OBJECT_TYPE, ecx);
3899257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ j(below, &first_non_object, Label::kNear);
390080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
390180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // Return non-zero (eax is not zero)
3902257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Label return_not_equal;
390380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    STATIC_ASSERT(kHeapObjectTag != 0);
390480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ bind(&return_not_equal);
390580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ ret(0);
390680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
390780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ bind(&first_non_object);
390880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // Check for oddballs: true, false, null, undefined.
390980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ CmpInstanceType(ecx, ODDBALL_TYPE);
391080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ j(equal, &return_not_equal);
391180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
39123fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    __ CmpObjectType(edx, FIRST_SPEC_OBJECT_TYPE, ecx);
391380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ j(above_equal, &return_not_equal);
391480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
391580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // Check for oddballs: true, false, null, undefined.
391680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ CmpInstanceType(ecx, ODDBALL_TYPE);
391780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ j(equal, &return_not_equal);
391880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
391980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // Fall through to the general case.
392080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ bind(&slow);
392180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
392280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
392380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Generate the number comparison code.
392480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  if (include_number_compare_) {
392580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    Label non_number_comparison;
392680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    Label unordered;
39278b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch    if (CpuFeatures::IsSupported(SSE2)) {
392880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      CpuFeatures::Scope use_sse2(SSE2);
392980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      CpuFeatures::Scope use_cmov(CMOV);
393080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
393180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      FloatingPointHelper::LoadSSE2Operands(masm, &non_number_comparison);
393280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ ucomisd(xmm0, xmm1);
393380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
393480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      // Don't base result on EFLAGS when a NaN is involved.
3935257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ j(parity_even, &unordered);
393680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      // Return a result of -1, 0, or 1, based on EFLAGS.
393780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ mov(eax, 0);  // equal
393880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ mov(ecx, Immediate(Smi::FromInt(1)));
393980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ cmov(above, eax, Operand(ecx));
394080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ mov(ecx, Immediate(Smi::FromInt(-1)));
394180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ cmov(below, eax, Operand(ecx));
394280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ ret(0);
394380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    } else {
394480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      FloatingPointHelper::CheckFloatOperands(
394580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen          masm, &non_number_comparison, ebx);
394680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      FloatingPointHelper::LoadFloatOperand(masm, eax);
394780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      FloatingPointHelper::LoadFloatOperand(masm, edx);
394880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ FCmp();
394980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
395080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      // Don't base result on EFLAGS when a NaN is involved.
3951257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ j(parity_even, &unordered);
395280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
3953257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      Label below_label, above_label;
395480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      // Return a result of -1, 0, or 1, based on EFLAGS.
3955257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ j(below, &below_label);
3956257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ j(above, &above_label);
395780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
39589fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block      __ Set(eax, Immediate(0));
395980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ ret(0);
396080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
396180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ bind(&below_label);
396280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ mov(eax, Immediate(Smi::FromInt(-1)));
396380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ ret(0);
396480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
396580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ bind(&above_label);
396680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ mov(eax, Immediate(Smi::FromInt(1)));
396780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ ret(0);
396880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    }
396980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
397080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // If one of the numbers was NaN, then the result is always false.
397180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // The cc is never not-equal.
397280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ bind(&unordered);
397380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    ASSERT(cc_ != not_equal);
397480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    if (cc_ == less || cc_ == less_equal) {
397580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ mov(eax, Immediate(Smi::FromInt(1)));
397680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    } else {
397780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ mov(eax, Immediate(Smi::FromInt(-1)));
397880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    }
397980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ ret(0);
398080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
398180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // The number comparison code did not provide a valid result.
398280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ bind(&non_number_comparison);
398380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
398480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
398580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Fast negative check for symbol-to-symbol equality.
398680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label check_for_strings;
398780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  if (cc_ == equal) {
398880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    BranchIfNonSymbol(masm, &check_for_strings, eax, ecx);
398980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    BranchIfNonSymbol(masm, &check_for_strings, edx, ecx);
399080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
399180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // We've already checked for object identity, so if both operands
399280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // are symbols they aren't equal. Register eax already holds a
399380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // non-zero value, which indicates not equal, so just return.
399480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ ret(0);
399580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
399680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
399780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&check_for_strings);
399880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
399980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ JumpIfNotBothSequentialAsciiStrings(edx, eax, ecx, ebx,
400080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                         &check_unequal_objects);
400180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
400280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Inline comparison of ascii strings.
4003257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  if (cc_ == equal) {
4004257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    StringCompareStub::GenerateFlatAsciiStringEquals(masm,
400580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                                     edx,
400680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                                     eax,
400780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                                     ecx,
4008257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                                     ebx);
4009257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  } else {
4010257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    StringCompareStub::GenerateCompareFlatAsciiStrings(masm,
4011257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                                       edx,
4012257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                                       eax,
4013257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                                       ecx,
4014257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                                       ebx,
4015257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                                       edi);
4016257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
401780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#ifdef DEBUG
401880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ Abort("Unexpected fall-through from string comparison");
401980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#endif
402080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
402180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&check_unequal_objects);
402280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  if (cc_ == equal && !strict_) {
402380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // Non-strict equality.  Objects are unequal if
402480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // they are both JSObjects and not undetectable,
402580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // and their pointers are different.
4026257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Label not_both_objects;
4027257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Label return_unequal;
402880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // At most one is a smi, so we can test for smi by adding the two.
402980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // A smi plus a heap object has the low bit set, a heap object plus
403080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // a heap object has the low bit clear.
403180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    STATIC_ASSERT(kSmiTag == 0);
403280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    STATIC_ASSERT(kSmiTagMask == 1);
403380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ lea(ecx, Operand(eax, edx, times_1, 0));
403480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ test(ecx, Immediate(kSmiTagMask));
4035257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ j(not_zero, &not_both_objects, Label::kNear);
40363fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    __ CmpObjectType(eax, FIRST_SPEC_OBJECT_TYPE, ecx);
4037257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ j(below, &not_both_objects, Label::kNear);
40383fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    __ CmpObjectType(edx, FIRST_SPEC_OBJECT_TYPE, ebx);
4039257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ j(below, &not_both_objects, Label::kNear);
404080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // We do not bail out after this point.  Both are JSObjects, and
404180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // they are equal if and only if both are undetectable.
404280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // The and of the undetectable flags is 1 if and only if they are equal.
404380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ test_b(FieldOperand(ecx, Map::kBitFieldOffset),
404480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen              1 << Map::kIsUndetectable);
4045257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ j(zero, &return_unequal, Label::kNear);
404680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ test_b(FieldOperand(ebx, Map::kBitFieldOffset),
404780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen              1 << Map::kIsUndetectable);
4048257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ j(zero, &return_unequal, Label::kNear);
404980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // The objects are both undetectable, so they both compare as the value
405080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // undefined, and are equal.
405180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ Set(eax, Immediate(EQUAL));
405280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ bind(&return_unequal);
405380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // Return non-equal by returning the non-zero object pointer in eax,
405480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // or return equal if we fell through to here.
405580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ ret(0);  // rax, rdx were pushed
405680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ bind(&not_both_objects);
405780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
405880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
405980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Push arguments below the return address.
406080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ pop(ecx);
406180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ push(edx);
406280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ push(eax);
406380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
406480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Figure out which native to call and setup the arguments.
406580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Builtins::JavaScript builtin;
406680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  if (cc_ == equal) {
406780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    builtin = strict_ ? Builtins::STRICT_EQUALS : Builtins::EQUALS;
406880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  } else {
406980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    builtin = Builtins::COMPARE;
407080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ push(Immediate(Smi::FromInt(NegativeComparisonResult(cc_))));
407180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
407280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
407380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Restore return address on the stack.
407480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ push(ecx);
407580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
407680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Call the native; it returns -1 (less), 0 (equal), or 1 (greater)
407780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // tagged as a small integer.
407880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ InvokeBuiltin(builtin, JUMP_FUNCTION);
407980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
408080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
408180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
408280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid CompareStub::BranchIfNonSymbol(MacroAssembler* masm,
408380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                    Label* label,
408480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                    Register object,
408580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                    Register scratch) {
40863fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ JumpIfSmi(object, label);
408780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(scratch, FieldOperand(object, HeapObject::kMapOffset));
408880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movzx_b(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset));
408980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ and_(scratch, kIsSymbolMask | kIsNotStringMask);
409080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cmp(scratch, kSymbolTag | kStringTag);
409180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(not_equal, label);
409280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
409380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
409480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
409580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StackCheckStub::Generate(MacroAssembler* masm) {
4096f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  __ TailCallRuntime(Runtime::kStackGuard, 0, 1);
409780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
409880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
409980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
410080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid CallFunctionStub::Generate(MacroAssembler* masm) {
410180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label slow;
410280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
4103257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // The receiver might implicitly be the global object. This is
4104257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // indicated by passing the hole as the receiver to the call
4105257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // function stub.
4106257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  if (ReceiverMightBeImplicit()) {
4107257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Label call;
410880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // Get the receiver from the stack.
410980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // +1 ~ return address
411080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ mov(eax, Operand(esp, (argc_ + 1) * kPointerSize));
4111257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Call as function is indicated with the hole.
4112257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ cmp(eax, masm->isolate()->factory()->the_hole_value());
4113257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ j(not_equal, &call, Label::kNear);
4114257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Patch the receiver on the stack with the global receiver object.
4115257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ mov(ebx, GlobalObjectOperand());
4116257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ mov(ebx, FieldOperand(ebx, GlobalObject::kGlobalReceiverOffset));
4117257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ mov(Operand(esp, (argc_ + 1) * kPointerSize), ebx);
4118257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ bind(&call);
411980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
412080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
412180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Get the function to call from the stack.
412280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // +2 ~ receiver, return address
412380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(edi, Operand(esp, (argc_ + 2) * kPointerSize));
412480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
412580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check that the function really is a JavaScript function.
41263fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ JumpIfSmi(edi, &slow);
412780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Goto slow case if we do not have a function.
412880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx);
4129257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(not_equal, &slow);
413080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
413180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Fast-case: Just invoke the function.
413280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  ParameterCount actual(argc_);
4133257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
4134257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  if (ReceiverMightBeImplicit()) {
4135257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Label call_as_function;
4136257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ cmp(eax, masm->isolate()->factory()->the_hole_value());
4137257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ j(equal, &call_as_function);
4138257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ InvokeFunction(edi,
4139257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                      actual,
4140257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                      JUMP_FUNCTION,
4141257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                      NullCallWrapper(),
4142257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                      CALL_AS_METHOD);
4143257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ bind(&call_as_function);
4144257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
4145257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ InvokeFunction(edi,
4146257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                    actual,
4147257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                    JUMP_FUNCTION,
4148257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                    NullCallWrapper(),
4149257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                    CALL_AS_FUNCTION);
415080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
415180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Slow-case: Non-function called.
415280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&slow);
415380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // CALL_NON_FUNCTION expects the non-function callee as receiver (instead
415480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // of the original receiver from the call site).
415580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(Operand(esp, (argc_ + 1) * kPointerSize), edi);
415680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ Set(eax, Immediate(argc_));
415780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ Set(ebx, Immediate(0));
415880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ GetBuiltinEntry(edx, Builtins::CALL_NON_FUNCTION);
415944f0eee88ff00398ff7f715fab053374d808c90dSteve Block  Handle<Code> adaptor =
416044f0eee88ff00398ff7f715fab053374d808c90dSteve Block      masm->isolate()->builtins()->ArgumentsAdaptorTrampoline();
41613fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ SetCallKind(ecx, CALL_AS_METHOD);
416280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ jmp(adaptor, RelocInfo::CODE_TARGET);
416380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
416480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
416580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
416644f0eee88ff00398ff7f715fab053374d808c90dSteve Blockbool CEntryStub::NeedsImmovableCode() {
416744f0eee88ff00398ff7f715fab053374d808c90dSteve Block  return false;
416844f0eee88ff00398ff7f715fab053374d808c90dSteve Block}
416944f0eee88ff00398ff7f715fab053374d808c90dSteve Block
417044f0eee88ff00398ff7f715fab053374d808c90dSteve Block
417180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid CEntryStub::GenerateThrowTOS(MacroAssembler* masm) {
4172e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ Throw(eax);
417380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
417480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
417580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
417680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid CEntryStub::GenerateCore(MacroAssembler* masm,
417780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                              Label* throw_normal_exception,
417880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                              Label* throw_termination_exception,
417980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                              Label* throw_out_of_memory_exception,
418080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                              bool do_gc,
41811e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block                              bool always_allocate_scope) {
418280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // eax: result parameter for PerformGC, if any
418380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // ebx: pointer to C function  (C callee-saved)
418480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // ebp: frame pointer  (restored after C call)
418580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // esp: stack pointer  (restored after C call)
418680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // edi: number of arguments including receiver  (C callee-saved)
418780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // esi: pointer to the first argument (C callee-saved)
418880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
418980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Result returned in eax, or eax+edx if result_size_ is 2.
419080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
419180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check stack alignment.
419280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  if (FLAG_debug_code) {
419380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ CheckStackAlignment();
419480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
419580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
419680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  if (do_gc) {
419780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // Pass failure code returned from last attempt as first argument to
419880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // PerformGC. No need to use PrepareCallCFunction/CallCFunction here as the
419980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // stack alignment is known to be correct. This function takes one argument
420080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // which is passed on the stack, and we know that the stack has been
420180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // prepared to pass at least one argument.
420280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ mov(Operand(esp, 0 * kPointerSize), eax);  // Result.
420380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ call(FUNCTION_ADDR(Runtime::PerformGC), RelocInfo::RUNTIME_ENTRY);
420480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
420580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
420680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  ExternalReference scope_depth =
420744f0eee88ff00398ff7f715fab053374d808c90dSteve Block      ExternalReference::heap_always_allocate_scope_depth(masm->isolate());
420880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  if (always_allocate_scope) {
420980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ inc(Operand::StaticVariable(scope_depth));
421080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
421180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
421280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Call C function.
421380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(Operand(esp, 0 * kPointerSize), edi);  // argc.
421480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(Operand(esp, 1 * kPointerSize), esi);  // argv.
421544f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ mov(Operand(esp, 2 * kPointerSize),
421644f0eee88ff00398ff7f715fab053374d808c90dSteve Block         Immediate(ExternalReference::isolate_address()));
421780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ call(Operand(ebx));
421880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Result is in eax or edx:eax - do not destroy these registers!
421980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
422080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  if (always_allocate_scope) {
422180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ dec(Operand::StaticVariable(scope_depth));
422280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
422380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
422480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Make sure we're not trying to return 'the hole' from the runtime
422580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // call as this may lead to crashes in the IC code later.
422680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  if (FLAG_debug_code) {
4227257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Label okay;
422844f0eee88ff00398ff7f715fab053374d808c90dSteve Block    __ cmp(eax, masm->isolate()->factory()->the_hole_value());
4229257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ j(not_equal, &okay, Label::kNear);
423080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ int3();
423180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ bind(&okay);
423280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
423380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
423480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check for failure result.
423580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label failure_returned;
423680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  STATIC_ASSERT(((kFailureTag + 1) & kFailureTagMask) == 0);
423780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ lea(ecx, Operand(eax, 1));
423880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Lower 2 bits of ecx are 0 iff eax has failure tag.
423980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ test(ecx, Immediate(kFailureTagMask));
4240257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(zero, &failure_returned);
424180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
424244f0eee88ff00398ff7f715fab053374d808c90dSteve Block  ExternalReference pending_exception_address(
424344f0eee88ff00398ff7f715fab053374d808c90dSteve Block      Isolate::k_pending_exception_address, masm->isolate());
42441e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
42451e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  // Check that there is no pending exception, otherwise we
42461e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  // should have returned some failure value.
42471e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  if (FLAG_debug_code) {
42481e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    __ push(edx);
42491e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    __ mov(edx, Operand::StaticVariable(
425044f0eee88ff00398ff7f715fab053374d808c90dSteve Block        ExternalReference::the_hole_value_location(masm->isolate())));
4251257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Label okay;
42521e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    __ cmp(edx, Operand::StaticVariable(pending_exception_address));
42531e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    // Cannot use check here as it attempts to generate call into runtime.
4254257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ j(equal, &okay, Label::kNear);
42551e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    __ int3();
42561e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    __ bind(&okay);
42571e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    __ pop(edx);
42581e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  }
42591e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
426080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Exit the JavaScript to C++ exit frame.
4261b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ LeaveExitFrame(save_doubles_);
426280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ ret(0);
426380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
426480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Handling of failure.
426580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&failure_returned);
426680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
426780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label retry;
426880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // If the returned exception is RETRY_AFTER_GC continue at retry label
426980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  STATIC_ASSERT(Failure::RETRY_AFTER_GC == 0);
427080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ test(eax, Immediate(((1 << kFailureTypeTagSize) - 1) << kFailureTagSize));
4271257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(zero, &retry);
427280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
427380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Special handling of out of memory exceptions.
427480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cmp(eax, reinterpret_cast<int32_t>(Failure::OutOfMemoryException()));
427580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(equal, throw_out_of_memory_exception);
427680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
427780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Retrieve the pending exception and clear the variable.
427844f0eee88ff00398ff7f715fab053374d808c90dSteve Block  ExternalReference the_hole_location =
427944f0eee88ff00398ff7f715fab053374d808c90dSteve Block      ExternalReference::the_hole_value_location(masm->isolate());
428080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(eax, Operand::StaticVariable(pending_exception_address));
428144f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ mov(edx, Operand::StaticVariable(the_hole_location));
428280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(Operand::StaticVariable(pending_exception_address), edx);
428380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
428480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Special handling of termination exceptions which are uncatchable
428580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // by javascript code.
428644f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ cmp(eax, masm->isolate()->factory()->termination_exception());
428780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(equal, throw_termination_exception);
428880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
428980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Handle normal exception.
429080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ jmp(throw_normal_exception);
429180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
429280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Retry.
429380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&retry);
429480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
429580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
429680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
429780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid CEntryStub::GenerateThrowUncatchable(MacroAssembler* masm,
429880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                          UncatchableExceptionType type) {
4299e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ ThrowUncatchable(type, eax);
430080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
430180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
430280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
430380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid CEntryStub::Generate(MacroAssembler* masm) {
430480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // eax: number of arguments including receiver
430580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // ebx: pointer to C function  (C callee-saved)
430680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // ebp: frame pointer  (restored after C call)
430780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // esp: stack pointer  (restored after C call)
430880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // esi: current context (C callee-saved)
430980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // edi: JS function of the caller (C callee-saved)
431080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
431180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // NOTE: Invocations of builtins may return failure objects instead
431280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // of a proper result. The builtin entry handles this by performing
431380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // a garbage collection and retrying the builtin (twice).
431480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
431580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Enter the exit frame that transitions from JavaScript to C++.
4316b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ EnterExitFrame(save_doubles_);
431780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
431880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // eax: result parameter for PerformGC, if any (setup below)
431980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // ebx: pointer to builtin function  (C callee-saved)
432080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // ebp: frame pointer  (restored after C call)
432180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // esp: stack pointer  (restored after C call)
432280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // edi: number of arguments including receiver (C callee-saved)
432380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // esi: argv pointer (C callee-saved)
432480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
432580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label throw_normal_exception;
432680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label throw_termination_exception;
432780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label throw_out_of_memory_exception;
432880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
432980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Call into the runtime system.
433080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  GenerateCore(masm,
433180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen               &throw_normal_exception,
433280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen               &throw_termination_exception,
433380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen               &throw_out_of_memory_exception,
433480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen               false,
433580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen               false);
433680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
433780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Do space-specific GC and retry runtime call.
433880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  GenerateCore(masm,
433980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen               &throw_normal_exception,
434080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen               &throw_termination_exception,
434180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen               &throw_out_of_memory_exception,
434280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen               true,
434380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen               false);
434480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
434580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Do full GC and retry runtime call one final time.
434680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Failure* failure = Failure::InternalError();
434780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(eax, Immediate(reinterpret_cast<int32_t>(failure)));
434880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  GenerateCore(masm,
434980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen               &throw_normal_exception,
435080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen               &throw_termination_exception,
435180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen               &throw_out_of_memory_exception,
435280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen               true,
435380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen               true);
435480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
435580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&throw_out_of_memory_exception);
435680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  GenerateThrowUncatchable(masm, OUT_OF_MEMORY);
435780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
435880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&throw_termination_exception);
435980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  GenerateThrowUncatchable(masm, TERMINATION);
436080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
436180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&throw_normal_exception);
436280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  GenerateThrowTOS(masm);
436380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
436480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
436580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
436680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid JSEntryStub::GenerateBody(MacroAssembler* masm, bool is_construct) {
436780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label invoke, exit;
436880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label not_outermost_js, not_outermost_js_2;
436980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
437080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Setup frame.
437180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ push(ebp);
437280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(ebp, Operand(esp));
437380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
437480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Push marker in two places.
437580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  int marker = is_construct ? StackFrame::ENTRY_CONSTRUCT : StackFrame::ENTRY;
437680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ push(Immediate(Smi::FromInt(marker)));  // context slot
437780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ push(Immediate(Smi::FromInt(marker)));  // function slot
437880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Save callee-saved registers (C calling conventions).
437980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ push(edi);
438080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ push(esi);
438180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ push(ebx);
438280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
438380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Save copies of the top frame descriptor on the stack.
438444f0eee88ff00398ff7f715fab053374d808c90dSteve Block  ExternalReference c_entry_fp(Isolate::k_c_entry_fp_address, masm->isolate());
438580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ push(Operand::StaticVariable(c_entry_fp));
438680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
438780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // If this is the outermost JS call, set js_entry_sp value.
438844f0eee88ff00398ff7f715fab053374d808c90dSteve Block  ExternalReference js_entry_sp(Isolate::k_js_entry_sp_address,
438944f0eee88ff00398ff7f715fab053374d808c90dSteve Block                                masm->isolate());
439080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cmp(Operand::StaticVariable(js_entry_sp), Immediate(0));
439180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(not_equal, &not_outermost_js);
439280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(Operand::StaticVariable(js_entry_sp), ebp);
4393053d10c438f14580aaf4ab1b2aad93a5a4fe8b82Steve Block  __ push(Immediate(Smi::FromInt(StackFrame::OUTERMOST_JSENTRY_FRAME)));
4394053d10c438f14580aaf4ab1b2aad93a5a4fe8b82Steve Block  Label cont;
4395053d10c438f14580aaf4ab1b2aad93a5a4fe8b82Steve Block  __ jmp(&cont);
439680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&not_outermost_js);
4397053d10c438f14580aaf4ab1b2aad93a5a4fe8b82Steve Block  __ push(Immediate(Smi::FromInt(StackFrame::INNER_JSENTRY_FRAME)));
4398053d10c438f14580aaf4ab1b2aad93a5a4fe8b82Steve Block  __ bind(&cont);
439980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
440080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Call a faked try-block that does the invoke.
440180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ call(&invoke);
440280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
440380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Caught exception: Store result (exception) in the pending
440480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // exception field in the JSEnv and return a failure sentinel.
440544f0eee88ff00398ff7f715fab053374d808c90dSteve Block  ExternalReference pending_exception(Isolate::k_pending_exception_address,
440644f0eee88ff00398ff7f715fab053374d808c90dSteve Block                                      masm->isolate());
440780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(Operand::StaticVariable(pending_exception), eax);
440880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(eax, reinterpret_cast<int32_t>(Failure::Exception()));
440980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ jmp(&exit);
441080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
441180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Invoke: Link this frame into the handler chain.
441280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&invoke);
441380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ PushTryHandler(IN_JS_ENTRY, JS_ENTRY_HANDLER);
441480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
441580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Clear any pending exceptions.
441644f0eee88ff00398ff7f715fab053374d808c90dSteve Block  ExternalReference the_hole_location =
441744f0eee88ff00398ff7f715fab053374d808c90dSteve Block      ExternalReference::the_hole_value_location(masm->isolate());
441844f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ mov(edx, Operand::StaticVariable(the_hole_location));
441980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(Operand::StaticVariable(pending_exception), edx);
442080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
442180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Fake a receiver (NULL).
442280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ push(Immediate(0));  // receiver
442380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
442480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Invoke the function by calling through JS entry trampoline
442580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // builtin and pop the faked function when we return. Notice that we
442680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // cannot store a reference to the trampoline code directly in this
442780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // stub, because the builtin stubs may not have been generated yet.
442880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  if (is_construct) {
442944f0eee88ff00398ff7f715fab053374d808c90dSteve Block    ExternalReference construct_entry(
443044f0eee88ff00398ff7f715fab053374d808c90dSteve Block        Builtins::kJSConstructEntryTrampoline,
443144f0eee88ff00398ff7f715fab053374d808c90dSteve Block        masm->isolate());
443280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ mov(edx, Immediate(construct_entry));
443380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  } else {
443444f0eee88ff00398ff7f715fab053374d808c90dSteve Block    ExternalReference entry(Builtins::kJSEntryTrampoline,
443544f0eee88ff00398ff7f715fab053374d808c90dSteve Block                            masm->isolate());
443680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ mov(edx, Immediate(entry));
443780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
443880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(edx, Operand(edx, 0));  // deref address
443980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ lea(edx, FieldOperand(edx, Code::kHeaderSize));
444080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ call(Operand(edx));
444180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
444280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Unlink this frame from the handler chain.
4443053d10c438f14580aaf4ab1b2aad93a5a4fe8b82Steve Block  __ PopTryHandler();
444480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
4445053d10c438f14580aaf4ab1b2aad93a5a4fe8b82Steve Block  __ bind(&exit);
4446053d10c438f14580aaf4ab1b2aad93a5a4fe8b82Steve Block  // Check if the current stack frame is marked as the outermost JS frame.
4447053d10c438f14580aaf4ab1b2aad93a5a4fe8b82Steve Block  __ pop(ebx);
4448053d10c438f14580aaf4ab1b2aad93a5a4fe8b82Steve Block  __ cmp(Operand(ebx),
4449053d10c438f14580aaf4ab1b2aad93a5a4fe8b82Steve Block         Immediate(Smi::FromInt(StackFrame::OUTERMOST_JSENTRY_FRAME)));
445080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(not_equal, &not_outermost_js_2);
445180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(Operand::StaticVariable(js_entry_sp), Immediate(0));
445280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&not_outermost_js_2);
445380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
445480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Restore the top frame descriptor from the stack.
445544f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ pop(Operand::StaticVariable(ExternalReference(
445644f0eee88ff00398ff7f715fab053374d808c90dSteve Block      Isolate::k_c_entry_fp_address,
445744f0eee88ff00398ff7f715fab053374d808c90dSteve Block      masm->isolate())));
445880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
445980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Restore callee-saved registers (C calling conventions).
446080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ pop(ebx);
446180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ pop(esi);
446280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ pop(edi);
446380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ add(Operand(esp), Immediate(2 * kPointerSize));  // remove markers
446480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
446580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Restore frame pointer and return.
446680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ pop(ebp);
446780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ ret(0);
446880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
446980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
447080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
4471086aeeaae12517475c22695a200be45495516549Ben Murdoch// Generate stub code for instanceof.
4472086aeeaae12517475c22695a200be45495516549Ben Murdoch// This code can patch a call site inlined cache of the instance of check,
4473086aeeaae12517475c22695a200be45495516549Ben Murdoch// which looks like this.
4474086aeeaae12517475c22695a200be45495516549Ben Murdoch//
4475086aeeaae12517475c22695a200be45495516549Ben Murdoch//   81 ff XX XX XX XX   cmp    edi, <the hole, patched to a map>
4476086aeeaae12517475c22695a200be45495516549Ben Murdoch//   75 0a               jne    <some near label>
4477086aeeaae12517475c22695a200be45495516549Ben Murdoch//   b8 XX XX XX XX      mov    eax, <the hole, patched to either true or false>
4478086aeeaae12517475c22695a200be45495516549Ben Murdoch//
4479086aeeaae12517475c22695a200be45495516549Ben Murdoch// If call site patching is requested the stack will have the delta from the
4480086aeeaae12517475c22695a200be45495516549Ben Murdoch// return address to the cmp instruction just below the return address. This
4481086aeeaae12517475c22695a200be45495516549Ben Murdoch// also means that call site patching can only take place with arguments in
4482086aeeaae12517475c22695a200be45495516549Ben Murdoch// registers. TOS looks like this when call site patching is requested
4483086aeeaae12517475c22695a200be45495516549Ben Murdoch//
4484086aeeaae12517475c22695a200be45495516549Ben Murdoch//   esp[0] : return address
4485086aeeaae12517475c22695a200be45495516549Ben Murdoch//   esp[4] : delta from return address to cmp instruction
4486086aeeaae12517475c22695a200be45495516549Ben Murdoch//
448780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid InstanceofStub::Generate(MacroAssembler* masm) {
4488086aeeaae12517475c22695a200be45495516549Ben Murdoch  // Call site inlining and patching implies arguments in registers.
4489086aeeaae12517475c22695a200be45495516549Ben Murdoch  ASSERT(HasArgsInRegisters() || !HasCallSiteInlineCheck());
4490086aeeaae12517475c22695a200be45495516549Ben Murdoch
4491b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Fixed register usage throughout the stub.
4492b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  Register object = eax;  // Object (lhs).
4493b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  Register map = ebx;  // Map of the object.
4494b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  Register function = edx;  // Function (rhs).
4495b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  Register prototype = edi;  // Prototype of the function.
4496b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  Register scratch = ecx;
4497b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
4498086aeeaae12517475c22695a200be45495516549Ben Murdoch  // Constants describing the call site code to patch.
4499086aeeaae12517475c22695a200be45495516549Ben Murdoch  static const int kDeltaToCmpImmediate = 2;
4500086aeeaae12517475c22695a200be45495516549Ben Murdoch  static const int kDeltaToMov = 8;
4501086aeeaae12517475c22695a200be45495516549Ben Murdoch  static const int kDeltaToMovImmediate = 9;
4502086aeeaae12517475c22695a200be45495516549Ben Murdoch  static const int8_t kCmpEdiImmediateByte1 = BitCast<int8_t, uint8_t>(0x81);
4503086aeeaae12517475c22695a200be45495516549Ben Murdoch  static const int8_t kCmpEdiImmediateByte2 = BitCast<int8_t, uint8_t>(0xff);
4504086aeeaae12517475c22695a200be45495516549Ben Murdoch  static const int8_t kMovEaxImmediateByte = BitCast<int8_t, uint8_t>(0xb8);
4505086aeeaae12517475c22695a200be45495516549Ben Murdoch
450644f0eee88ff00398ff7f715fab053374d808c90dSteve Block  ExternalReference roots_address =
450744f0eee88ff00398ff7f715fab053374d808c90dSteve Block      ExternalReference::roots_address(masm->isolate());
4508086aeeaae12517475c22695a200be45495516549Ben Murdoch
4509086aeeaae12517475c22695a200be45495516549Ben Murdoch  ASSERT_EQ(object.code(), InstanceofStub::left().code());
4510086aeeaae12517475c22695a200be45495516549Ben Murdoch  ASSERT_EQ(function.code(), InstanceofStub::right().code());
4511086aeeaae12517475c22695a200be45495516549Ben Murdoch
4512b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Get the object and function - they are always both needed.
4513b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  Label slow, not_js_object;
4514086aeeaae12517475c22695a200be45495516549Ben Murdoch  if (!HasArgsInRegisters()) {
4515b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ mov(object, Operand(esp, 2 * kPointerSize));
4516b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ mov(function, Operand(esp, 1 * kPointerSize));
4517b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  }
451880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
451980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check that the left hand is a JS object.
45203fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ JumpIfSmi(object, &not_js_object);
4521b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ IsObjectJSObjectType(object, map, scratch, &not_js_object);
452280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
4523086aeeaae12517475c22695a200be45495516549Ben Murdoch  // If there is a call site cache don't look in the global cache, but do the
4524086aeeaae12517475c22695a200be45495516549Ben Murdoch  // real lookup and update the call site cache.
4525086aeeaae12517475c22695a200be45495516549Ben Murdoch  if (!HasCallSiteInlineCheck()) {
4526086aeeaae12517475c22695a200be45495516549Ben Murdoch    // Look up the function and the map in the instanceof cache.
4527257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Label miss;
4528086aeeaae12517475c22695a200be45495516549Ben Murdoch    __ mov(scratch, Immediate(Heap::kInstanceofCacheFunctionRootIndex));
4529086aeeaae12517475c22695a200be45495516549Ben Murdoch    __ cmp(function,
4530086aeeaae12517475c22695a200be45495516549Ben Murdoch           Operand::StaticArray(scratch, times_pointer_size, roots_address));
4531257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ j(not_equal, &miss, Label::kNear);
4532086aeeaae12517475c22695a200be45495516549Ben Murdoch    __ mov(scratch, Immediate(Heap::kInstanceofCacheMapRootIndex));
4533086aeeaae12517475c22695a200be45495516549Ben Murdoch    __ cmp(map, Operand::StaticArray(
4534086aeeaae12517475c22695a200be45495516549Ben Murdoch        scratch, times_pointer_size, roots_address));
4535257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ j(not_equal, &miss, Label::kNear);
4536086aeeaae12517475c22695a200be45495516549Ben Murdoch    __ mov(scratch, Immediate(Heap::kInstanceofCacheAnswerRootIndex));
4537086aeeaae12517475c22695a200be45495516549Ben Murdoch    __ mov(eax, Operand::StaticArray(
4538086aeeaae12517475c22695a200be45495516549Ben Murdoch        scratch, times_pointer_size, roots_address));
4539086aeeaae12517475c22695a200be45495516549Ben Murdoch    __ ret((HasArgsInRegisters() ? 0 : 2) * kPointerSize);
4540086aeeaae12517475c22695a200be45495516549Ben Murdoch    __ bind(&miss);
4541086aeeaae12517475c22695a200be45495516549Ben Murdoch  }
4542086aeeaae12517475c22695a200be45495516549Ben Murdoch
4543b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Get the prototype of the function.
4544b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ TryGetFunctionPrototype(function, prototype, scratch, &slow);
454580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
454680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check that the function prototype is a JS object.
45473fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ JumpIfSmi(prototype, &slow);
4548b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ IsObjectJSObjectType(prototype, scratch, scratch, &slow);
4549b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
4550086aeeaae12517475c22695a200be45495516549Ben Murdoch  // Update the global instanceof or call site inlined cache with the current
4551086aeeaae12517475c22695a200be45495516549Ben Murdoch  // map and function. The cached answer will be set when it is known below.
4552086aeeaae12517475c22695a200be45495516549Ben Murdoch  if (!HasCallSiteInlineCheck()) {
4553b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ mov(scratch, Immediate(Heap::kInstanceofCacheMapRootIndex));
4554b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ mov(Operand::StaticArray(scratch, times_pointer_size, roots_address), map);
4555b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ mov(scratch, Immediate(Heap::kInstanceofCacheFunctionRootIndex));
4556b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ mov(Operand::StaticArray(scratch, times_pointer_size, roots_address),
4557b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch         function);
4558086aeeaae12517475c22695a200be45495516549Ben Murdoch  } else {
4559086aeeaae12517475c22695a200be45495516549Ben Murdoch    // The constants for the code patching are based on no push instructions
4560086aeeaae12517475c22695a200be45495516549Ben Murdoch    // at the call site.
4561086aeeaae12517475c22695a200be45495516549Ben Murdoch    ASSERT(HasArgsInRegisters());
4562086aeeaae12517475c22695a200be45495516549Ben Murdoch    // Get return address and delta to inlined map check.
4563086aeeaae12517475c22695a200be45495516549Ben Murdoch    __ mov(scratch, Operand(esp, 0 * kPointerSize));
4564086aeeaae12517475c22695a200be45495516549Ben Murdoch    __ sub(scratch, Operand(esp, 1 * kPointerSize));
4565086aeeaae12517475c22695a200be45495516549Ben Murdoch    if (FLAG_debug_code) {
4566086aeeaae12517475c22695a200be45495516549Ben Murdoch      __ cmpb(Operand(scratch, 0), kCmpEdiImmediateByte1);
4567086aeeaae12517475c22695a200be45495516549Ben Murdoch      __ Assert(equal, "InstanceofStub unexpected call site cache (cmp 1)");
4568086aeeaae12517475c22695a200be45495516549Ben Murdoch      __ cmpb(Operand(scratch, 1), kCmpEdiImmediateByte2);
4569086aeeaae12517475c22695a200be45495516549Ben Murdoch      __ Assert(equal, "InstanceofStub unexpected call site cache (cmp 2)");
4570086aeeaae12517475c22695a200be45495516549Ben Murdoch    }
4571086aeeaae12517475c22695a200be45495516549Ben Murdoch    __ mov(Operand(scratch, kDeltaToCmpImmediate), map);
4572086aeeaae12517475c22695a200be45495516549Ben Murdoch  }
4573b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
4574b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Loop through the prototype chain of the object looking for the function
4575b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // prototype.
4576b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ mov(scratch, FieldOperand(map, Map::kPrototypeOffset));
4577257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label loop, is_instance, is_not_instance;
457880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&loop);
4579b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ cmp(scratch, Operand(prototype));
4580257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(equal, &is_instance, Label::kNear);
458144f0eee88ff00398ff7f715fab053374d808c90dSteve Block  Factory* factory = masm->isolate()->factory();
458244f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ cmp(Operand(scratch), Immediate(factory->null_value()));
4583257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(equal, &is_not_instance, Label::kNear);
4584b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ mov(scratch, FieldOperand(scratch, HeapObject::kMapOffset));
4585b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ mov(scratch, FieldOperand(scratch, Map::kPrototypeOffset));
458680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ jmp(&loop);
458780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
458880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&is_instance);
4589086aeeaae12517475c22695a200be45495516549Ben Murdoch  if (!HasCallSiteInlineCheck()) {
4590086aeeaae12517475c22695a200be45495516549Ben Murdoch    __ Set(eax, Immediate(0));
4591086aeeaae12517475c22695a200be45495516549Ben Murdoch    __ mov(scratch, Immediate(Heap::kInstanceofCacheAnswerRootIndex));
4592086aeeaae12517475c22695a200be45495516549Ben Murdoch    __ mov(Operand::StaticArray(scratch,
4593086aeeaae12517475c22695a200be45495516549Ben Murdoch                                times_pointer_size, roots_address), eax);
4594086aeeaae12517475c22695a200be45495516549Ben Murdoch  } else {
4595086aeeaae12517475c22695a200be45495516549Ben Murdoch    // Get return address and delta to inlined map check.
459644f0eee88ff00398ff7f715fab053374d808c90dSteve Block    __ mov(eax, factory->true_value());
4597086aeeaae12517475c22695a200be45495516549Ben Murdoch    __ mov(scratch, Operand(esp, 0 * kPointerSize));
4598086aeeaae12517475c22695a200be45495516549Ben Murdoch    __ sub(scratch, Operand(esp, 1 * kPointerSize));
4599086aeeaae12517475c22695a200be45495516549Ben Murdoch    if (FLAG_debug_code) {
4600086aeeaae12517475c22695a200be45495516549Ben Murdoch      __ cmpb(Operand(scratch, kDeltaToMov), kMovEaxImmediateByte);
4601086aeeaae12517475c22695a200be45495516549Ben Murdoch      __ Assert(equal, "InstanceofStub unexpected call site cache (mov)");
4602086aeeaae12517475c22695a200be45495516549Ben Murdoch    }
4603086aeeaae12517475c22695a200be45495516549Ben Murdoch    __ mov(Operand(scratch, kDeltaToMovImmediate), eax);
4604086aeeaae12517475c22695a200be45495516549Ben Murdoch    if (!ReturnTrueFalseObject()) {
4605086aeeaae12517475c22695a200be45495516549Ben Murdoch      __ Set(eax, Immediate(0));
4606086aeeaae12517475c22695a200be45495516549Ben Murdoch    }
4607086aeeaae12517475c22695a200be45495516549Ben Murdoch  }
4608086aeeaae12517475c22695a200be45495516549Ben Murdoch  __ ret((HasArgsInRegisters() ? 0 : 2) * kPointerSize);
460980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
461080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&is_not_instance);
4611086aeeaae12517475c22695a200be45495516549Ben Murdoch  if (!HasCallSiteInlineCheck()) {
4612086aeeaae12517475c22695a200be45495516549Ben Murdoch    __ Set(eax, Immediate(Smi::FromInt(1)));
4613086aeeaae12517475c22695a200be45495516549Ben Murdoch    __ mov(scratch, Immediate(Heap::kInstanceofCacheAnswerRootIndex));
4614086aeeaae12517475c22695a200be45495516549Ben Murdoch    __ mov(Operand::StaticArray(
4615086aeeaae12517475c22695a200be45495516549Ben Murdoch        scratch, times_pointer_size, roots_address), eax);
4616086aeeaae12517475c22695a200be45495516549Ben Murdoch  } else {
4617086aeeaae12517475c22695a200be45495516549Ben Murdoch    // Get return address and delta to inlined map check.
461844f0eee88ff00398ff7f715fab053374d808c90dSteve Block    __ mov(eax, factory->false_value());
4619086aeeaae12517475c22695a200be45495516549Ben Murdoch    __ mov(scratch, Operand(esp, 0 * kPointerSize));
4620086aeeaae12517475c22695a200be45495516549Ben Murdoch    __ sub(scratch, Operand(esp, 1 * kPointerSize));
4621086aeeaae12517475c22695a200be45495516549Ben Murdoch    if (FLAG_debug_code) {
4622086aeeaae12517475c22695a200be45495516549Ben Murdoch      __ cmpb(Operand(scratch, kDeltaToMov), kMovEaxImmediateByte);
4623086aeeaae12517475c22695a200be45495516549Ben Murdoch      __ Assert(equal, "InstanceofStub unexpected call site cache (mov)");
4624086aeeaae12517475c22695a200be45495516549Ben Murdoch    }
4625086aeeaae12517475c22695a200be45495516549Ben Murdoch    __ mov(Operand(scratch, kDeltaToMovImmediate), eax);
4626086aeeaae12517475c22695a200be45495516549Ben Murdoch    if (!ReturnTrueFalseObject()) {
4627086aeeaae12517475c22695a200be45495516549Ben Murdoch      __ Set(eax, Immediate(Smi::FromInt(1)));
4628086aeeaae12517475c22695a200be45495516549Ben Murdoch    }
4629086aeeaae12517475c22695a200be45495516549Ben Murdoch  }
4630086aeeaae12517475c22695a200be45495516549Ben Murdoch  __ ret((HasArgsInRegisters() ? 0 : 2) * kPointerSize);
4631b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
4632b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  Label object_not_null, object_not_null_or_smi;
4633b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ bind(&not_js_object);
4634b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Before null, smi and string value checks, check that the rhs is a function
4635b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // as for a non-function rhs an exception needs to be thrown.
46363fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ JumpIfSmi(function, &slow);
4637b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ CmpObjectType(function, JS_FUNCTION_TYPE, scratch);
4638257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(not_equal, &slow);
4639b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
4640b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Null is not instance of anything.
464144f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ cmp(object, factory->null_value());
4642b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ j(not_equal, &object_not_null);
4643b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ Set(eax, Immediate(Smi::FromInt(1)));
4644086aeeaae12517475c22695a200be45495516549Ben Murdoch  __ ret((HasArgsInRegisters() ? 0 : 2) * kPointerSize);
4645b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
4646b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ bind(&object_not_null);
4647b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Smi values is not instance of anything.
46483fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ JumpIfNotSmi(object, &object_not_null_or_smi);
4649b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ Set(eax, Immediate(Smi::FromInt(1)));
4650086aeeaae12517475c22695a200be45495516549Ben Murdoch  __ ret((HasArgsInRegisters() ? 0 : 2) * kPointerSize);
4651b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
4652b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ bind(&object_not_null_or_smi);
4653b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // String values is not instance of anything.
4654b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  Condition is_string = masm->IsObjectStringType(object, scratch, scratch);
4655b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ j(NegateCondition(is_string), &slow);
4656b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ Set(eax, Immediate(Smi::FromInt(1)));
4657086aeeaae12517475c22695a200be45495516549Ben Murdoch  __ ret((HasArgsInRegisters() ? 0 : 2) * kPointerSize);
465880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
465980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Slow-case: Go through the JavaScript implementation.
466080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&slow);
4661086aeeaae12517475c22695a200be45495516549Ben Murdoch  if (!ReturnTrueFalseObject()) {
4662086aeeaae12517475c22695a200be45495516549Ben Murdoch    // Tail call the builtin which returns 0 or 1.
4663086aeeaae12517475c22695a200be45495516549Ben Murdoch    if (HasArgsInRegisters()) {
4664086aeeaae12517475c22695a200be45495516549Ben Murdoch      // Push arguments below return address.
4665086aeeaae12517475c22695a200be45495516549Ben Murdoch      __ pop(scratch);
4666086aeeaae12517475c22695a200be45495516549Ben Murdoch      __ push(object);
4667086aeeaae12517475c22695a200be45495516549Ben Murdoch      __ push(function);
4668086aeeaae12517475c22695a200be45495516549Ben Murdoch      __ push(scratch);
4669086aeeaae12517475c22695a200be45495516549Ben Murdoch    }
4670086aeeaae12517475c22695a200be45495516549Ben Murdoch    __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION);
4671086aeeaae12517475c22695a200be45495516549Ben Murdoch  } else {
4672086aeeaae12517475c22695a200be45495516549Ben Murdoch    // Call the builtin and convert 0/1 to true/false.
4673086aeeaae12517475c22695a200be45495516549Ben Murdoch    __ EnterInternalFrame();
4674b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ push(object);
4675b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ push(function);
4676086aeeaae12517475c22695a200be45495516549Ben Murdoch    __ InvokeBuiltin(Builtins::INSTANCE_OF, CALL_FUNCTION);
4677086aeeaae12517475c22695a200be45495516549Ben Murdoch    __ LeaveInternalFrame();
4678257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Label true_value, done;
4679086aeeaae12517475c22695a200be45495516549Ben Murdoch    __ test(eax, Operand(eax));
4680257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ j(zero, &true_value, Label::kNear);
468144f0eee88ff00398ff7f715fab053374d808c90dSteve Block    __ mov(eax, factory->false_value());
4682257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ jmp(&done, Label::kNear);
4683086aeeaae12517475c22695a200be45495516549Ben Murdoch    __ bind(&true_value);
468444f0eee88ff00398ff7f715fab053374d808c90dSteve Block    __ mov(eax, factory->true_value());
4685086aeeaae12517475c22695a200be45495516549Ben Murdoch    __ bind(&done);
4686086aeeaae12517475c22695a200be45495516549Ben Murdoch    __ ret((HasArgsInRegisters() ? 0 : 2) * kPointerSize);
4687b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  }
468880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
468980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
469080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
4691086aeeaae12517475c22695a200be45495516549Ben MurdochRegister InstanceofStub::left() { return eax; }
4692086aeeaae12517475c22695a200be45495516549Ben Murdoch
4693086aeeaae12517475c22695a200be45495516549Ben Murdoch
4694086aeeaae12517475c22695a200be45495516549Ben MurdochRegister InstanceofStub::right() { return edx; }
4695086aeeaae12517475c22695a200be45495516549Ben Murdoch
4696086aeeaae12517475c22695a200be45495516549Ben Murdoch
469780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenint CompareStub::MinorKey() {
469880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Encode the three parameters in a unique 16 bit value. To avoid duplicate
469980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // stubs the never NaN NaN condition is only taken into account if the
470080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // condition is equals.
470180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  ASSERT(static_cast<unsigned>(cc_) < (1 << 12));
470280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  ASSERT(lhs_.is(no_reg) && rhs_.is(no_reg));
470380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  return ConditionField::encode(static_cast<unsigned>(cc_))
470480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen         | RegisterField::encode(false)   // lhs_ and rhs_ are not used
470580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen         | StrictField::encode(strict_)
470680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen         | NeverNanNanField::encode(cc_ == equal ? never_nan_nan_ : false)
47070d5e116f6aee03185f237311a943491bb079a768Kristian Monsen         | IncludeNumberCompareField::encode(include_number_compare_)
47080d5e116f6aee03185f237311a943491bb079a768Kristian Monsen         | IncludeSmiCompareField::encode(include_smi_compare_);
470980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
471080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
471180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
471280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// Unfortunately you have to run without snapshots to see most of these
471380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// names in the profile since most compare stubs end up in the snapshot.
47143fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdochvoid CompareStub::PrintName(StringStream* stream) {
471580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  ASSERT(lhs_.is(no_reg) && rhs_.is(no_reg));
471680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  const char* cc_name;
471780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  switch (cc_) {
471880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    case less: cc_name = "LT"; break;
471980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    case greater: cc_name = "GT"; break;
472080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    case less_equal: cc_name = "LE"; break;
472180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    case greater_equal: cc_name = "GE"; break;
472280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    case equal: cc_name = "EQ"; break;
472380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    case not_equal: cc_name = "NE"; break;
472480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    default: cc_name = "UnknownCondition"; break;
472580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
47263fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  bool is_equality = cc_ == equal || cc_ == not_equal;
47273fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  stream->Add("CompareStub_%s", cc_name);
47283fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  if (strict_ && is_equality) stream->Add("_STRICT");
47293fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  if (never_nan_nan_ && is_equality) stream->Add("_NO_NAN");
47303fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  if (!include_number_compare_) stream->Add("_NO_NUMBER");
47313fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  if (!include_smi_compare_) stream->Add("_NO_SMI");
473280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
473380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
473480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
473580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// -------------------------------------------------------------------------
473680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// StringCharCodeAtGenerator
473780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
473880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StringCharCodeAtGenerator::GenerateFast(MacroAssembler* masm) {
473980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label flat_string;
474080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label ascii_string;
474180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label got_char_code;
474280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
474380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // If the receiver is a smi trigger the non-string case.
474480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  STATIC_ASSERT(kSmiTag == 0);
47453fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ JumpIfSmi(object_, receiver_not_string_);
474680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
474780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Fetch the instance type of the receiver into result register.
474880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(result_, FieldOperand(object_, HeapObject::kMapOffset));
474980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movzx_b(result_, FieldOperand(result_, Map::kInstanceTypeOffset));
475080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // If the receiver is not a string trigger the non-string case.
475180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ test(result_, Immediate(kIsNotStringMask));
475280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(not_zero, receiver_not_string_);
475380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
475480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // If the index is non-smi trigger the non-smi case.
475580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  STATIC_ASSERT(kSmiTag == 0);
47563fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ JumpIfNotSmi(index_, &index_not_smi_);
475780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
475880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Put smi-tagged index into scratch register.
475980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(scratch_, index_);
476080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&got_smi_index_);
476180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
476280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check for index out of range.
476380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cmp(scratch_, FieldOperand(object_, String::kLengthOffset));
476480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(above_equal, index_out_of_range_);
476580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
476680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // We need special handling for non-flat strings.
476780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  STATIC_ASSERT(kSeqStringTag == 0);
476880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ test(result_, Immediate(kStringRepresentationMask));
476980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(zero, &flat_string);
477080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
477180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Handle non-flat strings.
477280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ test(result_, Immediate(kIsConsStringMask));
477380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(zero, &call_runtime_);
477480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
477580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // ConsString.
477680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check whether the right hand side is the empty string (i.e. if
477780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // this is really a flat string in a cons string). If that is not
477880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // the case we would rather go to the runtime system now to flatten
477980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // the string.
478080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cmp(FieldOperand(object_, ConsString::kSecondOffset),
478144f0eee88ff00398ff7f715fab053374d808c90dSteve Block         Immediate(masm->isolate()->factory()->empty_string()));
478280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(not_equal, &call_runtime_);
478380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Get the first of the two strings and load its instance type.
478480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(object_, FieldOperand(object_, ConsString::kFirstOffset));
478580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(result_, FieldOperand(object_, HeapObject::kMapOffset));
478680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movzx_b(result_, FieldOperand(result_, Map::kInstanceTypeOffset));
478780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // If the first cons component is also non-flat, then go to runtime.
478880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  STATIC_ASSERT(kSeqStringTag == 0);
478980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ test(result_, Immediate(kStringRepresentationMask));
479080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(not_zero, &call_runtime_);
479180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
479280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check for 1-byte or 2-byte string.
479380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&flat_string);
479480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  STATIC_ASSERT(kAsciiStringTag != 0);
479580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ test(result_, Immediate(kStringEncodingMask));
479680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(not_zero, &ascii_string);
479780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
479880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // 2-byte string.
479980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Load the 2-byte character code into the result register.
480080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize == 1);
480180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movzx_w(result_, FieldOperand(object_,
480280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                   scratch_, times_1,  // Scratch is smi-tagged.
480380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                   SeqTwoByteString::kHeaderSize));
480480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ jmp(&got_char_code);
480580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
480680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // ASCII string.
480780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Load the byte into the result register.
480880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&ascii_string);
480980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiUntag(scratch_);
481080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movzx_b(result_, FieldOperand(object_,
481180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                   scratch_, times_1,
481280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                   SeqAsciiString::kHeaderSize));
481380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&got_char_code);
481480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiTag(result_);
481580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&exit_);
481680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
481780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
481880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
481980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StringCharCodeAtGenerator::GenerateSlow(
482080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    MacroAssembler* masm, const RuntimeCallHelper& call_helper) {
482180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ Abort("Unexpected fallthrough to CharCodeAt slow case");
482280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
482380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Index is not a smi.
482480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&index_not_smi_);
482580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // If index is a heap number, try converting it to an integer.
482644f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ CheckMap(index_,
482744f0eee88ff00398ff7f715fab053374d808c90dSteve Block              masm->isolate()->factory()->heap_number_map(),
482844f0eee88ff00398ff7f715fab053374d808c90dSteve Block              index_not_number_,
4829257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch              DONT_DO_SMI_CHECK);
483080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  call_helper.BeforeCall(masm);
483180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ push(object_);
483280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ push(index_);
483380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ push(index_);  // Consumed by runtime conversion function.
483480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  if (index_flags_ == STRING_INDEX_IS_NUMBER) {
483580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ CallRuntime(Runtime::kNumberToIntegerMapMinusZero, 1);
483680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  } else {
483780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    ASSERT(index_flags_ == STRING_INDEX_IS_ARRAY_INDEX);
483880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // NumberToSmi discards numbers that are not exact integers.
483980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ CallRuntime(Runtime::kNumberToSmi, 1);
484080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
484180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  if (!scratch_.is(eax)) {
484280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // Save the conversion result before the pop instructions below
484380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // have a chance to overwrite it.
484480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ mov(scratch_, eax);
484580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
484680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ pop(index_);
484780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ pop(object_);
484880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Reload the instance type.
484980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(result_, FieldOperand(object_, HeapObject::kMapOffset));
485080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movzx_b(result_, FieldOperand(result_, Map::kInstanceTypeOffset));
485180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  call_helper.AfterCall(masm);
485280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // If index is still not a smi, it must be out of range.
485380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  STATIC_ASSERT(kSmiTag == 0);
48543fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ JumpIfNotSmi(scratch_, index_out_of_range_);
485580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Otherwise, return to the fast path.
485680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ jmp(&got_smi_index_);
485780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
485880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Call runtime. We get here when the receiver is a string and the
485980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // index is a number, but the code of getting the actual character
486080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // is too complex (e.g., when the string needs to be flattened).
486180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&call_runtime_);
486280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  call_helper.BeforeCall(masm);
486380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ push(object_);
486480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ push(index_);
486580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ CallRuntime(Runtime::kStringCharCodeAt, 2);
486680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  if (!result_.is(eax)) {
486780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ mov(result_, eax);
486880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
486980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  call_helper.AfterCall(masm);
487080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ jmp(&exit_);
487180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
487280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ Abort("Unexpected fallthrough from CharCodeAt slow case");
487380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
487480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
487580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
487680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// -------------------------------------------------------------------------
487780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// StringCharFromCodeGenerator
487880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
487980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StringCharFromCodeGenerator::GenerateFast(MacroAssembler* masm) {
488080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Fast case of Heap::LookupSingleCharacterStringFromCode.
488180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  STATIC_ASSERT(kSmiTag == 0);
488280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  STATIC_ASSERT(kSmiShiftSize == 0);
488380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  ASSERT(IsPowerOf2(String::kMaxAsciiCharCode + 1));
488480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ test(code_,
488580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen          Immediate(kSmiTagMask |
488680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                    ((~String::kMaxAsciiCharCode) << kSmiTagSize)));
4887257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(not_zero, &slow_case_);
488880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
488944f0eee88ff00398ff7f715fab053374d808c90dSteve Block  Factory* factory = masm->isolate()->factory();
489044f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ Set(result_, Immediate(factory->single_character_string_cache()));
489180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  STATIC_ASSERT(kSmiTag == 0);
489280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  STATIC_ASSERT(kSmiTagSize == 1);
489380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  STATIC_ASSERT(kSmiShiftSize == 0);
489480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // At this point code register contains smi tagged ascii char code.
489580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(result_, FieldOperand(result_,
489680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                               code_, times_half_pointer_size,
489780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                               FixedArray::kHeaderSize));
489844f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ cmp(result_, factory->undefined_value());
4899257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(equal, &slow_case_);
490080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&exit_);
490180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
490280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
490380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
490480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StringCharFromCodeGenerator::GenerateSlow(
490580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    MacroAssembler* masm, const RuntimeCallHelper& call_helper) {
490680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ Abort("Unexpected fallthrough to CharFromCode slow case");
490780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
490880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&slow_case_);
490980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  call_helper.BeforeCall(masm);
491080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ push(code_);
491180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ CallRuntime(Runtime::kCharFromCode, 1);
491280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  if (!result_.is(eax)) {
491380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ mov(result_, eax);
491480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
491580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  call_helper.AfterCall(masm);
491680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ jmp(&exit_);
491780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
491880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ Abort("Unexpected fallthrough from CharFromCode slow case");
491980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
492080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
492180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
492280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// -------------------------------------------------------------------------
492380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// StringCharAtGenerator
492480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
492580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StringCharAtGenerator::GenerateFast(MacroAssembler* masm) {
492680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  char_code_at_generator_.GenerateFast(masm);
492780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  char_from_code_generator_.GenerateFast(masm);
492880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
492980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
493080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
493180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StringCharAtGenerator::GenerateSlow(
493280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    MacroAssembler* masm, const RuntimeCallHelper& call_helper) {
493380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  char_code_at_generator_.GenerateSlow(masm, call_helper);
493480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  char_from_code_generator_.GenerateSlow(masm, call_helper);
493580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
493680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
493780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
493880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StringAddStub::Generate(MacroAssembler* masm) {
49399ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick  Label string_add_runtime, call_builtin;
49409ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick  Builtins::JavaScript builtin_id = Builtins::ADD;
494180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
494280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Load the two arguments.
494380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(eax, Operand(esp, 2 * kPointerSize));  // First argument.
494480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(edx, Operand(esp, 1 * kPointerSize));  // Second argument.
494580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
494680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Make sure that both arguments are strings if not known in advance.
49479ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick  if (flags_ == NO_STRING_ADD_FLAGS) {
49483fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    __ JumpIfSmi(eax, &string_add_runtime);
494980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ CmpObjectType(eax, FIRST_NONSTRING_TYPE, ebx);
495080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ j(above_equal, &string_add_runtime);
495180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
495280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // First argument is a a string, test second.
49533fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    __ JumpIfSmi(edx, &string_add_runtime);
495480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ CmpObjectType(edx, FIRST_NONSTRING_TYPE, ebx);
495580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ j(above_equal, &string_add_runtime);
49569ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick  } else {
49579ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick    // Here at least one of the arguments is definitely a string.
49589ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick    // We convert the one that is not known to be a string.
49599ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick    if ((flags_ & NO_STRING_CHECK_LEFT_IN_STUB) == 0) {
49609ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick      ASSERT((flags_ & NO_STRING_CHECK_RIGHT_IN_STUB) != 0);
49619ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick      GenerateConvertArgument(masm, 2 * kPointerSize, eax, ebx, ecx, edi,
49629ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick                              &call_builtin);
49639ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick      builtin_id = Builtins::STRING_ADD_RIGHT;
49649ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick    } else if ((flags_ & NO_STRING_CHECK_RIGHT_IN_STUB) == 0) {
49659ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick      ASSERT((flags_ & NO_STRING_CHECK_LEFT_IN_STUB) != 0);
49669ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick      GenerateConvertArgument(masm, 1 * kPointerSize, edx, ebx, ecx, edi,
49679ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick                              &call_builtin);
49689ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick      builtin_id = Builtins::STRING_ADD_LEFT;
49699ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick    }
497080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
497180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
497280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Both arguments are strings.
497380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // eax: first string
497480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // edx: second string
497580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check if either of the strings are empty. In that case return the other.
4976257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label second_not_zero_length, both_not_zero_length;
497780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(ecx, FieldOperand(edx, String::kLengthOffset));
497880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  STATIC_ASSERT(kSmiTag == 0);
497980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ test(ecx, Operand(ecx));
4980257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(not_zero, &second_not_zero_length, Label::kNear);
498180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Second string is empty, result is first string which is already in eax.
498244f0eee88ff00398ff7f715fab053374d808c90dSteve Block  Counters* counters = masm->isolate()->counters();
498344f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ IncrementCounter(counters->string_add_native(), 1);
498480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ ret(2 * kPointerSize);
498580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&second_not_zero_length);
498680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(ebx, FieldOperand(eax, String::kLengthOffset));
498780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  STATIC_ASSERT(kSmiTag == 0);
498880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ test(ebx, Operand(ebx));
4989257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(not_zero, &both_not_zero_length, Label::kNear);
499080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // First string is empty, result is second string which is in edx.
499180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(eax, edx);
499244f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ IncrementCounter(counters->string_add_native(), 1);
499380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ ret(2 * kPointerSize);
499480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
499580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Both strings are non-empty.
499680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // eax: first string
499780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // ebx: length of first string as a smi
499880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // ecx: length of second string as a smi
499980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // edx: second string
500080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Look at the length of the result of adding the two strings.
500180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label string_add_flat_result, longer_than_two;
500280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&both_not_zero_length);
500380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ add(ebx, Operand(ecx));
500480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  STATIC_ASSERT(Smi::kMaxValue == String::kMaxLength);
500580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Handle exceptionally long strings in the runtime system.
500680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(overflow, &string_add_runtime);
500744f0eee88ff00398ff7f715fab053374d808c90dSteve Block  // Use the symbol table when adding two one character strings, as it
500844f0eee88ff00398ff7f715fab053374d808c90dSteve Block  // helps later optimizations to return a symbol here.
500980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cmp(Operand(ebx), Immediate(Smi::FromInt(2)));
501080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(not_equal, &longer_than_two);
501180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
501280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check that both strings are non-external ascii strings.
501380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ JumpIfNotBothSequentialAsciiStrings(eax, edx, ebx, ecx,
501480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                         &string_add_runtime);
501580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
50169ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick  // Get the two characters forming the new string.
501780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movzx_b(ebx, FieldOperand(eax, SeqAsciiString::kHeaderSize));
501880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movzx_b(ecx, FieldOperand(edx, SeqAsciiString::kHeaderSize));
501980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
502080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Try to lookup two character string in symbol table. If it is not found
502180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // just allocate a new one.
50229ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick  Label make_two_character_string, make_two_character_string_no_reload;
502380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  StringHelper::GenerateTwoCharacterSymbolTableProbe(
50249ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick      masm, ebx, ecx, eax, edx, edi,
50259ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick      &make_two_character_string_no_reload, &make_two_character_string);
502644f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ IncrementCounter(counters->string_add_native(), 1);
502780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ ret(2 * kPointerSize);
502880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
50299ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick  // Allocate a two character string.
503080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&make_two_character_string);
50319ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick  // Reload the arguments.
50329ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick  __ mov(eax, Operand(esp, 2 * kPointerSize));  // First argument.
50339ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick  __ mov(edx, Operand(esp, 1 * kPointerSize));  // Second argument.
50349ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick  // Get the two characters forming the new string.
50359ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick  __ movzx_b(ebx, FieldOperand(eax, SeqAsciiString::kHeaderSize));
50369ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick  __ movzx_b(ecx, FieldOperand(edx, SeqAsciiString::kHeaderSize));
50379ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick  __ bind(&make_two_character_string_no_reload);
503844f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ IncrementCounter(counters->string_add_make_two_char(), 1);
50399ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick  __ AllocateAsciiString(eax,  // Result.
50409ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick                         2,    // Length.
50419ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick                         edi,  // Scratch 1.
50429ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick                         edx,  // Scratch 2.
50439ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick                         &string_add_runtime);
50449ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick  // Pack both characters in ebx.
50459ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick  __ shl(ecx, kBitsPerByte);
50469ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick  __ or_(ebx, Operand(ecx));
50479ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick  // Set the characters in the new string.
50489ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick  __ mov_w(FieldOperand(eax, SeqAsciiString::kHeaderSize), ebx);
504944f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ IncrementCounter(counters->string_add_native(), 1);
50509ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick  __ ret(2 * kPointerSize);
505180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
505280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&longer_than_two);
505380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check if resulting string will be flat.
505480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cmp(Operand(ebx), Immediate(Smi::FromInt(String::kMinNonFlatLength)));
505580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(below, &string_add_flat_result);
505680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
505780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // If result is not supposed to be flat allocate a cons string object. If both
505880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // strings are ascii the result is an ascii cons string.
505980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label non_ascii, allocated, ascii_data;
506080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(edi, FieldOperand(eax, HeapObject::kMapOffset));
506180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movzx_b(ecx, FieldOperand(edi, Map::kInstanceTypeOffset));
506280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(edi, FieldOperand(edx, HeapObject::kMapOffset));
506380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movzx_b(edi, FieldOperand(edi, Map::kInstanceTypeOffset));
506480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ and_(ecx, Operand(edi));
506580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  STATIC_ASSERT(kStringEncodingMask == kAsciiStringTag);
506680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ test(ecx, Immediate(kAsciiStringTag));
506780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(zero, &non_ascii);
506880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&ascii_data);
506980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Allocate an acsii cons string.
507080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ AllocateAsciiConsString(ecx, edi, no_reg, &string_add_runtime);
507180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&allocated);
507280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Fill the fields of the cons string.
507380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  if (FLAG_debug_code) __ AbortIfNotSmi(ebx);
507480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(FieldOperand(ecx, ConsString::kLengthOffset), ebx);
507580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(FieldOperand(ecx, ConsString::kHashFieldOffset),
507680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen         Immediate(String::kEmptyHashField));
507780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(FieldOperand(ecx, ConsString::kFirstOffset), eax);
507880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(FieldOperand(ecx, ConsString::kSecondOffset), edx);
507980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(eax, ecx);
508044f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ IncrementCounter(counters->string_add_native(), 1);
508180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ ret(2 * kPointerSize);
508280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&non_ascii);
508380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // At least one of the strings is two-byte. Check whether it happens
508480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // to contain only ascii characters.
508580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // ecx: first instance type AND second instance type.
508680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // edi: second instance type.
508780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ test(ecx, Immediate(kAsciiDataHintMask));
508880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(not_zero, &ascii_data);
508980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(ecx, FieldOperand(eax, HeapObject::kMapOffset));
509080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset));
509180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ xor_(edi, Operand(ecx));
509280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  STATIC_ASSERT(kAsciiStringTag != 0 && kAsciiDataHintTag != 0);
509380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ and_(edi, kAsciiStringTag | kAsciiDataHintTag);
509480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cmp(edi, kAsciiStringTag | kAsciiDataHintTag);
509580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(equal, &ascii_data);
509680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Allocate a two byte cons string.
509780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ AllocateConsString(ecx, edi, no_reg, &string_add_runtime);
509880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ jmp(&allocated);
509980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
510080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Handle creating a flat result. First check that both strings are not
510180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // external strings.
510280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // eax: first string
510380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // ebx: length of resulting flat string as a smi
510480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // edx: second string
510580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&string_add_flat_result);
510680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(ecx, FieldOperand(eax, HeapObject::kMapOffset));
510780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset));
510880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ and_(ecx, kStringRepresentationMask);
510980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cmp(ecx, kExternalStringTag);
511080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(equal, &string_add_runtime);
511180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset));
511280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset));
511380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ and_(ecx, kStringRepresentationMask);
511480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cmp(ecx, kExternalStringTag);
511580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(equal, &string_add_runtime);
511680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Now check if both strings are ascii strings.
511780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // eax: first string
511880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // ebx: length of resulting flat string as a smi
511980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // edx: second string
512080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label non_ascii_string_add_flat_result;
512180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  STATIC_ASSERT(kStringEncodingMask == kAsciiStringTag);
512280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(ecx, FieldOperand(eax, HeapObject::kMapOffset));
512380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ test_b(FieldOperand(ecx, Map::kInstanceTypeOffset), kAsciiStringTag);
512480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(zero, &non_ascii_string_add_flat_result);
512580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset));
512680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ test_b(FieldOperand(ecx, Map::kInstanceTypeOffset), kAsciiStringTag);
512780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(zero, &string_add_runtime);
512880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
512980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Both strings are ascii strings.  As they are short they are both flat.
513080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // ebx: length of resulting flat string as a smi
513180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiUntag(ebx);
513280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ AllocateAsciiString(eax, ebx, ecx, edx, edi, &string_add_runtime);
513380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // eax: result string
513480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(ecx, eax);
513580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Locate first character of result.
513680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ add(Operand(ecx), Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag));
513780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Load first argument and locate first character.
513880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(edx, Operand(esp, 2 * kPointerSize));
513980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(edi, FieldOperand(edx, String::kLengthOffset));
514080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiUntag(edi);
514180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ add(Operand(edx), Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag));
514280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // eax: result string
514380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // ecx: first character of result
514480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // edx: first char of first argument
514580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // edi: length of first argument
514680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  StringHelper::GenerateCopyCharacters(masm, ecx, edx, edi, ebx, true);
514780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Load second argument and locate first character.
514880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(edx, Operand(esp, 1 * kPointerSize));
514980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(edi, FieldOperand(edx, String::kLengthOffset));
515080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiUntag(edi);
515180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ add(Operand(edx), Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag));
515280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // eax: result string
515380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // ecx: next character of result
515480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // edx: first char of second argument
515580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // edi: length of second argument
515680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  StringHelper::GenerateCopyCharacters(masm, ecx, edx, edi, ebx, true);
515744f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ IncrementCounter(counters->string_add_native(), 1);
515880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ ret(2 * kPointerSize);
515980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
516080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Handle creating a flat two byte result.
516180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // eax: first string - known to be two byte
516280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // ebx: length of resulting flat string as a smi
516380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // edx: second string
516480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&non_ascii_string_add_flat_result);
516580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset));
516680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ test_b(FieldOperand(ecx, Map::kInstanceTypeOffset), kAsciiStringTag);
516780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(not_zero, &string_add_runtime);
516880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Both strings are two byte strings. As they are short they are both
516980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // flat.
517080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiUntag(ebx);
517180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ AllocateTwoByteString(eax, ebx, ecx, edx, edi, &string_add_runtime);
517280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // eax: result string
517380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(ecx, eax);
517480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Locate first character of result.
517580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ add(Operand(ecx),
517680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen         Immediate(SeqTwoByteString::kHeaderSize - kHeapObjectTag));
517780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Load first argument and locate first character.
517880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(edx, Operand(esp, 2 * kPointerSize));
517980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(edi, FieldOperand(edx, String::kLengthOffset));
518080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiUntag(edi);
518180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ add(Operand(edx),
518280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen         Immediate(SeqTwoByteString::kHeaderSize - kHeapObjectTag));
518380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // eax: result string
518480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // ecx: first character of result
518580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // edx: first char of first argument
518680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // edi: length of first argument
518780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  StringHelper::GenerateCopyCharacters(masm, ecx, edx, edi, ebx, false);
518880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Load second argument and locate first character.
518980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(edx, Operand(esp, 1 * kPointerSize));
519080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(edi, FieldOperand(edx, String::kLengthOffset));
519180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiUntag(edi);
519280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ add(Operand(edx), Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag));
519380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // eax: result string
519480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // ecx: next character of result
519580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // edx: first char of second argument
519680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // edi: length of second argument
519780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  StringHelper::GenerateCopyCharacters(masm, ecx, edx, edi, ebx, false);
519844f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ IncrementCounter(counters->string_add_native(), 1);
519980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ ret(2 * kPointerSize);
520080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
520180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Just jump to runtime to add the two strings.
520280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&string_add_runtime);
520380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ TailCallRuntime(Runtime::kStringAdd, 2, 1);
52049ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick
52059ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick  if (call_builtin.is_linked()) {
52069ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick    __ bind(&call_builtin);
52079ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick    __ InvokeBuiltin(builtin_id, JUMP_FUNCTION);
52089ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick  }
52099ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick}
52109ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick
52119ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick
52129ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrickvoid StringAddStub::GenerateConvertArgument(MacroAssembler* masm,
52139ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick                                            int stack_offset,
52149ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick                                            Register arg,
52159ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick                                            Register scratch1,
52169ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick                                            Register scratch2,
52179ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick                                            Register scratch3,
52189ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick                                            Label* slow) {
52199ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick  // First check if the argument is already a string.
52209ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick  Label not_string, done;
52213fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ JumpIfSmi(arg, &not_string);
52229ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick  __ CmpObjectType(arg, FIRST_NONSTRING_TYPE, scratch1);
52239ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick  __ j(below, &done);
52249ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick
52259ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick  // Check the number to string cache.
52269ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick  Label not_cached;
52279ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick  __ bind(&not_string);
52289ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick  // Puts the cached result into scratch1.
52299ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick  NumberToStringStub::GenerateLookupNumberStringCache(masm,
52309ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick                                                      arg,
52319ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick                                                      scratch1,
52329ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick                                                      scratch2,
52339ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick                                                      scratch3,
52349ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick                                                      false,
52359ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick                                                      &not_cached);
52369ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick  __ mov(arg, scratch1);
52379ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick  __ mov(Operand(esp, stack_offset), arg);
52389ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick  __ jmp(&done);
52399ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick
52409ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick  // Check if the argument is a safe string wrapper.
52419ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick  __ bind(&not_cached);
52423fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ JumpIfSmi(arg, slow);
52439ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick  __ CmpObjectType(arg, JS_VALUE_TYPE, scratch1);  // map -> scratch1.
52449ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick  __ j(not_equal, slow);
52459ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick  __ test_b(FieldOperand(scratch1, Map::kBitField2Offset),
52469ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick            1 << Map::kStringWrapperSafeForDefaultValueOf);
52479ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick  __ j(zero, slow);
52489ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick  __ mov(arg, FieldOperand(arg, JSValue::kValueOffset));
52499ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick  __ mov(Operand(esp, stack_offset), arg);
52509ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick
52519ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick  __ bind(&done);
525280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
525380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
525480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
525580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StringHelper::GenerateCopyCharacters(MacroAssembler* masm,
525680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                          Register dest,
525780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                          Register src,
525880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                          Register count,
525980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                          Register scratch,
526080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                          bool ascii) {
5261257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label loop;
526280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&loop);
526380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // This loop just copies one character at a time, as it is only used for very
526480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // short strings.
526580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  if (ascii) {
526680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ mov_b(scratch, Operand(src, 0));
526780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ mov_b(Operand(dest, 0), scratch);
526880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ add(Operand(src), Immediate(1));
526980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ add(Operand(dest), Immediate(1));
527080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  } else {
527180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ mov_w(scratch, Operand(src, 0));
527280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ mov_w(Operand(dest, 0), scratch);
527380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ add(Operand(src), Immediate(2));
527480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ add(Operand(dest), Immediate(2));
527580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
527680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ sub(Operand(count), Immediate(1));
527780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(not_zero, &loop);
527880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
527980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
528080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
528180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StringHelper::GenerateCopyCharactersREP(MacroAssembler* masm,
528280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                             Register dest,
528380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                             Register src,
528480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                             Register count,
528580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                             Register scratch,
528680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                             bool ascii) {
528780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Copy characters using rep movs of doublewords.
528880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // The destination is aligned on a 4 byte boundary because we are
528980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // copying to the beginning of a newly allocated string.
529080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  ASSERT(dest.is(edi));  // rep movs destination
529180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  ASSERT(src.is(esi));  // rep movs source
529280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  ASSERT(count.is(ecx));  // rep movs count
529380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  ASSERT(!scratch.is(dest));
529480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  ASSERT(!scratch.is(src));
529580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  ASSERT(!scratch.is(count));
529680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
529780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Nothing to do for zero characters.
529880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label done;
529980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ test(count, Operand(count));
530080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(zero, &done);
530180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
530280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Make count the number of bytes to copy.
530380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  if (!ascii) {
530480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ shl(count, 1);
530580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
530680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
530780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Don't enter the rep movs if there are less than 4 bytes to copy.
5308257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label last_bytes;
530980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ test(count, Immediate(~3));
5310257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(zero, &last_bytes, Label::kNear);
531180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
531280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Copy from edi to esi using rep movs instruction.
531380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(scratch, count);
531480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ sar(count, 2);  // Number of doublewords to copy.
531580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cld();
531680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ rep_movs();
531780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
531880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Find number of bytes left.
531980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(count, scratch);
532080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ and_(count, 3);
532180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
532280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check if there are more bytes to copy.
532380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&last_bytes);
532480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ test(count, Operand(count));
532580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(zero, &done);
532680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
532780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Copy remaining characters.
5328257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label loop;
532980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&loop);
533080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov_b(scratch, Operand(src, 0));
533180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov_b(Operand(dest, 0), scratch);
533280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ add(Operand(src), Immediate(1));
533380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ add(Operand(dest), Immediate(1));
533480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ sub(Operand(count), Immediate(1));
533580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(not_zero, &loop);
533680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
533780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&done);
533880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
533980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
534080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
534180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StringHelper::GenerateTwoCharacterSymbolTableProbe(MacroAssembler* masm,
534280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                                        Register c1,
534380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                                        Register c2,
534480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                                        Register scratch1,
534580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                                        Register scratch2,
534680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                                        Register scratch3,
53479ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick                                                        Label* not_probed,
534880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                                        Label* not_found) {
534980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Register scratch3 is the general scratch register in this function.
535080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Register scratch = scratch3;
535180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
535280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Make sure that both characters are not digits as such strings has a
535380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // different hash algorithm. Don't try to look for these in the symbol table.
5354257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label not_array_index;
535580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(scratch, c1);
535680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ sub(Operand(scratch), Immediate(static_cast<int>('0')));
535780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cmp(Operand(scratch), Immediate(static_cast<int>('9' - '0')));
5358257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(above, &not_array_index, Label::kNear);
535980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(scratch, c2);
536080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ sub(Operand(scratch), Immediate(static_cast<int>('0')));
536180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cmp(Operand(scratch), Immediate(static_cast<int>('9' - '0')));
53629ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick  __ j(below_equal, not_probed);
536380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
536480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&not_array_index);
536580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Calculate the two character string hash.
536680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Register hash = scratch1;
536780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  GenerateHashInit(masm, hash, c1, scratch);
536880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  GenerateHashAddCharacter(masm, hash, c2, scratch);
536980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  GenerateHashGetHash(masm, hash, scratch);
537080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
537180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Collect the two characters in a register.
537280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Register chars = c1;
537380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ shl(c2, kBitsPerByte);
537480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ or_(chars, Operand(c2));
537580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
537680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // chars: two character string, char 1 in byte 0 and char 2 in byte 1.
537780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // hash:  hash of two character string.
537880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
537980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Load the symbol table.
538080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Register symbol_table = c2;
538144f0eee88ff00398ff7f715fab053374d808c90dSteve Block  ExternalReference roots_address =
538244f0eee88ff00398ff7f715fab053374d808c90dSteve Block      ExternalReference::roots_address(masm->isolate());
538380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(scratch, Immediate(Heap::kSymbolTableRootIndex));
538480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(symbol_table,
538580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen         Operand::StaticArray(scratch, times_pointer_size, roots_address));
538680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
538780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Calculate capacity mask from the symbol table capacity.
538880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Register mask = scratch2;
538980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(mask, FieldOperand(symbol_table, SymbolTable::kCapacityOffset));
539080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiUntag(mask);
539180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ sub(Operand(mask), Immediate(1));
539280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
539380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Registers
539480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // chars:        two character string, char 1 in byte 0 and char 2 in byte 1.
539580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // hash:         hash of two character string
539680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // symbol_table: symbol table
539780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // mask:         capacity mask
539880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // scratch:      -
539980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
540080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Perform a number of probes in the symbol table.
540180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  static const int kProbes = 4;
540280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label found_in_symbol_table;
540380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label next_probe[kProbes], next_probe_pop_mask[kProbes];
540480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  for (int i = 0; i < kProbes; i++) {
540580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // Calculate entry in symbol table.
540680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ mov(scratch, hash);
540780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    if (i > 0) {
540880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ add(Operand(scratch), Immediate(SymbolTable::GetProbeOffset(i)));
540980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    }
541080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ and_(scratch, Operand(mask));
541180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
541280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // Load the entry from the symbol table.
541380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    Register candidate = scratch;  // Scratch register contains candidate.
541480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    STATIC_ASSERT(SymbolTable::kEntrySize == 1);
541580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ mov(candidate,
541680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen           FieldOperand(symbol_table,
541780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                        scratch,
541880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                        times_pointer_size,
541980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                        SymbolTable::kElementsStartOffset));
542080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
542180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // If entry is undefined no string with this hash can be found.
542244f0eee88ff00398ff7f715fab053374d808c90dSteve Block    Factory* factory = masm->isolate()->factory();
542344f0eee88ff00398ff7f715fab053374d808c90dSteve Block    __ cmp(candidate, factory->undefined_value());
542480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ j(equal, not_found);
542544f0eee88ff00398ff7f715fab053374d808c90dSteve Block    __ cmp(candidate, factory->null_value());
542644f0eee88ff00398ff7f715fab053374d808c90dSteve Block    __ j(equal, &next_probe[i]);
542780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
542880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // If length is not 2 the string is not a candidate.
542980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ cmp(FieldOperand(candidate, String::kLengthOffset),
543080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen           Immediate(Smi::FromInt(2)));
543180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ j(not_equal, &next_probe[i]);
543280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
543380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // As we are out of registers save the mask on the stack and use that
543480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // register as a temporary.
543580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ push(mask);
543680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    Register temp = mask;
543780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
543880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // Check that the candidate is a non-external ascii string.
543980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ mov(temp, FieldOperand(candidate, HeapObject::kMapOffset));
544080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ movzx_b(temp, FieldOperand(temp, Map::kInstanceTypeOffset));
544180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ JumpIfInstanceTypeIsNotSequentialAscii(
544280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen        temp, temp, &next_probe_pop_mask[i]);
544380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
544480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // Check if the two characters match.
544580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ mov(temp, FieldOperand(candidate, SeqAsciiString::kHeaderSize));
544680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ and_(temp, 0x0000ffff);
544780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ cmp(chars, Operand(temp));
544880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ j(equal, &found_in_symbol_table);
544980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ bind(&next_probe_pop_mask[i]);
545080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ pop(mask);
545180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ bind(&next_probe[i]);
545280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
545380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
545480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // No matching 2 character string found by probing.
545580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ jmp(not_found);
545680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
545780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Scratch register contains result when we fall through to here.
545880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Register result = scratch;
545980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&found_in_symbol_table);
546080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ pop(mask);  // Pop saved mask from the stack.
546180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  if (!result.is(eax)) {
546280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ mov(eax, result);
546380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
546480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
546580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
546680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
546780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StringHelper::GenerateHashInit(MacroAssembler* masm,
546880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                    Register hash,
546980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                    Register character,
547080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                    Register scratch) {
547180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // hash = character + (character << 10);
547280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(hash, character);
547380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ shl(hash, 10);
547480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ add(hash, Operand(character));
547580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // hash ^= hash >> 6;
547680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(scratch, hash);
547780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ sar(scratch, 6);
547880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ xor_(hash, Operand(scratch));
547980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
548080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
548180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
548280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StringHelper::GenerateHashAddCharacter(MacroAssembler* masm,
548380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                            Register hash,
548480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                            Register character,
548580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                            Register scratch) {
548680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // hash += character;
548780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ add(hash, Operand(character));
548880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // hash += hash << 10;
548980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(scratch, hash);
549080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ shl(scratch, 10);
549180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ add(hash, Operand(scratch));
549280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // hash ^= hash >> 6;
549380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(scratch, hash);
549480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ sar(scratch, 6);
549580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ xor_(hash, Operand(scratch));
549680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
549780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
549880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
549980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StringHelper::GenerateHashGetHash(MacroAssembler* masm,
550080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                       Register hash,
550180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                       Register scratch) {
550280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // hash += hash << 3;
550380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(scratch, hash);
550480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ shl(scratch, 3);
550580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ add(hash, Operand(scratch));
550680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // hash ^= hash >> 11;
550780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(scratch, hash);
550880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ sar(scratch, 11);
550980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ xor_(hash, Operand(scratch));
551080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // hash += hash << 15;
551180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(scratch, hash);
551280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ shl(scratch, 15);
551380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ add(hash, Operand(scratch));
551480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
551580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // if (hash == 0) hash = 27;
5516257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label hash_not_zero;
551780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ test(hash, Operand(hash));
5518257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(not_zero, &hash_not_zero, Label::kNear);
551980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(hash, Immediate(27));
552080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&hash_not_zero);
552180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
552280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
552380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
552480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid SubStringStub::Generate(MacroAssembler* masm) {
552580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label runtime;
552680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
552780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Stack frame on entry.
552880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  //  esp[0]: return address
552980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  //  esp[4]: to
553080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  //  esp[8]: from
553180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  //  esp[12]: string
553280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
553380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Make sure first argument is a string.
553480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(eax, Operand(esp, 3 * kPointerSize));
553580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  STATIC_ASSERT(kSmiTag == 0);
55363fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ JumpIfSmi(eax, &runtime);
553780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Condition is_string = masm->IsObjectStringType(eax, ebx, ebx);
553880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(NegateCondition(is_string), &runtime);
553980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
554080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // eax: string
554180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // ebx: instance type
554280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
554380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Calculate length of sub string using the smi values.
554480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label result_longer_than_two;
554580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(ecx, Operand(esp, 1 * kPointerSize));  // To index.
55463fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ JumpIfNotSmi(ecx, &runtime);
554780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(edx, Operand(esp, 2 * kPointerSize));  // From index.
55483fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ JumpIfNotSmi(edx, &runtime);
554980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ sub(ecx, Operand(edx));
555080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cmp(ecx, FieldOperand(eax, String::kLengthOffset));
555180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label return_eax;
555280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(equal, &return_eax);
555380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Special handling of sub-strings of length 1 and 2. One character strings
555480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // are handled in the runtime system (looked up in the single character
555580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // cache). Two character strings are looked for in the symbol cache.
555680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiUntag(ecx);  // Result length is no longer smi.
555780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cmp(ecx, 2);
555880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(greater, &result_longer_than_two);
555980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(less, &runtime);
556080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
556180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Sub string of length 2 requested.
556280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // eax: string
556380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // ebx: instance type
556480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // ecx: sub string length (value is 2)
556580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // edx: from index (smi)
556680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ JumpIfInstanceTypeIsNotSequentialAscii(ebx, ebx, &runtime);
556780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
556880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Get the two characters forming the sub string.
556980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiUntag(edx);  // From index is no longer smi.
557080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movzx_b(ebx, FieldOperand(eax, edx, times_1, SeqAsciiString::kHeaderSize));
557180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movzx_b(ecx,
557280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen             FieldOperand(eax, edx, times_1, SeqAsciiString::kHeaderSize + 1));
557380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
557480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Try to lookup two character string in symbol table.
557580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label make_two_character_string;
557680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  StringHelper::GenerateTwoCharacterSymbolTableProbe(
55779ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick      masm, ebx, ecx, eax, edx, edi,
55789ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick      &make_two_character_string, &make_two_character_string);
557980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ ret(3 * kPointerSize);
558080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
558180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&make_two_character_string);
558280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Setup registers for allocating the two character string.
558380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(eax, Operand(esp, 3 * kPointerSize));
558480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset));
558580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movzx_b(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset));
558680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ Set(ecx, Immediate(2));
558780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
558880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&result_longer_than_two);
558980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // eax: string
559080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // ebx: instance type
559180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // ecx: result string length
559280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check for flat ascii string
559380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label non_ascii_flat;
559480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ JumpIfInstanceTypeIsNotSequentialAscii(ebx, ebx, &non_ascii_flat);
559580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
559680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Allocate the result.
559780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ AllocateAsciiString(eax, ecx, ebx, edx, edi, &runtime);
559880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
559980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // eax: result string
560080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // ecx: result string length
560180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(edx, esi);  // esi used by following code.
560280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Locate first character of result.
560380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(edi, eax);
560480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ add(Operand(edi), Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag));
560580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Load string argument and locate character of sub string start.
560680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(esi, Operand(esp, 3 * kPointerSize));
560780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ add(Operand(esi), Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag));
560880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(ebx, Operand(esp, 2 * kPointerSize));  // from
560980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiUntag(ebx);
561080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ add(esi, Operand(ebx));
561180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
561280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // eax: result string
561380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // ecx: result length
561480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // edx: original value of esi
561580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // edi: first character of result
561680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // esi: character of sub string start
561780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  StringHelper::GenerateCopyCharactersREP(masm, edi, esi, ecx, ebx, true);
561880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(esi, edx);  // Restore esi.
561944f0eee88ff00398ff7f715fab053374d808c90dSteve Block  Counters* counters = masm->isolate()->counters();
562044f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ IncrementCounter(counters->sub_string_native(), 1);
562180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ ret(3 * kPointerSize);
562280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
562380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&non_ascii_flat);
562480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // eax: string
562580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // ebx: instance type & kStringRepresentationMask | kStringEncodingMask
562680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // ecx: result string length
562780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check for flat two byte string
562880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cmp(ebx, kSeqStringTag | kTwoByteStringTag);
562980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(not_equal, &runtime);
563080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
563180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Allocate the result.
563280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ AllocateTwoByteString(eax, ecx, ebx, edx, edi, &runtime);
563380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
563480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // eax: result string
563580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // ecx: result string length
563680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(edx, esi);  // esi used by following code.
563780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Locate first character of result.
563880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(edi, eax);
563980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ add(Operand(edi),
564080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen         Immediate(SeqTwoByteString::kHeaderSize - kHeapObjectTag));
564180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Load string argument and locate character of sub string start.
564280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(esi, Operand(esp, 3 * kPointerSize));
564380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ add(Operand(esi),
564480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen         Immediate(SeqTwoByteString::kHeaderSize - kHeapObjectTag));
564580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(ebx, Operand(esp, 2 * kPointerSize));  // from
564680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // As from is a smi it is 2 times the value which matches the size of a two
564780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // byte character.
564880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  STATIC_ASSERT(kSmiTag == 0);
564980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  STATIC_ASSERT(kSmiTagSize + kSmiShiftSize == 1);
565080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ add(esi, Operand(ebx));
565180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
565280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // eax: result string
565380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // ecx: result length
565480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // edx: original value of esi
565580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // edi: first character of result
565680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // esi: character of sub string start
565780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  StringHelper::GenerateCopyCharactersREP(masm, edi, esi, ecx, ebx, false);
565880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(esi, edx);  // Restore esi.
565980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
566080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&return_eax);
566144f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ IncrementCounter(counters->sub_string_native(), 1);
566280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ ret(3 * kPointerSize);
566380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
566480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Just jump to runtime to create the sub string.
566580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&runtime);
566680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ TailCallRuntime(Runtime::kSubString, 3, 1);
566780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
566880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
566980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
5670257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid StringCompareStub::GenerateFlatAsciiStringEquals(MacroAssembler* masm,
5671257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                                      Register left,
5672257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                                      Register right,
5673257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                                      Register scratch1,
5674257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                                      Register scratch2) {
5675257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Register length = scratch1;
5676257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5677257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Compare lengths.
5678257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label strings_not_equal, check_zero_length;
5679257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ mov(length, FieldOperand(left, String::kLengthOffset));
5680257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ cmp(length, FieldOperand(right, String::kLengthOffset));
5681257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(equal, &check_zero_length, Label::kNear);
5682257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&strings_not_equal);
5683257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Set(eax, Immediate(Smi::FromInt(NOT_EQUAL)));
5684257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ ret(0);
5685257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5686257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Check if the length is zero.
5687257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label compare_chars;
5688257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&check_zero_length);
5689257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  STATIC_ASSERT(kSmiTag == 0);
5690257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ test(length, Operand(length));
5691257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(not_zero, &compare_chars, Label::kNear);
5692257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Set(eax, Immediate(Smi::FromInt(EQUAL)));
5693257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ ret(0);
5694257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5695257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Compare characters.
5696257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&compare_chars);
5697257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  GenerateAsciiCharsCompareLoop(masm, left, right, length, scratch2,
5698257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                &strings_not_equal, Label::kNear);
5699257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5700257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Characters are equal.
5701257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Set(eax, Immediate(Smi::FromInt(EQUAL)));
5702257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ ret(0);
5703257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch}
5704257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5705257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
570680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StringCompareStub::GenerateCompareFlatAsciiStrings(MacroAssembler* masm,
570780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                                        Register left,
570880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                                        Register right,
570980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                                        Register scratch1,
571080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                                        Register scratch2,
571180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                                        Register scratch3) {
571244f0eee88ff00398ff7f715fab053374d808c90dSteve Block  Counters* counters = masm->isolate()->counters();
571344f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ IncrementCounter(counters->string_compare_native(), 1);
571480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
571580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Find minimum length.
5716257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label left_shorter;
571780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(scratch1, FieldOperand(left, String::kLengthOffset));
571880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(scratch3, scratch1);
571980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ sub(scratch3, FieldOperand(right, String::kLengthOffset));
572080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
572180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Register length_delta = scratch3;
572280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
5723257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(less_equal, &left_shorter, Label::kNear);
572480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Right string is shorter. Change scratch1 to be length of right string.
572580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ sub(scratch1, Operand(length_delta));
572680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&left_shorter);
572780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
572880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Register min_length = scratch1;
572980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
573080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // If either length is zero, just compare lengths.
5731257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label compare_lengths;
573280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ test(min_length, Operand(min_length));
5733257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(zero, &compare_lengths, Label::kNear);
573480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
5735257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Compare characters.
5736257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label result_not_equal;
5737257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  GenerateAsciiCharsCompareLoop(masm, left, right, min_length, scratch2,
5738257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                &result_not_equal, Label::kNear);
573980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
574080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Compare lengths -  strings up to min-length are equal.
574180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&compare_lengths);
574280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ test(length_delta, Operand(length_delta));
5743257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(not_zero, &result_not_equal, Label::kNear);
574480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
574580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Result is EQUAL.
574680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  STATIC_ASSERT(EQUAL == 0);
574780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  STATIC_ASSERT(kSmiTag == 0);
574880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ Set(eax, Immediate(Smi::FromInt(EQUAL)));
574980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ ret(0);
575080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
5751257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label result_greater;
575280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&result_not_equal);
5753257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(greater, &result_greater, Label::kNear);
575480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
575580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Result is LESS.
575680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ Set(eax, Immediate(Smi::FromInt(LESS)));
575780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ ret(0);
575880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
575980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Result is GREATER.
576080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&result_greater);
576180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ Set(eax, Immediate(Smi::FromInt(GREATER)));
576280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ ret(0);
576380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
576480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
576580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
5766257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid StringCompareStub::GenerateAsciiCharsCompareLoop(
5767257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    MacroAssembler* masm,
5768257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Register left,
5769257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Register right,
5770257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Register length,
5771257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Register scratch,
5772257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Label* chars_not_equal,
5773257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Label::Distance chars_not_equal_near) {
5774257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Change index to run from -length to -1 by adding length to string
5775257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // start. This means that loop ends when index reaches zero, which
5776257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // doesn't need an additional compare.
5777257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ SmiUntag(length);
5778257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ lea(left,
5779257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch         FieldOperand(left, length, times_1, SeqAsciiString::kHeaderSize));
5780257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ lea(right,
5781257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch         FieldOperand(right, length, times_1, SeqAsciiString::kHeaderSize));
5782257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ neg(length);
5783257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Register index = length;  // index = -length;
5784257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5785257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Compare loop.
5786257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label loop;
5787257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&loop);
5788257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ mov_b(scratch, Operand(left, index, times_1, 0));
5789257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ cmpb(scratch, Operand(right, index, times_1, 0));
5790257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(not_equal, chars_not_equal, chars_not_equal_near);
5791257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ add(Operand(index), Immediate(1));
5792257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(not_zero, &loop);
5793257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch}
5794257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5795257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
579680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StringCompareStub::Generate(MacroAssembler* masm) {
579780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label runtime;
579880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
579980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Stack frame on entry.
580080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  //  esp[0]: return address
580180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  //  esp[4]: right string
580280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  //  esp[8]: left string
580380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
580480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(edx, Operand(esp, 2 * kPointerSize));  // left
580580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ mov(eax, Operand(esp, 1 * kPointerSize));  // right
580680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
5807257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label not_same;
580880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cmp(edx, Operand(eax));
5809257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(not_equal, &not_same, Label::kNear);
581080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  STATIC_ASSERT(EQUAL == 0);
581180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  STATIC_ASSERT(kSmiTag == 0);
581280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ Set(eax, Immediate(Smi::FromInt(EQUAL)));
581344f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ IncrementCounter(masm->isolate()->counters()->string_compare_native(), 1);
581480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ ret(2 * kPointerSize);
581580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
581680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&not_same);
581780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
581880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check that both objects are sequential ascii strings.
581980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ JumpIfNotBothSequentialAsciiStrings(edx, eax, ecx, ebx, &runtime);
582080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
582180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Compare flat ascii strings.
582280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Drop arguments from the stack.
582380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ pop(ecx);
582480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ add(Operand(esp), Immediate(2 * kPointerSize));
582580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ push(ecx);
582680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  GenerateCompareFlatAsciiStrings(masm, edx, eax, ecx, ebx, edi);
582780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
582880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Call the runtime; it returns -1 (less), 0 (equal), or 1 (greater)
582980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // tagged as a small integer.
583080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&runtime);
583180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ TailCallRuntime(Runtime::kStringCompare, 2, 1);
583280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
583380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
5834b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
5835b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdochvoid ICCompareStub::GenerateSmis(MacroAssembler* masm) {
5836b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  ASSERT(state_ == CompareIC::SMIS);
5837257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label miss;
5838b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ mov(ecx, Operand(edx));
5839b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ or_(ecx, Operand(eax));
58403fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ JumpIfNotSmi(ecx, &miss, Label::kNear);
5841b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
5842b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  if (GetCondition() == equal) {
5843b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    // For equality we do not care about the sign of the result.
5844b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ sub(eax, Operand(edx));
5845b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  } else {
5846257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Label done;
5847b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ sub(edx, Operand(eax));
5848257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ j(no_overflow, &done, Label::kNear);
5849b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    // Correct sign of result in case of overflow.
5850b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ not_(edx);
5851b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ bind(&done);
5852b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ mov(eax, edx);
5853b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  }
5854b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ ret(0);
5855b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
5856b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ bind(&miss);
5857b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  GenerateMiss(masm);
5858b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch}
5859b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
5860b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
5861b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdochvoid ICCompareStub::GenerateHeapNumbers(MacroAssembler* masm) {
5862b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  ASSERT(state_ == CompareIC::HEAP_NUMBERS);
5863b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
5864257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label generic_stub;
5865257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label unordered;
5866257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label miss;
5867b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ mov(ecx, Operand(edx));
5868b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ and_(ecx, Operand(eax));
58693fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ JumpIfSmi(ecx, &generic_stub, Label::kNear);
5870b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
5871b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ CmpObjectType(eax, HEAP_NUMBER_TYPE, ecx);
5872257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(not_equal, &miss, Label::kNear);
5873b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ CmpObjectType(edx, HEAP_NUMBER_TYPE, ecx);
5874257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(not_equal, &miss, Label::kNear);
5875b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
5876b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Inlining the double comparison and falling back to the general compare
5877b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // stub if NaN is involved or SS2 or CMOV is unsupported.
58788b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  if (CpuFeatures::IsSupported(SSE2) && CpuFeatures::IsSupported(CMOV)) {
5879b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    CpuFeatures::Scope scope1(SSE2);
5880b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    CpuFeatures::Scope scope2(CMOV);
5881b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
5882b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    // Load left and right operand
5883b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ movdbl(xmm0, FieldOperand(edx, HeapNumber::kValueOffset));
5884b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ movdbl(xmm1, FieldOperand(eax, HeapNumber::kValueOffset));
5885b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
5886b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    // Compare operands
5887b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ ucomisd(xmm0, xmm1);
5888b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
5889b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    // Don't base result on EFLAGS when a NaN is involved.
5890257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ j(parity_even, &unordered, Label::kNear);
5891b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
5892b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    // Return a result of -1, 0, or 1, based on EFLAGS.
5893b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    // Performing mov, because xor would destroy the flag register.
5894b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ mov(eax, 0);  // equal
5895b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ mov(ecx, Immediate(Smi::FromInt(1)));
5896b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ cmov(above, eax, Operand(ecx));
5897b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ mov(ecx, Immediate(Smi::FromInt(-1)));
5898b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ cmov(below, eax, Operand(ecx));
5899b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ ret(0);
5900b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
5901b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ bind(&unordered);
5902b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  }
5903b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
5904b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  CompareStub stub(GetCondition(), strict(), NO_COMPARE_FLAGS);
5905b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ bind(&generic_stub);
5906b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ jmp(stub.GetCode(), RelocInfo::CODE_TARGET);
5907b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
5908b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ bind(&miss);
5909b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  GenerateMiss(masm);
5910b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch}
5911b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
5912b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
5913257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid ICCompareStub::GenerateSymbols(MacroAssembler* masm) {
5914257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  ASSERT(state_ == CompareIC::SYMBOLS);
5915257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  ASSERT(GetCondition() == equal);
5916257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5917257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Registers containing left and right operands respectively.
5918257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Register left = edx;
5919257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Register right = eax;
5920257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Register tmp1 = ecx;
5921257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Register tmp2 = ebx;
5922257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5923257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Check that both operands are heap objects.
5924257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label miss;
5925257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ mov(tmp1, Operand(left));
5926257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  STATIC_ASSERT(kSmiTag == 0);
5927257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ and_(tmp1, Operand(right));
59283fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ JumpIfSmi(tmp1, &miss, Label::kNear);
5929257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5930257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Check that both operands are symbols.
5931257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ mov(tmp1, FieldOperand(left, HeapObject::kMapOffset));
5932257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ mov(tmp2, FieldOperand(right, HeapObject::kMapOffset));
5933257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ movzx_b(tmp1, FieldOperand(tmp1, Map::kInstanceTypeOffset));
5934257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ movzx_b(tmp2, FieldOperand(tmp2, Map::kInstanceTypeOffset));
5935257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  STATIC_ASSERT(kSymbolTag != 0);
5936257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ and_(tmp1, Operand(tmp2));
5937257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ test(tmp1, Immediate(kIsSymbolMask));
5938257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(zero, &miss, Label::kNear);
5939257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5940257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Symbols are compared by identity.
5941257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label done;
5942257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ cmp(left, Operand(right));
5943257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Make sure eax is non-zero. At this point input operands are
5944257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // guaranteed to be non-zero.
5945257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  ASSERT(right.is(eax));
5946257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(not_equal, &done, Label::kNear);
5947257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  STATIC_ASSERT(EQUAL == 0);
5948257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  STATIC_ASSERT(kSmiTag == 0);
5949257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Set(eax, Immediate(Smi::FromInt(EQUAL)));
5950257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&done);
5951257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ ret(0);
5952257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5953257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&miss);
5954257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  GenerateMiss(masm);
5955257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch}
5956257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5957257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5958257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid ICCompareStub::GenerateStrings(MacroAssembler* masm) {
5959257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  ASSERT(state_ == CompareIC::STRINGS);
5960257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  ASSERT(GetCondition() == equal);
5961257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label miss;
5962257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5963257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Registers containing left and right operands respectively.
5964257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Register left = edx;
5965257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Register right = eax;
5966257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Register tmp1 = ecx;
5967257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Register tmp2 = ebx;
5968257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Register tmp3 = edi;
5969257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5970257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Check that both operands are heap objects.
5971257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ mov(tmp1, Operand(left));
5972257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  STATIC_ASSERT(kSmiTag == 0);
5973257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ and_(tmp1, Operand(right));
59743fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ JumpIfSmi(tmp1, &miss);
5975257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5976257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Check that both operands are strings. This leaves the instance
5977257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // types loaded in tmp1 and tmp2.
5978257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ mov(tmp1, FieldOperand(left, HeapObject::kMapOffset));
5979257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ mov(tmp2, FieldOperand(right, HeapObject::kMapOffset));
5980257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ movzx_b(tmp1, FieldOperand(tmp1, Map::kInstanceTypeOffset));
5981257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ movzx_b(tmp2, FieldOperand(tmp2, Map::kInstanceTypeOffset));
5982257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ mov(tmp3, tmp1);
5983257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  STATIC_ASSERT(kNotStringTag != 0);
5984257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ or_(tmp3, Operand(tmp2));
5985257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ test(tmp3, Immediate(kIsNotStringMask));
5986257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(not_zero, &miss);
5987257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5988257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Fast check for identical strings.
5989257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label not_same;
5990257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ cmp(left, Operand(right));
5991257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(not_equal, &not_same, Label::kNear);
5992257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  STATIC_ASSERT(EQUAL == 0);
5993257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  STATIC_ASSERT(kSmiTag == 0);
5994257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Set(eax, Immediate(Smi::FromInt(EQUAL)));
5995257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ ret(0);
5996257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5997257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Handle not identical strings.
5998257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&not_same);
5999257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6000257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Check that both strings are symbols. If they are, we're done
6001257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // because we already know they are not identical.
6002257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label do_compare;
6003257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  STATIC_ASSERT(kSymbolTag != 0);
6004257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ and_(tmp1, Operand(tmp2));
6005257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ test(tmp1, Immediate(kIsSymbolMask));
6006257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(zero, &do_compare, Label::kNear);
6007257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Make sure eax is non-zero. At this point input operands are
6008257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // guaranteed to be non-zero.
6009257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  ASSERT(right.is(eax));
6010257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ ret(0);
6011257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6012257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Check that both strings are sequential ASCII.
6013257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label runtime;
6014257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&do_compare);
6015257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ JumpIfNotBothSequentialAsciiStrings(left, right, tmp1, tmp2, &runtime);
6016257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6017257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Compare flat ASCII strings. Returns when done.
6018257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  StringCompareStub::GenerateFlatAsciiStringEquals(
6019257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      masm, left, right, tmp1, tmp2);
6020257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6021257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Handle more complex cases in runtime.
6022257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&runtime);
6023257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ pop(tmp1);  // Return address.
6024257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ push(left);
6025257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ push(right);
6026257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ push(tmp1);
6027257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ TailCallRuntime(Runtime::kStringEquals, 2, 1);
6028257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6029257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&miss);
6030257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  GenerateMiss(masm);
6031257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch}
6032257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6033257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6034b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdochvoid ICCompareStub::GenerateObjects(MacroAssembler* masm) {
6035b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  ASSERT(state_ == CompareIC::OBJECTS);
6036257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label miss;
6037b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ mov(ecx, Operand(edx));
6038b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ and_(ecx, Operand(eax));
60393fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ JumpIfSmi(ecx, &miss, Label::kNear);
6040b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
6041b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ CmpObjectType(eax, JS_OBJECT_TYPE, ecx);
6042257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(not_equal, &miss, Label::kNear);
6043b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ CmpObjectType(edx, JS_OBJECT_TYPE, ecx);
6044257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(not_equal, &miss, Label::kNear);
6045b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
6046b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  ASSERT(GetCondition() == equal);
6047b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ sub(eax, Operand(edx));
6048b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ ret(0);
6049b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
6050b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ bind(&miss);
6051b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  GenerateMiss(masm);
6052b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch}
6053b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
6054b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
6055b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdochvoid ICCompareStub::GenerateMiss(MacroAssembler* masm) {
6056b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Save the registers.
6057b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ pop(ecx);
6058b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ push(edx);
6059b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ push(eax);
6060b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ push(ecx);
6061b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
6062b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Call the runtime system in a fresh internal frame.
606344f0eee88ff00398ff7f715fab053374d808c90dSteve Block  ExternalReference miss = ExternalReference(IC_Utility(IC::kCompareIC_Miss),
606444f0eee88ff00398ff7f715fab053374d808c90dSteve Block                                             masm->isolate());
6065b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ EnterInternalFrame();
6066b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ push(edx);
6067b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ push(eax);
6068b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ push(Immediate(Smi::FromInt(op_)));
6069b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ CallExternalReference(miss, 3);
6070b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ LeaveInternalFrame();
6071b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
6072b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Compute the entry point of the rewritten stub.
6073b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ lea(edi, FieldOperand(eax, Code::kHeaderSize));
6074b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
6075b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Restore registers.
6076b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ pop(ecx);
6077b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ pop(eax);
6078b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ pop(edx);
6079b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ push(ecx);
6080b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
6081b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Do a tail call to the rewritten stub.
6082b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ jmp(Operand(edi));
6083b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch}
6084b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
6085b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
6086257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// Helper function used to check that the dictionary doesn't contain
6087257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// the property. This function may return false negatives, so miss_label
6088257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// must always call a backup property check that is complete.
6089257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// This function is safe to call if the receiver has fast properties.
6090257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// Name must be a symbol and receiver must be a heap object.
6091257744e915dfc84d6d07a6b2accf8402d9ffc708Ben MurdochMaybeObject* StringDictionaryLookupStub::GenerateNegativeLookup(
6092257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    MacroAssembler* masm,
6093257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Label* miss,
6094257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Label* done,
6095257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Register properties,
6096257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    String* name,
6097257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Register r0) {
6098257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  ASSERT(name->IsSymbol());
6099257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6100257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // If names of slots in range from 1 to kProbes - 1 for the hash value are
6101257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // not equal to the name and kProbes-th slot is not used (its name is the
6102257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // undefined value), it guarantees the hash table doesn't contain the
6103257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // property. It's true even if some slots represent deleted properties
6104257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // (their names are the null value).
6105257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  for (int i = 0; i < kInlinedProbes; i++) {
6106257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Compute the masked index: (hash + i + i * i) & mask.
6107257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Register index = r0;
6108257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Capacity is smi 2^n.
6109257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ mov(index, FieldOperand(properties, kCapacityOffset));
6110257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ dec(index);
6111257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ and_(Operand(index),
6112257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch           Immediate(Smi::FromInt(name->Hash() +
6113257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                   StringDictionary::GetProbeOffset(i))));
6114257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6115257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Scale the index by multiplying by the entry size.
6116257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    ASSERT(StringDictionary::kEntrySize == 3);
6117257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ lea(index, Operand(index, index, times_2, 0));  // index *= 3.
6118257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Register entity_name = r0;
6119257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Having undefined at this place means the name is not contained.
6120257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    ASSERT_EQ(kSmiTagSize, 1);
6121257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ mov(entity_name, Operand(properties, index, times_half_pointer_size,
6122257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                kElementsStartOffset - kHeapObjectTag));
6123257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ cmp(entity_name, masm->isolate()->factory()->undefined_value());
6124257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ j(equal, done);
6125257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6126257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Stop if found the property.
6127257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ cmp(entity_name, Handle<String>(name));
6128257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ j(equal, miss);
6129257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6130257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Check if the entry name is not a symbol.
6131257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ mov(entity_name, FieldOperand(entity_name, HeapObject::kMapOffset));
6132257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ test_b(FieldOperand(entity_name, Map::kInstanceTypeOffset),
6133257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch              kIsSymbolMask);
6134257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ j(zero, miss);
6135257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
6136257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6137257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  StringDictionaryLookupStub stub(properties,
6138257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                  r0,
6139257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                  r0,
6140257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                  StringDictionaryLookupStub::NEGATIVE_LOOKUP);
6141257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ push(Immediate(Handle<Object>(name)));
6142257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ push(Immediate(name->Hash()));
6143257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  MaybeObject* result = masm->TryCallStub(&stub);
6144257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  if (result->IsFailure()) return result;
6145257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ test(r0, Operand(r0));
6146257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(not_zero, miss);
6147257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ jmp(done);
6148257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  return result;
6149257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch}
6150257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6151257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6152257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// Probe the string dictionary in the |elements| register. Jump to the
6153257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// |done| label if a property with the given name is found leaving the
6154257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// index into the dictionary in |r0|. Jump to the |miss| label
6155257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// otherwise.
6156257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid StringDictionaryLookupStub::GeneratePositiveLookup(MacroAssembler* masm,
6157257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                                        Label* miss,
6158257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                                        Label* done,
6159257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                                        Register elements,
6160257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                                        Register name,
6161257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                                        Register r0,
6162257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                                        Register r1) {
6163257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Assert that name contains a string.
6164257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  if (FLAG_debug_code) __ AbortIfNotString(name);
6165257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6166257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ mov(r1, FieldOperand(elements, kCapacityOffset));
6167257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ shr(r1, kSmiTagSize);  // convert smi to int
6168257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ dec(r1);
6169257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6170257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Generate an unrolled loop that performs a few probes before
6171257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // giving up. Measurements done on Gmail indicate that 2 probes
6172257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // cover ~93% of loads from dictionaries.
6173257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  for (int i = 0; i < kInlinedProbes; i++) {
6174257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Compute the masked index: (hash + i + i * i) & mask.
6175257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ mov(r0, FieldOperand(name, String::kHashFieldOffset));
6176257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ shr(r0, String::kHashShift);
6177257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    if (i > 0) {
6178257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ add(Operand(r0), Immediate(StringDictionary::GetProbeOffset(i)));
6179257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    }
6180257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ and_(r0, Operand(r1));
6181257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6182257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Scale the index by multiplying by the entry size.
6183257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    ASSERT(StringDictionary::kEntrySize == 3);
6184257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ lea(r0, Operand(r0, r0, times_2, 0));  // r0 = r0 * 3
6185257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6186257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Check if the key is identical to the name.
6187257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ cmp(name, Operand(elements,
6188257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                         r0,
6189257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                         times_4,
6190257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                         kElementsStartOffset - kHeapObjectTag));
6191257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ j(equal, done);
6192257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
6193257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6194257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  StringDictionaryLookupStub stub(elements,
6195257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                  r1,
6196257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                  r0,
6197257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                  POSITIVE_LOOKUP);
6198257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ push(name);
6199257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ mov(r0, FieldOperand(name, String::kHashFieldOffset));
6200257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ shr(r0, String::kHashShift);
6201257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ push(r0);
6202257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ CallStub(&stub);
6203257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6204257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ test(r1, Operand(r1));
6205257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(zero, miss);
6206257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ jmp(done);
6207257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch}
6208257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6209257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6210257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid StringDictionaryLookupStub::Generate(MacroAssembler* masm) {
6211257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Stack frame on entry:
6212257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  //  esp[0 * kPointerSize]: return address.
6213257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  //  esp[1 * kPointerSize]: key's hash.
6214257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  //  esp[2 * kPointerSize]: key.
6215257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Registers:
6216257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  //  dictionary_: StringDictionary to probe.
6217257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  //  result_: used as scratch.
6218257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  //  index_: will hold an index of entry if lookup is successful.
6219257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  //          might alias with result_.
6220257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Returns:
6221257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  //  result_ is zero if lookup failed, non zero otherwise.
6222257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6223257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label in_dictionary, maybe_in_dictionary, not_in_dictionary;
6224257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6225257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Register scratch = result_;
6226257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6227257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ mov(scratch, FieldOperand(dictionary_, kCapacityOffset));
6228257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ dec(scratch);
6229257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ SmiUntag(scratch);
6230257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ push(scratch);
6231257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6232257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // If names of slots in range from 1 to kProbes - 1 for the hash value are
6233257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // not equal to the name and kProbes-th slot is not used (its name is the
6234257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // undefined value), it guarantees the hash table doesn't contain the
6235257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // property. It's true even if some slots represent deleted properties
6236257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // (their names are the null value).
6237257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  for (int i = kInlinedProbes; i < kTotalProbes; i++) {
6238257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Compute the masked index: (hash + i + i * i) & mask.
6239257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ mov(scratch, Operand(esp, 2 * kPointerSize));
6240257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    if (i > 0) {
6241257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ add(Operand(scratch),
6242257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch             Immediate(StringDictionary::GetProbeOffset(i)));
6243257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    }
6244257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ and_(scratch, Operand(esp, 0));
6245257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6246257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Scale the index by multiplying by the entry size.
6247257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    ASSERT(StringDictionary::kEntrySize == 3);
6248257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ lea(index_, Operand(scratch, scratch, times_2, 0));  // index *= 3.
6249257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6250257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Having undefined at this place means the name is not contained.
6251257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    ASSERT_EQ(kSmiTagSize, 1);
6252257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ mov(scratch, Operand(dictionary_,
6253257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                            index_,
6254257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                            times_pointer_size,
6255257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                            kElementsStartOffset - kHeapObjectTag));
6256257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ cmp(scratch, masm->isolate()->factory()->undefined_value());
6257257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ j(equal, &not_in_dictionary);
6258257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6259257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Stop if found the property.
6260257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ cmp(scratch, Operand(esp, 3 * kPointerSize));
6261257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ j(equal, &in_dictionary);
6262257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6263257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    if (i != kTotalProbes - 1 && mode_ == NEGATIVE_LOOKUP) {
6264257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // If we hit a non symbol key during negative lookup
6265257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // we have to bailout as this key might be equal to the
6266257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // key we are looking for.
6267257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6268257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // Check if the entry name is not a symbol.
6269257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ mov(scratch, FieldOperand(scratch, HeapObject::kMapOffset));
6270257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ test_b(FieldOperand(scratch, Map::kInstanceTypeOffset),
6271257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                kIsSymbolMask);
6272257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ j(zero, &maybe_in_dictionary);
6273257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    }
6274257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
6275257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6276257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&maybe_in_dictionary);
6277257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // If we are doing negative lookup then probing failure should be
6278257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // treated as a lookup success. For positive lookup probing failure
6279257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // should be treated as lookup failure.
6280257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  if (mode_ == POSITIVE_LOOKUP) {
6281257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ mov(result_, Immediate(0));
6282257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ Drop(1);
6283257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ ret(2 * kPointerSize);
6284257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
6285257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6286257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&in_dictionary);
6287257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ mov(result_, Immediate(1));
6288257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Drop(1);
6289257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ ret(2 * kPointerSize);
6290257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6291257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&not_in_dictionary);
6292257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ mov(result_, Immediate(0));
6293257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Drop(1);
6294257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ ret(2 * kPointerSize);
6295257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch}
6296257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
6297257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
629880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#undef __
629980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
630080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} }  // namespace v8::internal
630180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
630280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#endif  // V8_TARGET_ARCH_IA32
6303