code-stubs-x64.cc revision 589d6979ff2ef66fca2d8fa51404c369ca5e9250
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_X64)
3180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
3280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#include "bootstrapper.h"
3380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#include "code-stubs.h"
3480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#include "regexp-macro-assembler.h"
3580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
3680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsennamespace v8 {
3780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsennamespace internal {
3880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
3980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#define __ ACCESS_MASM(masm)
401e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
411e0659c275bb392c045087af4f6b0d7565cb3d77Steve Blockvoid ToNumberStub::Generate(MacroAssembler* masm) {
421e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  // The ToNumber stub takes one argument in eax.
43257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label check_heap_number, call_builtin;
441e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  __ SmiTest(rax);
45257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(not_zero, &check_heap_number, Label::kNear);
461e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  __ Ret();
471e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
481e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  __ bind(&check_heap_number);
4944f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ CompareRoot(FieldOperand(rax, HeapObject::kMapOffset),
5044f0eee88ff00398ff7f715fab053374d808c90dSteve Block                 Heap::kHeapNumberMapRootIndex);
51257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(not_equal, &call_builtin, Label::kNear);
521e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  __ Ret();
531e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
541e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  __ bind(&call_builtin);
551e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  __ pop(rcx);  // Pop return address.
561e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  __ push(rax);
571e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  __ push(rcx);  // Push return address.
581e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  __ InvokeBuiltin(Builtins::TO_NUMBER, JUMP_FUNCTION);
591e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block}
601e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
611e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
6280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid FastNewClosureStub::Generate(MacroAssembler* masm) {
6380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Create a new closure from the given function info in new
6480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // space. Set the context to the current context in rsi.
6580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label gc;
6680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ AllocateInNewSpace(JSFunction::kSize, rax, rbx, rcx, &gc, TAG_OBJECT);
6780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
6880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Get the function info from the stack.
6980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rdx, Operand(rsp, 1 * kPointerSize));
7080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
7144f0eee88ff00398ff7f715fab053374d808c90dSteve Block  int map_index = strict_mode_ == kStrictMode
7244f0eee88ff00398ff7f715fab053374d808c90dSteve Block      ? Context::STRICT_MODE_FUNCTION_MAP_INDEX
7344f0eee88ff00398ff7f715fab053374d808c90dSteve Block      : Context::FUNCTION_MAP_INDEX;
7444f0eee88ff00398ff7f715fab053374d808c90dSteve Block
7580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Compute the function map in the current global context and set that
7680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // as the map of the allocated object.
7780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rcx, Operand(rsi, Context::SlotOffset(Context::GLOBAL_INDEX)));
7880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rcx, FieldOperand(rcx, GlobalObject::kGlobalContextOffset));
7944f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ movq(rcx, Operand(rcx, Context::SlotOffset(map_index)));
8080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(FieldOperand(rax, JSObject::kMapOffset), rcx);
8180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
8280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Initialize the rest of the function. We don't have to update the
8380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // write barrier because the allocated object is in new space.
8480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ LoadRoot(rbx, Heap::kEmptyFixedArrayRootIndex);
8580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ LoadRoot(rcx, Heap::kTheHoleValueRootIndex);
86b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ LoadRoot(rdi, Heap::kUndefinedValueRootIndex);
8780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(FieldOperand(rax, JSObject::kPropertiesOffset), rbx);
8880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(FieldOperand(rax, JSObject::kElementsOffset), rbx);
8980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(FieldOperand(rax, JSFunction::kPrototypeOrInitialMapOffset), rcx);
9080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(FieldOperand(rax, JSFunction::kSharedFunctionInfoOffset), rdx);
9180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(FieldOperand(rax, JSFunction::kContextOffset), rsi);
9280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(FieldOperand(rax, JSFunction::kLiteralsOffset), rbx);
93b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ movq(FieldOperand(rax, JSFunction::kNextFunctionLinkOffset), rdi);
9480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
9580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Initialize the code pointer in the function to be the one
9680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // found in the shared function info object.
9780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rdx, FieldOperand(rdx, SharedFunctionInfo::kCodeOffset));
9880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ lea(rdx, FieldOperand(rdx, Code::kHeaderSize));
9980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(FieldOperand(rax, JSFunction::kCodeEntryOffset), rdx);
10080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
10180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
10280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Return and remove the on-stack parameter.
10380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ ret(1 * kPointerSize);
10480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
10580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Create a new closure through the slower runtime call.
10680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&gc);
10780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ pop(rcx);  // Temporarily remove return address.
10880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ pop(rdx);
10980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ push(rsi);
11080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ push(rdx);
11144f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ PushRoot(Heap::kFalseValueRootIndex);
11280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ push(rcx);  // Restore return address.
1138a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  __ TailCallRuntime(Runtime::kNewClosure, 3, 1);
11480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
11580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
11680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
11780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid FastNewContextStub::Generate(MacroAssembler* masm) {
11880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Try to allocate the context in new space.
11980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label gc;
12080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  int length = slots_ + Context::MIN_CONTEXT_SLOTS;
12180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ AllocateInNewSpace((length * kPointerSize) + FixedArray::kHeaderSize,
12280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                        rax, rbx, rcx, &gc, TAG_OBJECT);
12380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
12480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Get the function from the stack.
12580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rcx, Operand(rsp, 1 * kPointerSize));
12680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
12780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Setup the object header.
1283fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ LoadRoot(kScratchRegister, Heap::kFunctionContextMapRootIndex);
12980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(FieldOperand(rax, HeapObject::kMapOffset), kScratchRegister);
13080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ Move(FieldOperand(rax, FixedArray::kLengthOffset), Smi::FromInt(length));
13180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
13280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Setup the fixed slots.
1339fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  __ Set(rbx, 0);  // Set to NULL.
13480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(Operand(rax, Context::SlotOffset(Context::CLOSURE_INDEX)), rcx);
1353fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ movq(Operand(rax, Context::SlotOffset(Context::PREVIOUS_INDEX)), rsi);
13680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(Operand(rax, Context::SlotOffset(Context::EXTENSION_INDEX)), rbx);
13780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
1383fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // Copy the global object from the previous context.
13980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rbx, Operand(rsi, Context::SlotOffset(Context::GLOBAL_INDEX)));
14080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(Operand(rax, Context::SlotOffset(Context::GLOBAL_INDEX)), rbx);
14180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
14280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Initialize the rest of the slots to undefined.
14380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ LoadRoot(rbx, Heap::kUndefinedValueRootIndex);
14480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  for (int i = Context::MIN_CONTEXT_SLOTS; i < length; i++) {
14580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ movq(Operand(rax, Context::SlotOffset(i)), rbx);
14680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
14780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
14880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Return and remove the on-stack parameter.
14980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rsi, rax);
15080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ ret(1 * kPointerSize);
15180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
15280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Need to collect. Call into runtime system.
15380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&gc);
1543fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ TailCallRuntime(Runtime::kNewFunctionContext, 1, 1);
15580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
15680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
15780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
15880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid FastCloneShallowArrayStub::Generate(MacroAssembler* masm) {
15980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Stack layout on entry:
16080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  //
16180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // [rsp + kPointerSize]: constant elements.
16280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // [rsp + (2 * kPointerSize)]: literal index.
16380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // [rsp + (3 * kPointerSize)]: literals array.
16480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
16580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // All sizes here are multiples of kPointerSize.
16680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  int elements_size = (length_ > 0) ? FixedArray::SizeFor(length_) : 0;
16780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  int size = JSArray::kSize + elements_size;
16880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
16980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Load boilerplate object into rcx and check if we need to create a
17080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // boilerplate.
17180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label slow_case;
17280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rcx, Operand(rsp, 3 * kPointerSize));
17380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rax, Operand(rsp, 2 * kPointerSize));
17480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  SmiIndex index = masm->SmiToIndex(rax, rax, kPointerSizeLog2);
17580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rcx,
17680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen          FieldOperand(rcx, index.reg, index.scale, FixedArray::kHeaderSize));
17780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ CompareRoot(rcx, Heap::kUndefinedValueRootIndex);
17880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(equal, &slow_case);
17980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
18080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  if (FLAG_debug_code) {
18180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    const char* message;
18280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    Heap::RootListIndex expected_map_index;
18380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    if (mode_ == CLONE_ELEMENTS) {
18480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      message = "Expected (writable) fixed array";
18580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      expected_map_index = Heap::kFixedArrayMapRootIndex;
18680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    } else {
18780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      ASSERT(mode_ == COPY_ON_WRITE_ELEMENTS);
18880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      message = "Expected copy-on-write fixed array";
18980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      expected_map_index = Heap::kFixedCOWArrayMapRootIndex;
19080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    }
19180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ push(rcx);
19280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ movq(rcx, FieldOperand(rcx, JSArray::kElementsOffset));
19380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ CompareRoot(FieldOperand(rcx, HeapObject::kMapOffset),
19480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                   expected_map_index);
19580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ Assert(equal, message);
19680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ pop(rcx);
19780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
19880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
19980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Allocate both the JS array and the elements array in one big
20080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // allocation. This avoids multiple limit checks.
20180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ AllocateInNewSpace(size, rax, rbx, rdx, &slow_case, TAG_OBJECT);
20280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
20380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Copy the JS array part.
20480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  for (int i = 0; i < JSArray::kSize; i += kPointerSize) {
20580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    if ((i != JSArray::kElementsOffset) || (length_ == 0)) {
20680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ movq(rbx, FieldOperand(rcx, i));
20780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ movq(FieldOperand(rax, i), rbx);
20880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    }
20980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
21080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
21180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  if (length_ > 0) {
21280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // Get hold of the elements array of the boilerplate and setup the
21380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // elements pointer in the resulting object.
21480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ movq(rcx, FieldOperand(rcx, JSArray::kElementsOffset));
21580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ lea(rdx, Operand(rax, JSArray::kSize));
21680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ movq(FieldOperand(rax, JSArray::kElementsOffset), rdx);
21780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
21880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // Copy the elements array.
21980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    for (int i = 0; i < elements_size; i += kPointerSize) {
22080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ movq(rbx, FieldOperand(rcx, i));
22180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ movq(FieldOperand(rdx, i), rbx);
22280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    }
22380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
22480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
22580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Return and remove the on-stack parameters.
22680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ ret(3 * kPointerSize);
22780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
22880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&slow_case);
22980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ TailCallRuntime(Runtime::kCreateArrayLiteralShallow, 3, 1);
23080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
23180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
23280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
23369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch// The stub expects its argument on the stack and returns its result in tos_:
23469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch// zero for false, and a non-zero value for true.
23580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid ToBooleanStub::Generate(MacroAssembler* masm) {
23669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  Label patch;
23769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  const Register argument = rax;
2383fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  const Register map = rdx;
2393fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
24069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  if (!types_.IsEmpty()) {
24169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    __ movq(argument, Operand(rsp, 1 * kPointerSize));
24269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  }
24380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
244257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // undefined -> false
24569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  CheckOddball(masm, UNDEFINED, Heap::kUndefinedValueRootIndex, false);
246257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
247257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Boolean -> its value
24869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  CheckOddball(masm, BOOLEAN, Heap::kFalseValueRootIndex, false);
24969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  CheckOddball(masm, BOOLEAN, Heap::kTrueValueRootIndex, true);
250257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
2513fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // 'null' -> false.
25269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  CheckOddball(masm, NULL_TYPE, Heap::kNullValueRootIndex, false);
25369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch
25469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  if (types_.Contains(SMI)) {
25569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    // Smis: 0 -> false, all other -> true
25669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    Label not_smi;
25769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    __ JumpIfNotSmi(argument, &not_smi, Label::kNear);
25869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    // argument contains the correct return value already
25969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    if (!tos_.is(argument)) {
26069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch      __ movq(tos_, argument);
26169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    }
26269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    __ ret(1 * kPointerSize);
26369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    __ bind(&not_smi);
26469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  } else if (types_.NeedsMap()) {
26569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    // If we need a map later and have a Smi -> patch.
26669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    __ JumpIfSmi(argument, &patch, Label::kNear);
26769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  }
26880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
26969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  if (types_.NeedsMap()) {
27069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    __ movq(map, FieldOperand(argument, HeapObject::kMapOffset));
27169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch
27269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    if (types_.CanBeUndetectable()) {
27369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch      __ testb(FieldOperand(map, Map::kBitFieldOffset),
27469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch               Immediate(1 << Map::kIsUndetectable));
27569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch      // Undetectable -> false.
27669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch      Label not_undetectable;
27769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch      __ j(zero, &not_undetectable, Label::kNear);
27869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch      __ Set(tos_, 0);
27969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch      __ ret(1 * kPointerSize);
28069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch      __ bind(&not_undetectable);
28169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    }
28269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  }
28380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
28469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  if (types_.Contains(SPEC_OBJECT)) {
28569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    // spec object -> true.
28669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    Label not_js_object;
28769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    __ CmpInstanceType(map, FIRST_SPEC_OBJECT_TYPE);
28869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    __ j(below, &not_js_object, Label::kNear);
28969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    // argument contains the correct return value already.
29069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    if (!tos_.is(argument)) {
29169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch      __ Set(tos_, 1);
29269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    }
29369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    __ ret(1 * kPointerSize);
29469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    __ bind(&not_js_object);
29569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  }
29680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
29769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  if (types_.Contains(STRING)) {
29869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    // String value -> false iff empty.
29969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    Label not_string;
30069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    __ CmpInstanceType(map, FIRST_NONSTRING_TYPE);
30169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    __ j(above_equal, &not_string, Label::kNear);
30269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    __ movq(tos_, FieldOperand(argument, String::kLengthOffset));
30369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    __ ret(1 * kPointerSize);  // the string length is OK as the return value
30469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    __ bind(&not_string);
30569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  }
30680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
30769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  if (types_.Contains(HEAP_NUMBER)) {
30869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    // heap number -> false iff +0, -0, or NaN.
30969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    Label not_heap_number, false_result;
31069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    __ CompareRoot(map, Heap::kHeapNumberMapRootIndex);
31169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    __ j(not_equal, &not_heap_number, Label::kNear);
31269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    __ xorps(xmm0, xmm0);
31369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    __ ucomisd(xmm0, FieldOperand(argument, HeapNumber::kValueOffset));
31469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    __ j(zero, &false_result, Label::kNear);
31569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    // argument contains the correct return value already.
31669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    if (!tos_.is(argument)) {
31769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch      __ Set(tos_, 1);
31869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    }
31969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    __ ret(1 * kPointerSize);
32069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    __ bind(&false_result);
32169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    __ Set(tos_, 0);
32269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    __ ret(1 * kPointerSize);
32369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    __ bind(&not_heap_number);
32469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  }
32580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
32669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ bind(&patch);
32769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  GenerateTypeTransition(masm);
32869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch}
32980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
33069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch
33169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdochvoid ToBooleanStub::CheckOddball(MacroAssembler* masm,
33269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch                                 Type type,
33369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch                                 Heap::RootListIndex value,
33469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch                                 bool result) {
33569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  const Register argument = rax;
33669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  if (types_.Contains(type)) {
33769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    // If we see an expected oddball, return its ToBoolean value tos_.
33869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    Label different_value;
33969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    __ CompareRoot(argument, value);
34069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    __ j(not_equal, &different_value, Label::kNear);
34169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    if (!result) {
34269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch      // If we have to return zero, there is no way around clearing tos_.
34369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch      __ Set(tos_, 0);
34469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    } else if (!tos_.is(argument)) {
34569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch      // If we have to return non-zero, we can re-use the argument if it is the
34669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch      // same register as the result, because we never see Smi-zero here.
34769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch      __ Set(tos_, 1);
34869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    }
34969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    __ ret(1 * kPointerSize);
35069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    __ bind(&different_value);
35169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  }
35269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch}
35369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch
35469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch
35569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdochvoid ToBooleanStub::GenerateTypeTransition(MacroAssembler* masm) {
35669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ pop(rcx);  // Get return address, operand is now on top of stack.
35769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ Push(Smi::FromInt(tos_.code()));
35869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ Push(Smi::FromInt(types_.ToByte()));
35969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ push(rcx);  // Push return address.
36069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  // Patch the caller to an appropriate specialized stub and return the
36169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  // operation result to the caller of the stub.
36269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ TailCallExternalReference(
36369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch      ExternalReference(IC_Utility(IC::kToBoolean_Patch), masm->isolate()),
36469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch      3,
36569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch      1);
36680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
36780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
36880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
36980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenclass FloatingPointHelper : public AllStatic {
37080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen public:
37180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Load the operands from rdx and rax into xmm0 and xmm1, as doubles.
37280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // If the operands are not both numbers, jump to not_numbers.
37380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Leaves rdx and rax unchanged.  SmiOperands assumes both are smis.
37480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // NumberOperands assumes both are smis or heap numbers.
37580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  static void LoadSSE2SmiOperands(MacroAssembler* masm);
37680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  static void LoadSSE2NumberOperands(MacroAssembler* masm);
37780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  static void LoadSSE2UnknownOperands(MacroAssembler* masm,
37880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                      Label* not_numbers);
37980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
38080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Takes the operands in rdx and rax and loads them as integers in rax
38180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // and rcx.
38280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  static void LoadAsIntegers(MacroAssembler* masm,
38380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                             Label* operand_conversion_failure,
38480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                             Register heap_number_map);
38580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // As above, but we know the operands to be numbers. In that case,
38680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // conversion can't fail.
38780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  static void LoadNumbersAsIntegers(MacroAssembler* masm);
38880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
3898b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  // Tries to convert two values to smis losslessly.
3908b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  // This fails if either argument is not a Smi nor a HeapNumber,
3918b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  // or if it's a HeapNumber with a value that can't be converted
3928b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  // losslessly to a Smi. In that case, control transitions to the
3938b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  // on_not_smis label.
3948b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  // On success, either control goes to the on_success label (if one is
3958b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  // provided), or it falls through at the end of the code (if on_success
3968b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  // is NULL).
3978b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  // On success, both first and second holds Smi tagged values.
3988b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  // One of first or second must be non-Smi when entering.
3998b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  static void NumbersToSmis(MacroAssembler* masm,
4008b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch                            Register first,
4018b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch                            Register second,
4028b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch                            Register scratch1,
4038b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch                            Register scratch2,
4048b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch                            Register scratch3,
4058b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch                            Label* on_success,
4068b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch                            Label* on_not_smis);
4078b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch};
40880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
40980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
410257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// Get the integer part of a heap number.
411257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// Overwrites the contents of rdi, rbx and rcx. Result cannot be rdi or rbx.
412257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid IntegerConvert(MacroAssembler* masm,
413257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                    Register result,
414257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                    Register source) {
415257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Result may be rcx. If result and source are the same register, source will
416257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // be overwritten.
417257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  ASSERT(!result.is(rdi) && !result.is(rbx));
418257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // TODO(lrn): When type info reaches here, if value is a 32-bit integer, use
419257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // cvttsd2si (32-bit version) directly.
420257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Register double_exponent = rbx;
421257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Register double_value = rdi;
422257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label done, exponent_63_plus;
423257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Get double and extract exponent.
424257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ movq(double_value, FieldOperand(source, HeapNumber::kValueOffset));
425257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Clear result preemptively, in case we need to return zero.
426257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ xorl(result, result);
427257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ movq(xmm0, double_value);  // Save copy in xmm0 in case we need it there.
428257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Double to remove sign bit, shift exponent down to least significant bits.
429257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // and subtract bias to get the unshifted, unbiased exponent.
430257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ lea(double_exponent, Operand(double_value, double_value, times_1, 0));
431257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ shr(double_exponent, Immediate(64 - HeapNumber::kExponentBits));
432257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ subl(double_exponent, Immediate(HeapNumber::kExponentBias));
433257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Check whether the exponent is too big for a 63 bit unsigned integer.
434257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ cmpl(double_exponent, Immediate(63));
435257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(above_equal, &exponent_63_plus, Label::kNear);
436257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Handle exponent range 0..62.
437257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ cvttsd2siq(result, xmm0);
438257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ jmp(&done, Label::kNear);
439257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
440257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&exponent_63_plus);
441257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Exponent negative or 63+.
442257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ cmpl(double_exponent, Immediate(83));
443257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // If exponent negative or above 83, number contains no significant bits in
444257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // the range 0..2^31, so result is zero, and rcx already holds zero.
445257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(above, &done, Label::kNear);
446257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
447257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Exponent in rage 63..83.
448257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Mantissa * 2^exponent contains bits in the range 2^0..2^31, namely
449257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // the least significant exponent-52 bits.
450257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
451257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Negate low bits of mantissa if value is negative.
452257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ addq(double_value, double_value);  // Move sign bit to carry.
453257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ sbbl(result, result);  // And convert carry to -1 in result register.
454257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // if scratch2 is negative, do (scratch2-1)^-1, otherwise (scratch2-0)^0.
455257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ addl(double_value, result);
456257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Do xor in opposite directions depending on where we want the result
457257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // (depending on whether result is rcx or not).
458257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
459257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  if (result.is(rcx)) {
460257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ xorl(double_value, result);
461257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Left shift mantissa by (exponent - mantissabits - 1) to save the
462257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // bits that have positional values below 2^32 (the extra -1 comes from the
463257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // doubling done above to move the sign bit into the carry flag).
464257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ leal(rcx, Operand(double_exponent, -HeapNumber::kMantissaBits - 1));
465257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ shll_cl(double_value);
466257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ movl(result, double_value);
467257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  } else {
468257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // As the then-branch, but move double-value to result before shifting.
469257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ xorl(result, double_value);
470257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ leal(rcx, Operand(double_exponent, -HeapNumber::kMantissaBits - 1));
471257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ shll_cl(result);
472257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
473257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
474257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&done);
475257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch}
476257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
477257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
478257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::Generate(MacroAssembler* masm) {
479257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  switch (operand_type_) {
480257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case UnaryOpIC::UNINITIALIZED:
481257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      GenerateTypeTransition(masm);
482257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      break;
483257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case UnaryOpIC::SMI:
484257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      GenerateSmiStub(masm);
485257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      break;
486257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case UnaryOpIC::HEAP_NUMBER:
487257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      GenerateHeapNumberStub(masm);
488257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      break;
489257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case UnaryOpIC::GENERIC:
490257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      GenerateGenericStub(masm);
491257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      break;
492257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
493257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch}
494257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
495257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
496257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::GenerateTypeTransition(MacroAssembler* masm) {
497257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ pop(rcx);  // Save return address.
4983fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
4993fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ push(rax);  // the operand
500257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Push(Smi::FromInt(op_));
5013fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ Push(Smi::FromInt(mode_));
502257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Push(Smi::FromInt(operand_type_));
503257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
504257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ push(rcx);  // Push return address.
505257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
506257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Patch the caller to an appropriate specialized stub and return the
507257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // operation result to the caller of the stub.
508257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ TailCallExternalReference(
5093fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch      ExternalReference(IC_Utility(IC::kUnaryOp_Patch), masm->isolate()), 4, 1);
510257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch}
511257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
512257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
513257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// TODO(svenpanne): Use virtual functions instead of switch.
514257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::GenerateSmiStub(MacroAssembler* masm) {
515257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  switch (op_) {
516257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case Token::SUB:
517257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      GenerateSmiStubSub(masm);
518257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      break;
519257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case Token::BIT_NOT:
520257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      GenerateSmiStubBitNot(masm);
521257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      break;
522257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    default:
523257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      UNREACHABLE();
524257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
525257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch}
526257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
527257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
528257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::GenerateSmiStubSub(MacroAssembler* masm) {
529257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label slow;
530257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  GenerateSmiCodeSub(masm, &slow, &slow, Label::kNear, Label::kNear);
531257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&slow);
532257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  GenerateTypeTransition(masm);
533257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch}
534257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
535257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
536257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::GenerateSmiStubBitNot(MacroAssembler* masm) {
537257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label non_smi;
538257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  GenerateSmiCodeBitNot(masm, &non_smi, Label::kNear);
539257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&non_smi);
540257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  GenerateTypeTransition(masm);
541257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch}
542257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
543257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
544257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::GenerateSmiCodeSub(MacroAssembler* masm,
545257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                     Label* non_smi,
546257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                     Label* slow,
547257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                     Label::Distance non_smi_near,
548257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                     Label::Distance slow_near) {
549257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label done;
550257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ JumpIfNotSmi(rax, non_smi, non_smi_near);
551257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ SmiNeg(rax, rax, &done, Label::kNear);
552257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ jmp(slow, slow_near);
553257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&done);
554257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ ret(0);
555257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch}
556257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
557257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
558257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::GenerateSmiCodeBitNot(MacroAssembler* masm,
559257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                        Label* non_smi,
560257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                        Label::Distance non_smi_near) {
561257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ JumpIfNotSmi(rax, non_smi, non_smi_near);
562257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ SmiNot(rax, rax);
563257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ ret(0);
564257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch}
565257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
566257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
567257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// TODO(svenpanne): Use virtual functions instead of switch.
568257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::GenerateHeapNumberStub(MacroAssembler* masm) {
569257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  switch (op_) {
570257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case Token::SUB:
571257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      GenerateHeapNumberStubSub(masm);
572257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      break;
573257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case Token::BIT_NOT:
574257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      GenerateHeapNumberStubBitNot(masm);
575257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      break;
576257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    default:
577257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      UNREACHABLE();
578257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
579257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch}
580257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
581257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
582257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::GenerateHeapNumberStubSub(MacroAssembler* masm) {
583257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label non_smi, slow, call_builtin;
584257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  GenerateSmiCodeSub(masm, &non_smi, &call_builtin, Label::kNear);
585257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&non_smi);
586257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  GenerateHeapNumberCodeSub(masm, &slow);
587257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&slow);
588257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  GenerateTypeTransition(masm);
589257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&call_builtin);
590257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  GenerateGenericCodeFallback(masm);
591257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch}
592257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
593257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
594257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::GenerateHeapNumberStubBitNot(
595257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    MacroAssembler* masm) {
596257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label non_smi, slow;
597257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  GenerateSmiCodeBitNot(masm, &non_smi, Label::kNear);
598257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&non_smi);
599257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  GenerateHeapNumberCodeBitNot(masm, &slow);
600257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&slow);
601257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  GenerateTypeTransition(masm);
602257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch}
603257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
604257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
605257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::GenerateHeapNumberCodeSub(MacroAssembler* masm,
606257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                            Label* slow) {
607257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Check if the operand is a heap number.
608257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ CompareRoot(FieldOperand(rax, HeapObject::kMapOffset),
609257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                 Heap::kHeapNumberMapRootIndex);
610257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(not_equal, slow);
611257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
612257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Operand is a float, negate its value by flipping the sign bit.
613257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  if (mode_ == UNARY_OVERWRITE) {
614257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ Set(kScratchRegister, 0x01);
615257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ shl(kScratchRegister, Immediate(63));
616257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ xor_(FieldOperand(rax, HeapNumber::kValueOffset), kScratchRegister);
617257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  } else {
618257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Allocate a heap number before calculating the answer,
619257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // so we don't have an untagged double around during GC.
620257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Label slow_allocate_heapnumber, heapnumber_allocated;
621257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ AllocateHeapNumber(rcx, rbx, &slow_allocate_heapnumber);
622257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ jmp(&heapnumber_allocated);
623257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
624257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ bind(&slow_allocate_heapnumber);
625257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ EnterInternalFrame();
626257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ push(rax);
627257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ CallRuntime(Runtime::kNumberAlloc, 0);
628257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ movq(rcx, rax);
629257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ pop(rax);
630257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ LeaveInternalFrame();
631257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ bind(&heapnumber_allocated);
632257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // rcx: allocated 'empty' number
633257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
634257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Copy the double value to the new heap number, flipping the sign.
635257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ movq(rdx, FieldOperand(rax, HeapNumber::kValueOffset));
636257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ Set(kScratchRegister, 0x01);
637257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ shl(kScratchRegister, Immediate(63));
638257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ xor_(rdx, kScratchRegister);  // Flip sign.
639257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ movq(FieldOperand(rcx, HeapNumber::kValueOffset), rdx);
640257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ movq(rax, rcx);
641257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
642257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ ret(0);
643257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch}
644257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
645257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
646257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::GenerateHeapNumberCodeBitNot(MacroAssembler* masm,
647257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                               Label* slow) {
648257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Check if the operand is a heap number.
649257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ CompareRoot(FieldOperand(rax, HeapObject::kMapOffset),
650257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                 Heap::kHeapNumberMapRootIndex);
651257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(not_equal, slow);
652257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
653257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Convert the heap number in rax to an untagged integer in rcx.
654257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  IntegerConvert(masm, rax, rax);
655257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
656257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Do the bitwise operation and smi tag the result.
657257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ notl(rax);
658257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Integer32ToSmi(rax, rax);
659257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ ret(0);
660257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch}
661257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
662257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
663257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// TODO(svenpanne): Use virtual functions instead of switch.
664257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::GenerateGenericStub(MacroAssembler* masm) {
665257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  switch (op_) {
666257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case Token::SUB:
667257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      GenerateGenericStubSub(masm);
668257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      break;
669257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case Token::BIT_NOT:
670257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      GenerateGenericStubBitNot(masm);
671257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      break;
672257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    default:
673257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      UNREACHABLE();
674257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
675257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch}
676257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
677257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
678257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::GenerateGenericStubSub(MacroAssembler* masm) {
679257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label non_smi, slow;
680257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  GenerateSmiCodeSub(masm, &non_smi, &slow, Label::kNear);
681257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&non_smi);
682257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  GenerateHeapNumberCodeSub(masm, &slow);
683257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&slow);
684257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  GenerateGenericCodeFallback(masm);
685257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch}
686257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
687257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
688257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::GenerateGenericStubBitNot(MacroAssembler* masm) {
689257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label non_smi, slow;
690257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  GenerateSmiCodeBitNot(masm, &non_smi, Label::kNear);
691257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&non_smi);
692257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  GenerateHeapNumberCodeBitNot(masm, &slow);
693257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&slow);
694257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  GenerateGenericCodeFallback(masm);
695257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch}
696257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
697257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
698257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid UnaryOpStub::GenerateGenericCodeFallback(MacroAssembler* masm) {
699257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Handle the slow case by jumping to the JavaScript builtin.
700257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ pop(rcx);  // pop return address
701257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ push(rax);
702257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ push(rcx);  // push return address
703257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  switch (op_) {
704257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case Token::SUB:
705257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ InvokeBuiltin(Builtins::UNARY_MINUS, JUMP_FUNCTION);
706257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      break;
707257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case Token::BIT_NOT:
708257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ InvokeBuiltin(Builtins::BIT_NOT, JUMP_FUNCTION);
709257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      break;
710257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    default:
711257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      UNREACHABLE();
712257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
713257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch}
714257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
715257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
7163fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdochvoid UnaryOpStub::PrintName(StringStream* stream) {
717257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  const char* op_name = Token::Name(op_);
718257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  const char* overwrite_name = NULL;  // Make g++ happy.
719257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  switch (mode_) {
720257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case UNARY_NO_OVERWRITE: overwrite_name = "Alloc"; break;
721257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case UNARY_OVERWRITE: overwrite_name = "Overwrite"; break;
722257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
7233fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  stream->Add("UnaryOpStub_%s_%s_%s",
7243fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch              op_name,
7253fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch              overwrite_name,
7263fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch              UnaryOpIC::GetName(operand_type_));
727086aeeaae12517475c22695a200be45495516549Ben Murdoch}
728086aeeaae12517475c22695a200be45495516549Ben Murdoch
729086aeeaae12517475c22695a200be45495516549Ben Murdoch
730257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid BinaryOpStub::GenerateTypeTransition(MacroAssembler* masm) {
731086aeeaae12517475c22695a200be45495516549Ben Murdoch  __ pop(rcx);  // Save return address.
732086aeeaae12517475c22695a200be45495516549Ben Murdoch  __ push(rdx);
733086aeeaae12517475c22695a200be45495516549Ben Murdoch  __ push(rax);
734086aeeaae12517475c22695a200be45495516549Ben Murdoch  // Left and right arguments are now on top.
735086aeeaae12517475c22695a200be45495516549Ben Murdoch  // Push this stub's key. Although the operation and the type info are
736086aeeaae12517475c22695a200be45495516549Ben Murdoch  // encoded into the key, the encoding is opaque, so push them too.
737086aeeaae12517475c22695a200be45495516549Ben Murdoch  __ Push(Smi::FromInt(MinorKey()));
738086aeeaae12517475c22695a200be45495516549Ben Murdoch  __ Push(Smi::FromInt(op_));
739086aeeaae12517475c22695a200be45495516549Ben Murdoch  __ Push(Smi::FromInt(operands_type_));
740086aeeaae12517475c22695a200be45495516549Ben Murdoch
741086aeeaae12517475c22695a200be45495516549Ben Murdoch  __ push(rcx);  // Push return address.
742086aeeaae12517475c22695a200be45495516549Ben Murdoch
743086aeeaae12517475c22695a200be45495516549Ben Murdoch  // Patch the caller to an appropriate specialized stub and return the
744086aeeaae12517475c22695a200be45495516549Ben Murdoch  // operation result to the caller of the stub.
745086aeeaae12517475c22695a200be45495516549Ben Murdoch  __ TailCallExternalReference(
746257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      ExternalReference(IC_Utility(IC::kBinaryOp_Patch),
74744f0eee88ff00398ff7f715fab053374d808c90dSteve Block                        masm->isolate()),
748086aeeaae12517475c22695a200be45495516549Ben Murdoch      5,
749086aeeaae12517475c22695a200be45495516549Ben Murdoch      1);
750086aeeaae12517475c22695a200be45495516549Ben Murdoch}
751086aeeaae12517475c22695a200be45495516549Ben Murdoch
752086aeeaae12517475c22695a200be45495516549Ben Murdoch
753257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid BinaryOpStub::Generate(MacroAssembler* masm) {
754086aeeaae12517475c22695a200be45495516549Ben Murdoch  switch (operands_type_) {
755257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case BinaryOpIC::UNINITIALIZED:
756086aeeaae12517475c22695a200be45495516549Ben Murdoch      GenerateTypeTransition(masm);
757086aeeaae12517475c22695a200be45495516549Ben Murdoch      break;
758257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case BinaryOpIC::SMI:
759086aeeaae12517475c22695a200be45495516549Ben Murdoch      GenerateSmiStub(masm);
760086aeeaae12517475c22695a200be45495516549Ben Murdoch      break;
761257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case BinaryOpIC::INT32:
7621e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      UNREACHABLE();
7631e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      // The int32 case is identical to the Smi case.  We avoid creating this
7641e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      // ic state on x64.
765086aeeaae12517475c22695a200be45495516549Ben Murdoch      break;
766257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case BinaryOpIC::HEAP_NUMBER:
767086aeeaae12517475c22695a200be45495516549Ben Murdoch      GenerateHeapNumberStub(masm);
768086aeeaae12517475c22695a200be45495516549Ben Murdoch      break;
769257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case BinaryOpIC::ODDBALL:
77044f0eee88ff00398ff7f715fab053374d808c90dSteve Block      GenerateOddballStub(masm);
77144f0eee88ff00398ff7f715fab053374d808c90dSteve Block      break;
772257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case BinaryOpIC::BOTH_STRING:
773257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      GenerateBothStringStub(masm);
774257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      break;
775257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case BinaryOpIC::STRING:
776086aeeaae12517475c22695a200be45495516549Ben Murdoch      GenerateStringStub(masm);
777086aeeaae12517475c22695a200be45495516549Ben Murdoch      break;
778257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    case BinaryOpIC::GENERIC:
779086aeeaae12517475c22695a200be45495516549Ben Murdoch      GenerateGeneric(masm);
780086aeeaae12517475c22695a200be45495516549Ben Murdoch      break;
781086aeeaae12517475c22695a200be45495516549Ben Murdoch    default:
782086aeeaae12517475c22695a200be45495516549Ben Murdoch      UNREACHABLE();
783086aeeaae12517475c22695a200be45495516549Ben Murdoch  }
784086aeeaae12517475c22695a200be45495516549Ben Murdoch}
785086aeeaae12517475c22695a200be45495516549Ben Murdoch
786086aeeaae12517475c22695a200be45495516549Ben Murdoch
7873fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdochvoid BinaryOpStub::PrintName(StringStream* stream) {
788086aeeaae12517475c22695a200be45495516549Ben Murdoch  const char* op_name = Token::Name(op_);
789086aeeaae12517475c22695a200be45495516549Ben Murdoch  const char* overwrite_name;
790086aeeaae12517475c22695a200be45495516549Ben Murdoch  switch (mode_) {
791086aeeaae12517475c22695a200be45495516549Ben Murdoch    case NO_OVERWRITE: overwrite_name = "Alloc"; break;
792086aeeaae12517475c22695a200be45495516549Ben Murdoch    case OVERWRITE_RIGHT: overwrite_name = "OverwriteRight"; break;
793086aeeaae12517475c22695a200be45495516549Ben Murdoch    case OVERWRITE_LEFT: overwrite_name = "OverwriteLeft"; break;
794086aeeaae12517475c22695a200be45495516549Ben Murdoch    default: overwrite_name = "UnknownOverwrite"; break;
795086aeeaae12517475c22695a200be45495516549Ben Murdoch  }
7963fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  stream->Add("BinaryOpStub_%s_%s_%s",
7973fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch              op_name,
7983fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch              overwrite_name,
7993fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch              BinaryOpIC::GetName(operands_type_));
800086aeeaae12517475c22695a200be45495516549Ben Murdoch}
801086aeeaae12517475c22695a200be45495516549Ben Murdoch
802086aeeaae12517475c22695a200be45495516549Ben Murdoch
803257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid BinaryOpStub::GenerateSmiCode(
804257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    MacroAssembler* masm,
805086aeeaae12517475c22695a200be45495516549Ben Murdoch    Label* slow,
806086aeeaae12517475c22695a200be45495516549Ben Murdoch    SmiCodeGenerateHeapNumberResults allow_heapnumber_results) {
807086aeeaae12517475c22695a200be45495516549Ben Murdoch
808257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Arguments to BinaryOpStub are in rdx and rax.
8091e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  Register left = rdx;
8101e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  Register right = rax;
811086aeeaae12517475c22695a200be45495516549Ben Murdoch
8128b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  // We only generate heapnumber answers for overflowing calculations
8138b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  // for the four basic arithmetic operations and logical right shift by 0.
8148b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  bool generate_inline_heapnumber_results =
8158b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch      (allow_heapnumber_results == ALLOW_HEAPNUMBER_RESULTS) &&
8168b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch      (op_ == Token::ADD || op_ == Token::SUB ||
8178b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch       op_ == Token::MUL || op_ == Token::DIV || op_ == Token::SHR);
818086aeeaae12517475c22695a200be45495516549Ben Murdoch
8191e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  // Smi check of both operands.  If op is BIT_OR, the check is delayed
8201e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  // until after the OR operation.
8211e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  Label not_smis;
8221e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  Label use_fp_on_smis;
8238b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  Label fail;
8241e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
8251e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  if (op_ != Token::BIT_OR) {
8261e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    Comment smi_check_comment(masm, "-- Smi check arguments");
8271e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    __ JumpIfNotBothSmi(left, right, &not_smis);
8281e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  }
8291e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
8308b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  Label smi_values;
8318b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  __ bind(&smi_values);
8321e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  // Perform the operation.
8331e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  Comment perform_smi(masm, "-- Perform smi operation");
834086aeeaae12517475c22695a200be45495516549Ben Murdoch  switch (op_) {
835086aeeaae12517475c22695a200be45495516549Ben Murdoch    case Token::ADD:
8361e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      ASSERT(right.is(rax));
8371e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      __ SmiAdd(right, right, left, &use_fp_on_smis);  // ADD is commutative.
8381e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      break;
8391e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
840086aeeaae12517475c22695a200be45495516549Ben Murdoch    case Token::SUB:
8411e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      __ SmiSub(left, left, right, &use_fp_on_smis);
8421e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      __ movq(rax, left);
8431e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      break;
8441e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
845086aeeaae12517475c22695a200be45495516549Ben Murdoch    case Token::MUL:
8461e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      ASSERT(right.is(rax));
8471e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      __ SmiMul(right, right, left, &use_fp_on_smis);  // MUL is commutative.
8481e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      break;
8491e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
850086aeeaae12517475c22695a200be45495516549Ben Murdoch    case Token::DIV:
8511e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      // SmiDiv will not accept left in rdx or right in rax.
8521e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      left = rcx;
8531e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      right = rbx;
8541e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      __ movq(rbx, rax);
8551e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      __ movq(rcx, rdx);
8561e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      __ SmiDiv(rax, left, right, &use_fp_on_smis);
857086aeeaae12517475c22695a200be45495516549Ben Murdoch      break;
8581e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
859086aeeaae12517475c22695a200be45495516549Ben Murdoch    case Token::MOD:
8601e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      // SmiMod will not accept left in rdx or right in rax.
8611e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      left = rcx;
8621e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      right = rbx;
8631e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      __ movq(rbx, rax);
8641e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      __ movq(rcx, rdx);
8651e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      __ SmiMod(rax, left, right, &use_fp_on_smis);
8661e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      break;
8671e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
8681e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    case Token::BIT_OR: {
8691e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      ASSERT(right.is(rax));
8708b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch      __ SmiOrIfSmis(right, right, left, &not_smis);  // BIT_OR is commutative.
8711e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      break;
8721e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      }
873086aeeaae12517475c22695a200be45495516549Ben Murdoch    case Token::BIT_XOR:
8741e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      ASSERT(right.is(rax));
8751e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      __ SmiXor(right, right, left);  // BIT_XOR is commutative.
8761e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      break;
8771e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
8781e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    case Token::BIT_AND:
8791e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      ASSERT(right.is(rax));
8801e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      __ SmiAnd(right, right, left);  // BIT_AND is commutative.
8811e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      break;
8821e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
883086aeeaae12517475c22695a200be45495516549Ben Murdoch    case Token::SHL:
8841e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      __ SmiShiftLeft(left, left, right);
8851e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      __ movq(rax, left);
8861e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      break;
8871e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
8881e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    case Token::SAR:
8891e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      __ SmiShiftArithmeticRight(left, left, right);
8901e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      __ movq(rax, left);
8911e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      break;
8921e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
893086aeeaae12517475c22695a200be45495516549Ben Murdoch    case Token::SHR:
8948b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch      __ SmiShiftLogicalRight(left, left, right, &use_fp_on_smis);
8951e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      __ movq(rax, left);
896086aeeaae12517475c22695a200be45495516549Ben Murdoch      break;
8971e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
898086aeeaae12517475c22695a200be45495516549Ben Murdoch    default:
899086aeeaae12517475c22695a200be45495516549Ben Murdoch      UNREACHABLE();
900086aeeaae12517475c22695a200be45495516549Ben Murdoch  }
901086aeeaae12517475c22695a200be45495516549Ben Murdoch
9021e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  // 5. Emit return of result in rax.  Some operations have registers pushed.
9031e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  __ ret(0);
9041e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
9058b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  if (use_fp_on_smis.is_linked()) {
9068b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch    // 6. For some operations emit inline code to perform floating point
9078b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch    //    operations on known smis (e.g., if the result of the operation
9088b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch    //    overflowed the smi range).
9098b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch    __ bind(&use_fp_on_smis);
9108b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch    if (op_ == Token::DIV || op_ == Token::MOD) {
9118b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch      // Restore left and right to rdx and rax.
9128b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch      __ movq(rdx, rcx);
9138b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch      __ movq(rax, rbx);
9148b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch    }
9151e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
9168b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch    if (generate_inline_heapnumber_results) {
9178b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch      __ AllocateHeapNumber(rcx, rbx, slow);
9188b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch      Comment perform_float(masm, "-- Perform float operation on smis");
9198b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch      if (op_ == Token::SHR) {
9208b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch        __ SmiToInteger32(left, left);
9218b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch        __ cvtqsi2sd(xmm0, left);
9228b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch      } else {
9238b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch        FloatingPointHelper::LoadSSE2SmiOperands(masm);
9248b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch        switch (op_) {
9258b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch        case Token::ADD: __ addsd(xmm0, xmm1); break;
9268b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch        case Token::SUB: __ subsd(xmm0, xmm1); break;
9278b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch        case Token::MUL: __ mulsd(xmm0, xmm1); break;
9288b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch        case Token::DIV: __ divsd(xmm0, xmm1); break;
9298b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch        default: UNREACHABLE();
9308b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch        }
9318b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch      }
9328b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch      __ movsd(FieldOperand(rcx, HeapNumber::kValueOffset), xmm0);
9338b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch      __ movq(rax, rcx);
9348b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch      __ ret(0);
9358b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch    } else {
9368b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch      __ jmp(&fail);
9371e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    }
9381e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  }
9391e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
9401e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  // 7. Non-smi operands reach the end of the code generated by
9411e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  //    GenerateSmiCode, and fall through to subsequent code,
9421e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  //    with the operands in rdx and rax.
9438b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  //    But first we check if non-smi values are HeapNumbers holding
9448b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  //    values that could be smi.
9451e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  __ bind(&not_smis);
9468b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  Comment done_comment(masm, "-- Enter non-smi code");
9478b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  FloatingPointHelper::NumbersToSmis(masm, left, right, rbx, rdi, rcx,
9488b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch                                     &smi_values, &fail);
9498b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  __ jmp(&smi_values);
9508b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  __ bind(&fail);
9511e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block}
9521e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
9531e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
954257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid BinaryOpStub::GenerateFloatingPointCode(MacroAssembler* masm,
955257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                             Label* allocation_failure,
956257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                             Label* non_numeric_failure) {
957086aeeaae12517475c22695a200be45495516549Ben Murdoch  switch (op_) {
958086aeeaae12517475c22695a200be45495516549Ben Murdoch    case Token::ADD:
959086aeeaae12517475c22695a200be45495516549Ben Murdoch    case Token::SUB:
960086aeeaae12517475c22695a200be45495516549Ben Murdoch    case Token::MUL:
9611e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    case Token::DIV: {
9621e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      FloatingPointHelper::LoadSSE2UnknownOperands(masm, non_numeric_failure);
9631e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
9641e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      switch (op_) {
9651e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block        case Token::ADD: __ addsd(xmm0, xmm1); break;
9661e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block        case Token::SUB: __ subsd(xmm0, xmm1); break;
9671e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block        case Token::MUL: __ mulsd(xmm0, xmm1); break;
9681e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block        case Token::DIV: __ divsd(xmm0, xmm1); break;
9691e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block        default: UNREACHABLE();
9701e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      }
9711e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      GenerateHeapResultAllocation(masm, allocation_failure);
9721e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      __ movsd(FieldOperand(rax, HeapNumber::kValueOffset), xmm0);
9731e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      __ ret(0);
9741e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      break;
9751e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    }
9761e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    case Token::MOD: {
9771e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      // For MOD we jump to the allocation_failure label, to call runtime.
9781e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      __ jmp(allocation_failure);
9791e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      break;
9801e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    }
9811e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    case Token::BIT_OR:
9821e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    case Token::BIT_AND:
9831e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    case Token::BIT_XOR:
9841e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    case Token::SAR:
9851e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    case Token::SHL:
9861e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    case Token::SHR: {
9871e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      Label non_smi_shr_result;
9881e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      Register heap_number_map = r9;
9891e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      __ LoadRoot(heap_number_map, Heap::kHeapNumberMapRootIndex);
9901e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      FloatingPointHelper::LoadAsIntegers(masm, non_numeric_failure,
9911e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block                                          heap_number_map);
9921e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      switch (op_) {
9931e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block        case Token::BIT_OR:  __ orl(rax, rcx); break;
9941e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block        case Token::BIT_AND: __ andl(rax, rcx); break;
9951e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block        case Token::BIT_XOR: __ xorl(rax, rcx); break;
9961e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block        case Token::SAR: __ sarl_cl(rax); break;
9971e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block        case Token::SHL: __ shll_cl(rax); break;
9981e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block        case Token::SHR: {
9991e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block          __ shrl_cl(rax);
10001e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block          // Check if result is negative. This can only happen for a shift
10011e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block          // by zero.
10021e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block          __ testl(rax, rax);
10031e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block          __ j(negative, &non_smi_shr_result);
10041e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block          break;
10051e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block        }
10061e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block        default: UNREACHABLE();
10071e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      }
10081e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      STATIC_ASSERT(kSmiValueSize == 32);
10091e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      // Tag smi result and return.
10101e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      __ Integer32ToSmi(rax, rax);
10111e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      __ Ret();
10121e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
10131e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      // Logical shift right can produce an unsigned int32 that is not
10141e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      // an int32, and so is not in the smi range.  Allocate a heap number
10151e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      // in that case.
10161e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      if (op_ == Token::SHR) {
10171e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block        __ bind(&non_smi_shr_result);
10181e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block        Label allocation_failed;
10191e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block        __ movl(rbx, rax);  // rbx holds result value (uint32 value as int64).
10201e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block        // Allocate heap number in new space.
10211e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block        // Not using AllocateHeapNumber macro in order to reuse
10221e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block        // already loaded heap_number_map.
10231e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block        __ AllocateInNewSpace(HeapNumber::kSize,
10241e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block                              rax,
1025053d10c438f14580aaf4ab1b2aad93a5a4fe8b82Steve Block                              rdx,
10261e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block                              no_reg,
10271e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block                              &allocation_failed,
10281e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block                              TAG_OBJECT);
10291e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block        // Set the map.
10301e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block        if (FLAG_debug_code) {
10311e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block          __ AbortIfNotRootValue(heap_number_map,
10321e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block                                 Heap::kHeapNumberMapRootIndex,
10331e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block                                 "HeapNumberMap register clobbered.");
10341e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block        }
10351e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block        __ movq(FieldOperand(rax, HeapObject::kMapOffset),
10361e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block                heap_number_map);
10371e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block        __ cvtqsi2sd(xmm0, rbx);
10381e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block        __ movsd(FieldOperand(rax, HeapNumber::kValueOffset), xmm0);
10391e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block        __ Ret();
10401e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
10411e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block        __ bind(&allocation_failed);
10421e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block        // We need tagged values in rdx and rax for the following code,
10431e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block        // not int32 in rax and rcx.
10441e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block        __ Integer32ToSmi(rax, rcx);
1045053d10c438f14580aaf4ab1b2aad93a5a4fe8b82Steve Block        __ Integer32ToSmi(rdx, rbx);
10461e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block        __ jmp(allocation_failure);
10471e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      }
10481e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      break;
10491e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    }
10501e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    default: UNREACHABLE(); break;
10511e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  }
10521e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  // No fall-through from this generated code.
10531e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  if (FLAG_debug_code) {
10541e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    __ Abort("Unexpected fall-through in "
1055257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch             "BinaryStub::GenerateFloatingPointCode.");
10561e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  }
10571e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block}
10581e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
10591e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
1060257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid BinaryOpStub::GenerateStringAddCode(MacroAssembler* masm) {
1061e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  ASSERT(op_ == Token::ADD);
1062257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label left_not_string, call_runtime;
10631e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
1064e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  // Registers containing left and right operands respectively.
1065e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  Register left = rdx;
1066e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  Register right = rax;
10671e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
1068e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  // Test if left operand is a string.
1069257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ JumpIfSmi(left, &left_not_string, Label::kNear);
1070e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ CmpObjectType(left, FIRST_NONSTRING_TYPE, rcx);
1071257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(above_equal, &left_not_string, Label::kNear);
1072e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  StringAddStub string_add_left_stub(NO_STRING_CHECK_LEFT_IN_STUB);
1073e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  GenerateRegisterArgsPush(masm);
1074e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ TailCallStub(&string_add_left_stub);
10751e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
1076e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  // Left operand is not a string, test right.
1077e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ bind(&left_not_string);
1078257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ JumpIfSmi(right, &call_runtime, Label::kNear);
1079e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ CmpObjectType(right, FIRST_NONSTRING_TYPE, rcx);
1080257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(above_equal, &call_runtime, Label::kNear);
10811e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
1082e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  StringAddStub string_add_right_stub(NO_STRING_CHECK_RIGHT_IN_STUB);
1083e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  GenerateRegisterArgsPush(masm);
1084e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ TailCallStub(&string_add_right_stub);
10851e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
10861e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  // Neither argument is a string.
1087e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ bind(&call_runtime);
10881e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block}
10891e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
10901e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
1091257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid BinaryOpStub::GenerateCallRuntimeCode(MacroAssembler* masm) {
10921e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  GenerateRegisterArgsPush(masm);
10931e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  switch (op_) {
10941e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    case Token::ADD:
10951e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      __ InvokeBuiltin(Builtins::ADD, JUMP_FUNCTION);
10961e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      break;
10971e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    case Token::SUB:
10981e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      __ InvokeBuiltin(Builtins::SUB, JUMP_FUNCTION);
10991e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      break;
11001e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    case Token::MUL:
11011e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      __ InvokeBuiltin(Builtins::MUL, JUMP_FUNCTION);
11021e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      break;
1103086aeeaae12517475c22695a200be45495516549Ben Murdoch    case Token::DIV:
11041e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      __ InvokeBuiltin(Builtins::DIV, JUMP_FUNCTION);
1105086aeeaae12517475c22695a200be45495516549Ben Murdoch      break;
1106086aeeaae12517475c22695a200be45495516549Ben Murdoch    case Token::MOD:
11071e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      __ InvokeBuiltin(Builtins::MOD, JUMP_FUNCTION);
11081e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      break;
1109086aeeaae12517475c22695a200be45495516549Ben Murdoch    case Token::BIT_OR:
11101e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      __ InvokeBuiltin(Builtins::BIT_OR, JUMP_FUNCTION);
11111e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      break;
1112086aeeaae12517475c22695a200be45495516549Ben Murdoch    case Token::BIT_AND:
11131e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      __ InvokeBuiltin(Builtins::BIT_AND, JUMP_FUNCTION);
11141e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      break;
1115086aeeaae12517475c22695a200be45495516549Ben Murdoch    case Token::BIT_XOR:
11161e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      __ InvokeBuiltin(Builtins::BIT_XOR, JUMP_FUNCTION);
11171e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      break;
1118086aeeaae12517475c22695a200be45495516549Ben Murdoch    case Token::SAR:
11191e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      __ InvokeBuiltin(Builtins::SAR, JUMP_FUNCTION);
11201e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      break;
1121086aeeaae12517475c22695a200be45495516549Ben Murdoch    case Token::SHL:
11221e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      __ InvokeBuiltin(Builtins::SHL, JUMP_FUNCTION);
11231e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      break;
1124086aeeaae12517475c22695a200be45495516549Ben Murdoch    case Token::SHR:
11251e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      __ InvokeBuiltin(Builtins::SHR, JUMP_FUNCTION);
1126086aeeaae12517475c22695a200be45495516549Ben Murdoch      break;
1127086aeeaae12517475c22695a200be45495516549Ben Murdoch    default:
1128086aeeaae12517475c22695a200be45495516549Ben Murdoch      UNREACHABLE();
1129086aeeaae12517475c22695a200be45495516549Ben Murdoch  }
1130086aeeaae12517475c22695a200be45495516549Ben Murdoch}
1131086aeeaae12517475c22695a200be45495516549Ben Murdoch
1132086aeeaae12517475c22695a200be45495516549Ben Murdoch
1133257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid BinaryOpStub::GenerateSmiStub(MacroAssembler* masm) {
11348b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  Label call_runtime;
1135257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  if (result_type_ == BinaryOpIC::UNINITIALIZED ||
1136257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      result_type_ == BinaryOpIC::SMI) {
11378b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch    // Only allow smi results.
11388b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch    GenerateSmiCode(masm, NULL, NO_HEAPNUMBER_RESULTS);
11398b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  } else {
11408b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch    // Allow heap number result and don't make a transition if a heap number
11418b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch    // cannot be allocated.
11428b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch    GenerateSmiCode(masm, &call_runtime, ALLOW_HEAPNUMBER_RESULTS);
11438b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  }
11441e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
11458b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  // Code falls through if the result is not returned as either a smi or heap
11468b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  // number.
11471e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  GenerateTypeTransition(masm);
11488b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch
11498b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  if (call_runtime.is_linked()) {
11508b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch    __ bind(&call_runtime);
11518b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch    GenerateCallRuntimeCode(masm);
11528b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  }
1153086aeeaae12517475c22695a200be45495516549Ben Murdoch}
1154086aeeaae12517475c22695a200be45495516549Ben Murdoch
1155086aeeaae12517475c22695a200be45495516549Ben Murdoch
1156257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid BinaryOpStub::GenerateStringStub(MacroAssembler* masm) {
1157257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  ASSERT(operands_type_ == BinaryOpIC::STRING);
11581e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  ASSERT(op_ == Token::ADD);
11591e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  GenerateStringAddCode(masm);
1160e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  // Try to add arguments as strings, otherwise, transition to the generic
1161257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // BinaryOpIC type.
11621e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  GenerateTypeTransition(masm);
1163086aeeaae12517475c22695a200be45495516549Ben Murdoch}
1164086aeeaae12517475c22695a200be45495516549Ben Murdoch
1165086aeeaae12517475c22695a200be45495516549Ben Murdoch
1166257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid BinaryOpStub::GenerateBothStringStub(MacroAssembler* masm) {
1167257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label call_runtime;
1168257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  ASSERT(operands_type_ == BinaryOpIC::BOTH_STRING);
1169257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  ASSERT(op_ == Token::ADD);
1170257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // If both arguments are strings, call the string add stub.
1171257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Otherwise, do a transition.
1172257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1173257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Registers containing left and right operands respectively.
1174257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Register left = rdx;
1175257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Register right = rax;
1176257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1177257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Test if left operand is a string.
1178257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ JumpIfSmi(left, &call_runtime);
1179257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ CmpObjectType(left, FIRST_NONSTRING_TYPE, rcx);
1180257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(above_equal, &call_runtime);
1181257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1182257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Test if right operand is a string.
1183257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ JumpIfSmi(right, &call_runtime);
1184257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ CmpObjectType(right, FIRST_NONSTRING_TYPE, rcx);
1185257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(above_equal, &call_runtime);
1186257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1187257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  StringAddStub string_add_stub(NO_STRING_CHECK_IN_STUB);
1188257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  GenerateRegisterArgsPush(masm);
1189257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ TailCallStub(&string_add_stub);
1190257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1191257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&call_runtime);
1192257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  GenerateTypeTransition(masm);
1193257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch}
1194257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1195257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1196257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid BinaryOpStub::GenerateOddballStub(MacroAssembler* masm) {
119744f0eee88ff00398ff7f715fab053374d808c90dSteve Block  Label call_runtime;
119844f0eee88ff00398ff7f715fab053374d808c90dSteve Block
119944f0eee88ff00398ff7f715fab053374d808c90dSteve Block  if (op_ == Token::ADD) {
120044f0eee88ff00398ff7f715fab053374d808c90dSteve Block    // Handle string addition here, because it is the only operation
120144f0eee88ff00398ff7f715fab053374d808c90dSteve Block    // that does not do a ToNumber conversion on the operands.
120244f0eee88ff00398ff7f715fab053374d808c90dSteve Block    GenerateStringAddCode(masm);
120344f0eee88ff00398ff7f715fab053374d808c90dSteve Block  }
120444f0eee88ff00398ff7f715fab053374d808c90dSteve Block
120544f0eee88ff00398ff7f715fab053374d808c90dSteve Block  // Convert oddball arguments to numbers.
1206257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label check, done;
120744f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ CompareRoot(rdx, Heap::kUndefinedValueRootIndex);
1208257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(not_equal, &check, Label::kNear);
120944f0eee88ff00398ff7f715fab053374d808c90dSteve Block  if (Token::IsBitOp(op_)) {
121044f0eee88ff00398ff7f715fab053374d808c90dSteve Block    __ xor_(rdx, rdx);
121144f0eee88ff00398ff7f715fab053374d808c90dSteve Block  } else {
121244f0eee88ff00398ff7f715fab053374d808c90dSteve Block    __ LoadRoot(rdx, Heap::kNanValueRootIndex);
121344f0eee88ff00398ff7f715fab053374d808c90dSteve Block  }
1214257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ jmp(&done, Label::kNear);
121544f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ bind(&check);
121644f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ CompareRoot(rax, Heap::kUndefinedValueRootIndex);
1217257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(not_equal, &done, Label::kNear);
121844f0eee88ff00398ff7f715fab053374d808c90dSteve Block  if (Token::IsBitOp(op_)) {
121944f0eee88ff00398ff7f715fab053374d808c90dSteve Block    __ xor_(rax, rax);
122044f0eee88ff00398ff7f715fab053374d808c90dSteve Block  } else {
122144f0eee88ff00398ff7f715fab053374d808c90dSteve Block    __ LoadRoot(rax, Heap::kNanValueRootIndex);
122244f0eee88ff00398ff7f715fab053374d808c90dSteve Block  }
122344f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ bind(&done);
122444f0eee88ff00398ff7f715fab053374d808c90dSteve Block
122544f0eee88ff00398ff7f715fab053374d808c90dSteve Block  GenerateHeapNumberStub(masm);
122644f0eee88ff00398ff7f715fab053374d808c90dSteve Block}
122744f0eee88ff00398ff7f715fab053374d808c90dSteve Block
122844f0eee88ff00398ff7f715fab053374d808c90dSteve Block
1229257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid BinaryOpStub::GenerateHeapNumberStub(MacroAssembler* masm) {
12301e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  Label gc_required, not_number;
12311e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  GenerateFloatingPointCode(masm, &gc_required, &not_number);
12321e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
12331e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  __ bind(&not_number);
12341e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  GenerateTypeTransition(masm);
12351e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
12361e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  __ bind(&gc_required);
12371e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  GenerateCallRuntimeCode(masm);
1238086aeeaae12517475c22695a200be45495516549Ben Murdoch}
1239086aeeaae12517475c22695a200be45495516549Ben Murdoch
1240086aeeaae12517475c22695a200be45495516549Ben Murdoch
1241257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid BinaryOpStub::GenerateGeneric(MacroAssembler* masm) {
12421e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  Label call_runtime, call_string_add_or_runtime;
12431e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
12441e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  GenerateSmiCode(masm, &call_runtime, ALLOW_HEAPNUMBER_RESULTS);
12451e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
12461e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  GenerateFloatingPointCode(masm, &call_runtime, &call_string_add_or_runtime);
12471e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
12481e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  __ bind(&call_string_add_or_runtime);
12491e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  if (op_ == Token::ADD) {
12501e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    GenerateStringAddCode(masm);
12511e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  }
12521e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
12531e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  __ bind(&call_runtime);
12541e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  GenerateCallRuntimeCode(masm);
1255086aeeaae12517475c22695a200be45495516549Ben Murdoch}
1256086aeeaae12517475c22695a200be45495516549Ben Murdoch
1257086aeeaae12517475c22695a200be45495516549Ben Murdoch
1258257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid BinaryOpStub::GenerateHeapResultAllocation(MacroAssembler* masm,
1259257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                                Label* alloc_failure) {
12601e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  Label skip_allocation;
12611e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  OverwriteMode mode = mode_;
12621e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  switch (mode) {
12631e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    case OVERWRITE_LEFT: {
12641e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      // If the argument in rdx is already an object, we skip the
12651e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      // allocation of a heap number.
12661e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      __ JumpIfNotSmi(rdx, &skip_allocation);
12671e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      // Allocate a heap number for the result. Keep eax and edx intact
12681e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      // for the possible runtime call.
12691e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      __ AllocateHeapNumber(rbx, rcx, alloc_failure);
12701e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      // Now rdx can be overwritten losing one of the arguments as we are
12711e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      // now done and will not need it any more.
12721e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      __ movq(rdx, rbx);
12731e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      __ bind(&skip_allocation);
12741e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      // Use object in rdx as a result holder
12751e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      __ movq(rax, rdx);
12761e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      break;
12771e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    }
12781e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    case OVERWRITE_RIGHT:
12791e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      // If the argument in rax is already an object, we skip the
12801e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      // allocation of a heap number.
12811e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      __ JumpIfNotSmi(rax, &skip_allocation);
12821e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      // Fall through!
12831e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    case NO_OVERWRITE:
12841e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      // Allocate a heap number for the result. Keep rax and rdx intact
12851e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      // for the possible runtime call.
12861e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      __ AllocateHeapNumber(rbx, rcx, alloc_failure);
12871e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      // Now rax can be overwritten losing one of the arguments as we are
12881e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      // now done and will not need it any more.
12891e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      __ movq(rax, rbx);
12901e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      __ bind(&skip_allocation);
12911e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      break;
12921e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    default: UNREACHABLE();
12931e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  }
1294086aeeaae12517475c22695a200be45495516549Ben Murdoch}
1295086aeeaae12517475c22695a200be45495516549Ben Murdoch
1296086aeeaae12517475c22695a200be45495516549Ben Murdoch
1297257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid BinaryOpStub::GenerateRegisterArgsPush(MacroAssembler* masm) {
1298086aeeaae12517475c22695a200be45495516549Ben Murdoch  __ pop(rcx);
1299086aeeaae12517475c22695a200be45495516549Ben Murdoch  __ push(rdx);
1300086aeeaae12517475c22695a200be45495516549Ben Murdoch  __ push(rax);
1301086aeeaae12517475c22695a200be45495516549Ben Murdoch  __ push(rcx);
1302b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch}
1303b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1304b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
130580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid TranscendentalCacheStub::Generate(MacroAssembler* masm) {
1306e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  // TAGGED case:
1307e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  //   Input:
1308e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  //     rsp[8]: argument (should be number).
1309e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  //     rsp[0]: return address.
1310e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  //   Output:
1311e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  //     rax: tagged double result.
1312e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  // UNTAGGED case:
1313e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  //   Input::
1314e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  //     rsp[0]: return address.
1315e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  //     xmm1: untagged double input argument
1316e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  //   Output:
1317e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  //     xmm1: untagged double result.
1318e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
131980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label runtime_call;
132080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label runtime_call_clear_stack;
1321e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  Label skip_cache;
1322e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  const bool tagged = (argument_type_ == TAGGED);
1323e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  if (tagged) {
1324257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Label input_not_smi, loaded;
1325e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch    // Test that rax is a number.
1326e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch    __ movq(rax, Operand(rsp, kPointerSize));
1327257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ JumpIfNotSmi(rax, &input_not_smi, Label::kNear);
1328e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch    // Input is a smi. Untag and load it onto the FPU stack.
1329e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch    // Then load the bits of the double into rbx.
1330e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch    __ SmiToInteger32(rax, rax);
1331e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch    __ subq(rsp, Immediate(kDoubleSize));
1332e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch    __ cvtlsi2sd(xmm1, rax);
1333e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch    __ movsd(Operand(rsp, 0), xmm1);
1334e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch    __ movq(rbx, xmm1);
1335e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch    __ movq(rdx, xmm1);
1336e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch    __ fld_d(Operand(rsp, 0));
1337e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch    __ addq(rsp, Immediate(kDoubleSize));
1338257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ jmp(&loaded, Label::kNear);
1339e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
1340e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch    __ bind(&input_not_smi);
1341e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch    // Check if input is a HeapNumber.
1342e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch    __ LoadRoot(rbx, Heap::kHeapNumberMapRootIndex);
1343e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch    __ cmpq(rbx, FieldOperand(rax, HeapObject::kMapOffset));
1344e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch    __ j(not_equal, &runtime_call);
1345e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch    // Input is a HeapNumber. Push it on the FPU stack and load its
1346e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch    // bits into rbx.
1347e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch    __ fld_d(FieldOperand(rax, HeapNumber::kValueOffset));
1348e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch    __ movq(rbx, FieldOperand(rax, HeapNumber::kValueOffset));
1349e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch    __ movq(rdx, rbx);
1350e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
1351e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch    __ bind(&loaded);
1352e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  } else {  // UNTAGGED.
1353e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch    __ movq(rbx, xmm1);
1354e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch    __ movq(rdx, xmm1);
1355e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  }
1356e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
1357e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  // ST[0] == double value, if TAGGED.
135880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rbx = bits of double value.
135980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rdx = also bits of double value.
136080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Compute hash (h is 32 bits, bits are 64 and the shifts are arithmetic):
136180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  //   h = h0 = bits ^ (bits >> 32);
136280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  //   h ^= h >> 16;
136380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  //   h ^= h >> 8;
136480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  //   h = h & (cacheSize - 1);
136580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // or h = (h0 ^ (h0 >> 8) ^ (h0 >> 16) ^ (h0 >> 24)) & (cacheSize - 1)
136680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ sar(rdx, Immediate(32));
136780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ xorl(rdx, rbx);
136880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movl(rcx, rdx);
136980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movl(rax, rdx);
137080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movl(rdi, rdx);
137180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ sarl(rdx, Immediate(8));
137280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ sarl(rcx, Immediate(16));
137380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ sarl(rax, Immediate(24));
137480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ xorl(rcx, rdx);
137580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ xorl(rax, rdi);
137680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ xorl(rcx, rax);
137744f0eee88ff00398ff7f715fab053374d808c90dSteve Block  ASSERT(IsPowerOf2(TranscendentalCache::SubCache::kCacheSize));
137844f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ andl(rcx, Immediate(TranscendentalCache::SubCache::kCacheSize - 1));
137980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
138080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // ST[0] == double value.
138180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rbx = bits of double value.
138280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rcx = TranscendentalCache::hash(double value).
138344f0eee88ff00398ff7f715fab053374d808c90dSteve Block  ExternalReference cache_array =
138444f0eee88ff00398ff7f715fab053374d808c90dSteve Block      ExternalReference::transcendental_cache_array_address(masm->isolate());
138544f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ movq(rax, cache_array);
138644f0eee88ff00398ff7f715fab053374d808c90dSteve Block  int cache_array_index =
138744f0eee88ff00398ff7f715fab053374d808c90dSteve Block      type_ * sizeof(Isolate::Current()->transcendental_cache()->caches_[0]);
138844f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ movq(rax, Operand(rax, cache_array_index));
138980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rax points to the cache for the type type_.
139080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // If NULL, the cache hasn't been initialized yet, so go through runtime.
139180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ testq(rax, rax);
1392e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ j(zero, &runtime_call_clear_stack);  // Only clears stack if TAGGED.
139380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#ifdef DEBUG
139480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check that the layout of cache elements match expectations.
139580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  {  // NOLINT - doesn't like a single brace on a line.
139644f0eee88ff00398ff7f715fab053374d808c90dSteve Block    TranscendentalCache::SubCache::Element test_elem[2];
139780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    char* elem_start = reinterpret_cast<char*>(&test_elem[0]);
139880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    char* elem2_start = reinterpret_cast<char*>(&test_elem[1]);
139980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    char* elem_in0  = reinterpret_cast<char*>(&(test_elem[0].in[0]));
140080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    char* elem_in1  = reinterpret_cast<char*>(&(test_elem[0].in[1]));
140180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    char* elem_out = reinterpret_cast<char*>(&(test_elem[0].output));
140280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // Two uint_32's and a pointer per element.
140380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    CHECK_EQ(16, static_cast<int>(elem2_start - elem_start));
140480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    CHECK_EQ(0, static_cast<int>(elem_in0 - elem_start));
140580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    CHECK_EQ(kIntSize, static_cast<int>(elem_in1 - elem_start));
140680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    CHECK_EQ(2 * kIntSize, static_cast<int>(elem_out - elem_start));
140780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
140880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#endif
140980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Find the address of the rcx'th entry in the cache, i.e., &rax[rcx*16].
141080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ addl(rcx, rcx);
141180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ lea(rcx, Operand(rax, rcx, times_8, 0));
141280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check if cache matches: Double value is stored in uint32_t[2] array.
1413257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label cache_miss;
141480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cmpq(rbx, Operand(rcx, 0));
1415257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(not_equal, &cache_miss, Label::kNear);
141680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Cache hit!
141780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rax, Operand(rcx, 2 * kIntSize));
1418e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  if (tagged) {
1419e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch    __ fstp(0);  // Clear FPU stack.
1420e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch    __ ret(kPointerSize);
1421e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  } else {  // UNTAGGED.
1422e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch    __ movsd(xmm1, FieldOperand(rax, HeapNumber::kValueOffset));
1423e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch    __ Ret();
1424e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  }
142580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
142680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&cache_miss);
142780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Update cache with new value.
1428e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  if (tagged) {
142980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ AllocateHeapNumber(rax, rdi, &runtime_call_clear_stack);
1430e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  } else {  // UNTAGGED.
1431e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch    __ AllocateHeapNumber(rax, rdi, &skip_cache);
1432e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch    __ movsd(FieldOperand(rax, HeapNumber::kValueOffset), xmm1);
1433e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch    __ fld_d(FieldOperand(rax, HeapNumber::kValueOffset));
1434e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  }
1435e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  GenerateOperation(masm);
143680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(Operand(rcx, 0), rbx);
143780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(Operand(rcx, 2 * kIntSize), rax);
143880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ fstp_d(FieldOperand(rax, HeapNumber::kValueOffset));
1439e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  if (tagged) {
1440e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch    __ ret(kPointerSize);
1441e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  } else {  // UNTAGGED.
1442e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch    __ movsd(xmm1, FieldOperand(rax, HeapNumber::kValueOffset));
1443e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch    __ Ret();
1444e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
1445e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch    // Skip cache and return answer directly, only in untagged case.
1446e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch    __ bind(&skip_cache);
1447e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch    __ subq(rsp, Immediate(kDoubleSize));
1448e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch    __ movsd(Operand(rsp, 0), xmm1);
1449e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch    __ fld_d(Operand(rsp, 0));
1450e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch    GenerateOperation(masm);
1451e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch    __ fstp_d(Operand(rsp, 0));
1452e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch    __ movsd(xmm1, Operand(rsp, 0));
1453e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch    __ addq(rsp, Immediate(kDoubleSize));
1454e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch    // We return the value in xmm1 without adding it to the cache, but
1455e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch    // we cause a scavenging GC so that future allocations will succeed.
1456e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch    __ EnterInternalFrame();
1457e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch    // Allocate an unused object bigger than a HeapNumber.
1458e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch    __ Push(Smi::FromInt(2 * kDoubleSize));
1459e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch    __ CallRuntimeSaveDoubles(Runtime::kAllocateInNewSpace);
1460e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch    __ LeaveInternalFrame();
1461e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch    __ Ret();
1462e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  }
146380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
1464e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  // Call runtime, doing whatever allocation and cleanup is necessary.
1465e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  if (tagged) {
1466e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch    __ bind(&runtime_call_clear_stack);
1467e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch    __ fstp(0);
1468e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch    __ bind(&runtime_call);
146944f0eee88ff00398ff7f715fab053374d808c90dSteve Block    __ TailCallExternalReference(
147044f0eee88ff00398ff7f715fab053374d808c90dSteve Block        ExternalReference(RuntimeFunction(), masm->isolate()), 1, 1);
1471e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  } else {  // UNTAGGED.
1472e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch    __ bind(&runtime_call_clear_stack);
1473e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch    __ bind(&runtime_call);
1474e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch    __ AllocateHeapNumber(rax, rdi, &skip_cache);
1475e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch    __ movsd(FieldOperand(rax, HeapNumber::kValueOffset), xmm1);
1476e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch    __ EnterInternalFrame();
1477e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch    __ push(rax);
1478e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch    __ CallRuntime(RuntimeFunction(), 1);
1479e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch    __ LeaveInternalFrame();
1480e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch    __ movsd(xmm1, FieldOperand(rax, HeapNumber::kValueOffset));
1481e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch    __ Ret();
1482e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  }
148380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
148480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
148580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
148680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian MonsenRuntime::FunctionId TranscendentalCacheStub::RuntimeFunction() {
148780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  switch (type_) {
148880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // Add more cases when necessary.
148980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    case TranscendentalCache::SIN: return Runtime::kMath_sin;
149080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    case TranscendentalCache::COS: return Runtime::kMath_cos;
1491b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case TranscendentalCache::LOG: return Runtime::kMath_log;
149280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    default:
149380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      UNIMPLEMENTED();
149480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      return Runtime::kAbort;
149580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
149680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
149780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
149880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
1499e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdochvoid TranscendentalCacheStub::GenerateOperation(MacroAssembler* masm) {
150080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Registers:
1501e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  // rax: Newly allocated HeapNumber, which must be preserved.
150280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rbx: Bits of input double. Must be preserved.
150380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rcx: Pointer to cache entry. Must be preserved.
150480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // st(0): Input double
150580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label done;
1506b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  if (type_ == TranscendentalCache::SIN || type_ == TranscendentalCache::COS) {
1507b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    // Both fsin and fcos require arguments in the range +/-2^63 and
1508b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    // return NaN for infinities and NaN. They can share all code except
1509b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    // the actual fsin/fcos operation.
1510b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    Label in_range;
1511b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    // If argument is outside the range -2^63..2^63, fsin/cos doesn't
1512b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    // work. We must reduce it to the appropriate range.
1513b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ movq(rdi, rbx);
1514b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    // Move exponent and sign bits to low bits.
1515b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ shr(rdi, Immediate(HeapNumber::kMantissaBits));
1516b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    // Remove sign bit.
1517b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ andl(rdi, Immediate((1 << HeapNumber::kExponentBits) - 1));
1518b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    int supported_exponent_limit = (63 + HeapNumber::kExponentBias);
1519b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ cmpl(rdi, Immediate(supported_exponent_limit));
1520b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ j(below, &in_range);
1521b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    // Check for infinity and NaN. Both return NaN for sin.
1522b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ cmpl(rdi, Immediate(0x7ff));
1523257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Label non_nan_result;
1524257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ j(not_equal, &non_nan_result, Label::kNear);
1525e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch    // Input is +/-Infinity or NaN. Result is NaN.
1526e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch    __ fstp(0);
1527e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch    __ LoadRoot(kScratchRegister, Heap::kNanValueRootIndex);
1528e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch    __ fld_d(FieldOperand(kScratchRegister, HeapNumber::kValueOffset));
1529e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch    __ jmp(&done);
1530e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
1531e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch    __ bind(&non_nan_result);
1532b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1533b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    // Use fpmod to restrict argument to the range +/-2*PI.
1534e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch    __ movq(rdi, rax);  // Save rax before using fnstsw_ax.
1535b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ fldpi();
1536b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ fadd(0);
1537b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ fld(1);
1538b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    // FPU Stack: input, 2*pi, input.
1539b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    {
1540b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      Label no_exceptions;
1541b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ fwait();
1542b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ fnstsw_ax();
1543b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // Clear if Illegal Operand or Zero Division exceptions are set.
1544b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ testl(rax, Immediate(5));  // #IO and #ZD flags of FPU status word.
1545b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ j(zero, &no_exceptions);
1546b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ fnclex();
1547b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ bind(&no_exceptions);
1548b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    }
154980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
1550b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    // Compute st(0) % st(1)
1551b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    {
1552257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      Label partial_remainder_loop;
1553b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ bind(&partial_remainder_loop);
1554b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ fprem1();
1555b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ fwait();
1556b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ fnstsw_ax();
1557b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ testl(rax, Immediate(0x400));  // Check C2 bit of FPU status word.
1558b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // If C2 is set, computation only has partial result. Loop to
1559b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // continue computation.
1560b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      __ j(not_zero, &partial_remainder_loop);
1561b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  }
1562b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    // FPU Stack: input, 2*pi, input % 2*pi
1563b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ fstp(2);
1564b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    // FPU Stack: input % 2*pi, 2*pi,
1565b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ fstp(0);
1566b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    // FPU Stack: input % 2*pi
1567e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch    __ movq(rax, rdi);  // Restore rax, pointer to the new HeapNumber.
1568b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ bind(&in_range);
1569b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    switch (type_) {
1570b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      case TranscendentalCache::SIN:
1571b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        __ fsin();
1572b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        break;
1573b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      case TranscendentalCache::COS:
1574b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        __ fcos();
1575b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        break;
1576b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      default:
1577b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        UNREACHABLE();
1578b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    }
1579b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ bind(&done);
1580b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  } else {
1581b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    ASSERT(type_ == TranscendentalCache::LOG);
1582b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ fldln2();
1583b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ fxch();
1584b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    __ fyl2x();
158580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
158680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
158780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
158880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
158980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// Input: rdx, rax are the left and right objects of a bit op.
159080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// Output: rax, rcx are left and right integers for a bit op.
159180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid FloatingPointHelper::LoadNumbersAsIntegers(MacroAssembler* masm) {
159280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check float operands.
159380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label done;
159480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label rax_is_smi;
159580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label rax_is_object;
159680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label rdx_is_object;
159780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
159880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ JumpIfNotSmi(rdx, &rdx_is_object);
159980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiToInteger32(rdx, rdx);
160080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ JumpIfSmi(rax, &rax_is_smi);
160180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
160280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&rax_is_object);
160380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  IntegerConvert(masm, rcx, rax);  // Uses rdi, rcx and rbx.
160480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ jmp(&done);
160580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
160680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&rdx_is_object);
160780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  IntegerConvert(masm, rdx, rdx);  // Uses rdi, rcx and rbx.
160880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ JumpIfNotSmi(rax, &rax_is_object);
160980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&rax_is_smi);
161080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiToInteger32(rcx, rax);
161180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
161280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&done);
161380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movl(rax, rdx);
161480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
161580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
161680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
161780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// Input: rdx, rax are the left and right objects of a bit op.
161880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// Output: rax, rcx are left and right integers for a bit op.
16191e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block// Jump to conversion_failure: rdx and rax are unchanged.
162080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid FloatingPointHelper::LoadAsIntegers(MacroAssembler* masm,
162180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                         Label* conversion_failure,
162280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                         Register heap_number_map) {
162380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check float operands.
162480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label arg1_is_object, check_undefined_arg1;
162580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label arg2_is_object, check_undefined_arg2;
162680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label load_arg2, done;
162780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
162880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ JumpIfNotSmi(rdx, &arg1_is_object);
16291e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  __ SmiToInteger32(r8, rdx);
163080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ jmp(&load_arg2);
163180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
163280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // If the argument is undefined it converts to zero (ECMA-262, section 9.5).
163380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&check_undefined_arg1);
163480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ CompareRoot(rdx, Heap::kUndefinedValueRootIndex);
163580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(not_equal, conversion_failure);
16368b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  __ Set(r8, 0);
163780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ jmp(&load_arg2);
163880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
163980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&arg1_is_object);
164080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cmpq(FieldOperand(rdx, HeapObject::kMapOffset), heap_number_map);
164180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(not_equal, &check_undefined_arg1);
16421e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  // Get the untagged integer version of the rdx heap number in rcx.
16431e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  IntegerConvert(masm, r8, rdx);
164480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
16451e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  // Here r8 has the untagged integer, rax has a Smi or a heap number.
164680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&load_arg2);
164780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Test if arg2 is a Smi.
164880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ JumpIfNotSmi(rax, &arg2_is_object);
16491e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  __ SmiToInteger32(rcx, rax);
165080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ jmp(&done);
165180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
165280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // If the argument is undefined it converts to zero (ECMA-262, section 9.5).
165380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&check_undefined_arg2);
165480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ CompareRoot(rax, Heap::kUndefinedValueRootIndex);
165580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(not_equal, conversion_failure);
16568b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  __ Set(rcx, 0);
165780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ jmp(&done);
165880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
165980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&arg2_is_object);
166080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cmpq(FieldOperand(rax, HeapObject::kMapOffset), heap_number_map);
166180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(not_equal, &check_undefined_arg2);
166280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Get the untagged integer version of the rax heap number in rcx.
166380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  IntegerConvert(masm, rcx, rax);
166480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&done);
16651e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  __ movl(rax, r8);
166680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
166780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
166880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
166980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid FloatingPointHelper::LoadSSE2SmiOperands(MacroAssembler* masm) {
167080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiToInteger32(kScratchRegister, rdx);
167180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cvtlsi2sd(xmm0, kScratchRegister);
167280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiToInteger32(kScratchRegister, rax);
167380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cvtlsi2sd(xmm1, kScratchRegister);
167480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
167580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
167680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
167780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid FloatingPointHelper::LoadSSE2NumberOperands(MacroAssembler* masm) {
167880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label load_smi_rdx, load_nonsmi_rax, load_smi_rax, done;
167980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Load operand in rdx into xmm0.
168080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ JumpIfSmi(rdx, &load_smi_rdx);
168180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movsd(xmm0, FieldOperand(rdx, HeapNumber::kValueOffset));
168280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Load operand in rax into xmm1.
168380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ JumpIfSmi(rax, &load_smi_rax);
168480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&load_nonsmi_rax);
168580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movsd(xmm1, FieldOperand(rax, HeapNumber::kValueOffset));
168680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ jmp(&done);
168780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
168880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&load_smi_rdx);
168980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiToInteger32(kScratchRegister, rdx);
169080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cvtlsi2sd(xmm0, kScratchRegister);
169180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ JumpIfNotSmi(rax, &load_nonsmi_rax);
169280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
169380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&load_smi_rax);
169480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiToInteger32(kScratchRegister, rax);
169580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cvtlsi2sd(xmm1, kScratchRegister);
169680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
169780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&done);
169880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
169980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
170080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
170180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid FloatingPointHelper::LoadSSE2UnknownOperands(MacroAssembler* masm,
170280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                                  Label* not_numbers) {
170380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label load_smi_rdx, load_nonsmi_rax, load_smi_rax, load_float_rax, done;
170480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Load operand in rdx into xmm0, or branch to not_numbers.
170580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ LoadRoot(rcx, Heap::kHeapNumberMapRootIndex);
170680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ JumpIfSmi(rdx, &load_smi_rdx);
170780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cmpq(FieldOperand(rdx, HeapObject::kMapOffset), rcx);
170880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(not_equal, not_numbers);  // Argument in rdx is not a number.
170980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movsd(xmm0, FieldOperand(rdx, HeapNumber::kValueOffset));
171080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Load operand in rax into xmm1, or branch to not_numbers.
171180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ JumpIfSmi(rax, &load_smi_rax);
171280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
171380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&load_nonsmi_rax);
171480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cmpq(FieldOperand(rax, HeapObject::kMapOffset), rcx);
171580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(not_equal, not_numbers);
171680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movsd(xmm1, FieldOperand(rax, HeapNumber::kValueOffset));
171780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ jmp(&done);
171880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
171980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&load_smi_rdx);
172080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiToInteger32(kScratchRegister, rdx);
172180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cvtlsi2sd(xmm0, kScratchRegister);
172280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ JumpIfNotSmi(rax, &load_nonsmi_rax);
172380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
172480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&load_smi_rax);
172580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiToInteger32(kScratchRegister, rax);
172680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cvtlsi2sd(xmm1, kScratchRegister);
172780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&done);
172880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
172980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
173080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
17318b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdochvoid FloatingPointHelper::NumbersToSmis(MacroAssembler* masm,
17328b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch                                        Register first,
17338b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch                                        Register second,
17348b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch                                        Register scratch1,
17358b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch                                        Register scratch2,
17368b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch                                        Register scratch3,
17378b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch                                        Label* on_success,
17388b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch                                        Label* on_not_smis)   {
17398b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  Register heap_number_map = scratch3;
17408b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  Register smi_result = scratch1;
17418b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  Label done;
17428b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch
17438b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  __ LoadRoot(heap_number_map, Heap::kHeapNumberMapRootIndex);
17448b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch
1745257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label first_smi;
1746257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ JumpIfSmi(first, &first_smi, Label::kNear);
17478b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  __ cmpq(FieldOperand(first, HeapObject::kMapOffset), heap_number_map);
17488b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  __ j(not_equal, on_not_smis);
17498b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  // Convert HeapNumber to smi if possible.
17508b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  __ movsd(xmm0, FieldOperand(first, HeapNumber::kValueOffset));
17518b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  __ movq(scratch2, xmm0);
17528b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  __ cvttsd2siq(smi_result, xmm0);
17538b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  // Check if conversion was successful by converting back and
17548b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  // comparing to the original double's bits.
17558b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  __ cvtlsi2sd(xmm1, smi_result);
17568b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  __ movq(kScratchRegister, xmm1);
17578b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  __ cmpq(scratch2, kScratchRegister);
17588b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  __ j(not_equal, on_not_smis);
17598b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  __ Integer32ToSmi(first, smi_result);
17608b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch
17618b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  __ JumpIfSmi(second, (on_success != NULL) ? on_success : &done);
17628b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  __ bind(&first_smi);
17638b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  if (FLAG_debug_code) {
17648b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch    // Second should be non-smi if we get here.
17658b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch    __ AbortIfSmi(second);
17668b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  }
17678b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  __ cmpq(FieldOperand(second, HeapObject::kMapOffset), heap_number_map);
17688b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  __ j(not_equal, on_not_smis);
17698b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  // Convert second to smi, if possible.
17708b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  __ movsd(xmm0, FieldOperand(second, HeapNumber::kValueOffset));
17718b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  __ movq(scratch2, xmm0);
17728b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  __ cvttsd2siq(smi_result, xmm0);
17738b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  __ cvtlsi2sd(xmm1, smi_result);
17748b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  __ movq(kScratchRegister, xmm1);
17758b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  __ cmpq(scratch2, kScratchRegister);
17768b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  __ j(not_equal, on_not_smis);
17778b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  __ Integer32ToSmi(second, smi_result);
17788b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  if (on_success != NULL) {
17798b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch    __ jmp(on_success);
17808b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  } else {
17818b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch    __ bind(&done);
17828b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  }
17838b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch}
17848b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch
17858b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch
1786e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdochvoid MathPowStub::Generate(MacroAssembler* masm) {
1787e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  // Registers are used as follows:
1788e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  // rdx = base
1789e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  // rax = exponent
1790e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  // rcx = temporary, result
1791e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
1792e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  Label allocate_return, call_runtime;
1793e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
1794e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  // Load input parameters.
1795e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ movq(rdx, Operand(rsp, 2 * kPointerSize));
1796e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ movq(rax, Operand(rsp, 1 * kPointerSize));
1797e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
1798e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  // Save 1 in xmm3 - we need this several times later on.
17998b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  __ Set(rcx, 1);
1800e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ cvtlsi2sd(xmm3, rcx);
1801e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
1802e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  Label exponent_nonsmi;
1803e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  Label base_nonsmi;
1804e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  // If the exponent is a heap number go to that specific case.
1805e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ JumpIfNotSmi(rax, &exponent_nonsmi);
1806e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ JumpIfNotSmi(rdx, &base_nonsmi);
1807e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
1808e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  // Optimized version when both exponent and base are smis.
1809e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  Label powi;
1810e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ SmiToInteger32(rdx, rdx);
1811e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ cvtlsi2sd(xmm0, rdx);
1812e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ jmp(&powi);
1813e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  // Exponent is a smi and base is a heapnumber.
1814e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ bind(&base_nonsmi);
1815e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ CompareRoot(FieldOperand(rdx, HeapObject::kMapOffset),
1816e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch                 Heap::kHeapNumberMapRootIndex);
1817e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ j(not_equal, &call_runtime);
1818e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
1819e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ movsd(xmm0, FieldOperand(rdx, HeapNumber::kValueOffset));
1820e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
1821e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  // Optimized version of pow if exponent is a smi.
1822e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  // xmm0 contains the base.
1823e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ bind(&powi);
1824e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ SmiToInteger32(rax, rax);
1825e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
1826e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  // Save exponent in base as we need to check if exponent is negative later.
1827e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  // We know that base and exponent are in different registers.
1828e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ movq(rdx, rax);
1829e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
1830e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  // Get absolute value of exponent.
1831257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label no_neg;
1832e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ cmpl(rax, Immediate(0));
1833257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(greater_equal, &no_neg, Label::kNear);
1834e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ negl(rax);
1835e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ bind(&no_neg);
1836e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
1837e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  // Load xmm1 with 1.
1838257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ movaps(xmm1, xmm3);
1839257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label while_true;
1840257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label no_multiply;
1841e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
1842e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ bind(&while_true);
1843e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ shrl(rax, Immediate(1));
1844257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(not_carry, &no_multiply, Label::kNear);
1845e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ mulsd(xmm1, xmm0);
1846e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ bind(&no_multiply);
1847e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ mulsd(xmm0, xmm0);
1848e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ j(not_zero, &while_true);
1849e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
1850e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  // Base has the original value of the exponent - if the exponent  is
1851e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  // negative return 1/result.
1852e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ testl(rdx, rdx);
1853e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ j(positive, &allocate_return);
1854e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  // Special case if xmm1 has reached infinity.
1855e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ divsd(xmm3, xmm1);
1856257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ movaps(xmm1, xmm3);
1857257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ xorps(xmm0, xmm0);
1858e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ ucomisd(xmm0, xmm1);
1859e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ j(equal, &call_runtime);
1860e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
1861e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ jmp(&allocate_return);
1862e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
1863e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  // Exponent (or both) is a heapnumber - no matter what we should now work
1864e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  // on doubles.
1865e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ bind(&exponent_nonsmi);
1866e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ CompareRoot(FieldOperand(rax, HeapObject::kMapOffset),
1867e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch                 Heap::kHeapNumberMapRootIndex);
1868e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ j(not_equal, &call_runtime);
1869e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ movsd(xmm1, FieldOperand(rax, HeapNumber::kValueOffset));
1870e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  // Test if exponent is nan.
1871e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ ucomisd(xmm1, xmm1);
1872e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ j(parity_even, &call_runtime);
1873e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
1874257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label base_not_smi, handle_special_cases;
1875257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ JumpIfNotSmi(rdx, &base_not_smi, Label::kNear);
1876e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ SmiToInteger32(rdx, rdx);
1877e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ cvtlsi2sd(xmm0, rdx);
1878257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ jmp(&handle_special_cases, Label::kNear);
1879e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
1880e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ bind(&base_not_smi);
1881e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ CompareRoot(FieldOperand(rdx, HeapObject::kMapOffset),
1882e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch                 Heap::kHeapNumberMapRootIndex);
1883e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ j(not_equal, &call_runtime);
1884e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ movl(rcx, FieldOperand(rdx, HeapNumber::kExponentOffset));
1885e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ andl(rcx, Immediate(HeapNumber::kExponentMask));
1886e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ cmpl(rcx, Immediate(HeapNumber::kExponentMask));
1887e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  // base is NaN or +/-Infinity
1888e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ j(greater_equal, &call_runtime);
1889e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ movsd(xmm0, FieldOperand(rdx, HeapNumber::kValueOffset));
1890e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
1891e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  // base is in xmm0 and exponent is in xmm1.
1892e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ bind(&handle_special_cases);
1893257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label not_minus_half;
1894e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  // Test for -0.5.
1895e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  // Load xmm2 with -0.5.
1896e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ movq(rcx, V8_UINT64_C(0xBFE0000000000000), RelocInfo::NONE);
1897e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ movq(xmm2, rcx);
1898e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  // xmm2 now has -0.5.
1899e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ ucomisd(xmm2, xmm1);
1900257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(not_equal, &not_minus_half, Label::kNear);
1901e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
1902e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  // Calculates reciprocal of square root.
1903e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  // sqrtsd returns -0 when input is -0.  ECMA spec requires +0.
1904257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ xorps(xmm1, xmm1);
1905e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ addsd(xmm1, xmm0);
1906e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ sqrtsd(xmm1, xmm1);
1907e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ divsd(xmm3, xmm1);
1908257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ movaps(xmm1, xmm3);
1909e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ jmp(&allocate_return);
1910e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
1911e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  // Test for 0.5.
1912e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ bind(&not_minus_half);
1913e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  // Load xmm2 with 0.5.
1914e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  // Since xmm3 is 1 and xmm2 is -0.5 this is simply xmm2 + xmm3.
1915e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ addsd(xmm2, xmm3);
1916e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  // xmm2 now has 0.5.
1917e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ ucomisd(xmm2, xmm1);
1918e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ j(not_equal, &call_runtime);
1919e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  // Calculates square root.
1920e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  // sqrtsd returns -0 when input is -0.  ECMA spec requires +0.
1921257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ xorps(xmm1, xmm1);
1922257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ addsd(xmm1, xmm0);  // Convert -0 to 0.
1923e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ sqrtsd(xmm1, xmm1);
1924e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
1925e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ bind(&allocate_return);
1926e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ AllocateHeapNumber(rcx, rax, &call_runtime);
1927e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ movsd(FieldOperand(rcx, HeapNumber::kValueOffset), xmm1);
1928e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ movq(rax, rcx);
1929e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ ret(2 * kPointerSize);
1930e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
1931e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ bind(&call_runtime);
1932e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ TailCallRuntime(Runtime::kMath_pow_cfunction, 2, 1);
1933e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch}
1934e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
1935e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
193680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid ArgumentsAccessStub::GenerateReadElement(MacroAssembler* masm) {
193780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // The key is in rdx and the parameter count is in rax.
193880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
193980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // The displacement is used for skipping the frame pointer on the
194080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // stack. It is the offset of the last parameter (if any) relative
194180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // to the frame pointer.
194280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  static const int kDisplacement = 1 * kPointerSize;
194380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
194480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check that the key is a smi.
194580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label slow;
194680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ JumpIfNotSmi(rdx, &slow);
194780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
194844f0eee88ff00398ff7f715fab053374d808c90dSteve Block  // Check if the calling frame is an arguments adaptor frame.  We look at the
194944f0eee88ff00398ff7f715fab053374d808c90dSteve Block  // context offset, and if the frame is not a regular one, then we find a
195044f0eee88ff00398ff7f715fab053374d808c90dSteve Block  // Smi instead of the context.  We can't use SmiCompare here, because that
195144f0eee88ff00398ff7f715fab053374d808c90dSteve Block  // only works for comparing two smis.
195280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label adaptor;
195380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rbx, Operand(rbp, StandardFrameConstants::kCallerFPOffset));
195444f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ Cmp(Operand(rbx, StandardFrameConstants::kContextOffset),
195544f0eee88ff00398ff7f715fab053374d808c90dSteve Block         Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR));
195680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(equal, &adaptor);
195780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
195880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check index against formal parameters count limit passed in
195980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // through register rax. Use unsigned comparison to get negative
196080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // check for free.
196180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cmpq(rdx, rax);
196280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(above_equal, &slow);
196380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
196480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Read the argument from the stack and return it.
196580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  SmiIndex index = masm->SmiToIndex(rax, rax, kPointerSizeLog2);
196680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ lea(rbx, Operand(rbp, index.reg, index.scale, 0));
196780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  index = masm->SmiToNegativeIndex(rdx, rdx, kPointerSizeLog2);
196880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rax, Operand(rbx, index.reg, index.scale, kDisplacement));
196980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ Ret();
197080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
197180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Arguments adaptor case: Check index against actual arguments
197280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // limit found in the arguments adaptor frame. Use unsigned
197380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // comparison to get negative check for free.
197480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&adaptor);
197580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rcx, Operand(rbx, ArgumentsAdaptorFrameConstants::kLengthOffset));
197680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cmpq(rdx, rcx);
197780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(above_equal, &slow);
197880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
197980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Read the argument from the stack and return it.
198080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  index = masm->SmiToIndex(rax, rcx, kPointerSizeLog2);
198180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ lea(rbx, Operand(rbx, index.reg, index.scale, 0));
198280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  index = masm->SmiToNegativeIndex(rdx, rdx, kPointerSizeLog2);
198380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rax, Operand(rbx, index.reg, index.scale, kDisplacement));
198480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ Ret();
198580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
198680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Slow-case: Handle non-smi or out-of-bounds access to arguments
198780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // by calling the runtime system.
198880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&slow);
198980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ pop(rbx);  // Return address.
199080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ push(rdx);
199180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ push(rbx);
199280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ TailCallRuntime(Runtime::kGetArgumentsProperty, 1, 1);
199380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
199480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
199580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
19963fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdochvoid ArgumentsAccessStub::GenerateNewNonStrictFast(MacroAssembler* masm) {
19973fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // Stack layout:
19983fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  //  rsp[0] : return address
19993fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  //  rsp[8] : number of parameters (tagged)
20003fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  //  rsp[16] : receiver displacement
20013fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  //  rsp[24] : function
20023fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // Registers used over the whole function:
20033fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  //  rbx: the mapped parameter count (untagged)
20043fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  //  rax: the allocated object (tagged).
20053fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
20063fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  Factory* factory = masm->isolate()->factory();
20073fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
20083fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ SmiToInteger64(rbx, Operand(rsp, 1 * kPointerSize));
20093fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // rbx = parameter count (untagged)
20103fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
20113fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // Check if the calling frame is an arguments adaptor frame.
20123fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  Label runtime;
20133fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  Label adaptor_frame, try_allocate;
20143fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ movq(rdx, Operand(rbp, StandardFrameConstants::kCallerFPOffset));
20153fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ movq(rcx, Operand(rdx, StandardFrameConstants::kContextOffset));
20163fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ Cmp(rcx, Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR));
20173fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ j(equal, &adaptor_frame);
20183fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
20193fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // No adaptor, parameter count = argument count.
20203fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ movq(rcx, rbx);
20213fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ jmp(&try_allocate, Label::kNear);
20223fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
20233fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // We have an adaptor frame. Patch the parameters pointer.
20243fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ bind(&adaptor_frame);
20253fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ SmiToInteger64(rcx,
20263fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch                    Operand(rdx,
20273fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch                            ArgumentsAdaptorFrameConstants::kLengthOffset));
20283fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ lea(rdx, Operand(rdx, rcx, times_pointer_size,
20293fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch                      StandardFrameConstants::kCallerSPOffset));
20303fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ movq(Operand(rsp, 2 * kPointerSize), rdx);
20313fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
20323fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // rbx = parameter count (untagged)
20333fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // rcx = argument count (untagged)
20343fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // Compute the mapped parameter count = min(rbx, rcx) in rbx.
20353fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ cmpq(rbx, rcx);
20363fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ j(less_equal, &try_allocate, Label::kNear);
20373fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ movq(rbx, rcx);
20383fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
20393fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ bind(&try_allocate);
20403fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
20413fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // Compute the sizes of backing store, parameter map, and arguments object.
20423fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // 1. Parameter map, has 2 extra words containing context and backing store.
20433fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  const int kParameterMapHeaderSize =
20443fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch      FixedArray::kHeaderSize + 2 * kPointerSize;
20453fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  Label no_parameter_map;
20463fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ testq(rbx, rbx);
20473fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ j(zero, &no_parameter_map, Label::kNear);
20483fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ lea(r8, Operand(rbx, times_pointer_size, kParameterMapHeaderSize));
20493fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ bind(&no_parameter_map);
20503fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
20513fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // 2. Backing store.
20523fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ lea(r8, Operand(r8, rcx, times_pointer_size, FixedArray::kHeaderSize));
20533fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
20543fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // 3. Arguments object.
20553fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ addq(r8, Immediate(Heap::kArgumentsObjectSize));
20563fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
20573fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // Do the allocation of all three objects in one go.
20583fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ AllocateInNewSpace(r8, rax, rdx, rdi, &runtime, TAG_OBJECT);
20593fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
20603fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // rax = address of new object(s) (tagged)
20613fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // rcx = argument count (untagged)
20623fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // Get the arguments boilerplate from the current (global) context into rdi.
20633fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  Label has_mapped_parameters, copy;
20643fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ movq(rdi, Operand(rsi, Context::SlotOffset(Context::GLOBAL_INDEX)));
20653fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ movq(rdi, FieldOperand(rdi, GlobalObject::kGlobalContextOffset));
20663fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ testq(rbx, rbx);
20673fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ j(not_zero, &has_mapped_parameters, Label::kNear);
20683fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
20693fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  const int kIndex = Context::ARGUMENTS_BOILERPLATE_INDEX;
20703fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ movq(rdi, Operand(rdi, Context::SlotOffset(kIndex)));
20713fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ jmp(&copy, Label::kNear);
20723fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
20733fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  const int kAliasedIndex = Context::ALIASED_ARGUMENTS_BOILERPLATE_INDEX;
20743fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ bind(&has_mapped_parameters);
20753fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ movq(rdi, Operand(rdi, Context::SlotOffset(kAliasedIndex)));
20763fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ bind(&copy);
20773fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
20783fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // rax = address of new object (tagged)
20793fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // rbx = mapped parameter count (untagged)
20803fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // rcx = argument count (untagged)
20813fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // rdi = address of boilerplate object (tagged)
20823fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // Copy the JS object part.
20833fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  for (int i = 0; i < JSObject::kHeaderSize; i += kPointerSize) {
20843fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    __ movq(rdx, FieldOperand(rdi, i));
20853fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    __ movq(FieldOperand(rax, i), rdx);
20863fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  }
20873fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
20883fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // Setup the callee in-object property.
20893fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  STATIC_ASSERT(Heap::kArgumentsCalleeIndex == 1);
20903fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ movq(rdx, Operand(rsp, 3 * kPointerSize));
20913fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ movq(FieldOperand(rax, JSObject::kHeaderSize +
20923fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch                       Heap::kArgumentsCalleeIndex * kPointerSize),
20933fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch          rdx);
20943fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
20953fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // Use the length (smi tagged) and set that as an in-object property too.
20963fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // Note: rcx is tagged from here on.
20973fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  STATIC_ASSERT(Heap::kArgumentsLengthIndex == 0);
20983fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ Integer32ToSmi(rcx, rcx);
20993fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ movq(FieldOperand(rax, JSObject::kHeaderSize +
21003fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch                       Heap::kArgumentsLengthIndex * kPointerSize),
21013fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch          rcx);
21023fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
21033fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // Setup the elements pointer in the allocated arguments object.
21043fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // If we allocated a parameter map, edi will point there, otherwise to the
21053fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // backing store.
21063fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ lea(rdi, Operand(rax, Heap::kArgumentsObjectSize));
21073fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ movq(FieldOperand(rax, JSObject::kElementsOffset), rdi);
21083fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
21093fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // rax = address of new object (tagged)
21103fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // rbx = mapped parameter count (untagged)
21113fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // rcx = argument count (tagged)
21123fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // rdi = address of parameter map or backing store (tagged)
21133fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
21143fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // Initialize parameter map. If there are no mapped arguments, we're done.
21153fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  Label skip_parameter_map;
21163fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ testq(rbx, rbx);
21173fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ j(zero, &skip_parameter_map);
21183fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
21193fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ LoadRoot(kScratchRegister, Heap::kNonStrictArgumentsElementsMapRootIndex);
21203fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // rbx contains the untagged argument count. Add 2 and tag to write.
21213fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ movq(FieldOperand(rdi, FixedArray::kMapOffset), kScratchRegister);
21223fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ Integer64PlusConstantToSmi(r9, rbx, 2);
21233fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ movq(FieldOperand(rdi, FixedArray::kLengthOffset), r9);
21243fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ movq(FieldOperand(rdi, FixedArray::kHeaderSize + 0 * kPointerSize), rsi);
21253fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ lea(r9, Operand(rdi, rbx, times_pointer_size, kParameterMapHeaderSize));
21263fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ movq(FieldOperand(rdi, FixedArray::kHeaderSize + 1 * kPointerSize), r9);
21273fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
21283fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // Copy the parameter slots and the holes in the arguments.
21293fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // We need to fill in mapped_parameter_count slots. They index the context,
21303fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // where parameters are stored in reverse order, at
21313fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  //   MIN_CONTEXT_SLOTS .. MIN_CONTEXT_SLOTS+parameter_count-1
21323fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // The mapped parameter thus need to get indices
21333fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  //   MIN_CONTEXT_SLOTS+parameter_count-1 ..
21343fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  //       MIN_CONTEXT_SLOTS+parameter_count-mapped_parameter_count
21353fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // We loop from right to left.
21363fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  Label parameters_loop, parameters_test;
21373fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
21383fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // Load tagged parameter count into r9.
21393fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ movq(r9, Operand(rsp, 1 * kPointerSize));
21403fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ Move(r8, Smi::FromInt(Context::MIN_CONTEXT_SLOTS));
21413fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ addq(r8, Operand(rsp, 3 * kPointerSize));
21423fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ subq(r8, r9);
21433fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ Move(r11, factory->the_hole_value());
21443fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ movq(rdx, rdi);
21453fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ SmiToInteger64(kScratchRegister, r9);
21463fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ lea(rdi, Operand(rdi, kScratchRegister,
21473fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch                      times_pointer_size,
21483fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch                      kParameterMapHeaderSize));
21493fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // r9 = loop variable (tagged)
21503fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // r8 = mapping index (tagged)
21513fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // r11 = the hole value
21523fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // rdx = address of parameter map (tagged)
21533fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // rdi = address of backing store (tagged)
21543fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ jmp(&parameters_test, Label::kNear);
21553fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
21563fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ bind(&parameters_loop);
21573fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ SmiSubConstant(r9, r9, Smi::FromInt(1));
21583fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ SmiToInteger64(kScratchRegister, r9);
21593fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ movq(FieldOperand(rdx, kScratchRegister,
21603fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch                       times_pointer_size,
21613fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch                       kParameterMapHeaderSize),
21623fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch          r8);
21633fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ movq(FieldOperand(rdi, kScratchRegister,
21643fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch                       times_pointer_size,
21653fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch                       FixedArray::kHeaderSize),
21663fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch          r11);
21673fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ SmiAddConstant(r8, r8, Smi::FromInt(1));
21683fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ bind(&parameters_test);
21693fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ SmiTest(r9);
21703fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ j(not_zero, &parameters_loop, Label::kNear);
21713fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
21723fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ bind(&skip_parameter_map);
21733fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
21743fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // rcx = argument count (tagged)
21753fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // rdi = address of backing store (tagged)
21763fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // Copy arguments header and remaining slots (if there are any).
21773fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ Move(FieldOperand(rdi, FixedArray::kMapOffset),
21783fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch          factory->fixed_array_map());
21793fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ movq(FieldOperand(rdi, FixedArray::kLengthOffset), rcx);
21803fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
21813fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  Label arguments_loop, arguments_test;
21823fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ movq(r8, rbx);
21833fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ movq(rdx, Operand(rsp, 2 * kPointerSize));
21843fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // Untag rcx and r8 for the loop below.
21853fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ SmiToInteger64(rcx, rcx);
21863fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ SmiToInteger64(r8, r8);
21873fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ lea(kScratchRegister, Operand(r8, times_pointer_size, 0));
21883fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ subq(rdx, kScratchRegister);
21893fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ jmp(&arguments_test, Label::kNear);
21903fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
21913fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ bind(&arguments_loop);
21923fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ subq(rdx, Immediate(kPointerSize));
21933fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ movq(r9, Operand(rdx, 0));
21943fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ movq(FieldOperand(rdi, r8,
21953fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch                       times_pointer_size,
21963fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch                       FixedArray::kHeaderSize),
21973fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch          r9);
21983fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ addq(r8, Immediate(1));
21993fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
22003fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ bind(&arguments_test);
22013fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ cmpq(r8, rcx);
22023fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ j(less, &arguments_loop, Label::kNear);
22033fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
22043fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // Return and remove the on-stack parameters.
22053fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ ret(3 * kPointerSize);
22063fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
22073fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // Do the runtime call to allocate the arguments object.
22083fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // rcx = argument count (untagged)
22093fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ bind(&runtime);
22103fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ Integer32ToSmi(rcx, rcx);
22113fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ movq(Operand(rsp, 1 * kPointerSize), rcx);  // Patch argument count.
22123fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ TailCallRuntime(Runtime::kNewStrictArgumentsFast, 3, 1);
22133fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch}
22143fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
22153fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
22163fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdochvoid ArgumentsAccessStub::GenerateNewNonStrictSlow(MacroAssembler* masm) {
22173fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // esp[0] : return address
22183fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // esp[8] : number of parameters
22193fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // esp[16] : receiver displacement
22203fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // esp[24] : function
22213fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
22223fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // Check if the calling frame is an arguments adaptor frame.
22233fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  Label runtime;
22243fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ movq(rdx, Operand(rbp, StandardFrameConstants::kCallerFPOffset));
22253fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ movq(rcx, Operand(rdx, StandardFrameConstants::kContextOffset));
22263fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ Cmp(rcx, Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR));
22273fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ j(not_equal, &runtime);
22283fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
22293fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // Patch the arguments.length and the parameters pointer.
22303fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ movq(rcx, Operand(rdx, ArgumentsAdaptorFrameConstants::kLengthOffset));
22313fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ movq(Operand(rsp, 1 * kPointerSize), rcx);
22323fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ SmiToInteger64(rcx, rcx);
22333fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ lea(rdx, Operand(rdx, rcx, times_pointer_size,
22343fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch              StandardFrameConstants::kCallerSPOffset));
22353fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ movq(Operand(rsp, 2 * kPointerSize), rdx);
22363fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
22373fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ bind(&runtime);
22383fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ TailCallRuntime(Runtime::kNewArgumentsFast, 3, 1);
22393fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch}
22403fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
22413fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
22423fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdochvoid ArgumentsAccessStub::GenerateNewStrict(MacroAssembler* masm) {
224380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rsp[0] : return address
224480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rsp[8] : number of parameters
224580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rsp[16] : receiver displacement
224680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rsp[24] : function
224780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
224880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check if the calling frame is an arguments adaptor frame.
224980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label adaptor_frame, try_allocate, runtime;
225080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rdx, Operand(rbp, StandardFrameConstants::kCallerFPOffset));
22513fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ movq(rcx, Operand(rdx, StandardFrameConstants::kContextOffset));
22523fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ Cmp(rcx, Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR));
225380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(equal, &adaptor_frame);
225480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
225580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Get the length from the frame.
22563fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ movq(rcx, Operand(rsp, 1 * kPointerSize));
22573fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ SmiToInteger64(rcx, rcx);
225880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ jmp(&try_allocate);
225980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
226080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Patch the arguments.length and the parameters pointer.
226180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&adaptor_frame);
22623fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ movq(rcx, Operand(rdx, ArgumentsAdaptorFrameConstants::kLengthOffset));
22633fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ movq(Operand(rsp, 1 * kPointerSize), rcx);
22643fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ SmiToInteger64(rcx, rcx);
22653fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ lea(rdx, Operand(rdx, rcx, times_pointer_size,
22663fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch                      StandardFrameConstants::kCallerSPOffset));
226780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(Operand(rsp, 2 * kPointerSize), rdx);
226880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
226980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Try the new space allocation. Start out with computing the size of
227080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // the arguments object and the elements array.
227180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label add_arguments_object;
227280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&try_allocate);
22733fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ testq(rcx, rcx);
22743fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ j(zero, &add_arguments_object, Label::kNear);
22753fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ lea(rcx, Operand(rcx, times_pointer_size, FixedArray::kHeaderSize));
227680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&add_arguments_object);
22773fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ addq(rcx, Immediate(Heap::kArgumentsObjectSizeStrict));
227880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
227980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Do the allocation of both objects in one go.
228080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ AllocateInNewSpace(rcx, rax, rdx, rbx, &runtime, TAG_OBJECT);
228180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
228280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Get the arguments boilerplate from the current (global) context.
228380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rdi, Operand(rsi, Context::SlotOffset(Context::GLOBAL_INDEX)));
228480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rdi, FieldOperand(rdi, GlobalObject::kGlobalContextOffset));
22853fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  const int offset =
22863fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch      Context::SlotOffset(Context::STRICT_MODE_ARGUMENTS_BOILERPLATE_INDEX);
22873fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ movq(rdi, Operand(rdi, offset));
228880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
228980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Copy the JS object part.
22903fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  for (int i = 0; i < JSObject::kHeaderSize; i += kPointerSize) {
22913fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    __ movq(rbx, FieldOperand(rdi, i));
22923fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    __ movq(FieldOperand(rax, i), rbx);
229344f0eee88ff00398ff7f715fab053374d808c90dSteve Block  }
229480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
229580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Get the length (smi tagged) and set that as an in-object property too.
22963fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  STATIC_ASSERT(Heap::kArgumentsLengthIndex == 0);
229780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rcx, Operand(rsp, 1 * kPointerSize));
229844f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ movq(FieldOperand(rax, JSObject::kHeaderSize +
22993fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch                       Heap::kArgumentsLengthIndex * kPointerSize),
230044f0eee88ff00398ff7f715fab053374d808c90dSteve Block          rcx);
230180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
230280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // If there are no actual arguments, we're done.
230380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label done;
23043fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ testq(rcx, rcx);
230580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(zero, &done);
230680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
23073fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // Get the parameters pointer from the stack.
230880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rdx, Operand(rsp, 2 * kPointerSize));
230980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
231080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Setup the elements pointer in the allocated arguments object and
231180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // initialize the header in the elements fixed array.
23123fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ lea(rdi, Operand(rax, Heap::kArgumentsObjectSizeStrict));
231380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(FieldOperand(rax, JSObject::kElementsOffset), rdi);
231480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ LoadRoot(kScratchRegister, Heap::kFixedArrayMapRootIndex);
231580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(FieldOperand(rdi, FixedArray::kMapOffset), kScratchRegister);
23163fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
23173fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
231880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(FieldOperand(rdi, FixedArray::kLengthOffset), rcx);
23193fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // Untag the length for the loop below.
23203fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ SmiToInteger64(rcx, rcx);
232180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
232280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Copy the fixed array slots.
232380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label loop;
232480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&loop);
23253fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ movq(rbx, Operand(rdx, -1 * kPointerSize));  // Skip receiver.
23263fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ movq(FieldOperand(rdi, FixedArray::kHeaderSize), rbx);
232780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ addq(rdi, Immediate(kPointerSize));
232880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ subq(rdx, Immediate(kPointerSize));
23293fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ decq(rcx);
233080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(not_zero, &loop);
233180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
233280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Return and remove the on-stack parameters.
233380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&done);
233480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ ret(3 * kPointerSize);
233580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
233680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Do the runtime call to allocate the arguments object.
233780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&runtime);
23383fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ TailCallRuntime(Runtime::kNewStrictArgumentsFast, 3, 1);
233980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
234080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
234180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
234280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid RegExpExecStub::Generate(MacroAssembler* masm) {
234380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Just jump directly to runtime if native RegExp is not selected at compile
234480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // time or if regexp entry in generated code is turned off runtime switch or
234580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // at compilation.
234680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#ifdef V8_INTERPRETED_REGEXP
234780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ TailCallRuntime(Runtime::kRegExpExec, 4, 1);
234880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#else  // V8_INTERPRETED_REGEXP
234980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  if (!FLAG_regexp_entry_native) {
235080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ TailCallRuntime(Runtime::kRegExpExec, 4, 1);
235180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    return;
235280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
235380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
235480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Stack frame on entry.
23551e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  //  rsp[0]: return address
23561e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  //  rsp[8]: last_match_info (expected JSArray)
23571e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  //  rsp[16]: previous index
23581e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  //  rsp[24]: subject string
23591e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  //  rsp[32]: JSRegExp object
236080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
236180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  static const int kLastMatchInfoOffset = 1 * kPointerSize;
236280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  static const int kPreviousIndexOffset = 2 * kPointerSize;
236380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  static const int kSubjectOffset = 3 * kPointerSize;
236480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  static const int kJSRegExpOffset = 4 * kPointerSize;
236580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
236680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label runtime;
236780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Ensure that a RegExp stack is allocated.
236844f0eee88ff00398ff7f715fab053374d808c90dSteve Block  Isolate* isolate = masm->isolate();
236980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  ExternalReference address_of_regexp_stack_memory_address =
237044f0eee88ff00398ff7f715fab053374d808c90dSteve Block      ExternalReference::address_of_regexp_stack_memory_address(isolate);
237180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  ExternalReference address_of_regexp_stack_memory_size =
237244f0eee88ff00398ff7f715fab053374d808c90dSteve Block      ExternalReference::address_of_regexp_stack_memory_size(isolate);
237344f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ Load(kScratchRegister, address_of_regexp_stack_memory_size);
237480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ testq(kScratchRegister, kScratchRegister);
237580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(zero, &runtime);
237680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
237780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check that the first argument is a JSRegExp object.
237880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rax, Operand(rsp, kJSRegExpOffset));
237980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ JumpIfSmi(rax, &runtime);
238080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ CmpObjectType(rax, JS_REGEXP_TYPE, kScratchRegister);
238180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(not_equal, &runtime);
238280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check that the RegExp has been compiled (data contains a fixed array).
238344f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ movq(rax, FieldOperand(rax, JSRegExp::kDataOffset));
238480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  if (FLAG_debug_code) {
238544f0eee88ff00398ff7f715fab053374d808c90dSteve Block    Condition is_smi = masm->CheckSmi(rax);
238680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ Check(NegateCondition(is_smi),
238780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen        "Unexpected type for RegExp data, FixedArray expected");
238844f0eee88ff00398ff7f715fab053374d808c90dSteve Block    __ CmpObjectType(rax, FIXED_ARRAY_TYPE, kScratchRegister);
238980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ Check(equal, "Unexpected type for RegExp data, FixedArray expected");
239080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
239180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
239244f0eee88ff00398ff7f715fab053374d808c90dSteve Block  // rax: RegExp data (FixedArray)
239380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check the type of the RegExp. Only continue if type is JSRegExp::IRREGEXP.
239444f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ SmiToInteger32(rbx, FieldOperand(rax, JSRegExp::kDataTagOffset));
239580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cmpl(rbx, Immediate(JSRegExp::IRREGEXP));
239680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(not_equal, &runtime);
239780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
239844f0eee88ff00398ff7f715fab053374d808c90dSteve Block  // rax: RegExp data (FixedArray)
239980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check that the number of captures fit in the static offsets vector buffer.
240080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiToInteger32(rdx,
240144f0eee88ff00398ff7f715fab053374d808c90dSteve Block                    FieldOperand(rax, JSRegExp::kIrregexpCaptureCountOffset));
240280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Calculate number of capture registers (number_of_captures + 1) * 2.
240380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ leal(rdx, Operand(rdx, rdx, times_1, 2));
240480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check that the static offsets vector buffer is large enough.
240580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cmpl(rdx, Immediate(OffsetsVector::kStaticOffsetsVectorSize));
240680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(above, &runtime);
240780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
240844f0eee88ff00398ff7f715fab053374d808c90dSteve Block  // rax: RegExp data (FixedArray)
240980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rdx: Number of capture registers
241080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check that the second argument is a string.
2411e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ movq(rdi, Operand(rsp, kSubjectOffset));
2412e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ JumpIfSmi(rdi, &runtime);
2413e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  Condition is_string = masm->IsObjectStringType(rdi, rbx, rbx);
241480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(NegateCondition(is_string), &runtime);
241580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
2416e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  // rdi: Subject string.
2417e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  // rax: RegExp data (FixedArray).
241880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rdx: Number of capture registers.
241980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check that the third argument is a positive smi less than the string
242080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // length. A negative value will be greater (unsigned comparison).
242180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rbx, Operand(rsp, kPreviousIndexOffset));
242280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ JumpIfNotSmi(rbx, &runtime);
2423e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ SmiCompare(rbx, FieldOperand(rdi, String::kLengthOffset));
242480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(above_equal, &runtime);
242580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
2426e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  // rax: RegExp data (FixedArray)
242780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rdx: Number of capture registers
242880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check that the fourth object is a JSArray object.
2429e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ movq(rdi, Operand(rsp, kLastMatchInfoOffset));
2430e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ JumpIfSmi(rdi, &runtime);
2431e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ CmpObjectType(rdi, JS_ARRAY_TYPE, kScratchRegister);
243280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(not_equal, &runtime);
243380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check that the JSArray is in fast case.
2434e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ movq(rbx, FieldOperand(rdi, JSArray::kElementsOffset));
2435e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ movq(rdi, FieldOperand(rbx, HeapObject::kMapOffset));
243644f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ CompareRoot(FieldOperand(rbx, HeapObject::kMapOffset),
243744f0eee88ff00398ff7f715fab053374d808c90dSteve Block                 Heap::kFixedArrayMapRootIndex);
243880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(not_equal, &runtime);
243980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check that the last match info has space for the capture registers and the
244080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // additional information. Ensure no overflow in add.
244180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  STATIC_ASSERT(FixedArray::kMaxLength < kMaxInt - FixedArray::kLengthOffset);
2442e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ SmiToInteger32(rdi, FieldOperand(rbx, FixedArray::kLengthOffset));
244380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ addl(rdx, Immediate(RegExpImpl::kLastMatchOverhead));
2444e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ cmpl(rdx, rdi);
244580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(greater, &runtime);
244680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
244769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  // Reset offset for possibly sliced string.
244869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ Set(r14, 0);
2449e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  // rax: RegExp data (FixedArray)
245080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check the representation and encoding of the subject string.
2451257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label seq_ascii_string, seq_two_byte_string, check_code;
2452e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ movq(rdi, Operand(rsp, kSubjectOffset));
245369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  // Make a copy of the original subject string.
245469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ movq(r15, rdi);
2455e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ movq(rbx, FieldOperand(rdi, HeapObject::kMapOffset));
245680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movzxbl(rbx, FieldOperand(rbx, Map::kInstanceTypeOffset));
245780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // First check for flat two byte string.
245880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ andb(rbx, Immediate(
245980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      kIsNotStringMask | kStringRepresentationMask | kStringEncodingMask));
246080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  STATIC_ASSERT((kStringTag | kSeqStringTag | kTwoByteStringTag) == 0);
2461257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(zero, &seq_two_byte_string, Label::kNear);
246280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Any other flat string must be a flat ascii string.
246369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ andb(rbx, Immediate(kIsNotStringMask | kStringRepresentationMask));
2464257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(zero, &seq_ascii_string, Label::kNear);
246580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
246669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  // Check for flat cons string or sliced string.
246780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // A flat cons string is a cons string where the second part is the empty
246880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // string. In that case the subject string is just the first part of the cons
246980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // string. Also in this case the first part of the cons string is known to be
247080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // a sequential string or an external string.
247169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  // In the case of a sliced string its offset has to be taken into account.
247269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  Label cons_string, check_encoding;
247369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  STATIC_ASSERT(kConsStringTag < kExternalStringTag);
247469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  STATIC_ASSERT(kSlicedStringTag > kExternalStringTag);
247569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ cmpq(rbx, Immediate(kExternalStringTag));
247669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ j(less, &cons_string, Label::kNear);
247769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ j(equal, &runtime);
247869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch
247969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  // String is sliced.
248069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ SmiToInteger32(r14, FieldOperand(rdi, SlicedString::kOffsetOffset));
248169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ movq(rdi, FieldOperand(rdi, SlicedString::kParentOffset));
248269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  // r14: slice offset
248369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  // r15: original subject string
248469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  // rdi: parent string
248569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ jmp(&check_encoding, Label::kNear);
248669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  // String is a cons string, check whether it is flat.
248769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ bind(&cons_string);
248844f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ CompareRoot(FieldOperand(rdi, ConsString::kSecondOffset),
248944f0eee88ff00398ff7f715fab053374d808c90dSteve Block                 Heap::kEmptyStringRootIndex);
249080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(not_equal, &runtime);
2491e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ movq(rdi, FieldOperand(rdi, ConsString::kFirstOffset));
249269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  // rdi: first part of cons string or parent of sliced string.
249369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  // rbx: map of first part of cons string or map of parent of sliced string.
249469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  // Is first part of cons or parent of slice a flat two byte string?
249569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ bind(&check_encoding);
2496e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ movq(rbx, FieldOperand(rdi, HeapObject::kMapOffset));
249780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ testb(FieldOperand(rbx, Map::kInstanceTypeOffset),
249880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen           Immediate(kStringRepresentationMask | kStringEncodingMask));
249980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  STATIC_ASSERT((kSeqStringTag | kTwoByteStringTag) == 0);
2500257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(zero, &seq_two_byte_string, Label::kNear);
250180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Any other flat string must be ascii.
250280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ testb(FieldOperand(rbx, Map::kInstanceTypeOffset),
250380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen           Immediate(kStringRepresentationMask));
250480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(not_zero, &runtime);
250580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
250680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&seq_ascii_string);
2507e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  // rdi: subject string (sequential ascii)
2508e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  // rax: RegExp data (FixedArray)
2509e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ movq(r11, FieldOperand(rax, JSRegExp::kDataAsciiCodeOffset));
2510e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ Set(rcx, 1);  // Type is ascii.
2511257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ jmp(&check_code, Label::kNear);
251280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
251380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&seq_two_byte_string);
2514e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  // rdi: subject string (flat two-byte)
2515e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  // rax: RegExp data (FixedArray)
2516e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ movq(r11, FieldOperand(rax, JSRegExp::kDataUC16CodeOffset));
2517e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ Set(rcx, 0);  // Type is two byte.
251880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
251980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&check_code);
252080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check that the irregexp code has been generated for the actual string
252180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // encoding. If it has, the field contains a code object otherwise it contains
2522257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // smi (code flushing support)
2523257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ JumpIfSmi(r11, &runtime);
252480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
2525e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  // rdi: subject string
2526e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  // rcx: encoding of subject string (1 if ascii, 0 if two_byte);
252780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // r11: code
252880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Load used arguments before starting to push arguments for call to native
252980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // RegExp code to avoid handling changing stack height.
253080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiToInteger64(rbx, Operand(rsp, kPreviousIndexOffset));
253180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
2532e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  // rdi: subject string
253380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rbx: previous index
2534e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  // rcx: encoding of subject string (1 if ascii 0 if two_byte);
253580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // r11: code
253680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // All checks done. Now push arguments for native regexp code.
253744f0eee88ff00398ff7f715fab053374d808c90dSteve Block  Counters* counters = masm->isolate()->counters();
253844f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ IncrementCounter(counters->regexp_entry_native(), 1);
253980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
254044f0eee88ff00398ff7f715fab053374d808c90dSteve Block  // Isolates: note we add an additional parameter here (isolate pointer).
254144f0eee88ff00398ff7f715fab053374d808c90dSteve Block  static const int kRegExpExecuteArguments = 8;
254280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  int argument_slots_on_stack =
254380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      masm->ArgumentStackSlotsForCFunctionCall(kRegExpExecuteArguments);
254444f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ EnterApiExitFrame(argument_slots_on_stack);
254580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
254644f0eee88ff00398ff7f715fab053374d808c90dSteve Block  // Argument 8: Pass current isolate address.
254744f0eee88ff00398ff7f715fab053374d808c90dSteve Block  // __ movq(Operand(rsp, (argument_slots_on_stack - 1) * kPointerSize),
254844f0eee88ff00398ff7f715fab053374d808c90dSteve Block  //     Immediate(ExternalReference::isolate_address()));
254944f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ LoadAddress(kScratchRegister, ExternalReference::isolate_address());
255080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(Operand(rsp, (argument_slots_on_stack - 1) * kPointerSize),
255144f0eee88ff00398ff7f715fab053374d808c90dSteve Block          kScratchRegister);
255244f0eee88ff00398ff7f715fab053374d808c90dSteve Block
255344f0eee88ff00398ff7f715fab053374d808c90dSteve Block  // Argument 7: Indicate that this is a direct call from JavaScript.
255444f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ movq(Operand(rsp, (argument_slots_on_stack - 2) * kPointerSize),
255580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen          Immediate(1));
255680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
255780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Argument 6: Start (high end) of backtracking stack memory area.
255880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(kScratchRegister, address_of_regexp_stack_memory_address);
255980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(r9, Operand(kScratchRegister, 0));
256080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(kScratchRegister, address_of_regexp_stack_memory_size);
256180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ addq(r9, Operand(kScratchRegister, 0));
256280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Argument 6 passed in r9 on Linux and on the stack on Windows.
256380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#ifdef _WIN64
256444f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ movq(Operand(rsp, (argument_slots_on_stack - 3) * kPointerSize), r9);
256580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#endif
256680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
256780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Argument 5: static offsets vector buffer.
256844f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ LoadAddress(r8,
256944f0eee88ff00398ff7f715fab053374d808c90dSteve Block                 ExternalReference::address_of_static_offsets_vector(isolate));
257080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Argument 5 passed in r8 on Linux and on the stack on Windows.
257180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#ifdef _WIN64
257244f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ movq(Operand(rsp, (argument_slots_on_stack - 4) * kPointerSize), r8);
257380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#endif
257480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
257580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // First four arguments are passed in registers on both Linux and Windows.
257680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#ifdef _WIN64
257780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Register arg4 = r9;
257880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Register arg3 = r8;
257980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Register arg2 = rdx;
258080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Register arg1 = rcx;
258180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#else
258280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Register arg4 = rcx;
258380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Register arg3 = rdx;
258480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Register arg2 = rsi;
258580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Register arg1 = rdi;
258680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#endif
258780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
258880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Keep track on aliasing between argX defined above and the registers used.
2589e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  // rdi: subject string
259080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rbx: previous index
2591e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  // rcx: encoding of subject string (1 if ascii 0 if two_byte);
259280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // r11: code
259369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  // r14: slice offset
259469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  // r15: original subject string
259569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch
259669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  // Argument 2: Previous index.
259769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ movq(arg2, rbx);
259880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
259980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Argument 4: End of string data
260080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Argument 3: Start of string data
260169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  Label setup_two_byte, setup_rest, got_length, length_not_from_slice;
260269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  // Prepare start and end index of the input.
260369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  // Load the length from the original sliced string if that is the case.
260469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ addq(rbx, r14);
260569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ SmiToInteger32(arg3, FieldOperand(r15, String::kLengthOffset));
260669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ addq(r14, arg3);  // Using arg3 as scratch.
260769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch
260869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  // rbx: start index of the input
260969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  // r14: end index of the input
261069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  // r15: original subject string
2611e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ testb(rcx, rcx);  // Last use of rcx as encoding of subject string.
2612257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(zero, &setup_two_byte, Label::kNear);
261369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ lea(arg4, FieldOperand(rdi, r14, times_1, SeqAsciiString::kHeaderSize));
2614e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ lea(arg3, FieldOperand(rdi, rbx, times_1, SeqAsciiString::kHeaderSize));
2615257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ jmp(&setup_rest, Label::kNear);
261680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&setup_two_byte);
261769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ lea(arg4, FieldOperand(rdi, r14, times_2, SeqTwoByteString::kHeaderSize));
2618e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ lea(arg3, FieldOperand(rdi, rbx, times_2, SeqTwoByteString::kHeaderSize));
261980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&setup_rest);
262080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
262169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  // Argument 1: Original subject string.
262269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  // The original subject is in the previous stack frame. Therefore we have to
262369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  // use rbp, which points exactly to one pointer size below the previous rsp.
262469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  // (Because creating a new stack frame pushes the previous rbp onto the stack
262569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  // and thereby moves up rsp by one kPointerSize.)
262669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ movq(arg1, r15);
262780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
262880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Locate the code entry and call it.
262980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ addq(r11, Immediate(Code::kHeaderSize - kHeapObjectTag));
2630e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ call(r11);
263180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
2632e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ LeaveApiExitFrame();
263380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
263480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check the result.
2635257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label success;
2636e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  Label exception;
263780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cmpl(rax, Immediate(NativeRegExpMacroAssembler::SUCCESS));
2638257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(equal, &success, Label::kNear);
263980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cmpl(rax, Immediate(NativeRegExpMacroAssembler::EXCEPTION));
2640e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ j(equal, &exception);
2641e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ cmpl(rax, Immediate(NativeRegExpMacroAssembler::FAILURE));
2642e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  // If none of the above, it can only be retry.
2643e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  // Handle that in the runtime system.
264480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(not_equal, &runtime);
2645e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
2646e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  // For failure return null.
2647e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ LoadRoot(rax, Heap::kNullValueRootIndex);
264880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ ret(4 * kPointerSize);
264980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
265080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Load RegExp data.
265180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&success);
265280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rax, Operand(rsp, kJSRegExpOffset));
265380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rcx, FieldOperand(rax, JSRegExp::kDataOffset));
265480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiToInteger32(rax,
265580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                    FieldOperand(rcx, JSRegExp::kIrregexpCaptureCountOffset));
265680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Calculate number of capture registers (number_of_captures + 1) * 2.
265780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ leal(rdx, Operand(rax, rax, times_1, 2));
265880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
265980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rdx: Number of capture registers
266080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Load last_match_info which is still known to be a fast case JSArray.
266180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rax, Operand(rsp, kLastMatchInfoOffset));
266280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rbx, FieldOperand(rax, JSArray::kElementsOffset));
266380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
266480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rbx: last_match_info backing store (FixedArray)
266580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rdx: number of capture registers
266680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Store the capture count.
266780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ Integer32ToSmi(kScratchRegister, rdx);
266880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(FieldOperand(rbx, RegExpImpl::kLastCaptureCountOffset),
266980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen          kScratchRegister);
267080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Store last subject and last input.
267180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rax, Operand(rsp, kSubjectOffset));
267280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(FieldOperand(rbx, RegExpImpl::kLastSubjectOffset), rax);
267380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rcx, rbx);
267480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ RecordWrite(rcx, RegExpImpl::kLastSubjectOffset, rax, rdi);
267580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rax, Operand(rsp, kSubjectOffset));
267680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(FieldOperand(rbx, RegExpImpl::kLastInputOffset), rax);
267780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rcx, rbx);
267880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ RecordWrite(rcx, RegExpImpl::kLastInputOffset, rax, rdi);
267980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
268080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Get the static offsets vector filled by the native regexp code.
268144f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ LoadAddress(rcx,
268244f0eee88ff00398ff7f715fab053374d808c90dSteve Block                 ExternalReference::address_of_static_offsets_vector(isolate));
268380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
268480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rbx: last_match_info backing store (FixedArray)
268580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rcx: offsets vector
268680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rdx: number of capture registers
2687257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label next_capture, done;
268880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Capture register counter starts from number of capture registers and
268980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // counts down until wraping after zero.
269080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&next_capture);
269180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ subq(rdx, Immediate(1));
2692257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(negative, &done, Label::kNear);
269380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Read the value from the static offsets vector buffer and make it a smi.
269480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movl(rdi, Operand(rcx, rdx, times_int_size, 0));
26950d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  __ Integer32ToSmi(rdi, rdi);
269680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Store the smi value in the last match info.
269780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(FieldOperand(rbx,
269880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                       rdx,
269980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                       times_pointer_size,
270080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                       RegExpImpl::kFirstCaptureOffset),
270180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen          rdi);
270280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ jmp(&next_capture);
270380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&done);
270480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
270580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Return last match info.
270680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rax, Operand(rsp, kLastMatchInfoOffset));
270780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ ret(4 * kPointerSize);
270880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
2709e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ bind(&exception);
2710e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  // Result must now be exception. If there is no pending exception already a
2711e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  // stack overflow (on the backtrack stack) was detected in RegExp code but
2712e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  // haven't created the exception yet. Handle that in the runtime system.
2713e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  // TODO(592): Rerunning the RegExp to get the stack overflow exception.
271444f0eee88ff00398ff7f715fab053374d808c90dSteve Block  ExternalReference pending_exception_address(
2715589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch      Isolate::kPendingExceptionAddress, isolate);
271644f0eee88ff00398ff7f715fab053374d808c90dSteve Block  Operand pending_exception_operand =
271744f0eee88ff00398ff7f715fab053374d808c90dSteve Block      masm->ExternalOperand(pending_exception_address, rbx);
271844f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ movq(rax, pending_exception_operand);
2719e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ LoadRoot(rdx, Heap::kTheHoleValueRootIndex);
2720e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ cmpq(rax, rdx);
2721e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ j(equal, &runtime);
272244f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ movq(pending_exception_operand, rdx);
2723e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
2724e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ CompareRoot(rax, Heap::kTerminationExceptionRootIndex);
2725257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label termination_exception;
2726257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(equal, &termination_exception, Label::kNear);
2727e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ Throw(rax);
2728e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
2729e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ bind(&termination_exception);
2730e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ ThrowUncatchable(TERMINATION, rax);
2731e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
273280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Do the runtime call to execute the regexp.
273380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&runtime);
273480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ TailCallRuntime(Runtime::kRegExpExec, 4, 1);
273580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#endif  // V8_INTERPRETED_REGEXP
273680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
273780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
273880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
2739b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdochvoid RegExpConstructResultStub::Generate(MacroAssembler* masm) {
2740b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  const int kMaxInlineLength = 100;
2741b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  Label slowcase;
2742b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  Label done;
2743b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ movq(r8, Operand(rsp, kPointerSize * 3));
2744b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ JumpIfNotSmi(r8, &slowcase);
2745b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ SmiToInteger32(rbx, r8);
2746b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ cmpl(rbx, Immediate(kMaxInlineLength));
2747b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ j(above, &slowcase);
2748b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Smi-tagging is equivalent to multiplying by 2.
2749b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  STATIC_ASSERT(kSmiTag == 0);
2750b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  STATIC_ASSERT(kSmiTagSize == 1);
27511e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  // Allocate RegExpResult followed by FixedArray with size in rbx.
2752b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // JSArray:   [Map][empty properties][Elements][Length-smi][index][input]
2753b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Elements:  [Map][Length][..elements..]
2754b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ AllocateInNewSpace(JSRegExpResult::kSize + FixedArray::kHeaderSize,
2755b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                        times_pointer_size,
2756b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                        rbx,  // In: Number of elements.
2757b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                        rax,  // Out: Start of allocation (tagged).
2758b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                        rcx,  // Out: End of allocation.
2759b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                        rdx,  // Scratch register
2760b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                        &slowcase,
2761b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                        TAG_OBJECT);
2762b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // rax: Start of allocated area, object-tagged.
2763b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // rbx: Number of array elements as int32.
2764b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // r8: Number of array elements as smi.
2765b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
2766b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Set JSArray map to global.regexp_result_map().
2767b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ movq(rdx, ContextOperand(rsi, Context::GLOBAL_INDEX));
2768b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ movq(rdx, FieldOperand(rdx, GlobalObject::kGlobalContextOffset));
2769b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ movq(rdx, ContextOperand(rdx, Context::REGEXP_RESULT_MAP_INDEX));
2770b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ movq(FieldOperand(rax, HeapObject::kMapOffset), rdx);
2771b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
2772b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Set empty properties FixedArray.
277344f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ LoadRoot(kScratchRegister, Heap::kEmptyFixedArrayRootIndex);
277444f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ movq(FieldOperand(rax, JSObject::kPropertiesOffset), kScratchRegister);
2775b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
2776b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Set elements to point to FixedArray allocated right after the JSArray.
2777b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ lea(rcx, Operand(rax, JSRegExpResult::kSize));
2778b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ movq(FieldOperand(rax, JSObject::kElementsOffset), rcx);
2779b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
2780b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Set input, index and length fields from arguments.
2781b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ movq(r8, Operand(rsp, kPointerSize * 1));
2782b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ movq(FieldOperand(rax, JSRegExpResult::kInputOffset), r8);
2783b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ movq(r8, Operand(rsp, kPointerSize * 2));
2784b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ movq(FieldOperand(rax, JSRegExpResult::kIndexOffset), r8);
2785b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ movq(r8, Operand(rsp, kPointerSize * 3));
2786b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ movq(FieldOperand(rax, JSArray::kLengthOffset), r8);
2787b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
2788b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Fill out the elements FixedArray.
2789b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // rax: JSArray.
2790b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // rcx: FixedArray.
2791b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // rbx: Number of elements in array as int32.
2792b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
2793b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Set map.
279444f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ LoadRoot(kScratchRegister, Heap::kFixedArrayMapRootIndex);
279544f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ movq(FieldOperand(rcx, HeapObject::kMapOffset), kScratchRegister);
2796b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Set length.
2797b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ Integer32ToSmi(rdx, rbx);
2798b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ movq(FieldOperand(rcx, FixedArray::kLengthOffset), rdx);
2799b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Fill contents of fixed-array with the-hole.
280044f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ LoadRoot(rdx, Heap::kTheHoleValueRootIndex);
2801b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ lea(rcx, FieldOperand(rcx, FixedArray::kHeaderSize));
2802b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Fill fixed array elements with hole.
2803b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // rax: JSArray.
2804b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // rbx: Number of elements in array that remains to be filled, as int32.
2805b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // rcx: Start of elements in FixedArray.
2806b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // rdx: the hole.
2807b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  Label loop;
2808b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ testl(rbx, rbx);
2809b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ bind(&loop);
28101e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  __ j(less_equal, &done);  // Jump if rcx is negative or zero.
2811b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ subl(rbx, Immediate(1));
2812b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ movq(Operand(rcx, rbx, times_pointer_size, 0), rdx);
2813b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ jmp(&loop);
2814b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
2815b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ bind(&done);
2816b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ ret(3 * kPointerSize);
2817b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
2818b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ bind(&slowcase);
2819b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ TailCallRuntime(Runtime::kRegExpConstructResult, 3, 1);
2820b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch}
2821b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
2822b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
282380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid NumberToStringStub::GenerateLookupNumberStringCache(MacroAssembler* masm,
282480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                                         Register object,
282580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                                         Register result,
282680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                                         Register scratch1,
282780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                                         Register scratch2,
282880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                                         bool object_is_smi,
282980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                                         Label* not_found) {
283080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Use of registers. Register result is used as a temporary.
283180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Register number_string_cache = result;
283280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Register mask = scratch1;
283380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Register scratch = scratch2;
283480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
283580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Load the number string cache.
283680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ LoadRoot(number_string_cache, Heap::kNumberStringCacheRootIndex);
283780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
283880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Make the hash mask from the length of the number string cache. It
283980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // contains two elements (number and string) for each cache entry.
284080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiToInteger32(
284180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      mask, FieldOperand(number_string_cache, FixedArray::kLengthOffset));
284280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ shrl(mask, Immediate(1));
284380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ subq(mask, Immediate(1));  // Make mask.
284480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
284580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Calculate the entry in the number string cache. The hash value in the
284680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // number string cache for smis is just the smi value, and the hash for
284780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // doubles is the xor of the upper and lower words. See
284880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Heap::GetNumberStringCache.
284980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label is_smi;
285080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label load_result_from_cache;
2851257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Factory* factory = masm->isolate()->factory();
285280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  if (!object_is_smi) {
285380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ JumpIfSmi(object, &is_smi);
2854257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ CheckMap(object,
2855257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                factory->heap_number_map(),
2856257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                not_found,
2857257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                DONT_DO_SMI_CHECK);
285880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
285980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    STATIC_ASSERT(8 == kDoubleSize);
286080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ movl(scratch, FieldOperand(object, HeapNumber::kValueOffset + 4));
286180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ xor_(scratch, FieldOperand(object, HeapNumber::kValueOffset));
286280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    GenerateConvertHashCodeToIndex(masm, scratch, mask);
286380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
286480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    Register index = scratch;
286580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    Register probe = mask;
286680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ movq(probe,
286780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen            FieldOperand(number_string_cache,
286880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                         index,
286980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                         times_1,
287080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                         FixedArray::kHeaderSize));
287180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ JumpIfSmi(probe, not_found);
287280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ movsd(xmm0, FieldOperand(object, HeapNumber::kValueOffset));
287380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ movsd(xmm1, FieldOperand(probe, HeapNumber::kValueOffset));
287480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ ucomisd(xmm0, xmm1);
287580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ j(parity_even, not_found);  // Bail out if NaN is involved.
287680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ j(not_equal, not_found);  // The cache did not contain this value.
287780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ jmp(&load_result_from_cache);
287880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
287980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
288080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&is_smi);
288180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiToInteger32(scratch, object);
288280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  GenerateConvertHashCodeToIndex(masm, scratch, mask);
288380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
288480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Register index = scratch;
288580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check if the entry is the smi we are looking for.
288680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cmpq(object,
288780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen          FieldOperand(number_string_cache,
288880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                       index,
288980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                       times_1,
289080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                       FixedArray::kHeaderSize));
289180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(not_equal, not_found);
289280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
289380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Get the result from the cache.
289480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&load_result_from_cache);
289580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(result,
289680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen          FieldOperand(number_string_cache,
289780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                       index,
289880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                       times_1,
289980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                       FixedArray::kHeaderSize + kPointerSize));
290044f0eee88ff00398ff7f715fab053374d808c90dSteve Block  Counters* counters = masm->isolate()->counters();
290144f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ IncrementCounter(counters->number_to_string_native(), 1);
290280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
290380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
290480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
290580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid NumberToStringStub::GenerateConvertHashCodeToIndex(MacroAssembler* masm,
290680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                                        Register hash,
290780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                                        Register mask) {
290880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ and_(hash, mask);
290980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Each entry in string cache consists of two pointer sized fields,
291080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // but times_twice_pointer_size (multiplication by 16) scale factor
291180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // is not supported by addrmode on x64 platform.
291280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // So we have to premultiply entry index before lookup.
291380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ shl(hash, Immediate(kPointerSizeLog2 + 1));
291480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
291580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
291680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
291780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid NumberToStringStub::Generate(MacroAssembler* masm) {
291880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label runtime;
291980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
292080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rbx, Operand(rsp, kPointerSize));
292180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
292280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Generate code to lookup number in the number string cache.
292380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  GenerateLookupNumberStringCache(masm, rbx, rax, r8, r9, false, &runtime);
292480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ ret(1 * kPointerSize);
292580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
292680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&runtime);
292780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Handle number to string in the runtime system if not found in the cache.
292880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ TailCallRuntime(Runtime::kNumberToStringSkipCache, 1, 1);
292980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
293080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
293180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
293280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenstatic int NegativeComparisonResult(Condition cc) {
293380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  ASSERT(cc != equal);
293480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  ASSERT((cc == less) || (cc == less_equal)
293580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      || (cc == greater) || (cc == greater_equal));
293680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  return (cc == greater || cc == greater_equal) ? LESS : GREATER;
293780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
293880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
293980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
294080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid CompareStub::Generate(MacroAssembler* masm) {
294180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  ASSERT(lhs_.is(no_reg) && rhs_.is(no_reg));
294280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
294380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label check_unequal_objects, done;
2944257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Factory* factory = masm->isolate()->factory();
29450d5e116f6aee03185f237311a943491bb079a768Kristian Monsen
29460d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  // Compare two smis if required.
29470d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  if (include_smi_compare_) {
29480d5e116f6aee03185f237311a943491bb079a768Kristian Monsen    Label non_smi, smi_done;
29490d5e116f6aee03185f237311a943491bb079a768Kristian Monsen    __ JumpIfNotBothSmi(rax, rdx, &non_smi);
29500d5e116f6aee03185f237311a943491bb079a768Kristian Monsen    __ subq(rdx, rax);
29510d5e116f6aee03185f237311a943491bb079a768Kristian Monsen    __ j(no_overflow, &smi_done);
2952f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    __ not_(rdx);  // Correct sign in case of overflow. rdx cannot be 0 here.
29530d5e116f6aee03185f237311a943491bb079a768Kristian Monsen    __ bind(&smi_done);
29540d5e116f6aee03185f237311a943491bb079a768Kristian Monsen    __ movq(rax, rdx);
29550d5e116f6aee03185f237311a943491bb079a768Kristian Monsen    __ ret(0);
29560d5e116f6aee03185f237311a943491bb079a768Kristian Monsen    __ bind(&non_smi);
29570d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  } else if (FLAG_debug_code) {
29580d5e116f6aee03185f237311a943491bb079a768Kristian Monsen    Label ok;
29590d5e116f6aee03185f237311a943491bb079a768Kristian Monsen    __ JumpIfNotSmi(rdx, &ok);
29600d5e116f6aee03185f237311a943491bb079a768Kristian Monsen    __ JumpIfNotSmi(rax, &ok);
29610d5e116f6aee03185f237311a943491bb079a768Kristian Monsen    __ Abort("CompareStub: smi operands");
29620d5e116f6aee03185f237311a943491bb079a768Kristian Monsen    __ bind(&ok);
29630d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  }
29640d5e116f6aee03185f237311a943491bb079a768Kristian Monsen
296580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // The compare stub returns a positive, negative, or zero 64-bit integer
296680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // value in rax, corresponding to result of comparing the two inputs.
296780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // NOTICE! This code is only reached after a smi-fast-case check, so
296880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // it is certain that at least one operand isn't a smi.
296980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
297080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Two identical objects are equal unless they are both NaN or undefined.
297180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  {
2972257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Label not_identical;
297380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ cmpq(rax, rdx);
2974257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ j(not_equal, &not_identical, Label::kNear);
297580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
297680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    if (cc_ != equal) {
297780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      // Check for undefined.  undefined OP undefined is false even though
297880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      // undefined == undefined.
2979257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      Label check_for_nan;
298080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ CompareRoot(rdx, Heap::kUndefinedValueRootIndex);
2981257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ j(not_equal, &check_for_nan, Label::kNear);
298280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ Set(rax, NegativeComparisonResult(cc_));
298380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ ret(0);
298480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ bind(&check_for_nan);
298580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    }
298680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
298744f0eee88ff00398ff7f715fab053374d808c90dSteve Block    // Test for NaN. Sadly, we can't just compare to FACTORY->nan_value(),
298880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // so we do the second best thing - test it ourselves.
298980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // Note: if cc_ != equal, never_nan_nan_ is not used.
299080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // We cannot set rax to EQUAL until just before return because
299180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // rax must be unchanged on jump to not_identical.
299280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    if (never_nan_nan_ && (cc_ == equal)) {
299380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ Set(rax, EQUAL);
299480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ ret(0);
299580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    } else {
2996257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      Label heap_number;
299780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      // If it's not a heap number, then return equal for (in)equality operator.
299880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ Cmp(FieldOperand(rdx, HeapObject::kMapOffset),
2999257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch             factory->heap_number_map());
3000257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ j(equal, &heap_number, Label::kNear);
300180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      if (cc_ != equal) {
30023fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch        // Call runtime on identical objects.  Otherwise return equal.
30033fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch        __ CmpObjectType(rax, FIRST_SPEC_OBJECT_TYPE, rcx);
3004257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        __ j(above_equal, &not_identical, Label::kNear);
300580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      }
300680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ Set(rax, EQUAL);
300780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ ret(0);
300880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
300980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ bind(&heap_number);
301080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      // It is a heap number, so return  equal if it's not NaN.
301180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      // For NaN, return 1 for every condition except greater and
301280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      // greater-equal.  Return -1 for them, so the comparison yields
301380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      // false for all conditions except not-equal.
301480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ Set(rax, EQUAL);
301580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ movsd(xmm0, FieldOperand(rdx, HeapNumber::kValueOffset));
301680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ ucomisd(xmm0, xmm0);
301780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ setcc(parity_even, rax);
301880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      // rax is 0 for equal non-NaN heapnumbers, 1 for NaNs.
301980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      if (cc_ == greater_equal || cc_ == greater) {
302080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen        __ neg(rax);
302180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      }
302280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ ret(0);
302380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    }
302480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
302580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ bind(&not_identical);
302680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
302780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
302880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  if (cc_ == equal) {  // Both strict and non-strict.
302980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    Label slow;  // Fallthrough label.
303080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
303180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // If we're doing a strict equality comparison, we don't have to do
303280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // type conversion, so we generate code to do fast comparison for objects
303380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // and oddballs. Non-smi numbers and strings still go through the usual
303480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // slow-case code.
303580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    if (strict_) {
303680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      // If either is a Smi (we know that not both are), then they can only
303780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      // be equal if the other is a HeapNumber. If so, use the slow case.
303880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      {
303980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen        Label not_smis;
304080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen        __ SelectNonSmi(rbx, rax, rdx, &not_smis);
304180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
304280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen        // Check if the non-smi operand is a heap number.
304380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen        __ Cmp(FieldOperand(rbx, HeapObject::kMapOffset),
3044257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch               factory->heap_number_map());
304580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen        // If heap number, handle it in the slow case.
304680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen        __ j(equal, &slow);
304780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen        // Return non-equal.  ebx (the lower half of rbx) is not zero.
304880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen        __ movq(rax, rbx);
304980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen        __ ret(0);
305080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
305180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen        __ bind(&not_smis);
305280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      }
305380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
305480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      // If either operand is a JSObject or an oddball value, then they are not
305580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      // equal since their pointers are different
305680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      // There is no test for undetectability in strict equality.
305780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
305880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      // If the first object is a JS object, we have done pointer comparison.
30593fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch      STATIC_ASSERT(LAST_TYPE == LAST_SPEC_OBJECT_TYPE);
3060257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      Label first_non_object;
30613fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch      __ CmpObjectType(rax, FIRST_SPEC_OBJECT_TYPE, rcx);
3062257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ j(below, &first_non_object, Label::kNear);
306380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      // Return non-zero (eax (not rax) is not zero)
306480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      Label return_not_equal;
306580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      STATIC_ASSERT(kHeapObjectTag != 0);
306680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ bind(&return_not_equal);
306780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ ret(0);
306880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
306980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ bind(&first_non_object);
307080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      // Check for oddballs: true, false, null, undefined.
307180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ CmpInstanceType(rcx, ODDBALL_TYPE);
307280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ j(equal, &return_not_equal);
307380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
30743fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch      __ CmpObjectType(rdx, FIRST_SPEC_OBJECT_TYPE, rcx);
307580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ j(above_equal, &return_not_equal);
307680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
307780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      // Check for oddballs: true, false, null, undefined.
307880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ CmpInstanceType(rcx, ODDBALL_TYPE);
307980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ j(equal, &return_not_equal);
308080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
308180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      // Fall through to the general case.
308280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    }
308380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ bind(&slow);
308480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
308580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
308680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Generate the number comparison code.
308780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  if (include_number_compare_) {
308880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    Label non_number_comparison;
3089257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Label unordered;
309080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    FloatingPointHelper::LoadSSE2UnknownOperands(masm, &non_number_comparison);
309180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ xorl(rax, rax);
309280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ xorl(rcx, rcx);
309380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ ucomisd(xmm0, xmm1);
309480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
309580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // Don't base result on EFLAGS when a NaN is involved.
3096257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ j(parity_even, &unordered, Label::kNear);
309780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // Return a result of -1, 0, or 1, based on EFLAGS.
309880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ setcc(above, rax);
309980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ setcc(below, rcx);
310080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ subq(rax, rcx);
310180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ ret(0);
310280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
310380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // If one of the numbers was NaN, then the result is always false.
310480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // The cc is never not-equal.
310580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ bind(&unordered);
310680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    ASSERT(cc_ != not_equal);
310780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    if (cc_ == less || cc_ == less_equal) {
310880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ Set(rax, 1);
310980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    } else {
311080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ Set(rax, -1);
311180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    }
311280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ ret(0);
311380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
311480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // The number comparison code did not provide a valid result.
311580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ bind(&non_number_comparison);
311680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
311780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
311880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Fast negative check for symbol-to-symbol equality.
311980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label check_for_strings;
312080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  if (cc_ == equal) {
312180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    BranchIfNonSymbol(masm, &check_for_strings, rax, kScratchRegister);
312280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    BranchIfNonSymbol(masm, &check_for_strings, rdx, kScratchRegister);
312380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
312480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // We've already checked for object identity, so if both operands
312580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // are symbols they aren't equal. Register eax (not rax) already holds a
312680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // non-zero value, which indicates not equal, so just return.
312780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ ret(0);
312880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
312980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
313080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&check_for_strings);
313180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
313280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ JumpIfNotBothSequentialAsciiStrings(
313380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      rdx, rax, rcx, rbx, &check_unequal_objects);
313480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
313580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Inline comparison of ascii strings.
3136257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  if (cc_ == equal) {
3137257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    StringCompareStub::GenerateFlatAsciiStringEquals(masm,
313880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                                     rdx,
313980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                                     rax,
314080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                                     rcx,
3141257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                                     rbx);
3142257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  } else {
3143257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    StringCompareStub::GenerateCompareFlatAsciiStrings(masm,
3144257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                                       rdx,
3145257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                                       rax,
3146257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                                       rcx,
3147257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                                       rbx,
3148257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                                       rdi,
3149257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                                       r8);
3150257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
315180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
315280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#ifdef DEBUG
315380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ Abort("Unexpected fall-through from string comparison");
315480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#endif
315580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
315680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&check_unequal_objects);
315780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  if (cc_ == equal && !strict_) {
315880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // Not strict equality.  Objects are unequal if
315980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // they are both JSObjects and not undetectable,
316080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // and their pointers are different.
3161257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Label not_both_objects, return_unequal;
316280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // At most one is a smi, so we can test for smi by adding the two.
316380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // A smi plus a heap object has the low bit set, a heap object plus
316480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // a heap object has the low bit clear.
316580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    STATIC_ASSERT(kSmiTag == 0);
316680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    STATIC_ASSERT(kSmiTagMask == 1);
316780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ lea(rcx, Operand(rax, rdx, times_1, 0));
316880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ testb(rcx, Immediate(kSmiTagMask));
3169257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ j(not_zero, &not_both_objects, Label::kNear);
31703fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    __ CmpObjectType(rax, FIRST_SPEC_OBJECT_TYPE, rbx);
3171257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ j(below, &not_both_objects, Label::kNear);
31723fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    __ CmpObjectType(rdx, FIRST_SPEC_OBJECT_TYPE, rcx);
3173257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ j(below, &not_both_objects, Label::kNear);
317480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ testb(FieldOperand(rbx, Map::kBitFieldOffset),
317580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen             Immediate(1 << Map::kIsUndetectable));
3176257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ j(zero, &return_unequal, Label::kNear);
317780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ testb(FieldOperand(rcx, Map::kBitFieldOffset),
317880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen             Immediate(1 << Map::kIsUndetectable));
3179257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ j(zero, &return_unequal, Label::kNear);
318080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // The objects are both undetectable, so they both compare as the value
318180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // undefined, and are equal.
318280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ Set(rax, EQUAL);
318380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ bind(&return_unequal);
31841e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    // Return non-equal by returning the non-zero object pointer in rax,
318580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // or return equal if we fell through to here.
318680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ ret(0);
318780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ bind(&not_both_objects);
318880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
318980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
319080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Push arguments below the return address to prepare jump to builtin.
319180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ pop(rcx);
319280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ push(rdx);
319380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ push(rax);
319480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
319580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Figure out which native to call and setup the arguments.
319680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Builtins::JavaScript builtin;
319780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  if (cc_ == equal) {
319880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    builtin = strict_ ? Builtins::STRICT_EQUALS : Builtins::EQUALS;
319980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  } else {
320080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    builtin = Builtins::COMPARE;
320180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ Push(Smi::FromInt(NegativeComparisonResult(cc_)));
320280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
320380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
320480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Restore return address on the stack.
320580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ push(rcx);
320680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
320780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Call the native; it returns -1 (less), 0 (equal), or 1 (greater)
320880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // tagged as a small integer.
320980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ InvokeBuiltin(builtin, JUMP_FUNCTION);
321080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
321180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
321280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
321380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid CompareStub::BranchIfNonSymbol(MacroAssembler* masm,
321480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                    Label* label,
321580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                    Register object,
321680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                    Register scratch) {
321780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ JumpIfSmi(object, label);
321880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(scratch, FieldOperand(object, HeapObject::kMapOffset));
321980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movzxbq(scratch,
322080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen             FieldOperand(scratch, Map::kInstanceTypeOffset));
322180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Ensure that no non-strings have the symbol bit set.
322280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  STATIC_ASSERT(LAST_TYPE < kNotStringTag + kIsSymbolMask);
322380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  STATIC_ASSERT(kSymbolTag != 0);
322480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ testb(scratch, Immediate(kIsSymbolMask));
322580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(zero, label);
322680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
322780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
322880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
322980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StackCheckStub::Generate(MacroAssembler* masm) {
3230f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  __ TailCallRuntime(Runtime::kStackGuard, 0, 1);
323180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
323280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
323380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
323480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid CallFunctionStub::Generate(MacroAssembler* masm) {
3235589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch  Label slow, non_function;
323680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
3237257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // The receiver might implicitly be the global object. This is
3238257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // indicated by passing the hole as the receiver to the call
3239257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // function stub.
3240257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  if (ReceiverMightBeImplicit()) {
3241257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Label call;
324280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // Get the receiver from the stack.
324380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // +1 ~ return address
324480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ movq(rax, Operand(rsp, (argc_ + 1) * kPointerSize));
3245257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Call as function is indicated with the hole.
3246257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ CompareRoot(rax, Heap::kTheHoleValueRootIndex);
3247257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ j(not_equal, &call, Label::kNear);
3248257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Patch the receiver on the stack with the global receiver object.
3249257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ movq(rbx, GlobalObjectOperand());
3250257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ movq(rbx, FieldOperand(rbx, GlobalObject::kGlobalReceiverOffset));
3251257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ movq(Operand(rsp, (argc_ + 1) * kPointerSize), rbx);
3252257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ bind(&call);
325380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
325480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
325580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Get the function to call from the stack.
325680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // +2 ~ receiver, return address
325780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rdi, Operand(rsp, (argc_ + 2) * kPointerSize));
325880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
325980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check that the function really is a JavaScript function.
3260589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch  __ JumpIfSmi(rdi, &non_function);
326180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Goto slow case if we do not have a function.
326280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ CmpObjectType(rdi, JS_FUNCTION_TYPE, rcx);
326380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(not_equal, &slow);
326480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
326580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Fast-case: Just invoke the function.
326680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  ParameterCount actual(argc_);
3267257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
3268257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  if (ReceiverMightBeImplicit()) {
3269257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Label call_as_function;
3270257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ CompareRoot(rax, Heap::kTheHoleValueRootIndex);
3271257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ j(equal, &call_as_function);
3272257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ InvokeFunction(rdi,
3273257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                      actual,
3274257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                      JUMP_FUNCTION,
3275257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                      NullCallWrapper(),
3276257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                      CALL_AS_METHOD);
3277257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ bind(&call_as_function);
3278257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
3279257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ InvokeFunction(rdi,
3280257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                    actual,
3281257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                    JUMP_FUNCTION,
3282257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                    NullCallWrapper(),
3283257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                    CALL_AS_FUNCTION);
328480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
328580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Slow-case: Non-function called.
328680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&slow);
3287589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch  // Check for function proxy.
3288589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch  __ CmpInstanceType(rcx, JS_FUNCTION_PROXY_TYPE);
3289589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch  __ j(not_equal, &non_function);
3290589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch  __ pop(rcx);
3291589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch  __ push(rdi);  // put proxy as additional argument under return address
3292589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch  __ push(rcx);
3293589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch  __ Set(rax, argc_ + 1);
3294589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch  __ Set(rbx, 0);
3295589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch  __ SetCallKind(rcx, CALL_AS_FUNCTION);
3296589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch  __ GetBuiltinEntry(rdx, Builtins::CALL_FUNCTION_PROXY);
3297589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch  {
3298589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch    Handle<Code> adaptor =
3299589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch      masm->isolate()->builtins()->ArgumentsAdaptorTrampoline();
3300589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch    __ jmp(adaptor, RelocInfo::CODE_TARGET);
3301589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch  }
3302589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch
330380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // CALL_NON_FUNCTION expects the non-function callee as receiver (instead
330480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // of the original receiver from the call site).
3305589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch  __ bind(&non_function);
330680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(Operand(rsp, (argc_ + 1) * kPointerSize), rdi);
330780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ Set(rax, argc_);
330880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ Set(rbx, 0);
3309589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch  __ SetCallKind(rcx, CALL_AS_METHOD);
331080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ GetBuiltinEntry(rdx, Builtins::CALL_NON_FUNCTION);
331144f0eee88ff00398ff7f715fab053374d808c90dSteve Block  Handle<Code> adaptor =
331244f0eee88ff00398ff7f715fab053374d808c90dSteve Block      Isolate::Current()->builtins()->ArgumentsAdaptorTrampoline();
331380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ Jump(adaptor, RelocInfo::CODE_TARGET);
331480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
331580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
331680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
331744f0eee88ff00398ff7f715fab053374d808c90dSteve Blockbool CEntryStub::NeedsImmovableCode() {
331844f0eee88ff00398ff7f715fab053374d808c90dSteve Block  return false;
331944f0eee88ff00398ff7f715fab053374d808c90dSteve Block}
332044f0eee88ff00398ff7f715fab053374d808c90dSteve Block
332144f0eee88ff00398ff7f715fab053374d808c90dSteve Block
332280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid CEntryStub::GenerateThrowTOS(MacroAssembler* masm) {
3323e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  // Throw exception in eax.
3324e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ Throw(rax);
332580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
332680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
332780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
332880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid CEntryStub::GenerateCore(MacroAssembler* masm,
332980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                              Label* throw_normal_exception,
333080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                              Label* throw_termination_exception,
333180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                              Label* throw_out_of_memory_exception,
333280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                              bool do_gc,
33331e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block                              bool always_allocate_scope) {
333480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rax: result parameter for PerformGC, if any.
333580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rbx: pointer to C function  (C callee-saved).
333680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rbp: frame pointer  (restored after C call).
333780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rsp: stack pointer  (restored after C call).
333880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // r14: number of arguments including receiver (C callee-saved).
333944f0eee88ff00398ff7f715fab053374d808c90dSteve Block  // r15: pointer to the first argument (C callee-saved).
334080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  //      This pointer is reused in LeaveExitFrame(), so it is stored in a
334180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  //      callee-saved register.
334280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
334380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Simple results returned in rax (both AMD64 and Win64 calling conventions).
334480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Complex results must be written to address passed as first argument.
334580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // AMD64 calling convention: a struct of two pointers in rax+rdx
334680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
334780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check stack alignment.
334880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  if (FLAG_debug_code) {
334980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ CheckStackAlignment();
335080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
335180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
335280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  if (do_gc) {
335380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // Pass failure code returned from last attempt as first argument to
335480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // PerformGC. No need to use PrepareCallCFunction/CallCFunction here as the
335580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // stack is known to be aligned. This function takes one argument which is
335680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // passed in register.
335780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#ifdef _WIN64
335880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ movq(rcx, rax);
335980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#else  // _WIN64
336080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ movq(rdi, rax);
336180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#endif
336280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ movq(kScratchRegister,
336380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen            FUNCTION_ADDR(Runtime::PerformGC),
336480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen            RelocInfo::RUNTIME_ENTRY);
336580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ call(kScratchRegister);
336680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
336780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
336880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  ExternalReference scope_depth =
336944f0eee88ff00398ff7f715fab053374d808c90dSteve Block      ExternalReference::heap_always_allocate_scope_depth(masm->isolate());
337080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  if (always_allocate_scope) {
337144f0eee88ff00398ff7f715fab053374d808c90dSteve Block    Operand scope_depth_operand = masm->ExternalOperand(scope_depth);
337244f0eee88ff00398ff7f715fab053374d808c90dSteve Block    __ incl(scope_depth_operand);
337380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
337480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
337580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Call C function.
337680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#ifdef _WIN64
337780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Windows 64-bit ABI passes arguments in rcx, rdx, r8, r9
337880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Store Arguments object on stack, below the 4 WIN64 ABI parameter slots.
33798a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  __ movq(StackSpaceOperand(0), r14);  // argc.
338044f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ movq(StackSpaceOperand(1), r15);  // argv.
338180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  if (result_size_ < 2) {
338280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // Pass a pointer to the Arguments object as the first argument.
338380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // Return result in single register (rax).
33848a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang    __ lea(rcx, StackSpaceOperand(0));
338544f0eee88ff00398ff7f715fab053374d808c90dSteve Block    __ LoadAddress(rdx, ExternalReference::isolate_address());
338680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  } else {
338780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    ASSERT_EQ(2, result_size_);
338880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // Pass a pointer to the result location as the first argument.
33898a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang    __ lea(rcx, StackSpaceOperand(2));
339080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // Pass a pointer to the Arguments object as the second argument.
33918a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang    __ lea(rdx, StackSpaceOperand(0));
339244f0eee88ff00398ff7f715fab053374d808c90dSteve Block    __ LoadAddress(r8, ExternalReference::isolate_address());
339380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
339480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
339580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#else  // _WIN64
339680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // GCC passes arguments in rdi, rsi, rdx, rcx, r8, r9.
339780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rdi, r14);  // argc.
339844f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ movq(rsi, r15);  // argv.
339944f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ movq(rdx, ExternalReference::isolate_address());
340080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#endif
340180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ call(rbx);
340280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Result is in rax - do not destroy this register!
340380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
340480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  if (always_allocate_scope) {
340544f0eee88ff00398ff7f715fab053374d808c90dSteve Block    Operand scope_depth_operand = masm->ExternalOperand(scope_depth);
340644f0eee88ff00398ff7f715fab053374d808c90dSteve Block    __ decl(scope_depth_operand);
340780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
340880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
340980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check for failure result.
341080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label failure_returned;
341180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  STATIC_ASSERT(((kFailureTag + 1) & kFailureTagMask) == 0);
341280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#ifdef _WIN64
341380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // If return value is on the stack, pop it to registers.
341480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  if (result_size_ > 1) {
341580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    ASSERT_EQ(2, result_size_);
341680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // Read result values stored on stack. Result is stored
341780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // above the four argument mirror slots and the two
341880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // Arguments object slots.
341980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ movq(rax, Operand(rsp, 6 * kPointerSize));
342080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ movq(rdx, Operand(rsp, 7 * kPointerSize));
342180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
342280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#endif
342380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ lea(rcx, Operand(rax, 1));
342480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Lower 2 bits of rcx are 0 iff rax has failure tag.
342580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ testl(rcx, Immediate(kFailureTagMask));
342680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(zero, &failure_returned);
342780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
342880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Exit the JavaScript to C++ exit frame.
34291e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  __ LeaveExitFrame(save_doubles_);
343080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ ret(0);
343180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
343280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Handling of failure.
343380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&failure_returned);
343480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
3435257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label retry;
343680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // If the returned exception is RETRY_AFTER_GC continue at retry label
343780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  STATIC_ASSERT(Failure::RETRY_AFTER_GC == 0);
343880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ testl(rax, Immediate(((1 << kFailureTypeTagSize) - 1) << kFailureTagSize));
3439257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(zero, &retry, Label::kNear);
344080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
344180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Special handling of out of memory exceptions.
344280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(kScratchRegister, Failure::OutOfMemoryException(), RelocInfo::NONE);
344380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cmpq(rax, kScratchRegister);
344480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(equal, throw_out_of_memory_exception);
344580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
344680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Retrieve the pending exception and clear the variable.
344744f0eee88ff00398ff7f715fab053374d808c90dSteve Block  ExternalReference pending_exception_address(
3448589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch      Isolate::kPendingExceptionAddress, masm->isolate());
344944f0eee88ff00398ff7f715fab053374d808c90dSteve Block  Operand pending_exception_operand =
345044f0eee88ff00398ff7f715fab053374d808c90dSteve Block      masm->ExternalOperand(pending_exception_address);
345144f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ movq(rax, pending_exception_operand);
345244f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ LoadRoot(rdx, Heap::kTheHoleValueRootIndex);
345344f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ movq(pending_exception_operand, rdx);
345480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
345580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Special handling of termination exceptions which are uncatchable
345680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // by javascript code.
345780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ CompareRoot(rax, Heap::kTerminationExceptionRootIndex);
345880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(equal, throw_termination_exception);
345980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
346080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Handle normal exception.
346180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ jmp(throw_normal_exception);
346280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
346380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Retry.
346480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&retry);
346580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
346680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
346780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
346880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid CEntryStub::GenerateThrowUncatchable(MacroAssembler* masm,
346980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                          UncatchableExceptionType type) {
3470e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ ThrowUncatchable(type, rax);
347180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
347280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
347380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
347480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid CEntryStub::Generate(MacroAssembler* masm) {
347580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rax: number of arguments including receiver
347680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rbx: pointer to C function  (C callee-saved)
347780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rbp: frame pointer of calling JS frame (restored after C call)
347880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rsp: stack pointer  (restored after C call)
347980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rsi: current context (restored)
348080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
348180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // NOTE: Invocations of builtins may return failure objects
348280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // instead of a proper result. The builtin entry handles
348380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // this by performing a garbage collection and retrying the
348480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // builtin once.
348580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
348680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Enter the exit frame that transitions from JavaScript to C++.
34878a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang#ifdef _WIN64
34888a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  int arg_stack_space = (result_size_ < 2 ? 2 : 4);
34898a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang#else
34908a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  int arg_stack_space = 0;
34918a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang#endif
34921e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  __ EnterExitFrame(arg_stack_space, save_doubles_);
349380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
349480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rax: Holds the context at this point, but should not be used.
349580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  //      On entry to code generated by GenerateCore, it must hold
349680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  //      a failure result if the collect_garbage argument to GenerateCore
349780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  //      is true.  This failure result can be the result of code
349880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  //      generated by a previous call to GenerateCore.  The value
349980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  //      of rax is then passed to Runtime::PerformGC.
350080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rbx: pointer to builtin function  (C callee-saved).
350180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rbp: frame pointer of exit frame  (restored after C call).
350280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rsp: stack pointer (restored after C call).
350380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // r14: number of arguments including receiver (C callee-saved).
350444f0eee88ff00398ff7f715fab053374d808c90dSteve Block  // r15: argv pointer (C callee-saved).
350580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
350680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label throw_normal_exception;
350780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label throw_termination_exception;
350880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label throw_out_of_memory_exception;
350980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
351080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Call into the runtime system.
351180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  GenerateCore(masm,
351280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen               &throw_normal_exception,
351380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen               &throw_termination_exception,
351480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen               &throw_out_of_memory_exception,
351580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen               false,
351680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen               false);
351780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
351880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Do space-specific GC and retry runtime call.
351980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  GenerateCore(masm,
352080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen               &throw_normal_exception,
352180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen               &throw_termination_exception,
352280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen               &throw_out_of_memory_exception,
352380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen               true,
352480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen               false);
352580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
352680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Do full GC and retry runtime call one final time.
352780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Failure* failure = Failure::InternalError();
352880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rax, failure, RelocInfo::NONE);
352980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  GenerateCore(masm,
353080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen               &throw_normal_exception,
353180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen               &throw_termination_exception,
353280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen               &throw_out_of_memory_exception,
353380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen               true,
353480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen               true);
353580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
353680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&throw_out_of_memory_exception);
353780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  GenerateThrowUncatchable(masm, OUT_OF_MEMORY);
353880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
353980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&throw_termination_exception);
354080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  GenerateThrowUncatchable(masm, TERMINATION);
354180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
354280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&throw_normal_exception);
354380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  GenerateThrowTOS(masm);
354480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
354580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
354680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
354780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid JSEntryStub::GenerateBody(MacroAssembler* masm, bool is_construct) {
354880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label invoke, exit;
354980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label not_outermost_js, not_outermost_js_2;
355044f0eee88ff00398ff7f715fab053374d808c90dSteve Block  {  // NOLINT. Scope block confuses linter.
355144f0eee88ff00398ff7f715fab053374d808c90dSteve Block    MacroAssembler::NoRootArrayScope uninitialized_root_register(masm);
355244f0eee88ff00398ff7f715fab053374d808c90dSteve Block    // Setup frame.
355344f0eee88ff00398ff7f715fab053374d808c90dSteve Block    __ push(rbp);
355444f0eee88ff00398ff7f715fab053374d808c90dSteve Block    __ movq(rbp, rsp);
355544f0eee88ff00398ff7f715fab053374d808c90dSteve Block
355644f0eee88ff00398ff7f715fab053374d808c90dSteve Block    // Push the stack frame type marker twice.
355744f0eee88ff00398ff7f715fab053374d808c90dSteve Block    int marker = is_construct ? StackFrame::ENTRY_CONSTRUCT : StackFrame::ENTRY;
355844f0eee88ff00398ff7f715fab053374d808c90dSteve Block    // Scratch register is neither callee-save, nor an argument register on any
355944f0eee88ff00398ff7f715fab053374d808c90dSteve Block    // platform. It's free to use at this point.
356044f0eee88ff00398ff7f715fab053374d808c90dSteve Block    // Cannot use smi-register for loading yet.
356144f0eee88ff00398ff7f715fab053374d808c90dSteve Block    __ movq(kScratchRegister,
356244f0eee88ff00398ff7f715fab053374d808c90dSteve Block            reinterpret_cast<uint64_t>(Smi::FromInt(marker)),
356344f0eee88ff00398ff7f715fab053374d808c90dSteve Block            RelocInfo::NONE);
356444f0eee88ff00398ff7f715fab053374d808c90dSteve Block    __ push(kScratchRegister);  // context slot
356544f0eee88ff00398ff7f715fab053374d808c90dSteve Block    __ push(kScratchRegister);  // function slot
356644f0eee88ff00398ff7f715fab053374d808c90dSteve Block    // Save callee-saved registers (X64/Win64 calling conventions).
356744f0eee88ff00398ff7f715fab053374d808c90dSteve Block    __ push(r12);
356844f0eee88ff00398ff7f715fab053374d808c90dSteve Block    __ push(r13);
356944f0eee88ff00398ff7f715fab053374d808c90dSteve Block    __ push(r14);
357044f0eee88ff00398ff7f715fab053374d808c90dSteve Block    __ push(r15);
357180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#ifdef _WIN64
357244f0eee88ff00398ff7f715fab053374d808c90dSteve Block    __ push(rdi);  // Only callee save in Win64 ABI, argument in AMD64 ABI.
357344f0eee88ff00398ff7f715fab053374d808c90dSteve Block    __ push(rsi);  // Only callee save in Win64 ABI, argument in AMD64 ABI.
357480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#endif
357544f0eee88ff00398ff7f715fab053374d808c90dSteve Block    __ push(rbx);
357644f0eee88ff00398ff7f715fab053374d808c90dSteve Block    // TODO(X64): On Win64, if we ever use XMM6-XMM15, the low low 64 bits are
357744f0eee88ff00398ff7f715fab053374d808c90dSteve Block    // callee save as well.
357844f0eee88ff00398ff7f715fab053374d808c90dSteve Block
357944f0eee88ff00398ff7f715fab053374d808c90dSteve Block    // Set up the roots and smi constant registers.
358044f0eee88ff00398ff7f715fab053374d808c90dSteve Block    // Needs to be done before any further smi loads.
358144f0eee88ff00398ff7f715fab053374d808c90dSteve Block    __ InitializeSmiConstantRegister();
358244f0eee88ff00398ff7f715fab053374d808c90dSteve Block    __ InitializeRootRegister();
358344f0eee88ff00398ff7f715fab053374d808c90dSteve Block  }
358480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
358544f0eee88ff00398ff7f715fab053374d808c90dSteve Block  Isolate* isolate = masm->isolate();
358680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
358744f0eee88ff00398ff7f715fab053374d808c90dSteve Block  // Save copies of the top frame descriptor on the stack.
3588589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch  ExternalReference c_entry_fp(Isolate::kCEntryFPAddress, isolate);
358944f0eee88ff00398ff7f715fab053374d808c90dSteve Block  {
359044f0eee88ff00398ff7f715fab053374d808c90dSteve Block    Operand c_entry_fp_operand = masm->ExternalOperand(c_entry_fp);
359144f0eee88ff00398ff7f715fab053374d808c90dSteve Block    __ push(c_entry_fp_operand);
359244f0eee88ff00398ff7f715fab053374d808c90dSteve Block  }
359380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
359480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // If this is the outermost JS call, set js_entry_sp value.
3595589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch  ExternalReference js_entry_sp(Isolate::kJSEntrySPAddress, isolate);
359644f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ Load(rax, js_entry_sp);
359780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ testq(rax, rax);
359880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(not_zero, &not_outermost_js);
3599053d10c438f14580aaf4ab1b2aad93a5a4fe8b82Steve Block  __ Push(Smi::FromInt(StackFrame::OUTERMOST_JSENTRY_FRAME));
360080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rax, rbp);
360144f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ Store(js_entry_sp, rax);
3602053d10c438f14580aaf4ab1b2aad93a5a4fe8b82Steve Block  Label cont;
3603053d10c438f14580aaf4ab1b2aad93a5a4fe8b82Steve Block  __ jmp(&cont);
360480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&not_outermost_js);
3605053d10c438f14580aaf4ab1b2aad93a5a4fe8b82Steve Block  __ Push(Smi::FromInt(StackFrame::INNER_JSENTRY_FRAME));
3606053d10c438f14580aaf4ab1b2aad93a5a4fe8b82Steve Block  __ bind(&cont);
360780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
360880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Call a faked try-block that does the invoke.
360980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ call(&invoke);
361080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
361180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Caught exception: Store result (exception) in the pending
361280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // exception field in the JSEnv and return a failure sentinel.
3613589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch  ExternalReference pending_exception(Isolate::kPendingExceptionAddress,
361444f0eee88ff00398ff7f715fab053374d808c90dSteve Block                                      isolate);
361544f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ Store(pending_exception, rax);
361680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rax, Failure::Exception(), RelocInfo::NONE);
361780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ jmp(&exit);
361880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
361980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Invoke: Link this frame into the handler chain.
362080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&invoke);
362180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ PushTryHandler(IN_JS_ENTRY, JS_ENTRY_HANDLER);
362280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
362380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Clear any pending exceptions.
362444f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ LoadRoot(rax, Heap::kTheHoleValueRootIndex);
362544f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ Store(pending_exception, rax);
362680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
362780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Fake a receiver (NULL).
362880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ push(Immediate(0));  // receiver
362980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
363080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Invoke the function by calling through JS entry trampoline
363180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // builtin and pop the faked function when we return. We load the address
363280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // from an external reference instead of inlining the call target address
363380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // directly in the code, because the builtin stubs may not have been
363480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // generated yet at the time this code is generated.
363580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  if (is_construct) {
363644f0eee88ff00398ff7f715fab053374d808c90dSteve Block    ExternalReference construct_entry(Builtins::kJSConstructEntryTrampoline,
363744f0eee88ff00398ff7f715fab053374d808c90dSteve Block                                      isolate);
363844f0eee88ff00398ff7f715fab053374d808c90dSteve Block    __ Load(rax, construct_entry);
363980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  } else {
364044f0eee88ff00398ff7f715fab053374d808c90dSteve Block    ExternalReference entry(Builtins::kJSEntryTrampoline, isolate);
364144f0eee88ff00398ff7f715fab053374d808c90dSteve Block    __ Load(rax, entry);
364280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
364380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ lea(kScratchRegister, FieldOperand(rax, Code::kHeaderSize));
364480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ call(kScratchRegister);
364580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
364680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Unlink this frame from the handler chain.
3647053d10c438f14580aaf4ab1b2aad93a5a4fe8b82Steve Block  __ PopTryHandler();
364880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
3649053d10c438f14580aaf4ab1b2aad93a5a4fe8b82Steve Block  __ bind(&exit);
3650053d10c438f14580aaf4ab1b2aad93a5a4fe8b82Steve Block  // Check if the current stack frame is marked as the outermost JS frame.
3651053d10c438f14580aaf4ab1b2aad93a5a4fe8b82Steve Block  __ pop(rbx);
3652053d10c438f14580aaf4ab1b2aad93a5a4fe8b82Steve Block  __ Cmp(rbx, Smi::FromInt(StackFrame::OUTERMOST_JSENTRY_FRAME));
365380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(not_equal, &not_outermost_js_2);
3654053d10c438f14580aaf4ab1b2aad93a5a4fe8b82Steve Block  __ movq(kScratchRegister, js_entry_sp);
365580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(Operand(kScratchRegister, 0), Immediate(0));
365680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&not_outermost_js_2);
365780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
365880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Restore the top frame descriptor from the stack.
3659053d10c438f14580aaf4ab1b2aad93a5a4fe8b82Steve Block  { Operand c_entry_fp_operand = masm->ExternalOperand(c_entry_fp);
366044f0eee88ff00398ff7f715fab053374d808c90dSteve Block    __ pop(c_entry_fp_operand);
366144f0eee88ff00398ff7f715fab053374d808c90dSteve Block  }
366280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
366380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Restore callee-saved registers (X64 conventions).
366480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ pop(rbx);
366580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#ifdef _WIN64
366680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Callee save on in Win64 ABI, arguments/volatile in AMD64 ABI.
366780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ pop(rsi);
366880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ pop(rdi);
366980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#endif
367080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ pop(r15);
367180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ pop(r14);
367280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ pop(r13);
367380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ pop(r12);
367480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ addq(rsp, Immediate(2 * kPointerSize));  // remove markers
367580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
367680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Restore frame pointer and return.
367780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ pop(rbp);
367880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ ret(0);
367980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
368080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
368180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
368280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid InstanceofStub::Generate(MacroAssembler* masm) {
368380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Implements "value instanceof function" operator.
368444f0eee88ff00398ff7f715fab053374d808c90dSteve Block  // Expected input state with no inline cache:
368580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  //   rsp[0] : return address
368680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  //   rsp[1] : function pointer
368780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  //   rsp[2] : value
368844f0eee88ff00398ff7f715fab053374d808c90dSteve Block  // Expected input state with an inline one-element cache:
368944f0eee88ff00398ff7f715fab053374d808c90dSteve Block  //   rsp[0] : return address
369044f0eee88ff00398ff7f715fab053374d808c90dSteve Block  //   rsp[1] : offset from return address to location of inline cache
369144f0eee88ff00398ff7f715fab053374d808c90dSteve Block  //   rsp[2] : function pointer
369244f0eee88ff00398ff7f715fab053374d808c90dSteve Block  //   rsp[3] : value
369380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Returns a bitwise zero to indicate that the value
369480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // is and instance of the function and anything else to
369580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // indicate that the value is not an instance.
369680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
36978b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  static const int kOffsetToMapCheckValue = 2;
36988b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  static const int kOffsetToResultValue = 18;
369944f0eee88ff00398ff7f715fab053374d808c90dSteve Block  // The last 4 bytes of the instruction sequence
37008b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  //   movq(rdi, FieldOperand(rax, HeapObject::kMapOffset))
370144f0eee88ff00398ff7f715fab053374d808c90dSteve Block  //   Move(kScratchRegister, FACTORY->the_hole_value())
370244f0eee88ff00398ff7f715fab053374d808c90dSteve Block  // in front of the hole value address.
370344f0eee88ff00398ff7f715fab053374d808c90dSteve Block  static const unsigned int kWordBeforeMapCheckValue = 0xBA49FF78;
370444f0eee88ff00398ff7f715fab053374d808c90dSteve Block  // The last 4 bytes of the instruction sequence
370544f0eee88ff00398ff7f715fab053374d808c90dSteve Block  //   __ j(not_equal, &cache_miss);
370644f0eee88ff00398ff7f715fab053374d808c90dSteve Block  //   __ LoadRoot(ToRegister(instr->result()), Heap::kTheHoleValueRootIndex);
370744f0eee88ff00398ff7f715fab053374d808c90dSteve Block  // before the offset of the hole value in the root array.
370844f0eee88ff00398ff7f715fab053374d808c90dSteve Block  static const unsigned int kWordBeforeResultValue = 0x458B4909;
370944f0eee88ff00398ff7f715fab053374d808c90dSteve Block  // Only the inline check flag is supported on X64.
371044f0eee88ff00398ff7f715fab053374d808c90dSteve Block  ASSERT(flags_ == kNoFlags || HasCallSiteInlineCheck());
371144f0eee88ff00398ff7f715fab053374d808c90dSteve Block  int extra_stack_space = HasCallSiteInlineCheck() ? kPointerSize : 0;
3712e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
371380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Get the object - go slow case if it's a smi.
371480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label slow;
371544f0eee88ff00398ff7f715fab053374d808c90dSteve Block
371644f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ movq(rax, Operand(rsp, 2 * kPointerSize + extra_stack_space));
371780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ JumpIfSmi(rax, &slow);
371880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
371980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check that the left hand is a JS object. Leave its map in rax.
37203fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ CmpObjectType(rax, FIRST_SPEC_OBJECT_TYPE, rax);
372180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(below, &slow);
37223fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ CmpInstanceType(rax, LAST_SPEC_OBJECT_TYPE);
372380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(above, &slow);
372480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
372580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Get the prototype of the function.
372644f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ movq(rdx, Operand(rsp, 1 * kPointerSize + extra_stack_space));
372780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rdx is function, rax is map.
372880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
372944f0eee88ff00398ff7f715fab053374d808c90dSteve Block  // If there is a call site cache don't look in the global cache, but do the
373044f0eee88ff00398ff7f715fab053374d808c90dSteve Block  // real lookup and update the call site cache.
373144f0eee88ff00398ff7f715fab053374d808c90dSteve Block  if (!HasCallSiteInlineCheck()) {
373244f0eee88ff00398ff7f715fab053374d808c90dSteve Block    // Look up the function and the map in the instanceof cache.
3733257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Label miss;
373444f0eee88ff00398ff7f715fab053374d808c90dSteve Block    __ CompareRoot(rdx, Heap::kInstanceofCacheFunctionRootIndex);
3735257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ j(not_equal, &miss, Label::kNear);
373644f0eee88ff00398ff7f715fab053374d808c90dSteve Block    __ CompareRoot(rax, Heap::kInstanceofCacheMapRootIndex);
3737257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ j(not_equal, &miss, Label::kNear);
373844f0eee88ff00398ff7f715fab053374d808c90dSteve Block    __ LoadRoot(rax, Heap::kInstanceofCacheAnswerRootIndex);
373944f0eee88ff00398ff7f715fab053374d808c90dSteve Block    __ ret(2 * kPointerSize);
374044f0eee88ff00398ff7f715fab053374d808c90dSteve Block    __ bind(&miss);
374144f0eee88ff00398ff7f715fab053374d808c90dSteve Block  }
374280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
374380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ TryGetFunctionPrototype(rdx, rbx, &slow);
374480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
374580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check that the function prototype is a JS object.
374680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ JumpIfSmi(rbx, &slow);
37473fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ CmpObjectType(rbx, FIRST_SPEC_OBJECT_TYPE, kScratchRegister);
374880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(below, &slow);
37493fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  __ CmpInstanceType(kScratchRegister, LAST_SPEC_OBJECT_TYPE);
375080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(above, &slow);
375180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
375280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Register mapping:
375380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  //   rax is object map.
375480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  //   rdx is function.
375580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  //   rbx is function prototype.
375644f0eee88ff00398ff7f715fab053374d808c90dSteve Block  if (!HasCallSiteInlineCheck()) {
375744f0eee88ff00398ff7f715fab053374d808c90dSteve Block    __ StoreRoot(rdx, Heap::kInstanceofCacheFunctionRootIndex);
375844f0eee88ff00398ff7f715fab053374d808c90dSteve Block    __ StoreRoot(rax, Heap::kInstanceofCacheMapRootIndex);
375944f0eee88ff00398ff7f715fab053374d808c90dSteve Block  } else {
376044f0eee88ff00398ff7f715fab053374d808c90dSteve Block    __ movq(kScratchRegister, Operand(rsp, 0 * kPointerSize));
376144f0eee88ff00398ff7f715fab053374d808c90dSteve Block    __ subq(kScratchRegister, Operand(rsp, 1 * kPointerSize));
376244f0eee88ff00398ff7f715fab053374d808c90dSteve Block    __ movq(Operand(kScratchRegister, kOffsetToMapCheckValue), rax);
376344f0eee88ff00398ff7f715fab053374d808c90dSteve Block    if (FLAG_debug_code) {
376444f0eee88ff00398ff7f715fab053374d808c90dSteve Block      __ movl(rdi, Immediate(kWordBeforeMapCheckValue));
376544f0eee88ff00398ff7f715fab053374d808c90dSteve Block      __ cmpl(Operand(kScratchRegister, kOffsetToMapCheckValue - 4), rdi);
37668b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch      __ Assert(equal, "InstanceofStub unexpected call site cache (check).");
376744f0eee88ff00398ff7f715fab053374d808c90dSteve Block    }
376844f0eee88ff00398ff7f715fab053374d808c90dSteve Block  }
376980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
377080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rcx, FieldOperand(rax, Map::kPrototypeOffset));
377180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
377280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Loop through the prototype chain looking for the function prototype.
3773257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label loop, is_instance, is_not_instance;
377480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ LoadRoot(kScratchRegister, Heap::kNullValueRootIndex);
377580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&loop);
377680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cmpq(rcx, rbx);
3777257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(equal, &is_instance, Label::kNear);
377880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cmpq(rcx, kScratchRegister);
377980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // The code at is_not_instance assumes that kScratchRegister contains a
378080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // non-zero GCable value (the null object in this case).
3781257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(equal, &is_not_instance, Label::kNear);
378280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rcx, FieldOperand(rcx, HeapObject::kMapOffset));
378380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rcx, FieldOperand(rcx, Map::kPrototypeOffset));
378480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ jmp(&loop);
378580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
378680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&is_instance);
378744f0eee88ff00398ff7f715fab053374d808c90dSteve Block  if (!HasCallSiteInlineCheck()) {
378844f0eee88ff00398ff7f715fab053374d808c90dSteve Block    __ xorl(rax, rax);
378944f0eee88ff00398ff7f715fab053374d808c90dSteve Block    // Store bitwise zero in the cache.  This is a Smi in GC terms.
379044f0eee88ff00398ff7f715fab053374d808c90dSteve Block    STATIC_ASSERT(kSmiTag == 0);
379144f0eee88ff00398ff7f715fab053374d808c90dSteve Block    __ StoreRoot(rax, Heap::kInstanceofCacheAnswerRootIndex);
379244f0eee88ff00398ff7f715fab053374d808c90dSteve Block  } else {
379344f0eee88ff00398ff7f715fab053374d808c90dSteve Block    // Store offset of true in the root array at the inline check site.
379444f0eee88ff00398ff7f715fab053374d808c90dSteve Block    ASSERT((Heap::kTrueValueRootIndex << kPointerSizeLog2) - kRootRegisterBias
379544f0eee88ff00398ff7f715fab053374d808c90dSteve Block        == 0xB0 - 0x100);
379644f0eee88ff00398ff7f715fab053374d808c90dSteve Block    __ movl(rax, Immediate(0xB0));  // TrueValue is at -10 * kPointerSize.
379744f0eee88ff00398ff7f715fab053374d808c90dSteve Block    __ movq(kScratchRegister, Operand(rsp, 0 * kPointerSize));
379844f0eee88ff00398ff7f715fab053374d808c90dSteve Block    __ subq(kScratchRegister, Operand(rsp, 1 * kPointerSize));
379944f0eee88ff00398ff7f715fab053374d808c90dSteve Block    __ movb(Operand(kScratchRegister, kOffsetToResultValue), rax);
380044f0eee88ff00398ff7f715fab053374d808c90dSteve Block    if (FLAG_debug_code) {
380144f0eee88ff00398ff7f715fab053374d808c90dSteve Block      __ movl(rax, Immediate(kWordBeforeResultValue));
380244f0eee88ff00398ff7f715fab053374d808c90dSteve Block      __ cmpl(Operand(kScratchRegister, kOffsetToResultValue - 4), rax);
38038b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch      __ Assert(equal, "InstanceofStub unexpected call site cache (mov).");
380444f0eee88ff00398ff7f715fab053374d808c90dSteve Block    }
38058b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch    __ Set(rax, 0);
380644f0eee88ff00398ff7f715fab053374d808c90dSteve Block  }
380744f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ ret(2 * kPointerSize + extra_stack_space);
380880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
380980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&is_not_instance);
381044f0eee88ff00398ff7f715fab053374d808c90dSteve Block  if (!HasCallSiteInlineCheck()) {
381144f0eee88ff00398ff7f715fab053374d808c90dSteve Block    // We have to store a non-zero value in the cache.
381244f0eee88ff00398ff7f715fab053374d808c90dSteve Block    __ StoreRoot(kScratchRegister, Heap::kInstanceofCacheAnswerRootIndex);
381344f0eee88ff00398ff7f715fab053374d808c90dSteve Block  } else {
381444f0eee88ff00398ff7f715fab053374d808c90dSteve Block    // Store offset of false in the root array at the inline check site.
381544f0eee88ff00398ff7f715fab053374d808c90dSteve Block    ASSERT((Heap::kFalseValueRootIndex << kPointerSizeLog2) - kRootRegisterBias
381644f0eee88ff00398ff7f715fab053374d808c90dSteve Block        == 0xB8 - 0x100);
381744f0eee88ff00398ff7f715fab053374d808c90dSteve Block    __ movl(rax, Immediate(0xB8));  // FalseValue is at -9 * kPointerSize.
381844f0eee88ff00398ff7f715fab053374d808c90dSteve Block    __ movq(kScratchRegister, Operand(rsp, 0 * kPointerSize));
381944f0eee88ff00398ff7f715fab053374d808c90dSteve Block    __ subq(kScratchRegister, Operand(rsp, 1 * kPointerSize));
382044f0eee88ff00398ff7f715fab053374d808c90dSteve Block    __ movb(Operand(kScratchRegister, kOffsetToResultValue), rax);
382144f0eee88ff00398ff7f715fab053374d808c90dSteve Block    if (FLAG_debug_code) {
382244f0eee88ff00398ff7f715fab053374d808c90dSteve Block      __ movl(rax, Immediate(kWordBeforeResultValue));
382344f0eee88ff00398ff7f715fab053374d808c90dSteve Block      __ cmpl(Operand(kScratchRegister, kOffsetToResultValue - 4), rax);
382444f0eee88ff00398ff7f715fab053374d808c90dSteve Block      __ Assert(equal, "InstanceofStub unexpected call site cache (mov)");
382544f0eee88ff00398ff7f715fab053374d808c90dSteve Block    }
382644f0eee88ff00398ff7f715fab053374d808c90dSteve Block  }
382744f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ ret(2 * kPointerSize + extra_stack_space);
382880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
382980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Slow-case: Go through the JavaScript implementation.
383080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&slow);
383144f0eee88ff00398ff7f715fab053374d808c90dSteve Block  if (HasCallSiteInlineCheck()) {
383244f0eee88ff00398ff7f715fab053374d808c90dSteve Block    // Remove extra value from the stack.
383344f0eee88ff00398ff7f715fab053374d808c90dSteve Block    __ pop(rcx);
383444f0eee88ff00398ff7f715fab053374d808c90dSteve Block    __ pop(rax);
383544f0eee88ff00398ff7f715fab053374d808c90dSteve Block    __ push(rcx);
383644f0eee88ff00398ff7f715fab053374d808c90dSteve Block  }
383780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION);
383880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
383980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
384080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
3841e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch// Passing arguments in registers is not supported.
3842e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen MurdochRegister InstanceofStub::left() { return no_reg; }
38431e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
38441e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
3845e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen MurdochRegister InstanceofStub::right() { return no_reg; }
38461e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
38471e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
384880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenint CompareStub::MinorKey() {
384980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Encode the three parameters in a unique 16 bit value. To avoid duplicate
385080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // stubs the never NaN NaN condition is only taken into account if the
385180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // condition is equals.
385280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  ASSERT(static_cast<unsigned>(cc_) < (1 << 12));
385380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  ASSERT(lhs_.is(no_reg) && rhs_.is(no_reg));
385480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  return ConditionField::encode(static_cast<unsigned>(cc_))
385580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen         | RegisterField::encode(false)    // lhs_ and rhs_ are not used
385680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen         | StrictField::encode(strict_)
385780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen         | NeverNanNanField::encode(cc_ == equal ? never_nan_nan_ : false)
38580d5e116f6aee03185f237311a943491bb079a768Kristian Monsen         | IncludeNumberCompareField::encode(include_number_compare_)
38590d5e116f6aee03185f237311a943491bb079a768Kristian Monsen         | IncludeSmiCompareField::encode(include_smi_compare_);
386080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
386180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
386280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
386380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// Unfortunately you have to run without snapshots to see most of these
386480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// names in the profile since most compare stubs end up in the snapshot.
38653fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdochvoid CompareStub::PrintName(StringStream* stream) {
386680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  ASSERT(lhs_.is(no_reg) && rhs_.is(no_reg));
386780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  const char* cc_name;
386880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  switch (cc_) {
386980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    case less: cc_name = "LT"; break;
387080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    case greater: cc_name = "GT"; break;
387180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    case less_equal: cc_name = "LE"; break;
387280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    case greater_equal: cc_name = "GE"; break;
387380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    case equal: cc_name = "EQ"; break;
387480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    case not_equal: cc_name = "NE"; break;
387580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    default: cc_name = "UnknownCondition"; break;
387680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
38773fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  bool is_equality = cc_ == equal || cc_ == not_equal;
38783fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  stream->Add("CompareStub_%s", cc_name);
38793fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  if (strict_ && is_equality) stream->Add("_STRICT");
38803fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  if (never_nan_nan_ && is_equality) stream->Add("_NO_NAN");
38813fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  if (!include_number_compare_) stream->Add("_NO_NUMBER");
38823fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  if (!include_smi_compare_) stream->Add("_NO_SMI");
388380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
388480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
388580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
388680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// -------------------------------------------------------------------------
388780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// StringCharCodeAtGenerator
388880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
388980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StringCharCodeAtGenerator::GenerateFast(MacroAssembler* masm) {
389080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label flat_string;
389180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label ascii_string;
389280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label got_char_code;
389369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  Label sliced_string;
389480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
389580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // If the receiver is a smi trigger the non-string case.
389680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ JumpIfSmi(object_, receiver_not_string_);
389780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
389880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Fetch the instance type of the receiver into result register.
389980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(result_, FieldOperand(object_, HeapObject::kMapOffset));
390080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movzxbl(result_, FieldOperand(result_, Map::kInstanceTypeOffset));
390180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // If the receiver is not a string trigger the non-string case.
390280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ testb(result_, Immediate(kIsNotStringMask));
390380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(not_zero, receiver_not_string_);
390480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
390580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // If the index is non-smi trigger the non-smi case.
390680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ JumpIfNotSmi(index_, &index_not_smi_);
390780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
390880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Put smi-tagged index into scratch register.
390980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(scratch_, index_);
391080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&got_smi_index_);
391180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
391280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check for index out of range.
391380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiCompare(scratch_, FieldOperand(object_, String::kLengthOffset));
391480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(above_equal, index_out_of_range_);
391580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
391680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // We need special handling for non-flat strings.
391780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  STATIC_ASSERT(kSeqStringTag == 0);
391880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ testb(result_, Immediate(kStringRepresentationMask));
391980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(zero, &flat_string);
392080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
392180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Handle non-flat strings.
392269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ and_(result_, Immediate(kStringRepresentationMask));
392369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  STATIC_ASSERT(kConsStringTag < kExternalStringTag);
392469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  STATIC_ASSERT(kSlicedStringTag > kExternalStringTag);
392569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ cmpb(result_, Immediate(kExternalStringTag));
392669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ j(greater, &sliced_string);
392769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ j(equal, &call_runtime_);
392880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
392980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // ConsString.
393080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check whether the right hand side is the empty string (i.e. if
393180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // this is really a flat string in a cons string). If that is not
393280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // the case we would rather go to the runtime system now to flatten
393380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // the string.
393469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  Label assure_seq_string;
393580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ CompareRoot(FieldOperand(object_, ConsString::kSecondOffset),
393680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                 Heap::kEmptyStringRootIndex);
393780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(not_equal, &call_runtime_);
393880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Get the first of the two strings and load its instance type.
393980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(object_, FieldOperand(object_, ConsString::kFirstOffset));
394069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ jmp(&assure_seq_string, Label::kNear);
394169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch
394269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  // SlicedString, unpack and add offset.
394369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ bind(&sliced_string);
394469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ addq(scratch_, FieldOperand(object_, SlicedString::kOffsetOffset));
394569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ movq(object_, FieldOperand(object_, SlicedString::kParentOffset));
394669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch
394769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ bind(&assure_seq_string);
394880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(result_, FieldOperand(object_, HeapObject::kMapOffset));
394980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movzxbl(result_, FieldOperand(result_, Map::kInstanceTypeOffset));
395080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // If the first cons component is also non-flat, then go to runtime.
395180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  STATIC_ASSERT(kSeqStringTag == 0);
395280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ testb(result_, Immediate(kStringRepresentationMask));
395380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(not_zero, &call_runtime_);
395469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  __ jmp(&flat_string);
395580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
395680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check for 1-byte or 2-byte string.
395780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&flat_string);
3958589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch  STATIC_ASSERT((kStringEncodingMask & kAsciiStringTag) != 0);
3959589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch  STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0);
396080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ testb(result_, Immediate(kStringEncodingMask));
396180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(not_zero, &ascii_string);
396280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
396380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // 2-byte string.
396480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Load the 2-byte character code into the result register.
396580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiToInteger32(scratch_, scratch_);
396680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movzxwl(result_, FieldOperand(object_,
396780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                   scratch_, times_2,
396880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                   SeqTwoByteString::kHeaderSize));
396980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ jmp(&got_char_code);
397080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
397180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // ASCII string.
397280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Load the byte into the result register.
397380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&ascii_string);
397480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiToInteger32(scratch_, scratch_);
397580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movzxbl(result_, FieldOperand(object_,
397680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                   scratch_, times_1,
397780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                   SeqAsciiString::kHeaderSize));
397880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&got_char_code);
397980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ Integer32ToSmi(result_, result_);
398080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&exit_);
398180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
398280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
398380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
398480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StringCharCodeAtGenerator::GenerateSlow(
398580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    MacroAssembler* masm, const RuntimeCallHelper& call_helper) {
398680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ Abort("Unexpected fallthrough to CharCodeAt slow case");
398780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
3988257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Factory* factory = masm->isolate()->factory();
398980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Index is not a smi.
399080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&index_not_smi_);
399180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // If index is a heap number, try converting it to an integer.
3992257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ CheckMap(index_,
3993257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch              factory->heap_number_map(),
3994257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch              index_not_number_,
3995257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch              DONT_DO_SMI_CHECK);
399680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  call_helper.BeforeCall(masm);
399780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ push(object_);
399880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ push(index_);
399980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ push(index_);  // Consumed by runtime conversion function.
400080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  if (index_flags_ == STRING_INDEX_IS_NUMBER) {
400180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ CallRuntime(Runtime::kNumberToIntegerMapMinusZero, 1);
400280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  } else {
400380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    ASSERT(index_flags_ == STRING_INDEX_IS_ARRAY_INDEX);
400480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // NumberToSmi discards numbers that are not exact integers.
400580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ CallRuntime(Runtime::kNumberToSmi, 1);
400680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
400780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  if (!scratch_.is(rax)) {
400880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // Save the conversion result before the pop instructions below
400980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // have a chance to overwrite it.
401080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ movq(scratch_, rax);
401180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
401280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ pop(index_);
401380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ pop(object_);
401480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Reload the instance type.
401580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(result_, FieldOperand(object_, HeapObject::kMapOffset));
401680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movzxbl(result_, FieldOperand(result_, Map::kInstanceTypeOffset));
401780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  call_helper.AfterCall(masm);
401880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // If index is still not a smi, it must be out of range.
401980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ JumpIfNotSmi(scratch_, index_out_of_range_);
402080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Otherwise, return to the fast path.
402180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ jmp(&got_smi_index_);
402280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
402380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Call runtime. We get here when the receiver is a string and the
402480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // index is a number, but the code of getting the actual character
402580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // is too complex (e.g., when the string needs to be flattened).
402680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&call_runtime_);
402780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  call_helper.BeforeCall(masm);
402880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ push(object_);
402980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ push(index_);
403080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ CallRuntime(Runtime::kStringCharCodeAt, 2);
403180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  if (!result_.is(rax)) {
403280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ movq(result_, rax);
403380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
403480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  call_helper.AfterCall(masm);
403580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ jmp(&exit_);
403680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
403780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ Abort("Unexpected fallthrough from CharCodeAt slow case");
403880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
403980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
404080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
404180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// -------------------------------------------------------------------------
404280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// StringCharFromCodeGenerator
404380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
404480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StringCharFromCodeGenerator::GenerateFast(MacroAssembler* masm) {
404580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Fast case of Heap::LookupSingleCharacterStringFromCode.
404680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ JumpIfNotSmi(code_, &slow_case_);
404780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiCompare(code_, Smi::FromInt(String::kMaxAsciiCharCode));
404880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(above, &slow_case_);
404980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
405080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ LoadRoot(result_, Heap::kSingleCharacterStringCacheRootIndex);
405180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  SmiIndex index = masm->SmiToIndex(kScratchRegister, code_, kPointerSizeLog2);
405280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(result_, FieldOperand(result_, index.reg, index.scale,
405380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                FixedArray::kHeaderSize));
405480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ CompareRoot(result_, Heap::kUndefinedValueRootIndex);
405580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(equal, &slow_case_);
405680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&exit_);
405780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
405880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
405980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
406080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StringCharFromCodeGenerator::GenerateSlow(
406180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    MacroAssembler* masm, const RuntimeCallHelper& call_helper) {
406280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ Abort("Unexpected fallthrough to CharFromCode slow case");
406380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
406480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&slow_case_);
406580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  call_helper.BeforeCall(masm);
406680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ push(code_);
406780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ CallRuntime(Runtime::kCharFromCode, 1);
406880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  if (!result_.is(rax)) {
406980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ movq(result_, rax);
407080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
407180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  call_helper.AfterCall(masm);
407280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ jmp(&exit_);
407380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
407480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ Abort("Unexpected fallthrough from CharFromCode slow case");
407580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
407680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
407780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
407880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// -------------------------------------------------------------------------
407980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// StringCharAtGenerator
408080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
408180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StringCharAtGenerator::GenerateFast(MacroAssembler* masm) {
408280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  char_code_at_generator_.GenerateFast(masm);
408380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  char_from_code_generator_.GenerateFast(masm);
408480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
408580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
408680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
408780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StringCharAtGenerator::GenerateSlow(
408880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    MacroAssembler* masm, const RuntimeCallHelper& call_helper) {
408980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  char_code_at_generator_.GenerateSlow(masm, call_helper);
409080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  char_from_code_generator_.GenerateSlow(masm, call_helper);
409180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
409280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
409380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
409480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StringAddStub::Generate(MacroAssembler* masm) {
4095e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  Label string_add_runtime, call_builtin;
4096e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  Builtins::JavaScript builtin_id = Builtins::ADD;
409780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
409880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Load the two arguments.
4099e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ movq(rax, Operand(rsp, 2 * kPointerSize));  // First argument (left).
4100e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ movq(rdx, Operand(rsp, 1 * kPointerSize));  // Second argument (right).
410180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
410280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Make sure that both arguments are strings if not known in advance.
4103e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  if (flags_ == NO_STRING_ADD_FLAGS) {
41043fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    __ JumpIfSmi(rax, &string_add_runtime);
410580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ CmpObjectType(rax, FIRST_NONSTRING_TYPE, r8);
410680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ j(above_equal, &string_add_runtime);
410780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
410880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // First argument is a a string, test second.
41093fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    __ JumpIfSmi(rdx, &string_add_runtime);
411080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ CmpObjectType(rdx, FIRST_NONSTRING_TYPE, r9);
411180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ j(above_equal, &string_add_runtime);
4112e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  } else {
4113e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch    // Here at least one of the arguments is definitely a string.
4114e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch    // We convert the one that is not known to be a string.
4115e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch    if ((flags_ & NO_STRING_CHECK_LEFT_IN_STUB) == 0) {
4116e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch      ASSERT((flags_ & NO_STRING_CHECK_RIGHT_IN_STUB) != 0);
4117e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch      GenerateConvertArgument(masm, 2 * kPointerSize, rax, rbx, rcx, rdi,
4118e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch                              &call_builtin);
4119e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch      builtin_id = Builtins::STRING_ADD_RIGHT;
4120e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch    } else if ((flags_ & NO_STRING_CHECK_RIGHT_IN_STUB) == 0) {
4121e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch      ASSERT((flags_ & NO_STRING_CHECK_LEFT_IN_STUB) != 0);
4122e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch      GenerateConvertArgument(masm, 1 * kPointerSize, rdx, rbx, rcx, rdi,
4123e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch                              &call_builtin);
4124e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch      builtin_id = Builtins::STRING_ADD_LEFT;
4125e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch    }
412680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
412780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
412880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Both arguments are strings.
412980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rax: first string
413080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rdx: second string
413180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check if either of the strings are empty. In that case return the other.
4132257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label second_not_zero_length, both_not_zero_length;
413380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rcx, FieldOperand(rdx, String::kLengthOffset));
413480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiTest(rcx);
4135257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(not_zero, &second_not_zero_length, Label::kNear);
413680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Second string is empty, result is first string which is already in rax.
413744f0eee88ff00398ff7f715fab053374d808c90dSteve Block  Counters* counters = masm->isolate()->counters();
413844f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ IncrementCounter(counters->string_add_native(), 1);
413980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ ret(2 * kPointerSize);
414080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&second_not_zero_length);
414180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rbx, FieldOperand(rax, String::kLengthOffset));
414280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiTest(rbx);
4143257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(not_zero, &both_not_zero_length, Label::kNear);
414480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // First string is empty, result is second string which is in rdx.
414580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rax, rdx);
414644f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ IncrementCounter(counters->string_add_native(), 1);
414780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ ret(2 * kPointerSize);
414880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
414980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Both strings are non-empty.
415080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rax: first string
415180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rbx: length of first string
415280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rcx: length of second string
415380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rdx: second string
4154e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  // r8: map of first string (if flags_ == NO_STRING_ADD_FLAGS)
4155e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  // r9: map of second string (if flags_ == NO_STRING_ADD_FLAGS)
415680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label string_add_flat_result, longer_than_two;
415780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&both_not_zero_length);
415880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
415980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // If arguments where known to be strings, maps are not loaded to r8 and r9
416080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // by the code above.
4161e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  if (flags_ != NO_STRING_ADD_FLAGS) {
416280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ movq(r8, FieldOperand(rax, HeapObject::kMapOffset));
416380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ movq(r9, FieldOperand(rdx, HeapObject::kMapOffset));
416480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
416580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Get the instance types of the two strings as they will be needed soon.
416680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movzxbl(r8, FieldOperand(r8, Map::kInstanceTypeOffset));
416780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movzxbl(r9, FieldOperand(r9, Map::kInstanceTypeOffset));
416880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
416980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Look at the length of the result of adding the two strings.
417080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  STATIC_ASSERT(String::kMaxLength <= Smi::kMaxValue / 2);
41710d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  __ SmiAdd(rbx, rbx, rcx);
417244f0eee88ff00398ff7f715fab053374d808c90dSteve Block  // Use the symbol table when adding two one character strings, as it
417344f0eee88ff00398ff7f715fab053374d808c90dSteve Block  // helps later optimizations to return a symbol here.
417480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiCompare(rbx, Smi::FromInt(2));
417580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(not_equal, &longer_than_two);
417680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
417780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check that both strings are non-external ascii strings.
417880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ JumpIfBothInstanceTypesAreNotSequentialAscii(r8, r9, rbx, rcx,
417980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                                  &string_add_runtime);
418080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
418180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Get the two characters forming the sub string.
418280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movzxbq(rbx, FieldOperand(rax, SeqAsciiString::kHeaderSize));
418380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movzxbq(rcx, FieldOperand(rdx, SeqAsciiString::kHeaderSize));
418480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
418580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Try to lookup two character string in symbol table. If it is not found
418680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // just allocate a new one.
418780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label make_two_character_string, make_flat_ascii_string;
418880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  StringHelper::GenerateTwoCharacterSymbolTableProbe(
418944f0eee88ff00398ff7f715fab053374d808c90dSteve Block      masm, rbx, rcx, r14, r11, rdi, r15, &make_two_character_string);
419044f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ IncrementCounter(counters->string_add_native(), 1);
419180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ ret(2 * kPointerSize);
419280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
419380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&make_two_character_string);
419480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ Set(rbx, 2);
419580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ jmp(&make_flat_ascii_string);
419680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
419780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&longer_than_two);
419880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check if resulting string will be flat.
419980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiCompare(rbx, Smi::FromInt(String::kMinNonFlatLength));
420080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(below, &string_add_flat_result);
420180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Handle exceptionally long strings in the runtime system.
420280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  STATIC_ASSERT((String::kMaxLength & 0x80000000) == 0);
420380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiCompare(rbx, Smi::FromInt(String::kMaxLength));
420480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(above, &string_add_runtime);
420580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
420680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // If result is not supposed to be flat, allocate a cons string object. If
420780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // both strings are ascii the result is an ascii cons string.
420880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rax: first string
420980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rbx: length of resulting flat string
421080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rdx: second string
421180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // r8: instance type of first string
421280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // r9: instance type of second string
421380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label non_ascii, allocated, ascii_data;
421480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movl(rcx, r8);
421580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ and_(rcx, r9);
4216589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch  STATIC_ASSERT((kStringEncodingMask & kAsciiStringTag) != 0);
4217589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch  STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0);
4218589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch  __ testl(rcx, Immediate(kStringEncodingMask));
421980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(zero, &non_ascii);
422080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&ascii_data);
422180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Allocate an acsii cons string.
422280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ AllocateAsciiConsString(rcx, rdi, no_reg, &string_add_runtime);
422380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&allocated);
422480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Fill the fields of the cons string.
422580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(FieldOperand(rcx, ConsString::kLengthOffset), rbx);
422680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(FieldOperand(rcx, ConsString::kHashFieldOffset),
422780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen          Immediate(String::kEmptyHashField));
422880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(FieldOperand(rcx, ConsString::kFirstOffset), rax);
422980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(FieldOperand(rcx, ConsString::kSecondOffset), rdx);
423080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rax, rcx);
423144f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ IncrementCounter(counters->string_add_native(), 1);
423280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ ret(2 * kPointerSize);
423380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&non_ascii);
423480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // At least one of the strings is two-byte. Check whether it happens
423580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // to contain only ascii characters.
423680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rcx: first instance type AND second instance type.
423780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // r8: first instance type.
423880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // r9: second instance type.
423980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ testb(rcx, Immediate(kAsciiDataHintMask));
424080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(not_zero, &ascii_data);
424180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ xor_(r8, r9);
424280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  STATIC_ASSERT(kAsciiStringTag != 0 && kAsciiDataHintTag != 0);
424380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ andb(r8, Immediate(kAsciiStringTag | kAsciiDataHintTag));
424480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cmpb(r8, Immediate(kAsciiStringTag | kAsciiDataHintTag));
424580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(equal, &ascii_data);
424680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Allocate a two byte cons string.
4247589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch  __ AllocateTwoByteConsString(rcx, rdi, no_reg, &string_add_runtime);
424880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ jmp(&allocated);
424980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
425080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Handle creating a flat result. First check that both strings are not
425180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // external strings.
425280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rax: first string
425380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rbx: length of resulting flat string as smi
425480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rdx: second string
425580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // r8: instance type of first string
425680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // r9: instance type of first string
425780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&string_add_flat_result);
425880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiToInteger32(rbx, rbx);
425980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movl(rcx, r8);
426080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ and_(rcx, Immediate(kStringRepresentationMask));
426180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cmpl(rcx, Immediate(kExternalStringTag));
426280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(equal, &string_add_runtime);
426380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movl(rcx, r9);
426480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ and_(rcx, Immediate(kStringRepresentationMask));
426580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cmpl(rcx, Immediate(kExternalStringTag));
426680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(equal, &string_add_runtime);
426769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  // We cannot encounter sliced strings here since:
426869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  STATIC_ASSERT(SlicedString::kMinLength >= String::kMinNonFlatLength);
426980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Now check if both strings are ascii strings.
427080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rax: first string
427180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rbx: length of resulting flat string
427280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rdx: second string
427380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // r8: instance type of first string
427480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // r9: instance type of second string
427580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label non_ascii_string_add_flat_result;
4276589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch  STATIC_ASSERT((kStringEncodingMask & kAsciiStringTag) != 0);
4277589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch  STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0);
4278589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch  __ testl(r8, Immediate(kStringEncodingMask));
427980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(zero, &non_ascii_string_add_flat_result);
4280589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch  __ testl(r9, Immediate(kStringEncodingMask));
428180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(zero, &string_add_runtime);
428280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
428380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&make_flat_ascii_string);
428480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Both strings are ascii strings. As they are short they are both flat.
428580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ AllocateAsciiString(rcx, rbx, rdi, r14, r11, &string_add_runtime);
428680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rcx: result string
428780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rbx, rcx);
428880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Locate first character of result.
428980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ addq(rcx, Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag));
429080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Locate first character of first argument
429180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiToInteger32(rdi, FieldOperand(rax, String::kLengthOffset));
429280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ addq(rax, Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag));
429380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rax: first char of first argument
429480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rbx: result string
429580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rcx: first character of result
429680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rdx: second string
429780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rdi: length of first argument
429880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  StringHelper::GenerateCopyCharacters(masm, rcx, rax, rdi, true);
429980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Locate first character of second argument.
430080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiToInteger32(rdi, FieldOperand(rdx, String::kLengthOffset));
430180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ addq(rdx, Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag));
430280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rbx: result string
430380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rcx: next character of result
430480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rdx: first char of second argument
430580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rdi: length of second argument
430680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  StringHelper::GenerateCopyCharacters(masm, rcx, rdx, rdi, true);
430780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rax, rbx);
430844f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ IncrementCounter(counters->string_add_native(), 1);
430980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ ret(2 * kPointerSize);
431080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
431180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Handle creating a flat two byte result.
431280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rax: first string - known to be two byte
431380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rbx: length of resulting flat string
431480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rdx: second string
431580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // r8: instance type of first string
431680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // r9: instance type of first string
431780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&non_ascii_string_add_flat_result);
4318589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch  STATIC_ASSERT((kStringEncodingMask & kAsciiStringTag) != 0);
4319589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch  STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0);
4320589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch  __ and_(r9, Immediate(kStringEncodingMask));
432180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(not_zero, &string_add_runtime);
432280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Both strings are two byte strings. As they are short they are both
432380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // flat.
432480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ AllocateTwoByteString(rcx, rbx, rdi, r14, r11, &string_add_runtime);
432580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rcx: result string
432680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rbx, rcx);
432780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Locate first character of result.
432880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ addq(rcx, Immediate(SeqTwoByteString::kHeaderSize - kHeapObjectTag));
432980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Locate first character of first argument.
433080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiToInteger32(rdi, FieldOperand(rax, String::kLengthOffset));
433180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ addq(rax, Immediate(SeqTwoByteString::kHeaderSize - kHeapObjectTag));
433280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rax: first char of first argument
433380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rbx: result string
433480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rcx: first character of result
433580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rdx: second argument
433680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rdi: length of first argument
433780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  StringHelper::GenerateCopyCharacters(masm, rcx, rax, rdi, false);
433880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Locate first character of second argument.
433980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiToInteger32(rdi, FieldOperand(rdx, String::kLengthOffset));
434080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ addq(rdx, Immediate(SeqTwoByteString::kHeaderSize - kHeapObjectTag));
434180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rbx: result string
434280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rcx: next character of result
434380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rdx: first char of second argument
434480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rdi: length of second argument
434580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  StringHelper::GenerateCopyCharacters(masm, rcx, rdx, rdi, false);
434680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rax, rbx);
434744f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ IncrementCounter(counters->string_add_native(), 1);
434880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ ret(2 * kPointerSize);
434980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
435080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Just jump to runtime to add the two strings.
435180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&string_add_runtime);
435280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ TailCallRuntime(Runtime::kStringAdd, 2, 1);
4353e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
4354e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  if (call_builtin.is_linked()) {
4355e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch    __ bind(&call_builtin);
4356e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch    __ InvokeBuiltin(builtin_id, JUMP_FUNCTION);
4357e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  }
4358e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch}
4359e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
4360e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
4361e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdochvoid StringAddStub::GenerateConvertArgument(MacroAssembler* masm,
4362e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch                                            int stack_offset,
4363e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch                                            Register arg,
4364e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch                                            Register scratch1,
4365e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch                                            Register scratch2,
4366e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch                                            Register scratch3,
4367e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch                                            Label* slow) {
4368e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  // First check if the argument is already a string.
4369e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  Label not_string, done;
4370e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ JumpIfSmi(arg, &not_string);
4371e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ CmpObjectType(arg, FIRST_NONSTRING_TYPE, scratch1);
4372e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ j(below, &done);
4373e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
4374e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  // Check the number to string cache.
4375e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  Label not_cached;
4376e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ bind(&not_string);
4377e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  // Puts the cached result into scratch1.
4378e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  NumberToStringStub::GenerateLookupNumberStringCache(masm,
4379e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch                                                      arg,
4380e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch                                                      scratch1,
4381e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch                                                      scratch2,
4382e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch                                                      scratch3,
4383e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch                                                      false,
4384e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch                                                      &not_cached);
4385e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ movq(arg, scratch1);
4386e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ movq(Operand(rsp, stack_offset), arg);
4387e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ jmp(&done);
4388e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
4389e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  // Check if the argument is a safe string wrapper.
4390e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ bind(&not_cached);
4391e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ JumpIfSmi(arg, slow);
4392e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ CmpObjectType(arg, JS_VALUE_TYPE, scratch1);  // map -> scratch1.
4393e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ j(not_equal, slow);
4394e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ testb(FieldOperand(scratch1, Map::kBitField2Offset),
4395e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch           Immediate(1 << Map::kStringWrapperSafeForDefaultValueOf));
4396e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ j(zero, slow);
4397e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ movq(arg, FieldOperand(arg, JSValue::kValueOffset));
4398e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ movq(Operand(rsp, stack_offset), arg);
4399e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
4400e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ bind(&done);
440180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
440280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
440380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
440480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StringHelper::GenerateCopyCharacters(MacroAssembler* masm,
440580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                          Register dest,
440680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                          Register src,
440780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                          Register count,
440880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                          bool ascii) {
440980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label loop;
441080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&loop);
441180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // This loop just copies one character at a time, as it is only used for very
441280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // short strings.
441380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  if (ascii) {
441480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ movb(kScratchRegister, Operand(src, 0));
441580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ movb(Operand(dest, 0), kScratchRegister);
441680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ incq(src);
441780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ incq(dest);
441880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  } else {
441980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ movzxwl(kScratchRegister, Operand(src, 0));
442080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ movw(Operand(dest, 0), kScratchRegister);
442180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ addq(src, Immediate(2));
442280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ addq(dest, Immediate(2));
442380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
442480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ decl(count);
442580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(not_zero, &loop);
442680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
442780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
442880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
442980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StringHelper::GenerateCopyCharactersREP(MacroAssembler* masm,
443080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                             Register dest,
443180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                             Register src,
443280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                             Register count,
443380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                             bool ascii) {
443480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Copy characters using rep movs of doublewords. Align destination on 4 byte
443580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // boundary before starting rep movs. Copy remaining characters after running
443680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rep movs.
443780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Count is positive int32, dest and src are character pointers.
443880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  ASSERT(dest.is(rdi));  // rep movs destination
443980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  ASSERT(src.is(rsi));  // rep movs source
444080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  ASSERT(count.is(rcx));  // rep movs count
444180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
444280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Nothing to do for zero characters.
4443257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label done;
444480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ testl(count, count);
4445257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(zero, &done, Label::kNear);
444680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
444780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Make count the number of bytes to copy.
444880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  if (!ascii) {
444980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    STATIC_ASSERT(2 == sizeof(uc16));
445080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ addl(count, count);
445180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
445280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
445380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Don't enter the rep movs if there are less than 4 bytes to copy.
4454257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label last_bytes;
445580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ testl(count, Immediate(~7));
4456257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(zero, &last_bytes, Label::kNear);
445780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
445880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Copy from edi to esi using rep movs instruction.
445980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movl(kScratchRegister, count);
446080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ shr(count, Immediate(3));  // Number of doublewords to copy.
446180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ repmovsq();
446280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
446380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Find number of bytes left.
446480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movl(count, kScratchRegister);
446580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ and_(count, Immediate(7));
446680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
446780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check if there are more bytes to copy.
446880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&last_bytes);
446980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ testl(count, count);
4470257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(zero, &done, Label::kNear);
447180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
447280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Copy remaining characters.
447380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label loop;
447480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&loop);
447580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movb(kScratchRegister, Operand(src, 0));
447680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movb(Operand(dest, 0), kScratchRegister);
447780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ incq(src);
447880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ incq(dest);
447980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ decl(count);
448080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(not_zero, &loop);
448180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
448280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&done);
448380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
448480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
448580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StringHelper::GenerateTwoCharacterSymbolTableProbe(MacroAssembler* masm,
448680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                                        Register c1,
448780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                                        Register c2,
448880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                                        Register scratch1,
448980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                                        Register scratch2,
449080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                                        Register scratch3,
449180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                                        Register scratch4,
449280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                                        Label* not_found) {
449380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Register scratch3 is the general scratch register in this function.
449480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Register scratch = scratch3;
449580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
449680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Make sure that both characters are not digits as such strings has a
449780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // different hash algorithm. Don't try to look for these in the symbol table.
4498257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label not_array_index;
449980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ leal(scratch, Operand(c1, -'0'));
450080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cmpl(scratch, Immediate(static_cast<int>('9' - '0')));
4501257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(above, &not_array_index, Label::kNear);
450280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ leal(scratch, Operand(c2, -'0'));
450380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cmpl(scratch, Immediate(static_cast<int>('9' - '0')));
450480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(below_equal, not_found);
450580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
450680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&not_array_index);
450780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Calculate the two character string hash.
450880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Register hash = scratch1;
450980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  GenerateHashInit(masm, hash, c1, scratch);
451080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  GenerateHashAddCharacter(masm, hash, c2, scratch);
451180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  GenerateHashGetHash(masm, hash, scratch);
451280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
451380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Collect the two characters in a register.
451480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Register chars = c1;
451580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ shl(c2, Immediate(kBitsPerByte));
451680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ orl(chars, c2);
451780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
451880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // chars: two character string, char 1 in byte 0 and char 2 in byte 1.
451980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // hash:  hash of two character string.
452080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
452180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Load the symbol table.
452280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Register symbol_table = c2;
452380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ LoadRoot(symbol_table, Heap::kSymbolTableRootIndex);
452480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
452580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Calculate capacity mask from the symbol table capacity.
452680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Register mask = scratch2;
452780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiToInteger32(mask,
452880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                    FieldOperand(symbol_table, SymbolTable::kCapacityOffset));
452980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ decl(mask);
453080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
453144f0eee88ff00398ff7f715fab053374d808c90dSteve Block  Register map = scratch4;
453280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
453380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Registers
453480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // chars:        two character string, char 1 in byte 0 and char 2 in byte 1.
453580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // hash:         hash of two character string (32-bit int)
453680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // symbol_table: symbol table
453780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // mask:         capacity mask (32-bit int)
453844f0eee88ff00398ff7f715fab053374d808c90dSteve Block  // map:          -
453980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // scratch:      -
454080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
454180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Perform a number of probes in the symbol table.
454280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  static const int kProbes = 4;
454380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label found_in_symbol_table;
454480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label next_probe[kProbes];
454580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  for (int i = 0; i < kProbes; i++) {
454680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // Calculate entry in symbol table.
454780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ movl(scratch, hash);
454880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    if (i > 0) {
454980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ addl(scratch, Immediate(SymbolTable::GetProbeOffset(i)));
455080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    }
455180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ andl(scratch, mask);
455280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
455344f0eee88ff00398ff7f715fab053374d808c90dSteve Block    // Load the entry from the symbol table.
455480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    Register candidate = scratch;  // Scratch register contains candidate.
455580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    STATIC_ASSERT(SymbolTable::kEntrySize == 1);
455680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ movq(candidate,
455780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen            FieldOperand(symbol_table,
455880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                         scratch,
455980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                         times_pointer_size,
456080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                         SymbolTable::kElementsStartOffset));
456180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
456280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // If entry is undefined no string with this hash can be found.
4563257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Label is_string;
456444f0eee88ff00398ff7f715fab053374d808c90dSteve Block    __ CmpObjectType(candidate, ODDBALL_TYPE, map);
4565257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ j(not_equal, &is_string, Label::kNear);
456644f0eee88ff00398ff7f715fab053374d808c90dSteve Block
456744f0eee88ff00398ff7f715fab053374d808c90dSteve Block    __ CompareRoot(candidate, Heap::kUndefinedValueRootIndex);
456880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ j(equal, not_found);
456944f0eee88ff00398ff7f715fab053374d808c90dSteve Block    // Must be null (deleted entry).
457044f0eee88ff00398ff7f715fab053374d808c90dSteve Block    __ jmp(&next_probe[i]);
457144f0eee88ff00398ff7f715fab053374d808c90dSteve Block
457244f0eee88ff00398ff7f715fab053374d808c90dSteve Block    __ bind(&is_string);
457380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
457480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // If length is not 2 the string is not a candidate.
457580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ SmiCompare(FieldOperand(candidate, String::kLengthOffset),
457680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                  Smi::FromInt(2));
457780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ j(not_equal, &next_probe[i]);
457880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
457980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // We use kScratchRegister as a temporary register in assumption that
458080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // JumpIfInstanceTypeIsNotSequentialAscii does not use it implicitly
458180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    Register temp = kScratchRegister;
458280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
458380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // Check that the candidate is a non-external ascii string.
458444f0eee88ff00398ff7f715fab053374d808c90dSteve Block    __ movzxbl(temp, FieldOperand(map, Map::kInstanceTypeOffset));
458580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ JumpIfInstanceTypeIsNotSequentialAscii(
458680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen        temp, temp, &next_probe[i]);
458780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
458880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // Check if the two characters match.
458980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ movl(temp, FieldOperand(candidate, SeqAsciiString::kHeaderSize));
459080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ andl(temp, Immediate(0x0000ffff));
459180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ cmpl(chars, temp);
459280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ j(equal, &found_in_symbol_table);
459380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ bind(&next_probe[i]);
459480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
459580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
459680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // No matching 2 character string found by probing.
459780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ jmp(not_found);
459880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
459980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Scratch register contains result when we fall through to here.
460080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Register result = scratch;
460180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&found_in_symbol_table);
460280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  if (!result.is(rax)) {
460380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ movq(rax, result);
460480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
460580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
460680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
460780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
460880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StringHelper::GenerateHashInit(MacroAssembler* masm,
460980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                    Register hash,
461080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                    Register character,
461180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                    Register scratch) {
461280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // hash = character + (character << 10);
461380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movl(hash, character);
461480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ shll(hash, Immediate(10));
461580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ addl(hash, character);
461680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // hash ^= hash >> 6;
461780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movl(scratch, hash);
461880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ sarl(scratch, Immediate(6));
461980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ xorl(hash, scratch);
462080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
462180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
462280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
462380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StringHelper::GenerateHashAddCharacter(MacroAssembler* masm,
462480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                            Register hash,
462580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                            Register character,
462680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                            Register scratch) {
462780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // hash += character;
462880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ addl(hash, character);
462980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // hash += hash << 10;
463080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movl(scratch, hash);
463180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ shll(scratch, Immediate(10));
463280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ addl(hash, scratch);
463380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // hash ^= hash >> 6;
463480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movl(scratch, hash);
463580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ sarl(scratch, Immediate(6));
463680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ xorl(hash, scratch);
463780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
463880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
463980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
464080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StringHelper::GenerateHashGetHash(MacroAssembler* masm,
464180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                       Register hash,
464280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                       Register scratch) {
464380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // hash += hash << 3;
464480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ leal(hash, Operand(hash, hash, times_8, 0));
464580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // hash ^= hash >> 11;
464680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movl(scratch, hash);
464780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ sarl(scratch, Immediate(11));
464880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ xorl(hash, scratch);
464980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // hash += hash << 15;
465080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movl(scratch, hash);
465180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ shll(scratch, Immediate(15));
465280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ addl(hash, scratch);
465380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
465480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // if (hash == 0) hash = 27;
465580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label hash_not_zero;
465680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(not_zero, &hash_not_zero);
46578b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  __ Set(hash, 27);
465880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&hash_not_zero);
465980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
466080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
466180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid SubStringStub::Generate(MacroAssembler* masm) {
466280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label runtime;
466380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
466480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Stack frame on entry.
466580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  //  rsp[0]: return address
466680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  //  rsp[8]: to
466780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  //  rsp[16]: from
466880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  //  rsp[24]: string
466980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
467080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  const int kToOffset = 1 * kPointerSize;
467180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  const int kFromOffset = kToOffset + kPointerSize;
467280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  const int kStringOffset = kFromOffset + kPointerSize;
467380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  const int kArgumentsSize = (kStringOffset + kPointerSize) - kToOffset;
467480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
467580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Make sure first argument is a string.
467680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rax, Operand(rsp, kStringOffset));
467780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  STATIC_ASSERT(kSmiTag == 0);
467880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ testl(rax, Immediate(kSmiTagMask));
467980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(zero, &runtime);
468080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Condition is_string = masm->IsObjectStringType(rax, rbx, rbx);
468180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(NegateCondition(is_string), &runtime);
468280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
468380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rax: string
468480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rbx: instance type
468580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Calculate length of sub string using the smi values.
468680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label result_longer_than_two;
468780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rcx, Operand(rsp, kToOffset));
468880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rdx, Operand(rsp, kFromOffset));
4689f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  __ JumpUnlessBothNonNegativeSmi(rcx, rdx, &runtime);
469080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
46910d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  __ SmiSub(rcx, rcx, rdx);  // Overflow doesn't happen.
469280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cmpq(FieldOperand(rax, String::kLengthOffset), rcx);
469380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label return_rax;
469480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(equal, &return_rax);
469580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Special handling of sub-strings of length 1 and 2. One character strings
469680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // are handled in the runtime system (looked up in the single character
469780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // cache). Two character strings are looked for in the symbol cache.
469880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiToInteger32(rcx, rcx);
469980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cmpl(rcx, Immediate(2));
470080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(greater, &result_longer_than_two);
470180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(less, &runtime);
470280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
470380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Sub string of length 2 requested.
470480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rax: string
470580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rbx: instance type
470680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rcx: sub string length (value is 2)
470780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rdx: from index (smi)
470880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ JumpIfInstanceTypeIsNotSequentialAscii(rbx, rbx, &runtime);
470980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
471080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Get the two characters forming the sub string.
471180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiToInteger32(rdx, rdx);  // From index is no longer smi.
471280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movzxbq(rbx, FieldOperand(rax, rdx, times_1, SeqAsciiString::kHeaderSize));
471380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movzxbq(rcx,
471480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen             FieldOperand(rax, rdx, times_1, SeqAsciiString::kHeaderSize + 1));
471580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
471680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Try to lookup two character string in symbol table.
471780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label make_two_character_string;
471880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  StringHelper::GenerateTwoCharacterSymbolTableProbe(
471980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      masm, rbx, rcx, rax, rdx, rdi, r14, &make_two_character_string);
472080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ ret(3 * kPointerSize);
472180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
472280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&make_two_character_string);
472380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Setup registers for allocating the two character string.
472480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rax, Operand(rsp, kStringOffset));
472580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rbx, FieldOperand(rax, HeapObject::kMapOffset));
472680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movzxbl(rbx, FieldOperand(rbx, Map::kInstanceTypeOffset));
472780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ Set(rcx, 2);
472880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
4729589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch  if (FLAG_string_slices) {
4730589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch    Label copy_routine;
4731589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch    // If coming from the make_two_character_string path, the string
4732589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch    // is too short to be sliced anyways.
4733589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch    STATIC_ASSERT(2 < SlicedString::kMinLength);
4734589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch    __ jmp(&copy_routine);
4735589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch    __ bind(&result_longer_than_two);
4736589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch
4737589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch    // rax: string
4738589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch    // rbx: instance type
4739589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch    // rcx: sub string length
4740589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch    // rdx: from index (smi)
4741589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch    Label allocate_slice, sliced_string, seq_string;
4742589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch    __ cmpq(rcx, Immediate(SlicedString::kMinLength));
4743589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch    // Short slice.  Copy instead of slicing.
4744589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch    __ j(less, &copy_routine);
4745589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch    STATIC_ASSERT(kSeqStringTag == 0);
4746589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch    __ testb(rbx, Immediate(kStringRepresentationMask));
4747589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch    __ j(zero, &seq_string, Label::kNear);
4748589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch    STATIC_ASSERT(kIsIndirectStringMask == (kSlicedStringTag & kConsStringTag));
4749589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch    STATIC_ASSERT(kIsIndirectStringMask != 0);
4750589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch    __ testb(rbx, Immediate(kIsIndirectStringMask));
4751589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch    // External string.  Jump to runtime.
4752589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch    __ j(zero, &runtime);
4753589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch
4754589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch    __ testb(rbx, Immediate(kSlicedNotConsMask));
4755589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch    __ j(not_zero, &sliced_string, Label::kNear);
4756589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch    // Cons string.  Check whether it is flat, then fetch first part.
4757589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch    __ CompareRoot(FieldOperand(rax, ConsString::kSecondOffset),
4758589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch                   Heap::kEmptyStringRootIndex);
4759589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch    __ j(not_equal, &runtime);
4760589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch    __ movq(rdi, FieldOperand(rax, ConsString::kFirstOffset));
4761589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch    __ jmp(&allocate_slice, Label::kNear);
4762589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch
4763589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch    __ bind(&sliced_string);
4764589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch    // Sliced string.  Fetch parent and correct start index by offset.
4765589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch    __ addq(rdx, FieldOperand(rax, SlicedString::kOffsetOffset));
4766589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch    __ movq(rdi, FieldOperand(rax, SlicedString::kParentOffset));
4767589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch    __ jmp(&allocate_slice, Label::kNear);
4768589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch
4769589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch    __ bind(&seq_string);
4770589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch    // Sequential string.  Just move string to the right register.
4771589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch    __ movq(rdi, rax);
4772589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch
4773589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch    __ bind(&allocate_slice);
4774589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch    // edi: underlying subject string
4775589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch    // ebx: instance type of original subject string
4776589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch    // edx: offset
4777589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch    // ecx: length
4778589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch    // Allocate new sliced string.  At this point we do not reload the instance
4779589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch    // type including the string encoding because we simply rely on the info
4780589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch    // provided by the original string.  It does not matter if the original
4781589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch    // string's encoding is wrong because we always have to recheck encoding of
4782589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch    // the newly created string's parent anyways due to externalized strings.
4783589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch    Label two_byte_slice, set_slice_header;
4784589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch    STATIC_ASSERT((kStringEncodingMask & kAsciiStringTag) != 0);
4785589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch    STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0);
4786589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch    __ testb(rbx, Immediate(kStringEncodingMask));
4787589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch    __ j(zero, &two_byte_slice, Label::kNear);
4788589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch    __ AllocateAsciiSlicedString(rax, rbx, no_reg, &runtime);
4789589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch    __ jmp(&set_slice_header, Label::kNear);
4790589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch    __ bind(&two_byte_slice);
4791589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch    __ AllocateTwoByteSlicedString(rax, rbx, no_reg, &runtime);
4792589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch    __ bind(&set_slice_header);
4793589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch    __ movq(FieldOperand(rax, SlicedString::kOffsetOffset), rdx);
4794589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch    __ Integer32ToSmi(rcx, rcx);
4795589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch    __ movq(FieldOperand(rax, SlicedString::kLengthOffset), rcx);
4796589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch    __ movq(FieldOperand(rax, SlicedString::kParentOffset), rdi);
4797589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch    __ movq(FieldOperand(rax, SlicedString::kHashFieldOffset),
4798589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch           Immediate(String::kEmptyHashField));
4799589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch    __ jmp(&return_rax);
4800589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch
4801589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch    __ bind(&copy_routine);
4802589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch  } else {
4803589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch    __ bind(&result_longer_than_two);
4804589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch  }
480580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
480680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rax: string
480780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rbx: instance type
480880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rcx: result string length
480980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check for flat ascii string
481080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label non_ascii_flat;
481180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ JumpIfInstanceTypeIsNotSequentialAscii(rbx, rbx, &non_ascii_flat);
481280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
481380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Allocate the result.
481480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ AllocateAsciiString(rax, rcx, rbx, rdx, rdi, &runtime);
481580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
481680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rax: result string
481780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rcx: result string length
481880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rdx, rsi);  // esi used by following code.
481980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Locate first character of result.
482080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ lea(rdi, FieldOperand(rax, SeqAsciiString::kHeaderSize));
482180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Load string argument and locate character of sub string start.
482280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rsi, Operand(rsp, kStringOffset));
482380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rbx, Operand(rsp, kFromOffset));
482480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  {
482580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    SmiIndex smi_as_index = masm->SmiToIndex(rbx, rbx, times_1);
482680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ lea(rsi, Operand(rsi, smi_as_index.reg, smi_as_index.scale,
482780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                        SeqAsciiString::kHeaderSize - kHeapObjectTag));
482880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
482980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
483080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rax: result string
483180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rcx: result length
483280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rdx: original value of rsi
483380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rdi: first character of result
483480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rsi: character of sub string start
483580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  StringHelper::GenerateCopyCharactersREP(masm, rdi, rsi, rcx, true);
483680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rsi, rdx);  // Restore rsi.
483744f0eee88ff00398ff7f715fab053374d808c90dSteve Block  Counters* counters = masm->isolate()->counters();
483844f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ IncrementCounter(counters->sub_string_native(), 1);
483980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ ret(kArgumentsSize);
484080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
484180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&non_ascii_flat);
484280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rax: string
484380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rbx: instance type & kStringRepresentationMask | kStringEncodingMask
484480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rcx: result string length
484580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check for sequential two byte string
484680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cmpb(rbx, Immediate(kSeqStringTag | kTwoByteStringTag));
484780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(not_equal, &runtime);
484880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
484980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Allocate the result.
485080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ AllocateTwoByteString(rax, rcx, rbx, rdx, rdi, &runtime);
485180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
485280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rax: result string
485380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rcx: result string length
485480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rdx, rsi);  // esi used by following code.
485580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Locate first character of result.
485680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ lea(rdi, FieldOperand(rax, SeqTwoByteString::kHeaderSize));
485780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Load string argument and locate character of sub string start.
485880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rsi, Operand(rsp, kStringOffset));
485980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rbx, Operand(rsp, kFromOffset));
486080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  {
486180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    SmiIndex smi_as_index = masm->SmiToIndex(rbx, rbx, times_2);
486280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ lea(rsi, Operand(rsi, smi_as_index.reg, smi_as_index.scale,
486380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                        SeqAsciiString::kHeaderSize - kHeapObjectTag));
486480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
486580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
486680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rax: result string
486780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rcx: result length
486880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rdx: original value of rsi
486980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rdi: first character of result
487080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rsi: character of sub string start
487180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  StringHelper::GenerateCopyCharactersREP(masm, rdi, rsi, rcx, false);
487280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rsi, rdx);  // Restore esi.
487380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
487480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&return_rax);
487544f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ IncrementCounter(counters->sub_string_native(), 1);
487680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ ret(kArgumentsSize);
487780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
487880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Just jump to runtime to create the sub string.
487980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&runtime);
488080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ TailCallRuntime(Runtime::kSubString, 3, 1);
488180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
488280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
488380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
4884257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid StringCompareStub::GenerateFlatAsciiStringEquals(MacroAssembler* masm,
4885257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                                      Register left,
4886257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                                      Register right,
4887257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                                      Register scratch1,
4888257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                                      Register scratch2) {
4889257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Register length = scratch1;
4890257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
4891257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Compare lengths.
4892257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label check_zero_length;
4893257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ movq(length, FieldOperand(left, String::kLengthOffset));
4894257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ SmiCompare(length, FieldOperand(right, String::kLengthOffset));
4895257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(equal, &check_zero_length, Label::kNear);
4896257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Move(rax, Smi::FromInt(NOT_EQUAL));
4897257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ ret(0);
4898257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
4899257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Check if the length is zero.
4900257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label compare_chars;
4901257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&check_zero_length);
4902257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  STATIC_ASSERT(kSmiTag == 0);
4903257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ SmiTest(length);
4904257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(not_zero, &compare_chars, Label::kNear);
4905257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Move(rax, Smi::FromInt(EQUAL));
4906257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ ret(0);
4907257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
4908257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Compare characters.
4909257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&compare_chars);
4910257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label strings_not_equal;
4911257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  GenerateAsciiCharsCompareLoop(masm, left, right, length, scratch2,
4912257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                &strings_not_equal, Label::kNear);
4913257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
4914257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Characters are equal.
4915257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Move(rax, Smi::FromInt(EQUAL));
4916257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ ret(0);
4917257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
4918257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Characters are not equal.
4919257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&strings_not_equal);
4920257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Move(rax, Smi::FromInt(NOT_EQUAL));
4921257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ ret(0);
4922257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch}
4923257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
4924257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
492580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StringCompareStub::GenerateCompareFlatAsciiStrings(MacroAssembler* masm,
492680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                                        Register left,
492780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                                        Register right,
492880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                                        Register scratch1,
492980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                                        Register scratch2,
493080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                                        Register scratch3,
493180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                                        Register scratch4) {
493280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Ensure that you can always subtract a string length from a non-negative
493380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // number (e.g. another length).
493480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  STATIC_ASSERT(String::kMaxLength < 0x7fffffff);
493580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
493680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Find minimum length and length difference.
493780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(scratch1, FieldOperand(left, String::kLengthOffset));
493880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(scratch4, scratch1);
493980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiSub(scratch4,
494080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen            scratch4,
49410d5e116f6aee03185f237311a943491bb079a768Kristian Monsen            FieldOperand(right, String::kLengthOffset));
494280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Register scratch4 now holds left.length - right.length.
494380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  const Register length_difference = scratch4;
4944257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label left_shorter;
4945257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(less, &left_shorter, Label::kNear);
494680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // The right string isn't longer that the left one.
494780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Get the right string's length by subtracting the (non-negative) difference
494880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // from the left string's length.
49490d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  __ SmiSub(scratch1, scratch1, length_difference);
495080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&left_shorter);
495180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Register scratch1 now holds Min(left.length, right.length).
495280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  const Register min_length = scratch1;
495380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
4954257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label compare_lengths;
495580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // If min-length is zero, go directly to comparing lengths.
495680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiTest(min_length);
4957257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(zero, &compare_lengths, Label::kNear);
495880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
4959257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Compare loop.
4960257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label result_not_equal;
4961257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  GenerateAsciiCharsCompareLoop(masm, left, right, min_length, scratch2,
4962257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                &result_not_equal, Label::kNear);
496380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
496480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Completed loop without finding different characters.
496580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Compare lengths (precomputed).
496680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&compare_lengths);
496780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiTest(length_difference);
4968257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(not_zero, &result_not_equal, Label::kNear);
496980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
497080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Result is EQUAL.
497180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ Move(rax, Smi::FromInt(EQUAL));
497280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ ret(0);
497380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
4974257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label result_greater;
497580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&result_not_equal);
497680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Unequal comparison of left to right, either character or length.
4977257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(greater, &result_greater, Label::kNear);
497880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
497980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Result is LESS.
498080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ Move(rax, Smi::FromInt(LESS));
498180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ ret(0);
498280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
498380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Result is GREATER.
498480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&result_greater);
498580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ Move(rax, Smi::FromInt(GREATER));
498680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ ret(0);
498780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
498880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
498980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
4990257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid StringCompareStub::GenerateAsciiCharsCompareLoop(
4991257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    MacroAssembler* masm,
4992257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Register left,
4993257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Register right,
4994257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Register length,
4995257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Register scratch,
4996257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Label* chars_not_equal,
4997257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Label::Distance near_jump) {
4998257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Change index to run from -length to -1 by adding length to string
4999257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // start. This means that loop ends when index reaches zero, which
5000257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // doesn't need an additional compare.
5001257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ SmiToInteger32(length, length);
5002257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ lea(left,
5003257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch         FieldOperand(left, length, times_1, SeqAsciiString::kHeaderSize));
5004257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ lea(right,
5005257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch         FieldOperand(right, length, times_1, SeqAsciiString::kHeaderSize));
5006257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ neg(length);
5007257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Register index = length;  // index = -length;
5008257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5009257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Compare loop.
5010257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label loop;
5011257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&loop);
5012257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ movb(scratch, Operand(left, index, times_1, 0));
5013257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ cmpb(scratch, Operand(right, index, times_1, 0));
5014257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(not_equal, chars_not_equal, near_jump);
5015257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ addq(index, Immediate(1));
5016257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(not_zero, &loop);
5017257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch}
5018257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5019257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
502080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StringCompareStub::Generate(MacroAssembler* masm) {
502180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label runtime;
502280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
502380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Stack frame on entry.
502480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  //  rsp[0]: return address
502580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  //  rsp[8]: right string
502680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  //  rsp[16]: left string
502780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
502880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rdx, Operand(rsp, 2 * kPointerSize));  // left
502980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rax, Operand(rsp, 1 * kPointerSize));  // right
503080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
503180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check for identity.
5032257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label not_same;
503380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cmpq(rdx, rax);
5034257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(not_equal, &not_same, Label::kNear);
503580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ Move(rax, Smi::FromInt(EQUAL));
503644f0eee88ff00398ff7f715fab053374d808c90dSteve Block  Counters* counters = masm->isolate()->counters();
503744f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ IncrementCounter(counters->string_compare_native(), 1);
503880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ ret(2 * kPointerSize);
503980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
504080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&not_same);
504180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
504280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check that both are sequential ASCII strings.
504380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ JumpIfNotBothSequentialAsciiStrings(rdx, rax, rcx, rbx, &runtime);
504480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
504580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Inline comparison of ascii strings.
504644f0eee88ff00398ff7f715fab053374d808c90dSteve Block  __ IncrementCounter(counters->string_compare_native(), 1);
504780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Drop arguments from the stack
504880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ pop(rcx);
504980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ addq(rsp, Immediate(2 * kPointerSize));
505080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ push(rcx);
505180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  GenerateCompareFlatAsciiStrings(masm, rdx, rax, rcx, rbx, rdi, r8);
505280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
505380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Call the runtime; it returns -1 (less), 0 (equal), or 1 (greater)
505480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // tagged as a small integer.
505580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&runtime);
505680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ TailCallRuntime(Runtime::kStringCompare, 2, 1);
505780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
505880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
5059e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
5060b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdochvoid ICCompareStub::GenerateSmis(MacroAssembler* masm) {
50611e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  ASSERT(state_ == CompareIC::SMIS);
5062257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label miss;
5063257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ JumpIfNotBothSmi(rdx, rax, &miss, Label::kNear);
50641e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
50651e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  if (GetCondition() == equal) {
50661e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    // For equality we do not care about the sign of the result.
50671e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    __ subq(rax, rdx);
50681e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  } else {
5069257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Label done;
50701e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    __ subq(rdx, rax);
5071257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ j(no_overflow, &done, Label::kNear);
50721e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    // Correct sign of result in case of overflow.
50731e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    __ SmiNot(rdx, rdx);
50741e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    __ bind(&done);
50751e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    __ movq(rax, rdx);
50761e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  }
50771e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  __ ret(0);
50781e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
50791e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  __ bind(&miss);
50801e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  GenerateMiss(masm);
5081b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch}
5082b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
5083b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
5084b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdochvoid ICCompareStub::GenerateHeapNumbers(MacroAssembler* masm) {
50851e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  ASSERT(state_ == CompareIC::HEAP_NUMBERS);
50861e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
5087257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label generic_stub;
5088257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label unordered;
5089257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label miss;
50901e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  Condition either_smi = masm->CheckEitherSmi(rax, rdx);
5091257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(either_smi, &generic_stub, Label::kNear);
50921e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
50931e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  __ CmpObjectType(rax, HEAP_NUMBER_TYPE, rcx);
5094257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(not_equal, &miss, Label::kNear);
50951e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  __ CmpObjectType(rdx, HEAP_NUMBER_TYPE, rcx);
5096257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(not_equal, &miss, Label::kNear);
50971e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
50981e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  // Load left and right operand
50991e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  __ movsd(xmm0, FieldOperand(rdx, HeapNumber::kValueOffset));
51001e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  __ movsd(xmm1, FieldOperand(rax, HeapNumber::kValueOffset));
51011e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
51021e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  // Compare operands
51031e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  __ ucomisd(xmm0, xmm1);
51041e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
51051e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  // Don't base result on EFLAGS when a NaN is involved.
5106257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(parity_even, &unordered, Label::kNear);
51071e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
51081e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  // Return a result of -1, 0, or 1, based on EFLAGS.
51091e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  // Performing mov, because xor would destroy the flag register.
51101e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  __ movl(rax, Immediate(0));
51111e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  __ movl(rcx, Immediate(0));
51121e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  __ setcc(above, rax);  // Add one to zero if carry clear and not equal.
51131e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  __ sbbq(rax, rcx);  // Subtract one if below (aka. carry set).
51141e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  __ ret(0);
51151e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
51161e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  __ bind(&unordered);
51171e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
51181e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  CompareStub stub(GetCondition(), strict(), NO_COMPARE_FLAGS);
51191e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  __ bind(&generic_stub);
51201e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  __ jmp(stub.GetCode(), RelocInfo::CODE_TARGET);
51211e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
51221e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  __ bind(&miss);
51231e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  GenerateMiss(masm);
5124b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch}
5125b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
5126b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
5127257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid ICCompareStub::GenerateSymbols(MacroAssembler* masm) {
5128257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  ASSERT(state_ == CompareIC::SYMBOLS);
5129257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  ASSERT(GetCondition() == equal);
5130257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5131257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Registers containing left and right operands respectively.
5132257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Register left = rdx;
5133257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Register right = rax;
5134257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Register tmp1 = rcx;
5135257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Register tmp2 = rbx;
5136257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5137257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Check that both operands are heap objects.
5138257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label miss;
5139257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Condition cond = masm->CheckEitherSmi(left, right, tmp1);
5140257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(cond, &miss, Label::kNear);
5141257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5142257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Check that both operands are symbols.
5143257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ movq(tmp1, FieldOperand(left, HeapObject::kMapOffset));
5144257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ movq(tmp2, FieldOperand(right, HeapObject::kMapOffset));
5145257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ movzxbq(tmp1, FieldOperand(tmp1, Map::kInstanceTypeOffset));
5146257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ movzxbq(tmp2, FieldOperand(tmp2, Map::kInstanceTypeOffset));
5147257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  STATIC_ASSERT(kSymbolTag != 0);
5148257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ and_(tmp1, tmp2);
5149257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ testb(tmp1, Immediate(kIsSymbolMask));
5150257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(zero, &miss, Label::kNear);
5151257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5152257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Symbols are compared by identity.
5153257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label done;
5154257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ cmpq(left, right);
5155257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Make sure rax is non-zero. At this point input operands are
5156257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // guaranteed to be non-zero.
5157257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  ASSERT(right.is(rax));
5158257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(not_equal, &done, Label::kNear);
5159257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  STATIC_ASSERT(EQUAL == 0);
5160257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  STATIC_ASSERT(kSmiTag == 0);
5161257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Move(rax, Smi::FromInt(EQUAL));
5162257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&done);
5163257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ ret(0);
5164257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5165257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&miss);
5166257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  GenerateMiss(masm);
5167257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch}
5168257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5169257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5170257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid ICCompareStub::GenerateStrings(MacroAssembler* masm) {
5171257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  ASSERT(state_ == CompareIC::STRINGS);
5172257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  ASSERT(GetCondition() == equal);
5173257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label miss;
5174257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5175257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Registers containing left and right operands respectively.
5176257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Register left = rdx;
5177257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Register right = rax;
5178257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Register tmp1 = rcx;
5179257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Register tmp2 = rbx;
5180257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Register tmp3 = rdi;
5181257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5182257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Check that both operands are heap objects.
5183257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Condition cond = masm->CheckEitherSmi(left, right, tmp1);
5184257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(cond, &miss);
5185257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5186257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Check that both operands are strings. This leaves the instance
5187257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // types loaded in tmp1 and tmp2.
5188257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ movq(tmp1, FieldOperand(left, HeapObject::kMapOffset));
5189257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ movq(tmp2, FieldOperand(right, HeapObject::kMapOffset));
5190257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ movzxbq(tmp1, FieldOperand(tmp1, Map::kInstanceTypeOffset));
5191257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ movzxbq(tmp2, FieldOperand(tmp2, Map::kInstanceTypeOffset));
5192257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ movq(tmp3, tmp1);
5193257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  STATIC_ASSERT(kNotStringTag != 0);
5194257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ or_(tmp3, tmp2);
5195257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ testb(tmp3, Immediate(kIsNotStringMask));
5196257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(not_zero, &miss);
5197257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5198257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Fast check for identical strings.
5199257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label not_same;
5200257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ cmpq(left, right);
5201257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(not_equal, &not_same, Label::kNear);
5202257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  STATIC_ASSERT(EQUAL == 0);
5203257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  STATIC_ASSERT(kSmiTag == 0);
5204257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Move(rax, Smi::FromInt(EQUAL));
5205257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ ret(0);
5206257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5207257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Handle not identical strings.
5208257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&not_same);
5209257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5210257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Check that both strings are symbols. If they are, we're done
5211257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // because we already know they are not identical.
5212257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label do_compare;
5213257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  STATIC_ASSERT(kSymbolTag != 0);
5214257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ and_(tmp1, tmp2);
5215257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ testb(tmp1, Immediate(kIsSymbolMask));
5216257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(zero, &do_compare, Label::kNear);
5217257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Make sure rax is non-zero. At this point input operands are
5218257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // guaranteed to be non-zero.
5219257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  ASSERT(right.is(rax));
5220257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ ret(0);
5221257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5222257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Check that both strings are sequential ASCII.
5223257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label runtime;
5224257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&do_compare);
5225257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ JumpIfNotBothSequentialAsciiStrings(left, right, tmp1, tmp2, &runtime);
5226257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5227257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Compare flat ASCII strings. Returns when done.
5228257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  StringCompareStub::GenerateFlatAsciiStringEquals(
5229257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      masm, left, right, tmp1, tmp2);
5230257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5231257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Handle more complex cases in runtime.
5232257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&runtime);
5233257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ pop(tmp1);  // Return address.
5234257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ push(left);
5235257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ push(right);
5236257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ push(tmp1);
5237257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ TailCallRuntime(Runtime::kStringEquals, 2, 1);
5238257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5239257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&miss);
5240257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  GenerateMiss(masm);
5241257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch}
5242257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5243257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5244b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdochvoid ICCompareStub::GenerateObjects(MacroAssembler* masm) {
52451e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  ASSERT(state_ == CompareIC::OBJECTS);
5246257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label miss;
52471e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  Condition either_smi = masm->CheckEitherSmi(rdx, rax);
5248257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(either_smi, &miss, Label::kNear);
52491e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
52501e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  __ CmpObjectType(rax, JS_OBJECT_TYPE, rcx);
5251257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(not_equal, &miss, Label::kNear);
52521e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  __ CmpObjectType(rdx, JS_OBJECT_TYPE, rcx);
5253257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(not_equal, &miss, Label::kNear);
52541e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
52551e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  ASSERT(GetCondition() == equal);
52561e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  __ subq(rax, rdx);
52571e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  __ ret(0);
52581e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
52591e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  __ bind(&miss);
52601e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  GenerateMiss(masm);
5261b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch}
5262b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
5263b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
5264b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdochvoid ICCompareStub::GenerateMiss(MacroAssembler* masm) {
52651e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  // Save the registers.
52661e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  __ pop(rcx);
52671e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  __ push(rdx);
52681e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  __ push(rax);
52691e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  __ push(rcx);
52701e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
52711e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  // Call the runtime system in a fresh internal frame.
527244f0eee88ff00398ff7f715fab053374d808c90dSteve Block  ExternalReference miss =
527344f0eee88ff00398ff7f715fab053374d808c90dSteve Block      ExternalReference(IC_Utility(IC::kCompareIC_Miss), masm->isolate());
52741e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  __ EnterInternalFrame();
52751e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  __ push(rdx);
52761e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  __ push(rax);
52771e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  __ Push(Smi::FromInt(op_));
52781e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  __ CallExternalReference(miss, 3);
52791e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  __ LeaveInternalFrame();
52801e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
52811e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  // Compute the entry point of the rewritten stub.
52821e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  __ lea(rdi, FieldOperand(rax, Code::kHeaderSize));
52831e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
52841e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  // Restore registers.
52851e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  __ pop(rcx);
52861e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  __ pop(rax);
52871e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  __ pop(rdx);
52881e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  __ push(rcx);
52891e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
52901e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  // Do a tail call to the rewritten stub.
52911e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  __ jmp(rdi);
52921e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block}
52931e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
52941e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
5295257744e915dfc84d6d07a6b2accf8402d9ffc708Ben MurdochMaybeObject* StringDictionaryLookupStub::GenerateNegativeLookup(
5296257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    MacroAssembler* masm,
5297257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Label* miss,
5298257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Label* done,
5299257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Register properties,
5300257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    String* name,
5301257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Register r0) {
5302257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // If names of slots in range from 1 to kProbes - 1 for the hash value are
5303257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // not equal to the name and kProbes-th slot is not used (its name is the
5304257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // undefined value), it guarantees the hash table doesn't contain the
5305257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // property. It's true even if some slots represent deleted properties
5306257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // (their names are the null value).
5307257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  for (int i = 0; i < kInlinedProbes; i++) {
5308257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // r0 points to properties hash.
5309257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Compute the masked index: (hash + i + i * i) & mask.
5310257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Register index = r0;
5311257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Capacity is smi 2^n.
5312257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ SmiToInteger32(index, FieldOperand(properties, kCapacityOffset));
5313257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ decl(index);
5314257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ and_(index,
5315257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch            Immediate(name->Hash() + StringDictionary::GetProbeOffset(i)));
5316257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5317257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Scale the index by multiplying by the entry size.
5318257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    ASSERT(StringDictionary::kEntrySize == 3);
5319257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ lea(index, Operand(index, index, times_2, 0));  // index *= 3.
5320257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5321257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Register entity_name = r0;
5322257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Having undefined at this place means the name is not contained.
5323257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    ASSERT_EQ(kSmiTagSize, 1);
5324257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ movq(entity_name, Operand(properties,
5325257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                 index,
5326257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                 times_pointer_size,
5327257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                 kElementsStartOffset - kHeapObjectTag));
5328257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ Cmp(entity_name, masm->isolate()->factory()->undefined_value());
5329257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ j(equal, done);
5330257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5331257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Stop if found the property.
5332257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ Cmp(entity_name, Handle<String>(name));
5333257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ j(equal, miss);
5334257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5335257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Check if the entry name is not a symbol.
5336257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ movq(entity_name, FieldOperand(entity_name, HeapObject::kMapOffset));
5337257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ testb(FieldOperand(entity_name, Map::kInstanceTypeOffset),
5338257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch             Immediate(kIsSymbolMask));
5339257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ j(zero, miss);
5340257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
5341257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5342257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  StringDictionaryLookupStub stub(properties,
5343257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                  r0,
5344257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                  r0,
5345257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                  StringDictionaryLookupStub::NEGATIVE_LOOKUP);
5346257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Push(Handle<Object>(name));
5347257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ push(Immediate(name->Hash()));
5348257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  MaybeObject* result = masm->TryCallStub(&stub);
5349257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  if (result->IsFailure()) return result;
5350257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ testq(r0, r0);
5351257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(not_zero, miss);
5352257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ jmp(done);
5353257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  return result;
5354257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch}
5355257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5356257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5357257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// Probe the string dictionary in the |elements| register. Jump to the
5358257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// |done| label if a property with the given name is found leaving the
5359257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// index into the dictionary in |r1|. Jump to the |miss| label
5360257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch// otherwise.
5361257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid StringDictionaryLookupStub::GeneratePositiveLookup(MacroAssembler* masm,
5362257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                                        Label* miss,
5363257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                                        Label* done,
5364257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                                        Register elements,
5365257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                                        Register name,
5366257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                                        Register r0,
5367257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                                        Register r1) {
5368257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Assert that name contains a string.
5369257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  if (FLAG_debug_code) __ AbortIfNotString(name);
5370257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5371257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ SmiToInteger32(r0, FieldOperand(elements, kCapacityOffset));
5372257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ decl(r0);
5373257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5374257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  for (int i = 0; i < kInlinedProbes; i++) {
5375257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Compute the masked index: (hash + i + i * i) & mask.
5376257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ movl(r1, FieldOperand(name, String::kHashFieldOffset));
5377257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ shrl(r1, Immediate(String::kHashShift));
5378257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    if (i > 0) {
5379257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ addl(r1, Immediate(StringDictionary::GetProbeOffset(i)));
5380257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    }
5381257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ and_(r1, r0);
5382257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5383257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Scale the index by multiplying by the entry size.
5384257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    ASSERT(StringDictionary::kEntrySize == 3);
5385257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ lea(r1, Operand(r1, r1, times_2, 0));  // r1 = r1 * 3
5386257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5387257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Check if the key is identical to the name.
5388257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ cmpq(name, Operand(elements, r1, times_pointer_size,
5389257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                          kElementsStartOffset - kHeapObjectTag));
5390257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ j(equal, done);
5391257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
5392257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5393257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  StringDictionaryLookupStub stub(elements,
5394257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                  r0,
5395257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                  r1,
5396257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                  POSITIVE_LOOKUP);
5397257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ push(name);
5398257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ movl(r0, FieldOperand(name, String::kHashFieldOffset));
5399257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ shrl(r0, Immediate(String::kHashShift));
5400257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ push(r0);
5401257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ CallStub(&stub);
5402257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5403257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ testq(r0, r0);
5404257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ j(zero, miss);
5405257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ jmp(done);
5406257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch}
5407257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5408257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5409257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochvoid StringDictionaryLookupStub::Generate(MacroAssembler* masm) {
5410257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Stack frame on entry:
5411257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  //  esp[0 * kPointerSize]: return address.
5412257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  //  esp[1 * kPointerSize]: key's hash.
5413257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  //  esp[2 * kPointerSize]: key.
5414257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Registers:
5415257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  //  dictionary_: StringDictionary to probe.
5416257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  //  result_: used as scratch.
5417257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  //  index_: will hold an index of entry if lookup is successful.
5418257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  //          might alias with result_.
5419257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // Returns:
5420257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  //  result_ is zero if lookup failed, non zero otherwise.
5421257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5422257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Label in_dictionary, maybe_in_dictionary, not_in_dictionary;
5423257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5424257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Register scratch = result_;
5425257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5426257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ SmiToInteger32(scratch, FieldOperand(dictionary_, kCapacityOffset));
5427257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ decl(scratch);
5428257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ push(scratch);
5429257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5430257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // If names of slots in range from 1 to kProbes - 1 for the hash value are
5431257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // not equal to the name and kProbes-th slot is not used (its name is the
5432257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // undefined value), it guarantees the hash table doesn't contain the
5433257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // property. It's true even if some slots represent deleted properties
5434257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // (their names are the null value).
5435257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  for (int i = kInlinedProbes; i < kTotalProbes; i++) {
5436257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Compute the masked index: (hash + i + i * i) & mask.
5437257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ movq(scratch, Operand(rsp, 2 * kPointerSize));
5438257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    if (i > 0) {
5439257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ addl(scratch, Immediate(StringDictionary::GetProbeOffset(i)));
5440257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    }
5441257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ and_(scratch, Operand(rsp, 0));
5442257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5443257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Scale the index by multiplying by the entry size.
5444257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    ASSERT(StringDictionary::kEntrySize == 3);
5445257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ lea(index_, Operand(scratch, scratch, times_2, 0));  // index *= 3.
5446257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5447257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Having undefined at this place means the name is not contained.
5448257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ movq(scratch, Operand(dictionary_,
5449257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                             index_,
5450257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                             times_pointer_size,
5451257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                             kElementsStartOffset - kHeapObjectTag));
5452257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5453257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ Cmp(scratch, masm->isolate()->factory()->undefined_value());
5454257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ j(equal, &not_in_dictionary);
5455257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5456257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    // Stop if found the property.
5457257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ cmpq(scratch, Operand(rsp, 3 * kPointerSize));
5458257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ j(equal, &in_dictionary);
5459257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5460257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    if (i != kTotalProbes - 1 && mode_ == NEGATIVE_LOOKUP) {
5461257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // If we hit a non symbol key during negative lookup
5462257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // we have to bailout as this key might be equal to the
5463257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // key we are looking for.
5464257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5465257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      // Check if the entry name is not a symbol.
5466257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ movq(scratch, FieldOperand(scratch, HeapObject::kMapOffset));
5467257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ testb(FieldOperand(scratch, Map::kInstanceTypeOffset),
5468257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch               Immediate(kIsSymbolMask));
5469257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ j(zero, &maybe_in_dictionary);
5470257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    }
5471257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
5472257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5473257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&maybe_in_dictionary);
5474257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // If we are doing negative lookup then probing failure should be
5475257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // treated as a lookup success. For positive lookup probing failure
5476257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  // should be treated as lookup failure.
5477257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  if (mode_ == POSITIVE_LOOKUP) {
5478257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ movq(scratch, Immediate(0));
5479257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ Drop(1);
5480257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ ret(2 * kPointerSize);
5481257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
5482257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5483257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&in_dictionary);
5484257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ movq(scratch, Immediate(1));
5485257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Drop(1);
5486257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ ret(2 * kPointerSize);
5487257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5488257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ bind(&not_in_dictionary);
5489257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ movq(scratch, Immediate(0));
5490257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Drop(1);
5491257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ ret(2 * kPointerSize);
5492257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch}
5493257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
5494257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
549580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#undef __
549680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
549780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} }  // namespace v8::internal
549880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
549980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#endif  // V8_TARGET_ARCH_X64
5500