code-stubs-x64.cc revision f87a203d89e1bbb6708282e0b64dbd13d59b723d
180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// Copyright 2010 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)
4080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid FastNewClosureStub::Generate(MacroAssembler* masm) {
4180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Create a new closure from the given function info in new
4280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // space. Set the context to the current context in rsi.
4380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label gc;
4480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ AllocateInNewSpace(JSFunction::kSize, rax, rbx, rcx, &gc, TAG_OBJECT);
4580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
4680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Get the function info from the stack.
4780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rdx, Operand(rsp, 1 * kPointerSize));
4880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
4980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Compute the function map in the current global context and set that
5080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // as the map of the allocated object.
5180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rcx, Operand(rsi, Context::SlotOffset(Context::GLOBAL_INDEX)));
5280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rcx, FieldOperand(rcx, GlobalObject::kGlobalContextOffset));
5380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rcx, Operand(rcx, Context::SlotOffset(Context::FUNCTION_MAP_INDEX)));
5480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(FieldOperand(rax, JSObject::kMapOffset), rcx);
5580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
5680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Initialize the rest of the function. We don't have to update the
5780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // write barrier because the allocated object is in new space.
5880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ LoadRoot(rbx, Heap::kEmptyFixedArrayRootIndex);
5980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ LoadRoot(rcx, Heap::kTheHoleValueRootIndex);
6080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(FieldOperand(rax, JSObject::kPropertiesOffset), rbx);
6180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(FieldOperand(rax, JSObject::kElementsOffset), rbx);
6280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(FieldOperand(rax, JSFunction::kPrototypeOrInitialMapOffset), rcx);
6380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(FieldOperand(rax, JSFunction::kSharedFunctionInfoOffset), rdx);
6480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(FieldOperand(rax, JSFunction::kContextOffset), rsi);
6580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(FieldOperand(rax, JSFunction::kLiteralsOffset), rbx);
6680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
6780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Initialize the code pointer in the function to be the one
6880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // found in the shared function info object.
6980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rdx, FieldOperand(rdx, SharedFunctionInfo::kCodeOffset));
7080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ lea(rdx, FieldOperand(rdx, Code::kHeaderSize));
7180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(FieldOperand(rax, JSFunction::kCodeEntryOffset), rdx);
7280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
7380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
7480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Return and remove the on-stack parameter.
7580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ ret(1 * kPointerSize);
7680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
7780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Create a new closure through the slower runtime call.
7880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&gc);
7980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ pop(rcx);  // Temporarily remove return address.
8080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ pop(rdx);
8180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ push(rsi);
8280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ push(rdx);
8380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ push(rcx);  // Restore return address.
8480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ TailCallRuntime(Runtime::kNewClosure, 2, 1);
8580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
8680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
8780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
8880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid FastNewContextStub::Generate(MacroAssembler* masm) {
8980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Try to allocate the context in new space.
9080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label gc;
9180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  int length = slots_ + Context::MIN_CONTEXT_SLOTS;
9280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ AllocateInNewSpace((length * kPointerSize) + FixedArray::kHeaderSize,
9380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                        rax, rbx, rcx, &gc, TAG_OBJECT);
9480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
9580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Get the function from the stack.
9680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rcx, Operand(rsp, 1 * kPointerSize));
9780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
9880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Setup the object header.
9980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ LoadRoot(kScratchRegister, Heap::kContextMapRootIndex);
10080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(FieldOperand(rax, HeapObject::kMapOffset), kScratchRegister);
10180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ Move(FieldOperand(rax, FixedArray::kLengthOffset), Smi::FromInt(length));
10280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
10380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Setup the fixed slots.
10480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ xor_(rbx, rbx);  // Set to NULL.
10580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(Operand(rax, Context::SlotOffset(Context::CLOSURE_INDEX)), rcx);
10680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(Operand(rax, Context::SlotOffset(Context::FCONTEXT_INDEX)), rax);
10780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(Operand(rax, Context::SlotOffset(Context::PREVIOUS_INDEX)), rbx);
10880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(Operand(rax, Context::SlotOffset(Context::EXTENSION_INDEX)), rbx);
10980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
11080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Copy the global object from the surrounding context.
11180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rbx, Operand(rsi, Context::SlotOffset(Context::GLOBAL_INDEX)));
11280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(Operand(rax, Context::SlotOffset(Context::GLOBAL_INDEX)), rbx);
11380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
11480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Initialize the rest of the slots to undefined.
11580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ LoadRoot(rbx, Heap::kUndefinedValueRootIndex);
11680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  for (int i = Context::MIN_CONTEXT_SLOTS; i < length; i++) {
11780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ movq(Operand(rax, Context::SlotOffset(i)), rbx);
11880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
11980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
12080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Return and remove the on-stack parameter.
12180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rsi, rax);
12280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ ret(1 * kPointerSize);
12380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
12480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Need to collect. Call into runtime system.
12580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&gc);
12680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ TailCallRuntime(Runtime::kNewContext, 1, 1);
12780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
12880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
12980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
13080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid FastCloneShallowArrayStub::Generate(MacroAssembler* masm) {
13180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Stack layout on entry:
13280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  //
13380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // [rsp + kPointerSize]: constant elements.
13480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // [rsp + (2 * kPointerSize)]: literal index.
13580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // [rsp + (3 * kPointerSize)]: literals array.
13680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
13780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // All sizes here are multiples of kPointerSize.
13880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  int elements_size = (length_ > 0) ? FixedArray::SizeFor(length_) : 0;
13980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  int size = JSArray::kSize + elements_size;
14080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
14180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Load boilerplate object into rcx and check if we need to create a
14280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // boilerplate.
14380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label slow_case;
14480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rcx, Operand(rsp, 3 * kPointerSize));
14580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rax, Operand(rsp, 2 * kPointerSize));
14680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  SmiIndex index = masm->SmiToIndex(rax, rax, kPointerSizeLog2);
14780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rcx,
14880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen          FieldOperand(rcx, index.reg, index.scale, FixedArray::kHeaderSize));
14980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ CompareRoot(rcx, Heap::kUndefinedValueRootIndex);
15080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(equal, &slow_case);
15180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
15280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  if (FLAG_debug_code) {
15380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    const char* message;
15480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    Heap::RootListIndex expected_map_index;
15580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    if (mode_ == CLONE_ELEMENTS) {
15680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      message = "Expected (writable) fixed array";
15780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      expected_map_index = Heap::kFixedArrayMapRootIndex;
15880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    } else {
15980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      ASSERT(mode_ == COPY_ON_WRITE_ELEMENTS);
16080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      message = "Expected copy-on-write fixed array";
16180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      expected_map_index = Heap::kFixedCOWArrayMapRootIndex;
16280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    }
16380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ push(rcx);
16480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ movq(rcx, FieldOperand(rcx, JSArray::kElementsOffset));
16580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ CompareRoot(FieldOperand(rcx, HeapObject::kMapOffset),
16680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                   expected_map_index);
16780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ Assert(equal, message);
16880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ pop(rcx);
16980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
17080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
17180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Allocate both the JS array and the elements array in one big
17280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // allocation. This avoids multiple limit checks.
17380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ AllocateInNewSpace(size, rax, rbx, rdx, &slow_case, TAG_OBJECT);
17480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
17580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Copy the JS array part.
17680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  for (int i = 0; i < JSArray::kSize; i += kPointerSize) {
17780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    if ((i != JSArray::kElementsOffset) || (length_ == 0)) {
17880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ movq(rbx, FieldOperand(rcx, i));
17980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ movq(FieldOperand(rax, i), rbx);
18080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    }
18180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
18280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
18380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  if (length_ > 0) {
18480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // Get hold of the elements array of the boilerplate and setup the
18580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // elements pointer in the resulting object.
18680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ movq(rcx, FieldOperand(rcx, JSArray::kElementsOffset));
18780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ lea(rdx, Operand(rax, JSArray::kSize));
18880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ movq(FieldOperand(rax, JSArray::kElementsOffset), rdx);
18980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
19080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // Copy the elements array.
19180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    for (int i = 0; i < elements_size; i += kPointerSize) {
19280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ movq(rbx, FieldOperand(rcx, i));
19380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ movq(FieldOperand(rdx, i), rbx);
19480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    }
19580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
19680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
19780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Return and remove the on-stack parameters.
19880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ ret(3 * kPointerSize);
19980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
20080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&slow_case);
20180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ TailCallRuntime(Runtime::kCreateArrayLiteralShallow, 3, 1);
20280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
20380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
20480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
20580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid ToBooleanStub::Generate(MacroAssembler* masm) {
2060d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  NearLabel false_result, true_result, not_string;
20780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rax, Operand(rsp, 1 * kPointerSize));
20880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
20980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // 'null' => false.
21080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ CompareRoot(rax, Heap::kNullValueRootIndex);
21180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(equal, &false_result);
21280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
21380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Get the map and type of the heap object.
21480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // We don't use CmpObjectType because we manipulate the type field.
21580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rdx, FieldOperand(rax, HeapObject::kMapOffset));
21680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movzxbq(rcx, FieldOperand(rdx, Map::kInstanceTypeOffset));
21780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
21880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Undetectable => false.
21980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movzxbq(rbx, FieldOperand(rdx, Map::kBitFieldOffset));
22080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ and_(rbx, Immediate(1 << Map::kIsUndetectable));
22180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(not_zero, &false_result);
22280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
22380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // JavaScript object => true.
22480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cmpq(rcx, Immediate(FIRST_JS_OBJECT_TYPE));
22580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(above_equal, &true_result);
22680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
22780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // String value => false iff empty.
22880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cmpq(rcx, Immediate(FIRST_NONSTRING_TYPE));
22980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(above_equal, &not_string);
23080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rdx, FieldOperand(rax, String::kLengthOffset));
23180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiTest(rdx);
23280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(zero, &false_result);
23380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ jmp(&true_result);
23480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
23580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&not_string);
23680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ CompareRoot(rdx, Heap::kHeapNumberMapRootIndex);
23780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(not_equal, &true_result);
23880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // HeapNumber => false iff +0, -0, or NaN.
23980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // These three cases set the zero flag when compared to zero using ucomisd.
24080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ xorpd(xmm0, xmm0);
24180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ ucomisd(xmm0, FieldOperand(rax, HeapNumber::kValueOffset));
24280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(zero, &false_result);
24380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Fall through to |true_result|.
24480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
24580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Return 1/0 for true/false in rax.
24680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&true_result);
24780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rax, Immediate(1));
24880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ ret(1 * kPointerSize);
24980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&false_result);
25080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ xor_(rax, rax);
25180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ ret(1 * kPointerSize);
25280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
25380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
25480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
25580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenconst char* GenericBinaryOpStub::GetName() {
25680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  if (name_ != NULL) return name_;
25780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  const int kMaxNameLength = 100;
25880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  name_ = Bootstrapper::AllocateAutoDeletedArray(kMaxNameLength);
25980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  if (name_ == NULL) return "OOM";
26080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  const char* op_name = Token::Name(op_);
26180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  const char* overwrite_name;
26280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  switch (mode_) {
26380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    case NO_OVERWRITE: overwrite_name = "Alloc"; break;
26480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    case OVERWRITE_RIGHT: overwrite_name = "OverwriteRight"; break;
26580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    case OVERWRITE_LEFT: overwrite_name = "OverwriteLeft"; break;
26680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    default: overwrite_name = "UnknownOverwrite"; break;
26780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
26880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
26980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  OS::SNPrintF(Vector<char>(name_, kMaxNameLength),
27080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen               "GenericBinaryOpStub_%s_%s%s_%s%s_%s_%s",
27180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen               op_name,
27280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen               overwrite_name,
27380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen               (flags_ & NO_SMI_CODE_IN_STUB) ? "_NoSmiInStub" : "",
27480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen               args_in_registers_ ? "RegArgs" : "StackArgs",
27580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen               args_reversed_ ? "_R" : "",
27680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen               static_operands_type_.ToString(),
27780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen               BinaryOpIC::GetName(runtime_operands_type_));
27880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  return name_;
27980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
28080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
28180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
28280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid GenericBinaryOpStub::GenerateCall(
28380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    MacroAssembler* masm,
28480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    Register left,
28580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    Register right) {
28680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  if (!ArgsInRegistersSupported()) {
28780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // Pass arguments on the stack.
28880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ push(left);
28980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ push(right);
29080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  } else {
29180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // The calling convention with registers is left in rdx and right in rax.
29280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    Register left_arg = rdx;
29380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    Register right_arg = rax;
29480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    if (!(left.is(left_arg) && right.is(right_arg))) {
29580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      if (left.is(right_arg) && right.is(left_arg)) {
29680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen        if (IsOperationCommutative()) {
29780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen          SetArgsReversed();
29880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen        } else {
29980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen          __ xchg(left, right);
30080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen        }
30180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      } else if (left.is(left_arg)) {
30280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen        __ movq(right_arg, right);
30380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      } else if (right.is(right_arg)) {
30480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen        __ movq(left_arg, left);
30580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      } else if (left.is(right_arg)) {
30680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen        if (IsOperationCommutative()) {
30780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen          __ movq(left_arg, right);
30880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen          SetArgsReversed();
30980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen        } else {
31080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen          // Order of moves important to avoid destroying left argument.
31180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen          __ movq(left_arg, left);
31280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen          __ movq(right_arg, right);
31380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen        }
31480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      } else if (right.is(left_arg)) {
31580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen        if (IsOperationCommutative()) {
31680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen          __ movq(right_arg, left);
31780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen          SetArgsReversed();
31880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen        } else {
31980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen          // Order of moves important to avoid destroying right argument.
32080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen          __ movq(right_arg, right);
32180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen          __ movq(left_arg, left);
32280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen        }
32380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      } else {
32480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen        // Order of moves is not important.
32580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen        __ movq(left_arg, left);
32680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen        __ movq(right_arg, right);
32780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      }
32880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    }
32980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
33080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // Update flags to indicate that arguments are in registers.
33180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    SetArgsInRegisters();
33280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ IncrementCounter(&Counters::generic_binary_stub_calls_regs, 1);
33380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
33480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
33580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Call the stub.
33680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ CallStub(this);
33780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
33880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
33980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
34080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid GenericBinaryOpStub::GenerateCall(
34180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    MacroAssembler* masm,
34280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    Register left,
34380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    Smi* right) {
34480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  if (!ArgsInRegistersSupported()) {
34580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // Pass arguments on the stack.
34680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ push(left);
34780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ Push(right);
34880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  } else {
34980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // The calling convention with registers is left in rdx and right in rax.
35080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    Register left_arg = rdx;
35180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    Register right_arg = rax;
35280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    if (left.is(left_arg)) {
35380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ Move(right_arg, right);
35480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    } else if (left.is(right_arg) && IsOperationCommutative()) {
35580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ Move(left_arg, right);
35680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      SetArgsReversed();
35780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    } else {
35880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      // For non-commutative operations, left and right_arg might be
35980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      // the same register.  Therefore, the order of the moves is
36080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      // important here in order to not overwrite left before moving
36180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      // it to left_arg.
36280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ movq(left_arg, left);
36380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ Move(right_arg, right);
36480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    }
36580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
36680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // Update flags to indicate that arguments are in registers.
36780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    SetArgsInRegisters();
36880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ IncrementCounter(&Counters::generic_binary_stub_calls_regs, 1);
36980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
37080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
37180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Call the stub.
37280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ CallStub(this);
37380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
37480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
37580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
37680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid GenericBinaryOpStub::GenerateCall(
37780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    MacroAssembler* masm,
37880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    Smi* left,
37980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    Register right) {
38080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  if (!ArgsInRegistersSupported()) {
38180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // Pass arguments on the stack.
38280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ Push(left);
38380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ push(right);
38480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  } else {
38580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // The calling convention with registers is left in rdx and right in rax.
38680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    Register left_arg = rdx;
38780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    Register right_arg = rax;
38880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    if (right.is(right_arg)) {
38980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ Move(left_arg, left);
39080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    } else if (right.is(left_arg) && IsOperationCommutative()) {
39180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ Move(right_arg, left);
39280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      SetArgsReversed();
39380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    } else {
39480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      // For non-commutative operations, right and left_arg might be
39580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      // the same register.  Therefore, the order of the moves is
39680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      // important here in order to not overwrite right before moving
39780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      // it to right_arg.
39880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ movq(right_arg, right);
39980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ Move(left_arg, left);
40080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    }
40180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // Update flags to indicate that arguments are in registers.
40280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    SetArgsInRegisters();
40380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ IncrementCounter(&Counters::generic_binary_stub_calls_regs, 1);
40480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
40580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
40680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Call the stub.
40780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ CallStub(this);
40880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
40980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
41080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
41180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenclass FloatingPointHelper : public AllStatic {
41280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen public:
41380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Load the operands from rdx and rax into xmm0 and xmm1, as doubles.
41480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // If the operands are not both numbers, jump to not_numbers.
41580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Leaves rdx and rax unchanged.  SmiOperands assumes both are smis.
41680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // NumberOperands assumes both are smis or heap numbers.
41780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  static void LoadSSE2SmiOperands(MacroAssembler* masm);
41880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  static void LoadSSE2NumberOperands(MacroAssembler* masm);
41980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  static void LoadSSE2UnknownOperands(MacroAssembler* masm,
42080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                      Label* not_numbers);
42180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
42280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Takes the operands in rdx and rax and loads them as integers in rax
42380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // and rcx.
42480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  static void LoadAsIntegers(MacroAssembler* masm,
42580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                             Label* operand_conversion_failure,
42680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                             Register heap_number_map);
42780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // As above, but we know the operands to be numbers. In that case,
42880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // conversion can't fail.
42980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  static void LoadNumbersAsIntegers(MacroAssembler* masm);
43080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen};
43180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
43280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
43380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid GenericBinaryOpStub::GenerateSmiCode(MacroAssembler* masm, Label* slow) {
43480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // 1. Move arguments into rdx, rax except for DIV and MOD, which need the
43580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // dividend in rax and rdx free for the division.  Use rax, rbx for those.
43680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Comment load_comment(masm, "-- Load arguments");
43780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Register left = rdx;
43880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Register right = rax;
43980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  if (op_ == Token::DIV || op_ == Token::MOD) {
44080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    left = rax;
44180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    right = rbx;
44280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    if (HasArgsInRegisters()) {
44380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ movq(rbx, rax);
44480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ movq(rax, rdx);
44580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    }
44680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
44780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  if (!HasArgsInRegisters()) {
44880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ movq(right, Operand(rsp, 1 * kPointerSize));
44980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ movq(left, Operand(rsp, 2 * kPointerSize));
45080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
45180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
45280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label not_smis;
45380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // 2. Smi check both operands.
45480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  if (static_operands_type_.IsSmi()) {
45580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // Skip smi check if we know that both arguments are smis.
45680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    if (FLAG_debug_code) {
45780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ AbortIfNotSmi(left);
45880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ AbortIfNotSmi(right);
45980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    }
46080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    if (op_ == Token::BIT_OR) {
46180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      // Handle OR here, since we do extra smi-checking in the or code below.
46280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ SmiOr(right, right, left);
46380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      GenerateReturn(masm);
46480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      return;
46580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    }
46680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  } else {
46780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    if (op_ != Token::BIT_OR) {
46880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      // Skip the check for OR as it is better combined with the
46980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      // actual operation.
47080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      Comment smi_check_comment(masm, "-- Smi check arguments");
47180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ JumpIfNotBothSmi(left, right, &not_smis);
47280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    }
47380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
47480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
47580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // 3. Operands are both smis (except for OR), perform the operation leaving
47680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // the result in rax and check the result if necessary.
47780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Comment perform_smi(masm, "-- Perform smi operation");
47880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label use_fp_on_smis;
47980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  switch (op_) {
48080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    case Token::ADD: {
48180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      ASSERT(right.is(rax));
48280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ SmiAdd(right, right, left, &use_fp_on_smis);  // ADD is commutative.
48380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      break;
48480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    }
48580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
48680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    case Token::SUB: {
48780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ SmiSub(left, left, right, &use_fp_on_smis);
48880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ movq(rax, left);
48980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      break;
49080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    }
49180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
49280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    case Token::MUL:
49380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      ASSERT(right.is(rax));
49480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ SmiMul(right, right, left, &use_fp_on_smis);  // MUL is commutative.
49580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      break;
49680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
49780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    case Token::DIV:
49880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      ASSERT(left.is(rax));
49980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ SmiDiv(left, left, right, &use_fp_on_smis);
50080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      break;
50180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
50280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    case Token::MOD:
50380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      ASSERT(left.is(rax));
50480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ SmiMod(left, left, right, slow);
50580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      break;
50680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
50780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    case Token::BIT_OR:
50880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      ASSERT(right.is(rax));
50980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ movq(rcx, right);  // Save the right operand.
51080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ SmiOr(right, right, left);  // BIT_OR is commutative.
51180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ testb(right, Immediate(kSmiTagMask));
51280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ j(not_zero, &not_smis);
51380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      break;
51480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
51580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    case Token::BIT_AND:
51680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      ASSERT(right.is(rax));
51780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ SmiAnd(right, right, left);  // BIT_AND is commutative.
51880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      break;
51980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
52080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    case Token::BIT_XOR:
52180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      ASSERT(right.is(rax));
52280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ SmiXor(right, right, left);  // BIT_XOR is commutative.
52380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      break;
52480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
52580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    case Token::SHL:
52680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    case Token::SHR:
52780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    case Token::SAR:
52880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      switch (op_) {
52980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen        case Token::SAR:
53080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen          __ SmiShiftArithmeticRight(left, left, right);
53180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen          break;
53280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen        case Token::SHR:
53380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen          __ SmiShiftLogicalRight(left, left, right, slow);
53480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen          break;
53580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen        case Token::SHL:
53680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen          __ SmiShiftLeft(left, left, right);
53780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen          break;
53880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen        default:
53980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen          UNREACHABLE();
54080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      }
54180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ movq(rax, left);
54280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      break;
54380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
54480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    default:
54580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      UNREACHABLE();
54680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      break;
54780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
54880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
54980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // 4. Emit return of result in rax.
55080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  GenerateReturn(masm);
55180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
55280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // 5. For some operations emit inline code to perform floating point
55380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // operations on known smis (e.g., if the result of the operation
55480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // overflowed the smi range).
55580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  switch (op_) {
55680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    case Token::ADD:
55780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    case Token::SUB:
55880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    case Token::MUL:
55980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    case Token::DIV: {
56080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      ASSERT(use_fp_on_smis.is_linked());
56180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ bind(&use_fp_on_smis);
56280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      if (op_ == Token::DIV) {
56380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen        __ movq(rdx, rax);
56480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen        __ movq(rax, rbx);
56580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      }
56680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      // left is rdx, right is rax.
56780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ AllocateHeapNumber(rbx, rcx, slow);
56880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      FloatingPointHelper::LoadSSE2SmiOperands(masm);
56980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      switch (op_) {
57080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen        case Token::ADD: __ addsd(xmm0, xmm1); break;
57180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen        case Token::SUB: __ subsd(xmm0, xmm1); break;
57280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen        case Token::MUL: __ mulsd(xmm0, xmm1); break;
57380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen        case Token::DIV: __ divsd(xmm0, xmm1); break;
57480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen        default: UNREACHABLE();
57580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      }
57680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ movsd(FieldOperand(rbx, HeapNumber::kValueOffset), xmm0);
57780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ movq(rax, rbx);
57880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      GenerateReturn(masm);
57980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    }
58080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    default:
58180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      break;
58280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
58380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
58480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // 6. Non-smi operands, fall out to the non-smi code with the operands in
58580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rdx and rax.
58680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Comment done_comment(masm, "-- Enter non-smi code");
58780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&not_smis);
58880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
58980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  switch (op_) {
59080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    case Token::DIV:
59180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    case Token::MOD:
59280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      // Operands are in rax, rbx at this point.
59380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ movq(rdx, rax);
59480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ movq(rax, rbx);
59580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      break;
59680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
59780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    case Token::BIT_OR:
59880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      // Right operand is saved in rcx and rax was destroyed by the smi
59980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      // operation.
60080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ movq(rax, rcx);
60180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      break;
60280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
60380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    default:
60480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      break;
60580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
60680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
60780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
60880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
60980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid GenericBinaryOpStub::Generate(MacroAssembler* masm) {
61080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label call_runtime;
61180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
61280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  if (ShouldGenerateSmiCode()) {
61380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    GenerateSmiCode(masm, &call_runtime);
61480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  } else if (op_ != Token::MOD) {
61580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    if (!HasArgsInRegisters()) {
61680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      GenerateLoadArguments(masm);
61780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    }
61880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
61980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Floating point case.
62080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  if (ShouldGenerateFPCode()) {
62180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    switch (op_) {
62280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      case Token::ADD:
62380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      case Token::SUB:
62480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      case Token::MUL:
62580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      case Token::DIV: {
62680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen        if (runtime_operands_type_ == BinaryOpIC::DEFAULT &&
62780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen            HasSmiCodeInStub()) {
62880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen          // Execution reaches this point when the first non-smi argument occurs
62980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen          // (and only if smi code is generated). This is the right moment to
63080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen          // patch to HEAP_NUMBERS state. The transition is attempted only for
63180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen          // the four basic operations. The stub stays in the DEFAULT state
63280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen          // forever for all other operations (also if smi code is skipped).
63380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen          GenerateTypeTransition(masm);
63480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen          break;
63580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen        }
63680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
63780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen        Label not_floats;
63880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen        // rax: y
63980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen        // rdx: x
64080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen        if (static_operands_type_.IsNumber()) {
64180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen          if (FLAG_debug_code) {
64280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen            // Assert at runtime that inputs are only numbers.
64380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen            __ AbortIfNotNumber(rdx);
64480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen            __ AbortIfNotNumber(rax);
64580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen          }
64680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen          FloatingPointHelper::LoadSSE2NumberOperands(masm);
64780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen        } else {
64880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen          FloatingPointHelper::LoadSSE2UnknownOperands(masm, &call_runtime);
64980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen        }
65080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
65180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen        switch (op_) {
65280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen          case Token::ADD: __ addsd(xmm0, xmm1); break;
65380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen          case Token::SUB: __ subsd(xmm0, xmm1); break;
65480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen          case Token::MUL: __ mulsd(xmm0, xmm1); break;
65580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen          case Token::DIV: __ divsd(xmm0, xmm1); break;
65680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen          default: UNREACHABLE();
65780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen        }
65880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen        // Allocate a heap number, if needed.
65980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen        Label skip_allocation;
66080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen        OverwriteMode mode = mode_;
66180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen        if (HasArgsReversed()) {
66280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen          if (mode == OVERWRITE_RIGHT) {
66380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen            mode = OVERWRITE_LEFT;
66480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen          } else if (mode == OVERWRITE_LEFT) {
66580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen            mode = OVERWRITE_RIGHT;
66680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen          }
66780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen        }
66880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen        switch (mode) {
66980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen          case OVERWRITE_LEFT:
67080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen            __ JumpIfNotSmi(rdx, &skip_allocation);
67180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen            __ AllocateHeapNumber(rbx, rcx, &call_runtime);
67280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen            __ movq(rdx, rbx);
67380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen            __ bind(&skip_allocation);
67480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen            __ movq(rax, rdx);
67580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen            break;
67680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen          case OVERWRITE_RIGHT:
67780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen            // If the argument in rax is already an object, we skip the
67880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen            // allocation of a heap number.
67980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen            __ JumpIfNotSmi(rax, &skip_allocation);
68080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen            // Fall through!
68180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen          case NO_OVERWRITE:
68280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen            // Allocate a heap number for the result. Keep rax and rdx intact
68380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen            // for the possible runtime call.
68480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen            __ AllocateHeapNumber(rbx, rcx, &call_runtime);
68580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen            __ movq(rax, rbx);
68680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen            __ bind(&skip_allocation);
68780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen            break;
68880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen          default: UNREACHABLE();
68980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen        }
69080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen        __ movsd(FieldOperand(rax, HeapNumber::kValueOffset), xmm0);
69180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen        GenerateReturn(masm);
69280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen        __ bind(&not_floats);
69380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen        if (runtime_operands_type_ == BinaryOpIC::DEFAULT &&
69480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen            !HasSmiCodeInStub()) {
69580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen            // Execution reaches this point when the first non-number argument
69680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen            // occurs (and only if smi code is skipped from the stub, otherwise
69780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen            // the patching has already been done earlier in this case branch).
69880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen            // A perfect moment to try patching to STRINGS for ADD operation.
69980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen            if (op_ == Token::ADD) {
70080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen              GenerateTypeTransition(masm);
70180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen            }
70280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen        }
70380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen        break;
70480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      }
70580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      case Token::MOD: {
70680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen        // For MOD we go directly to runtime in the non-smi case.
70780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen        break;
70880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      }
70980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      case Token::BIT_OR:
71080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      case Token::BIT_AND:
71180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      case Token::BIT_XOR:
71280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      case Token::SAR:
71380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      case Token::SHL:
71480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      case Token::SHR: {
71580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen        Label skip_allocation, non_smi_shr_result;
71680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen        Register heap_number_map = r9;
71780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen        __ LoadRoot(heap_number_map, Heap::kHeapNumberMapRootIndex);
71880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen        if (static_operands_type_.IsNumber()) {
71980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen          if (FLAG_debug_code) {
72080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen            // Assert at runtime that inputs are only numbers.
72180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen            __ AbortIfNotNumber(rdx);
72280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen            __ AbortIfNotNumber(rax);
72380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen          }
72480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen          FloatingPointHelper::LoadNumbersAsIntegers(masm);
72580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen        } else {
72680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen          FloatingPointHelper::LoadAsIntegers(masm,
72780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                              &call_runtime,
72880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                              heap_number_map);
72980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen        }
73080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen        switch (op_) {
73180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen          case Token::BIT_OR:  __ orl(rax, rcx); break;
73280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen          case Token::BIT_AND: __ andl(rax, rcx); break;
73380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen          case Token::BIT_XOR: __ xorl(rax, rcx); break;
73480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen          case Token::SAR: __ sarl_cl(rax); break;
73580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen          case Token::SHL: __ shll_cl(rax); break;
73680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen          case Token::SHR: {
73780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen            __ shrl_cl(rax);
73880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen            // Check if result is negative. This can only happen for a shift
73980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen            // by zero.
74080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen            __ testl(rax, rax);
74180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen            __ j(negative, &non_smi_shr_result);
74280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen            break;
74380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen          }
74480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen          default: UNREACHABLE();
74580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen        }
74680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
74780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen        STATIC_ASSERT(kSmiValueSize == 32);
74880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen        // Tag smi result and return.
74980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen        __ Integer32ToSmi(rax, rax);
75080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen        GenerateReturn(masm);
75180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
75280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen        // All bit-ops except SHR return a signed int32 that can be
75380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen        // returned immediately as a smi.
75480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen        // We might need to allocate a HeapNumber if we shift a negative
75580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen        // number right by zero (i.e., convert to UInt32).
75680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen        if (op_ == Token::SHR) {
75780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen          ASSERT(non_smi_shr_result.is_linked());
75880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen          __ bind(&non_smi_shr_result);
75980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen          // Allocate a heap number if needed.
76080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen          __ movl(rbx, rax);  // rbx holds result value (uint32 value as int64).
76180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen          switch (mode_) {
76280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen            case OVERWRITE_LEFT:
76380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen            case OVERWRITE_RIGHT:
76480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen              // If the operand was an object, we skip the
76580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen              // allocation of a heap number.
76680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen              __ movq(rax, Operand(rsp, mode_ == OVERWRITE_RIGHT ?
76780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                   1 * kPointerSize : 2 * kPointerSize));
76880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen              __ JumpIfNotSmi(rax, &skip_allocation);
76980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen              // Fall through!
77080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen            case NO_OVERWRITE:
77180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen              // Allocate heap number in new space.
77280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen              // Not using AllocateHeapNumber macro in order to reuse
77380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen              // already loaded heap_number_map.
77480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen              __ AllocateInNewSpace(HeapNumber::kSize,
77580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                    rax,
77680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                    rcx,
77780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                    no_reg,
77880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                    &call_runtime,
77980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                    TAG_OBJECT);
78080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen              // Set the map.
78180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen              if (FLAG_debug_code) {
78280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                __ AbortIfNotRootValue(heap_number_map,
78380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                       Heap::kHeapNumberMapRootIndex,
78480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                       "HeapNumberMap register clobbered.");
78580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen              }
78680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen              __ movq(FieldOperand(rax, HeapObject::kMapOffset),
78780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                      heap_number_map);
78880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen              __ bind(&skip_allocation);
78980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen              break;
79080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen            default: UNREACHABLE();
79180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen          }
79280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen          // Store the result in the HeapNumber and return.
79380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen          __ cvtqsi2sd(xmm0, rbx);
79480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen          __ movsd(FieldOperand(rax, HeapNumber::kValueOffset), xmm0);
79580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen          GenerateReturn(masm);
79680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen        }
79780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
79880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen        break;
79980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      }
80080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      default: UNREACHABLE(); break;
80180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    }
80280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
80380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
80480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // If all else fails, use the runtime system to get the correct
80580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // result. If arguments was passed in registers now place them on the
80680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // stack in the correct order below the return address.
80780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&call_runtime);
80880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
80980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  if (HasArgsInRegisters()) {
81080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    GenerateRegisterArgsPush(masm);
81180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
81280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
81380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  switch (op_) {
81480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    case Token::ADD: {
81580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      // Registers containing left and right operands respectively.
81680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      Register lhs, rhs;
81780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
81880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      if (HasArgsReversed()) {
81980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen        lhs = rax;
82080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen        rhs = rdx;
82180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      } else {
82280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen        lhs = rdx;
82380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen        rhs = rax;
82480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      }
82580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
82680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      // Test for string arguments before calling runtime.
82780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      Label not_strings, both_strings, not_string1, string1, string1_smi2;
82880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
82980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      // If this stub has already generated FP-specific code then the arguments
83080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      // are already in rdx and rax.
83180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      if (!ShouldGenerateFPCode() && !HasArgsInRegisters()) {
83280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen        GenerateLoadArguments(masm);
83380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      }
83480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
83580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      Condition is_smi;
83680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      is_smi = masm->CheckSmi(lhs);
83780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ j(is_smi, &not_string1);
83880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ CmpObjectType(lhs, FIRST_NONSTRING_TYPE, r8);
83980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ j(above_equal, &not_string1);
84080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
84180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      // First argument is a a string, test second.
84280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      is_smi = masm->CheckSmi(rhs);
84380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ j(is_smi, &string1_smi2);
84480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ CmpObjectType(rhs, FIRST_NONSTRING_TYPE, r9);
84580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ j(above_equal, &string1);
84680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
84780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      // First and second argument are strings.
84880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      StringAddStub string_add_stub(NO_STRING_CHECK_IN_STUB);
84980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ TailCallStub(&string_add_stub);
85080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
85180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ bind(&string1_smi2);
85280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      // First argument is a string, second is a smi. Try to lookup the number
85380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      // string for the smi in the number string cache.
85480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      NumberToStringStub::GenerateLookupNumberStringCache(
85580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen          masm, rhs, rbx, rcx, r8, true, &string1);
85680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
85780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      // Replace second argument on stack and tailcall string add stub to make
85880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      // the result.
85980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ movq(Operand(rsp, 1 * kPointerSize), rbx);
86080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ TailCallStub(&string_add_stub);
86180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
86280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      // Only first argument is a string.
86380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ bind(&string1);
86480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ InvokeBuiltin(Builtins::STRING_ADD_LEFT, JUMP_FUNCTION);
86580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
86680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      // First argument was not a string, test second.
86780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ bind(&not_string1);
86880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      is_smi = masm->CheckSmi(rhs);
86980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ j(is_smi, &not_strings);
87080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ CmpObjectType(rhs, FIRST_NONSTRING_TYPE, rhs);
87180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ j(above_equal, &not_strings);
87280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
87380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      // Only second argument is a string.
87480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ InvokeBuiltin(Builtins::STRING_ADD_RIGHT, JUMP_FUNCTION);
87580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
87680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ bind(&not_strings);
87780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      // Neither argument is a string.
87880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ InvokeBuiltin(Builtins::ADD, JUMP_FUNCTION);
87980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      break;
88080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    }
88180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    case Token::SUB:
88280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ InvokeBuiltin(Builtins::SUB, JUMP_FUNCTION);
88380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      break;
88480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    case Token::MUL:
88580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ InvokeBuiltin(Builtins::MUL, JUMP_FUNCTION);
88680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      break;
88780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    case Token::DIV:
88880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ InvokeBuiltin(Builtins::DIV, JUMP_FUNCTION);
88980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      break;
89080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    case Token::MOD:
89180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ InvokeBuiltin(Builtins::MOD, JUMP_FUNCTION);
89280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      break;
89380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    case Token::BIT_OR:
89480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ InvokeBuiltin(Builtins::BIT_OR, JUMP_FUNCTION);
89580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      break;
89680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    case Token::BIT_AND:
89780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ InvokeBuiltin(Builtins::BIT_AND, JUMP_FUNCTION);
89880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      break;
89980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    case Token::BIT_XOR:
90080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ InvokeBuiltin(Builtins::BIT_XOR, JUMP_FUNCTION);
90180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      break;
90280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    case Token::SAR:
90380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ InvokeBuiltin(Builtins::SAR, JUMP_FUNCTION);
90480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      break;
90580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    case Token::SHL:
90680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ InvokeBuiltin(Builtins::SHL, JUMP_FUNCTION);
90780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      break;
90880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    case Token::SHR:
90980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ InvokeBuiltin(Builtins::SHR, JUMP_FUNCTION);
91080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      break;
91180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    default:
91280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      UNREACHABLE();
91380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
91480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
91580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
91680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
91780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid GenericBinaryOpStub::GenerateLoadArguments(MacroAssembler* masm) {
91880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  ASSERT(!HasArgsInRegisters());
91980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rax, Operand(rsp, 1 * kPointerSize));
92080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rdx, Operand(rsp, 2 * kPointerSize));
92180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
92280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
92380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
92480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid GenericBinaryOpStub::GenerateReturn(MacroAssembler* masm) {
92580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // If arguments are not passed in registers remove them from the stack before
92680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // returning.
92780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  if (!HasArgsInRegisters()) {
92880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ ret(2 * kPointerSize);  // Remove both operands
92980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  } else {
93080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ ret(0);
93180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
93280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
93380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
93480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
93580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid GenericBinaryOpStub::GenerateRegisterArgsPush(MacroAssembler* masm) {
93680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  ASSERT(HasArgsInRegisters());
93780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ pop(rcx);
93880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  if (HasArgsReversed()) {
93980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ push(rax);
94080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ push(rdx);
94180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  } else {
94280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ push(rdx);
94380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ push(rax);
94480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
94580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ push(rcx);
94680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
94780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
94880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
94980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid GenericBinaryOpStub::GenerateTypeTransition(MacroAssembler* masm) {
95080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label get_result;
95180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
95280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Ensure the operands are on the stack.
95380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  if (HasArgsInRegisters()) {
95480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    GenerateRegisterArgsPush(masm);
95580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
95680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
95780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Left and right arguments are already on stack.
95880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ pop(rcx);  // Save the return address.
95980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
96080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Push this stub's key.
96180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ Push(Smi::FromInt(MinorKey()));
96280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
96380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Although the operation and the type info are encoded into the key,
96480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // the encoding is opaque, so push them too.
96580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ Push(Smi::FromInt(op_));
96680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
96780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ Push(Smi::FromInt(runtime_operands_type_));
96880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
96980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ push(rcx);  // The return address.
97080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
97180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Perform patching to an appropriate fast case and return the result.
97280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ TailCallExternalReference(
97380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      ExternalReference(IC_Utility(IC::kBinaryOp_Patch)),
97480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      5,
97580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      1);
97680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
97780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
97880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
97980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian MonsenHandle<Code> GetBinaryOpStub(int key, BinaryOpIC::TypeInfo type_info) {
98080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  GenericBinaryOpStub stub(key, type_info);
98180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  return stub.GetCode();
98280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
98380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
98480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
98580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid TranscendentalCacheStub::Generate(MacroAssembler* masm) {
98680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Input on stack:
98780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rsp[8]: argument (should be number).
98880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rsp[0]: return address.
98980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label runtime_call;
99080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label runtime_call_clear_stack;
99180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label input_not_smi;
9920d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  NearLabel loaded;
99380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Test that rax is a number.
99480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rax, Operand(rsp, kPointerSize));
99580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ JumpIfNotSmi(rax, &input_not_smi);
99680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Input is a smi. Untag and load it onto the FPU stack.
99780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Then load the bits of the double into rbx.
99880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiToInteger32(rax, rax);
99980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ subq(rsp, Immediate(kPointerSize));
100080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cvtlsi2sd(xmm1, rax);
100180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movsd(Operand(rsp, 0), xmm1);
100280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rbx, xmm1);
100380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rdx, xmm1);
100480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ fld_d(Operand(rsp, 0));
100580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ addq(rsp, Immediate(kPointerSize));
100680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ jmp(&loaded);
100780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
100880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&input_not_smi);
100980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check if input is a HeapNumber.
101080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ Move(rbx, Factory::heap_number_map());
101180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cmpq(rbx, FieldOperand(rax, HeapObject::kMapOffset));
101280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(not_equal, &runtime_call);
101380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Input is a HeapNumber. Push it on the FPU stack and load its
101480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // bits into rbx.
101580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ fld_d(FieldOperand(rax, HeapNumber::kValueOffset));
101680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rbx, FieldOperand(rax, HeapNumber::kValueOffset));
101780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rdx, rbx);
101880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&loaded);
101980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // ST[0] == double value
102080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rbx = bits of double value.
102180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rdx = also bits of double value.
102280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Compute hash (h is 32 bits, bits are 64 and the shifts are arithmetic):
102380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  //   h = h0 = bits ^ (bits >> 32);
102480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  //   h ^= h >> 16;
102580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  //   h ^= h >> 8;
102680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  //   h = h & (cacheSize - 1);
102780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // or h = (h0 ^ (h0 >> 8) ^ (h0 >> 16) ^ (h0 >> 24)) & (cacheSize - 1)
102880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ sar(rdx, Immediate(32));
102980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ xorl(rdx, rbx);
103080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movl(rcx, rdx);
103180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movl(rax, rdx);
103280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movl(rdi, rdx);
103380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ sarl(rdx, Immediate(8));
103480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ sarl(rcx, Immediate(16));
103580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ sarl(rax, Immediate(24));
103680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ xorl(rcx, rdx);
103780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ xorl(rax, rdi);
103880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ xorl(rcx, rax);
103980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  ASSERT(IsPowerOf2(TranscendentalCache::kCacheSize));
104080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ andl(rcx, Immediate(TranscendentalCache::kCacheSize - 1));
104180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
104280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // ST[0] == double value.
104380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rbx = bits of double value.
104480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rcx = TranscendentalCache::hash(double value).
104580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rax, ExternalReference::transcendental_cache_array_address());
104680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rax points to cache array.
104780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rax, Operand(rax, type_ * sizeof(TranscendentalCache::caches_[0])));
104880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rax points to the cache for the type type_.
104980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // If NULL, the cache hasn't been initialized yet, so go through runtime.
105080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ testq(rax, rax);
105180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(zero, &runtime_call_clear_stack);
105280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#ifdef DEBUG
105380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check that the layout of cache elements match expectations.
105480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  {  // NOLINT - doesn't like a single brace on a line.
105580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    TranscendentalCache::Element test_elem[2];
105680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    char* elem_start = reinterpret_cast<char*>(&test_elem[0]);
105780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    char* elem2_start = reinterpret_cast<char*>(&test_elem[1]);
105880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    char* elem_in0  = reinterpret_cast<char*>(&(test_elem[0].in[0]));
105980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    char* elem_in1  = reinterpret_cast<char*>(&(test_elem[0].in[1]));
106080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    char* elem_out = reinterpret_cast<char*>(&(test_elem[0].output));
106180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // Two uint_32's and a pointer per element.
106280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    CHECK_EQ(16, static_cast<int>(elem2_start - elem_start));
106380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    CHECK_EQ(0, static_cast<int>(elem_in0 - elem_start));
106480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    CHECK_EQ(kIntSize, static_cast<int>(elem_in1 - elem_start));
106580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    CHECK_EQ(2 * kIntSize, static_cast<int>(elem_out - elem_start));
106680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
106780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#endif
106880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Find the address of the rcx'th entry in the cache, i.e., &rax[rcx*16].
106980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ addl(rcx, rcx);
107080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ lea(rcx, Operand(rax, rcx, times_8, 0));
107180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check if cache matches: Double value is stored in uint32_t[2] array.
10720d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  NearLabel cache_miss;
107380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cmpq(rbx, Operand(rcx, 0));
107480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(not_equal, &cache_miss);
107580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Cache hit!
107680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rax, Operand(rcx, 2 * kIntSize));
107780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ fstp(0);  // Clear FPU stack.
107880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ ret(kPointerSize);
107980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
108080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&cache_miss);
108180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Update cache with new value.
108280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label nan_result;
108380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  GenerateOperation(masm, &nan_result);
108480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ AllocateHeapNumber(rax, rdi, &runtime_call_clear_stack);
108580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(Operand(rcx, 0), rbx);
108680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(Operand(rcx, 2 * kIntSize), rax);
108780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ fstp_d(FieldOperand(rax, HeapNumber::kValueOffset));
108880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ ret(kPointerSize);
108980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
109080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&runtime_call_clear_stack);
109180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ fstp(0);
109280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&runtime_call);
109380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ TailCallExternalReference(ExternalReference(RuntimeFunction()), 1, 1);
109480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
109580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&nan_result);
109680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ fstp(0);  // Remove argument from FPU stack.
109780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ LoadRoot(rax, Heap::kNanValueRootIndex);
109880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(Operand(rcx, 0), rbx);
109980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(Operand(rcx, 2 * kIntSize), rax);
110080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ ret(kPointerSize);
110180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
110280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
110380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
110480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian MonsenRuntime::FunctionId TranscendentalCacheStub::RuntimeFunction() {
110580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  switch (type_) {
110680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // Add more cases when necessary.
110780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    case TranscendentalCache::SIN: return Runtime::kMath_sin;
110880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    case TranscendentalCache::COS: return Runtime::kMath_cos;
110980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    default:
111080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      UNIMPLEMENTED();
111180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      return Runtime::kAbort;
111280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
111380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
111480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
111580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
111680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid TranscendentalCacheStub::GenerateOperation(MacroAssembler* masm,
111780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                                Label* on_nan_result) {
111880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Registers:
111980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rbx: Bits of input double. Must be preserved.
112080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rcx: Pointer to cache entry. Must be preserved.
112180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // st(0): Input double
112280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label done;
112380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  ASSERT(type_ == TranscendentalCache::SIN ||
112480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen         type_ == TranscendentalCache::COS);
112580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // More transcendental types can be added later.
112680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
112780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Both fsin and fcos require arguments in the range +/-2^63 and
112880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // return NaN for infinities and NaN. They can share all code except
112980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // the actual fsin/fcos operation.
113080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label in_range;
113180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // If argument is outside the range -2^63..2^63, fsin/cos doesn't
113280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // work. We must reduce it to the appropriate range.
113380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rdi, rbx);
113480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Move exponent and sign bits to low bits.
113580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ shr(rdi, Immediate(HeapNumber::kMantissaBits));
113680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Remove sign bit.
113780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ andl(rdi, Immediate((1 << HeapNumber::kExponentBits) - 1));
113880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  int supported_exponent_limit = (63 + HeapNumber::kExponentBias);
113980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cmpl(rdi, Immediate(supported_exponent_limit));
114080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(below, &in_range);
114180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check for infinity and NaN. Both return NaN for sin.
114280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cmpl(rdi, Immediate(0x7ff));
114380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(equal, on_nan_result);
114480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
114580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Use fpmod to restrict argument to the range +/-2*PI.
114680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ fldpi();
114780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ fadd(0);
114880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ fld(1);
114980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // FPU Stack: input, 2*pi, input.
115080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  {
115180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    Label no_exceptions;
115280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ fwait();
115380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ fnstsw_ax();
115480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // Clear if Illegal Operand or Zero Division exceptions are set.
115580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ testl(rax, Immediate(5));  // #IO and #ZD flags of FPU status word.
115680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ j(zero, &no_exceptions);
115780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ fnclex();
115880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ bind(&no_exceptions);
115980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
116080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
116180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Compute st(0) % st(1)
116280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  {
11630d5e116f6aee03185f237311a943491bb079a768Kristian Monsen    NearLabel partial_remainder_loop;
116480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ bind(&partial_remainder_loop);
116580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ fprem1();
116680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ fwait();
116780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ fnstsw_ax();
116880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ testl(rax, Immediate(0x400));  // Check C2 bit of FPU status word.
116980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // If C2 is set, computation only has partial result. Loop to
117080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // continue computation.
117180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ j(not_zero, &partial_remainder_loop);
117280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
117380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // FPU Stack: input, 2*pi, input % 2*pi
117480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ fstp(2);
117580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // FPU Stack: input % 2*pi, 2*pi,
117680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ fstp(0);
117780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // FPU Stack: input % 2*pi
117880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&in_range);
117980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  switch (type_) {
118080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    case TranscendentalCache::SIN:
118180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ fsin();
118280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      break;
118380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    case TranscendentalCache::COS:
118480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ fcos();
118580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      break;
118680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    default:
118780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      UNREACHABLE();
118880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
118980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&done);
119080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
119180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
119280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
119380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// Get the integer part of a heap number.
119480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// Overwrites the contents of rdi, rbx and rcx. Result cannot be rdi or rbx.
119580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid IntegerConvert(MacroAssembler* masm,
119680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                    Register result,
119780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                    Register source) {
119880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Result may be rcx. If result and source are the same register, source will
119980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // be overwritten.
120080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  ASSERT(!result.is(rdi) && !result.is(rbx));
120180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // TODO(lrn): When type info reaches here, if value is a 32-bit integer, use
120280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // cvttsd2si (32-bit version) directly.
120380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Register double_exponent = rbx;
120480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Register double_value = rdi;
12050d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  NearLabel done, exponent_63_plus;
120680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Get double and extract exponent.
120780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(double_value, FieldOperand(source, HeapNumber::kValueOffset));
120880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Clear result preemptively, in case we need to return zero.
120980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ xorl(result, result);
121080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(xmm0, double_value);  // Save copy in xmm0 in case we need it there.
121180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Double to remove sign bit, shift exponent down to least significant bits.
121280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // and subtract bias to get the unshifted, unbiased exponent.
121380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ lea(double_exponent, Operand(double_value, double_value, times_1, 0));
121480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ shr(double_exponent, Immediate(64 - HeapNumber::kExponentBits));
121580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ subl(double_exponent, Immediate(HeapNumber::kExponentBias));
121680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check whether the exponent is too big for a 63 bit unsigned integer.
121780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cmpl(double_exponent, Immediate(63));
121880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(above_equal, &exponent_63_plus);
121980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Handle exponent range 0..62.
122080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cvttsd2siq(result, xmm0);
122180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ jmp(&done);
122280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
122380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&exponent_63_plus);
122480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Exponent negative or 63+.
122580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cmpl(double_exponent, Immediate(83));
122680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // If exponent negative or above 83, number contains no significant bits in
122780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // the range 0..2^31, so result is zero, and rcx already holds zero.
122880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(above, &done);
122980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
123080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Exponent in rage 63..83.
123180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Mantissa * 2^exponent contains bits in the range 2^0..2^31, namely
123280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // the least significant exponent-52 bits.
123380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
123480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Negate low bits of mantissa if value is negative.
123580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ addq(double_value, double_value);  // Move sign bit to carry.
123680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ sbbl(result, result);  // And convert carry to -1 in result register.
123780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // if scratch2 is negative, do (scratch2-1)^-1, otherwise (scratch2-0)^0.
123880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ addl(double_value, result);
123980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Do xor in opposite directions depending on where we want the result
124080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // (depending on whether result is rcx or not).
124180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
124280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  if (result.is(rcx)) {
124380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ xorl(double_value, result);
124480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // Left shift mantissa by (exponent - mantissabits - 1) to save the
124580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // bits that have positional values below 2^32 (the extra -1 comes from the
124680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // doubling done above to move the sign bit into the carry flag).
124780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ leal(rcx, Operand(double_exponent, -HeapNumber::kMantissaBits - 1));
124880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ shll_cl(double_value);
124980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ movl(result, double_value);
125080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  } else {
125180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // As the then-branch, but move double-value to result before shifting.
125280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ xorl(result, double_value);
125380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ leal(rcx, Operand(double_exponent, -HeapNumber::kMantissaBits - 1));
125480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ shll_cl(result);
125580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
125680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
125780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&done);
125880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
125980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
126080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
126180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// Input: rdx, rax are the left and right objects of a bit op.
126280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// Output: rax, rcx are left and right integers for a bit op.
126380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid FloatingPointHelper::LoadNumbersAsIntegers(MacroAssembler* masm) {
126480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check float operands.
126580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label done;
126680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label rax_is_smi;
126780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label rax_is_object;
126880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label rdx_is_object;
126980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
127080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ JumpIfNotSmi(rdx, &rdx_is_object);
127180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiToInteger32(rdx, rdx);
127280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ JumpIfSmi(rax, &rax_is_smi);
127380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
127480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&rax_is_object);
127580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  IntegerConvert(masm, rcx, rax);  // Uses rdi, rcx and rbx.
127680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ jmp(&done);
127780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
127880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&rdx_is_object);
127980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  IntegerConvert(masm, rdx, rdx);  // Uses rdi, rcx and rbx.
128080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ JumpIfNotSmi(rax, &rax_is_object);
128180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&rax_is_smi);
128280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiToInteger32(rcx, rax);
128380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
128480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&done);
128580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movl(rax, rdx);
128680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
128780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
128880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
128980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// Input: rdx, rax are the left and right objects of a bit op.
129080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// Output: rax, rcx are left and right integers for a bit op.
129180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid FloatingPointHelper::LoadAsIntegers(MacroAssembler* masm,
129280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                         Label* conversion_failure,
129380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                         Register heap_number_map) {
129480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check float operands.
129580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label arg1_is_object, check_undefined_arg1;
129680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label arg2_is_object, check_undefined_arg2;
129780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label load_arg2, done;
129880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
129980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ JumpIfNotSmi(rdx, &arg1_is_object);
130080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiToInteger32(rdx, rdx);
130180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ jmp(&load_arg2);
130280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
130380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // If the argument is undefined it converts to zero (ECMA-262, section 9.5).
130480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&check_undefined_arg1);
130580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ CompareRoot(rdx, Heap::kUndefinedValueRootIndex);
130680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(not_equal, conversion_failure);
130780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movl(rdx, Immediate(0));
130880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ jmp(&load_arg2);
130980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
131080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&arg1_is_object);
131180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cmpq(FieldOperand(rdx, HeapObject::kMapOffset), heap_number_map);
131280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(not_equal, &check_undefined_arg1);
131380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Get the untagged integer version of the edx heap number in rcx.
131480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  IntegerConvert(masm, rdx, rdx);
131580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
131680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Here rdx has the untagged integer, rax has a Smi or a heap number.
131780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&load_arg2);
131880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Test if arg2 is a Smi.
131980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ JumpIfNotSmi(rax, &arg2_is_object);
132080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiToInteger32(rax, rax);
132180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movl(rcx, rax);
132280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ jmp(&done);
132380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
132480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // If the argument is undefined it converts to zero (ECMA-262, section 9.5).
132580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&check_undefined_arg2);
132680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ CompareRoot(rax, Heap::kUndefinedValueRootIndex);
132780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(not_equal, conversion_failure);
132880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movl(rcx, Immediate(0));
132980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ jmp(&done);
133080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
133180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&arg2_is_object);
133280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cmpq(FieldOperand(rax, HeapObject::kMapOffset), heap_number_map);
133380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(not_equal, &check_undefined_arg2);
133480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Get the untagged integer version of the rax heap number in rcx.
133580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  IntegerConvert(masm, rcx, rax);
133680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&done);
133780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movl(rax, rdx);
133880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
133980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
134080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
134180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid FloatingPointHelper::LoadSSE2SmiOperands(MacroAssembler* masm) {
134280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiToInteger32(kScratchRegister, rdx);
134380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cvtlsi2sd(xmm0, kScratchRegister);
134480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiToInteger32(kScratchRegister, rax);
134580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cvtlsi2sd(xmm1, kScratchRegister);
134680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
134780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
134880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
134980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid FloatingPointHelper::LoadSSE2NumberOperands(MacroAssembler* masm) {
135080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label load_smi_rdx, load_nonsmi_rax, load_smi_rax, done;
135180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Load operand in rdx into xmm0.
135280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ JumpIfSmi(rdx, &load_smi_rdx);
135380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movsd(xmm0, FieldOperand(rdx, HeapNumber::kValueOffset));
135480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Load operand in rax into xmm1.
135580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ JumpIfSmi(rax, &load_smi_rax);
135680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&load_nonsmi_rax);
135780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movsd(xmm1, FieldOperand(rax, HeapNumber::kValueOffset));
135880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ jmp(&done);
135980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
136080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&load_smi_rdx);
136180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiToInteger32(kScratchRegister, rdx);
136280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cvtlsi2sd(xmm0, kScratchRegister);
136380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ JumpIfNotSmi(rax, &load_nonsmi_rax);
136480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
136580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&load_smi_rax);
136680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiToInteger32(kScratchRegister, rax);
136780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cvtlsi2sd(xmm1, kScratchRegister);
136880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
136980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&done);
137080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
137180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
137280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
137380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid FloatingPointHelper::LoadSSE2UnknownOperands(MacroAssembler* masm,
137480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                                  Label* not_numbers) {
137580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label load_smi_rdx, load_nonsmi_rax, load_smi_rax, load_float_rax, done;
137680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Load operand in rdx into xmm0, or branch to not_numbers.
137780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ LoadRoot(rcx, Heap::kHeapNumberMapRootIndex);
137880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ JumpIfSmi(rdx, &load_smi_rdx);
137980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cmpq(FieldOperand(rdx, HeapObject::kMapOffset), rcx);
138080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(not_equal, not_numbers);  // Argument in rdx is not a number.
138180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movsd(xmm0, FieldOperand(rdx, HeapNumber::kValueOffset));
138280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Load operand in rax into xmm1, or branch to not_numbers.
138380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ JumpIfSmi(rax, &load_smi_rax);
138480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
138580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&load_nonsmi_rax);
138680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cmpq(FieldOperand(rax, HeapObject::kMapOffset), rcx);
138780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(not_equal, not_numbers);
138880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movsd(xmm1, FieldOperand(rax, HeapNumber::kValueOffset));
138980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ jmp(&done);
139080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
139180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&load_smi_rdx);
139280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiToInteger32(kScratchRegister, rdx);
139380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cvtlsi2sd(xmm0, kScratchRegister);
139480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ JumpIfNotSmi(rax, &load_nonsmi_rax);
139580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
139680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&load_smi_rax);
139780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiToInteger32(kScratchRegister, rax);
139880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cvtlsi2sd(xmm1, kScratchRegister);
139980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&done);
140080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
140180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
140280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
140380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid GenericUnaryOpStub::Generate(MacroAssembler* masm) {
140480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label slow, done;
140580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
140680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  if (op_ == Token::SUB) {
14070d5e116f6aee03185f237311a943491bb079a768Kristian Monsen    if (include_smi_code_) {
14080d5e116f6aee03185f237311a943491bb079a768Kristian Monsen      // Check whether the value is a smi.
14090d5e116f6aee03185f237311a943491bb079a768Kristian Monsen      Label try_float;
14100d5e116f6aee03185f237311a943491bb079a768Kristian Monsen      __ JumpIfNotSmi(rax, &try_float);
14110d5e116f6aee03185f237311a943491bb079a768Kristian Monsen      if (negative_zero_ == kIgnoreNegativeZero) {
14120d5e116f6aee03185f237311a943491bb079a768Kristian Monsen        __ SmiCompare(rax, Smi::FromInt(0));
14130d5e116f6aee03185f237311a943491bb079a768Kristian Monsen        __ j(equal, &done);
14140d5e116f6aee03185f237311a943491bb079a768Kristian Monsen      }
14150d5e116f6aee03185f237311a943491bb079a768Kristian Monsen      __ SmiNeg(rax, rax, &done);
1416f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      __ jmp(&slow);  // zero, if not handled above, and Smi::kMinValue.
14170d5e116f6aee03185f237311a943491bb079a768Kristian Monsen
14180d5e116f6aee03185f237311a943491bb079a768Kristian Monsen      // Try floating point case.
14190d5e116f6aee03185f237311a943491bb079a768Kristian Monsen      __ bind(&try_float);
14200d5e116f6aee03185f237311a943491bb079a768Kristian Monsen    } else if (FLAG_debug_code) {
14210d5e116f6aee03185f237311a943491bb079a768Kristian Monsen      __ AbortIfSmi(rax);
142280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    }
142380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
142480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ movq(rdx, FieldOperand(rax, HeapObject::kMapOffset));
142580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ CompareRoot(rdx, Heap::kHeapNumberMapRootIndex);
142680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ j(not_equal, &slow);
142780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // Operand is a float, negate its value by flipping sign bit.
142880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ movq(rdx, FieldOperand(rax, HeapNumber::kValueOffset));
142980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ movq(kScratchRegister, Immediate(0x01));
143080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ shl(kScratchRegister, Immediate(63));
143180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ xor_(rdx, kScratchRegister);  // Flip sign.
143280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // rdx is value to store.
143380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    if (overwrite_ == UNARY_OVERWRITE) {
143480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ movq(FieldOperand(rax, HeapNumber::kValueOffset), rdx);
143580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    } else {
143680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ AllocateHeapNumber(rcx, rbx, &slow);
143780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      // rcx: allocated 'empty' number
143880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ movq(FieldOperand(rcx, HeapNumber::kValueOffset), rdx);
143980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ movq(rax, rcx);
144080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    }
144180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  } else if (op_ == Token::BIT_NOT) {
14420d5e116f6aee03185f237311a943491bb079a768Kristian Monsen    if (include_smi_code_) {
14430d5e116f6aee03185f237311a943491bb079a768Kristian Monsen      Label try_float;
14440d5e116f6aee03185f237311a943491bb079a768Kristian Monsen      __ JumpIfNotSmi(rax, &try_float);
14450d5e116f6aee03185f237311a943491bb079a768Kristian Monsen      __ SmiNot(rax, rax);
14460d5e116f6aee03185f237311a943491bb079a768Kristian Monsen      __ jmp(&done);
14470d5e116f6aee03185f237311a943491bb079a768Kristian Monsen      // Try floating point case.
14480d5e116f6aee03185f237311a943491bb079a768Kristian Monsen      __ bind(&try_float);
14490d5e116f6aee03185f237311a943491bb079a768Kristian Monsen    } else if (FLAG_debug_code) {
14500d5e116f6aee03185f237311a943491bb079a768Kristian Monsen      __ AbortIfSmi(rax);
14510d5e116f6aee03185f237311a943491bb079a768Kristian Monsen    }
14520d5e116f6aee03185f237311a943491bb079a768Kristian Monsen
145380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // Check if the operand is a heap number.
145480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ movq(rdx, FieldOperand(rax, HeapObject::kMapOffset));
145580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ CompareRoot(rdx, Heap::kHeapNumberMapRootIndex);
145680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ j(not_equal, &slow);
145780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
145880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // Convert the heap number in rax to an untagged integer in rcx.
145980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    IntegerConvert(masm, rax, rax);
146080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
146180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // Do the bitwise operation and smi tag the result.
146280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ notl(rax);
146380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ Integer32ToSmi(rax, rax);
146480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
146580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
146680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Return from the stub.
146780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&done);
146880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ StubReturn(1);
146980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
147080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Handle the slow case by jumping to the JavaScript builtin.
147180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&slow);
147280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ pop(rcx);  // pop return address
147380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ push(rax);
147480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ push(rcx);  // push return address
147580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  switch (op_) {
147680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    case Token::SUB:
147780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ InvokeBuiltin(Builtins::UNARY_MINUS, JUMP_FUNCTION);
147880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      break;
147980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    case Token::BIT_NOT:
148080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ InvokeBuiltin(Builtins::BIT_NOT, JUMP_FUNCTION);
148180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      break;
148280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    default:
148380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      UNREACHABLE();
148480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
148580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
148680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
148780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
148880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid ArgumentsAccessStub::GenerateReadElement(MacroAssembler* masm) {
148980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // The key is in rdx and the parameter count is in rax.
149080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
149180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // The displacement is used for skipping the frame pointer on the
149280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // stack. It is the offset of the last parameter (if any) relative
149380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // to the frame pointer.
149480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  static const int kDisplacement = 1 * kPointerSize;
149580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
149680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check that the key is a smi.
149780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label slow;
149880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ JumpIfNotSmi(rdx, &slow);
149980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
150080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check if the calling frame is an arguments adaptor frame.
150180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label adaptor;
150280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rbx, Operand(rbp, StandardFrameConstants::kCallerFPOffset));
150380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiCompare(Operand(rbx, StandardFrameConstants::kContextOffset),
150480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR));
150580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(equal, &adaptor);
150680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
150780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check index against formal parameters count limit passed in
150880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // through register rax. Use unsigned comparison to get negative
150980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // check for free.
151080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cmpq(rdx, rax);
151180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(above_equal, &slow);
151280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
151380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Read the argument from the stack and return it.
151480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  SmiIndex index = masm->SmiToIndex(rax, rax, kPointerSizeLog2);
151580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ lea(rbx, Operand(rbp, index.reg, index.scale, 0));
151680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  index = masm->SmiToNegativeIndex(rdx, rdx, kPointerSizeLog2);
151780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rax, Operand(rbx, index.reg, index.scale, kDisplacement));
151880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ Ret();
151980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
152080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Arguments adaptor case: Check index against actual arguments
152180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // limit found in the arguments adaptor frame. Use unsigned
152280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // comparison to get negative check for free.
152380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&adaptor);
152480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rcx, Operand(rbx, ArgumentsAdaptorFrameConstants::kLengthOffset));
152580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cmpq(rdx, rcx);
152680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(above_equal, &slow);
152780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
152880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Read the argument from the stack and return it.
152980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  index = masm->SmiToIndex(rax, rcx, kPointerSizeLog2);
153080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ lea(rbx, Operand(rbx, index.reg, index.scale, 0));
153180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  index = masm->SmiToNegativeIndex(rdx, rdx, kPointerSizeLog2);
153280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rax, Operand(rbx, index.reg, index.scale, kDisplacement));
153380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ Ret();
153480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
153580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Slow-case: Handle non-smi or out-of-bounds access to arguments
153680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // by calling the runtime system.
153780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&slow);
153880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ pop(rbx);  // Return address.
153980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ push(rdx);
154080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ push(rbx);
154180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ TailCallRuntime(Runtime::kGetArgumentsProperty, 1, 1);
154280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
154380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
154480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
154580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid ArgumentsAccessStub::GenerateNewObject(MacroAssembler* masm) {
154680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rsp[0] : return address
154780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rsp[8] : number of parameters
154880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rsp[16] : receiver displacement
154980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rsp[24] : function
155080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
155180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // The displacement is used for skipping the return address and the
155280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // frame pointer on the stack. It is the offset of the last
155380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // parameter (if any) relative to the frame pointer.
155480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  static const int kDisplacement = 2 * kPointerSize;
155580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
155680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check if the calling frame is an arguments adaptor frame.
155780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label adaptor_frame, try_allocate, runtime;
155880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rdx, Operand(rbp, StandardFrameConstants::kCallerFPOffset));
155980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiCompare(Operand(rdx, StandardFrameConstants::kContextOffset),
156080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR));
156180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(equal, &adaptor_frame);
156280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
156380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Get the length from the frame.
156480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiToInteger32(rcx, Operand(rsp, 1 * kPointerSize));
156580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ jmp(&try_allocate);
156680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
156780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Patch the arguments.length and the parameters pointer.
156880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&adaptor_frame);
156980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiToInteger32(rcx,
157080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                    Operand(rdx,
157180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                            ArgumentsAdaptorFrameConstants::kLengthOffset));
157280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Space on stack must already hold a smi.
157380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ Integer32ToSmiField(Operand(rsp, 1 * kPointerSize), rcx);
157480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Do not clobber the length index for the indexing operation since
157580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // it is used compute the size for allocation later.
157680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ lea(rdx, Operand(rdx, rcx, times_pointer_size, kDisplacement));
157780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(Operand(rsp, 2 * kPointerSize), rdx);
157880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
157980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Try the new space allocation. Start out with computing the size of
158080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // the arguments object and the elements array.
158180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label add_arguments_object;
158280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&try_allocate);
158380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ testl(rcx, rcx);
158480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(zero, &add_arguments_object);
158580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ leal(rcx, Operand(rcx, times_pointer_size, FixedArray::kHeaderSize));
158680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&add_arguments_object);
158780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ addl(rcx, Immediate(Heap::kArgumentsObjectSize));
158880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
158980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Do the allocation of both objects in one go.
159080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ AllocateInNewSpace(rcx, rax, rdx, rbx, &runtime, TAG_OBJECT);
159180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
159280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Get the arguments boilerplate from the current (global) context.
159380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  int offset = Context::SlotOffset(Context::ARGUMENTS_BOILERPLATE_INDEX);
159480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rdi, Operand(rsi, Context::SlotOffset(Context::GLOBAL_INDEX)));
159580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rdi, FieldOperand(rdi, GlobalObject::kGlobalContextOffset));
159680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rdi, Operand(rdi, offset));
159780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
159880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Copy the JS object part.
159980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  STATIC_ASSERT(JSObject::kHeaderSize == 3 * kPointerSize);
160080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(kScratchRegister, FieldOperand(rdi, 0 * kPointerSize));
160180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rdx, FieldOperand(rdi, 1 * kPointerSize));
160280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rbx, FieldOperand(rdi, 2 * kPointerSize));
160380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(FieldOperand(rax, 0 * kPointerSize), kScratchRegister);
160480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(FieldOperand(rax, 1 * kPointerSize), rdx);
160580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(FieldOperand(rax, 2 * kPointerSize), rbx);
160680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
160780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Setup the callee in-object property.
160880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  ASSERT(Heap::arguments_callee_index == 0);
160980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(kScratchRegister, Operand(rsp, 3 * kPointerSize));
161080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(FieldOperand(rax, JSObject::kHeaderSize), kScratchRegister);
161180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
161280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Get the length (smi tagged) and set that as an in-object property too.
161380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  ASSERT(Heap::arguments_length_index == 1);
161480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rcx, Operand(rsp, 1 * kPointerSize));
161580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(FieldOperand(rax, JSObject::kHeaderSize + kPointerSize), rcx);
161680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
161780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // If there are no actual arguments, we're done.
161880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label done;
161980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiTest(rcx);
162080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(zero, &done);
162180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
162280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Get the parameters pointer from the stack and untag the length.
162380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rdx, Operand(rsp, 2 * kPointerSize));
162480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
162580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Setup the elements pointer in the allocated arguments object and
162680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // initialize the header in the elements fixed array.
162780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ lea(rdi, Operand(rax, Heap::kArgumentsObjectSize));
162880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(FieldOperand(rax, JSObject::kElementsOffset), rdi);
162980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ LoadRoot(kScratchRegister, Heap::kFixedArrayMapRootIndex);
163080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(FieldOperand(rdi, FixedArray::kMapOffset), kScratchRegister);
163180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(FieldOperand(rdi, FixedArray::kLengthOffset), rcx);
163280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiToInteger32(rcx, rcx);  // Untag length for the loop below.
163380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
163480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Copy the fixed array slots.
163580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label loop;
163680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&loop);
163780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(kScratchRegister, Operand(rdx, -1 * kPointerSize));  // Skip receiver.
163880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(FieldOperand(rdi, FixedArray::kHeaderSize), kScratchRegister);
163980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ addq(rdi, Immediate(kPointerSize));
164080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ subq(rdx, Immediate(kPointerSize));
164180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ decl(rcx);
164280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(not_zero, &loop);
164380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
164480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Return and remove the on-stack parameters.
164580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&done);
164680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ ret(3 * kPointerSize);
164780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
164880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Do the runtime call to allocate the arguments object.
164980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&runtime);
165080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ TailCallRuntime(Runtime::kNewArgumentsFast, 3, 1);
165180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
165280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
165380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
165480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid RegExpExecStub::Generate(MacroAssembler* masm) {
165580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Just jump directly to runtime if native RegExp is not selected at compile
165680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // time or if regexp entry in generated code is turned off runtime switch or
165780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // at compilation.
165880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#ifdef V8_INTERPRETED_REGEXP
165980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ TailCallRuntime(Runtime::kRegExpExec, 4, 1);
166080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#else  // V8_INTERPRETED_REGEXP
166180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  if (!FLAG_regexp_entry_native) {
166280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ TailCallRuntime(Runtime::kRegExpExec, 4, 1);
166380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    return;
166480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
166580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
166680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Stack frame on entry.
166780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  //  esp[0]: return address
166880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  //  esp[8]: last_match_info (expected JSArray)
166980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  //  esp[16]: previous index
167080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  //  esp[24]: subject string
167180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  //  esp[32]: JSRegExp object
167280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
167380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  static const int kLastMatchInfoOffset = 1 * kPointerSize;
167480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  static const int kPreviousIndexOffset = 2 * kPointerSize;
167580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  static const int kSubjectOffset = 3 * kPointerSize;
167680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  static const int kJSRegExpOffset = 4 * kPointerSize;
167780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
167880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label runtime;
167980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
168080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Ensure that a RegExp stack is allocated.
168180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  ExternalReference address_of_regexp_stack_memory_address =
168280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      ExternalReference::address_of_regexp_stack_memory_address();
168380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  ExternalReference address_of_regexp_stack_memory_size =
168480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      ExternalReference::address_of_regexp_stack_memory_size();
168580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(kScratchRegister, address_of_regexp_stack_memory_size);
168680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(kScratchRegister, Operand(kScratchRegister, 0));
168780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ testq(kScratchRegister, kScratchRegister);
168880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(zero, &runtime);
168980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
169080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
169180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check that the first argument is a JSRegExp object.
169280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rax, Operand(rsp, kJSRegExpOffset));
169380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ JumpIfSmi(rax, &runtime);
169480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ CmpObjectType(rax, JS_REGEXP_TYPE, kScratchRegister);
169580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(not_equal, &runtime);
169680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check that the RegExp has been compiled (data contains a fixed array).
169780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rcx, FieldOperand(rax, JSRegExp::kDataOffset));
169880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  if (FLAG_debug_code) {
169980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    Condition is_smi = masm->CheckSmi(rcx);
170080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ Check(NegateCondition(is_smi),
170180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen        "Unexpected type for RegExp data, FixedArray expected");
170280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ CmpObjectType(rcx, FIXED_ARRAY_TYPE, kScratchRegister);
170380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ Check(equal, "Unexpected type for RegExp data, FixedArray expected");
170480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
170580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
170680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rcx: RegExp data (FixedArray)
170780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check the type of the RegExp. Only continue if type is JSRegExp::IRREGEXP.
170880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiToInteger32(rbx, FieldOperand(rcx, JSRegExp::kDataTagOffset));
170980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cmpl(rbx, Immediate(JSRegExp::IRREGEXP));
171080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(not_equal, &runtime);
171180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
171280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rcx: RegExp data (FixedArray)
171380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check that the number of captures fit in the static offsets vector buffer.
171480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiToInteger32(rdx,
171580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                    FieldOperand(rcx, JSRegExp::kIrregexpCaptureCountOffset));
171680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Calculate number of capture registers (number_of_captures + 1) * 2.
171780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ leal(rdx, Operand(rdx, rdx, times_1, 2));
171880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check that the static offsets vector buffer is large enough.
171980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cmpl(rdx, Immediate(OffsetsVector::kStaticOffsetsVectorSize));
172080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(above, &runtime);
172180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
172280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rcx: RegExp data (FixedArray)
172380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rdx: Number of capture registers
172480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check that the second argument is a string.
172580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rax, Operand(rsp, kSubjectOffset));
172680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ JumpIfSmi(rax, &runtime);
172780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Condition is_string = masm->IsObjectStringType(rax, rbx, rbx);
172880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(NegateCondition(is_string), &runtime);
172980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
173080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rax: Subject string.
173180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rcx: RegExp data (FixedArray).
173280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rdx: Number of capture registers.
173380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check that the third argument is a positive smi less than the string
173480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // length. A negative value will be greater (unsigned comparison).
173580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rbx, Operand(rsp, kPreviousIndexOffset));
173680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ JumpIfNotSmi(rbx, &runtime);
173780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiCompare(rbx, FieldOperand(rax, String::kLengthOffset));
173880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(above_equal, &runtime);
173980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
174080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rcx: RegExp data (FixedArray)
174180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rdx: Number of capture registers
174280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check that the fourth object is a JSArray object.
174380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rax, Operand(rsp, kLastMatchInfoOffset));
174480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ JumpIfSmi(rax, &runtime);
174580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ CmpObjectType(rax, JS_ARRAY_TYPE, kScratchRegister);
174680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(not_equal, &runtime);
174780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check that the JSArray is in fast case.
174880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rbx, FieldOperand(rax, JSArray::kElementsOffset));
174980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rax, FieldOperand(rbx, HeapObject::kMapOffset));
175080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ Cmp(rax, Factory::fixed_array_map());
175180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(not_equal, &runtime);
175280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check that the last match info has space for the capture registers and the
175380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // additional information. Ensure no overflow in add.
175480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  STATIC_ASSERT(FixedArray::kMaxLength < kMaxInt - FixedArray::kLengthOffset);
175580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiToInteger32(rax, FieldOperand(rbx, FixedArray::kLengthOffset));
175680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ addl(rdx, Immediate(RegExpImpl::kLastMatchOverhead));
175780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cmpl(rdx, rax);
175880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(greater, &runtime);
175980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
176080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rcx: RegExp data (FixedArray)
176180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check the representation and encoding of the subject string.
17620d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  NearLabel seq_ascii_string, seq_two_byte_string, check_code;
176380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rax, Operand(rsp, kSubjectOffset));
176480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rbx, FieldOperand(rax, HeapObject::kMapOffset));
176580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movzxbl(rbx, FieldOperand(rbx, Map::kInstanceTypeOffset));
176680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // First check for flat two byte string.
176780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ andb(rbx, Immediate(
176880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      kIsNotStringMask | kStringRepresentationMask | kStringEncodingMask));
176980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  STATIC_ASSERT((kStringTag | kSeqStringTag | kTwoByteStringTag) == 0);
177080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(zero, &seq_two_byte_string);
177180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Any other flat string must be a flat ascii string.
177280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ testb(rbx, Immediate(kIsNotStringMask | kStringRepresentationMask));
177380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(zero, &seq_ascii_string);
177480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
177580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check for flat cons string.
177680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // A flat cons string is a cons string where the second part is the empty
177780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // string. In that case the subject string is just the first part of the cons
177880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // string. Also in this case the first part of the cons string is known to be
177980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // a sequential string or an external string.
178080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  STATIC_ASSERT(kExternalStringTag !=0);
178180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  STATIC_ASSERT((kConsStringTag & kExternalStringTag) == 0);
178280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ testb(rbx, Immediate(kIsNotStringMask | kExternalStringTag));
178380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(not_zero, &runtime);
178480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // String is a cons string.
178580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rdx, FieldOperand(rax, ConsString::kSecondOffset));
178680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ Cmp(rdx, Factory::empty_string());
178780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(not_equal, &runtime);
178880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rax, FieldOperand(rax, ConsString::kFirstOffset));
178980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rbx, FieldOperand(rax, HeapObject::kMapOffset));
179080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // String is a cons string with empty second part.
179180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rax: first part of cons string.
179280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rbx: map of first part of cons string.
179380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Is first part a flat two byte string?
179480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ testb(FieldOperand(rbx, Map::kInstanceTypeOffset),
179580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen           Immediate(kStringRepresentationMask | kStringEncodingMask));
179680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  STATIC_ASSERT((kSeqStringTag | kTwoByteStringTag) == 0);
179780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(zero, &seq_two_byte_string);
179880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Any other flat string must be ascii.
179980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ testb(FieldOperand(rbx, Map::kInstanceTypeOffset),
180080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen           Immediate(kStringRepresentationMask));
180180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(not_zero, &runtime);
180280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
180380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&seq_ascii_string);
180480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rax: subject string (sequential ascii)
180580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rcx: RegExp data (FixedArray)
180680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(r11, FieldOperand(rcx, JSRegExp::kDataAsciiCodeOffset));
180780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ Set(rdi, 1);  // Type is ascii.
180880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ jmp(&check_code);
180980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
181080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&seq_two_byte_string);
181180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rax: subject string (flat two-byte)
181280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rcx: RegExp data (FixedArray)
181380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(r11, FieldOperand(rcx, JSRegExp::kDataUC16CodeOffset));
181480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ Set(rdi, 0);  // Type is two byte.
181580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
181680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&check_code);
181780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check that the irregexp code has been generated for the actual string
181880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // encoding. If it has, the field contains a code object otherwise it contains
181980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // the hole.
182080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ CmpObjectType(r11, CODE_TYPE, kScratchRegister);
182180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(not_equal, &runtime);
182280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
182380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rax: subject string
182480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rdi: encoding of subject string (1 if ascii, 0 if two_byte);
182580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // r11: code
182680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Load used arguments before starting to push arguments for call to native
182780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // RegExp code to avoid handling changing stack height.
182880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiToInteger64(rbx, Operand(rsp, kPreviousIndexOffset));
182980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
183080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rax: subject string
183180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rbx: previous index
183280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rdi: encoding of subject string (1 if ascii 0 if two_byte);
183380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // r11: code
183480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // All checks done. Now push arguments for native regexp code.
183580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ IncrementCounter(&Counters::regexp_entry_native, 1);
183680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
183780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rsi is caller save on Windows and used to pass parameter on Linux.
183880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ push(rsi);
183980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
184080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  static const int kRegExpExecuteArguments = 7;
184180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ PrepareCallCFunction(kRegExpExecuteArguments);
184280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  int argument_slots_on_stack =
184380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      masm->ArgumentStackSlotsForCFunctionCall(kRegExpExecuteArguments);
184480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
184580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Argument 7: Indicate that this is a direct call from JavaScript.
184680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(Operand(rsp, (argument_slots_on_stack - 1) * kPointerSize),
184780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen          Immediate(1));
184880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
184980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Argument 6: Start (high end) of backtracking stack memory area.
185080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(kScratchRegister, address_of_regexp_stack_memory_address);
185180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(r9, Operand(kScratchRegister, 0));
185280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(kScratchRegister, address_of_regexp_stack_memory_size);
185380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ addq(r9, Operand(kScratchRegister, 0));
185480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Argument 6 passed in r9 on Linux and on the stack on Windows.
185580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#ifdef _WIN64
185680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(Operand(rsp, (argument_slots_on_stack - 2) * kPointerSize), r9);
185780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#endif
185880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
185980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Argument 5: static offsets vector buffer.
186080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(r8, ExternalReference::address_of_static_offsets_vector());
186180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Argument 5 passed in r8 on Linux and on the stack on Windows.
186280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#ifdef _WIN64
186380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(Operand(rsp, (argument_slots_on_stack - 3) * kPointerSize), r8);
186480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#endif
186580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
186680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // First four arguments are passed in registers on both Linux and Windows.
186780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#ifdef _WIN64
186880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Register arg4 = r9;
186980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Register arg3 = r8;
187080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Register arg2 = rdx;
187180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Register arg1 = rcx;
187280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#else
187380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Register arg4 = rcx;
187480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Register arg3 = rdx;
187580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Register arg2 = rsi;
187680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Register arg1 = rdi;
187780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#endif
187880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
187980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Keep track on aliasing between argX defined above and the registers used.
188080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rax: subject string
188180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rbx: previous index
188280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rdi: encoding of subject string (1 if ascii 0 if two_byte);
188380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // r11: code
188480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
188580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Argument 4: End of string data
188680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Argument 3: Start of string data
18870d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  NearLabel setup_two_byte, setup_rest;
188880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ testb(rdi, rdi);
188980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(zero, &setup_two_byte);
189080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiToInteger32(rdi, FieldOperand(rax, String::kLengthOffset));
189180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ lea(arg4, FieldOperand(rax, rdi, times_1, SeqAsciiString::kHeaderSize));
189280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ lea(arg3, FieldOperand(rax, rbx, times_1, SeqAsciiString::kHeaderSize));
189380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ jmp(&setup_rest);
189480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&setup_two_byte);
189580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiToInteger32(rdi, FieldOperand(rax, String::kLengthOffset));
189680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ lea(arg4, FieldOperand(rax, rdi, times_2, SeqTwoByteString::kHeaderSize));
189780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ lea(arg3, FieldOperand(rax, rbx, times_2, SeqTwoByteString::kHeaderSize));
189880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
189980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&setup_rest);
190080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Argument 2: Previous index.
190180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(arg2, rbx);
190280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
190380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Argument 1: Subject string.
190480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(arg1, rax);
190580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
190680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Locate the code entry and call it.
190780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ addq(r11, Immediate(Code::kHeaderSize - kHeapObjectTag));
190880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ CallCFunction(r11, kRegExpExecuteArguments);
190980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
191080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rsi is caller save, as it is used to pass parameter.
191180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ pop(rsi);
191280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
191380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check the result.
19140d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  NearLabel success;
191580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cmpl(rax, Immediate(NativeRegExpMacroAssembler::SUCCESS));
191680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(equal, &success);
19170d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  NearLabel failure;
191880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cmpl(rax, Immediate(NativeRegExpMacroAssembler::FAILURE));
191980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(equal, &failure);
192080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cmpl(rax, Immediate(NativeRegExpMacroAssembler::EXCEPTION));
192180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // If not exception it can only be retry. Handle that in the runtime system.
192280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(not_equal, &runtime);
192380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Result must now be exception. If there is no pending exception already a
192480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // stack overflow (on the backtrack stack) was detected in RegExp code but
192580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // haven't created the exception yet. Handle that in the runtime system.
192680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // TODO(592): Rerunning the RegExp to get the stack overflow exception.
192780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  ExternalReference pending_exception_address(Top::k_pending_exception_address);
192880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(kScratchRegister, pending_exception_address);
192980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ Cmp(kScratchRegister, Factory::the_hole_value());
193080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(equal, &runtime);
193180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&failure);
193280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // For failure and exception return null.
193380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ Move(rax, Factory::null_value());
193480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ ret(4 * kPointerSize);
193580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
193680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Load RegExp data.
193780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&success);
193880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rax, Operand(rsp, kJSRegExpOffset));
193980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rcx, FieldOperand(rax, JSRegExp::kDataOffset));
194080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiToInteger32(rax,
194180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                    FieldOperand(rcx, JSRegExp::kIrregexpCaptureCountOffset));
194280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Calculate number of capture registers (number_of_captures + 1) * 2.
194380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ leal(rdx, Operand(rax, rax, times_1, 2));
194480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
194580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rdx: Number of capture registers
194680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Load last_match_info which is still known to be a fast case JSArray.
194780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rax, Operand(rsp, kLastMatchInfoOffset));
194880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rbx, FieldOperand(rax, JSArray::kElementsOffset));
194980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
195080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rbx: last_match_info backing store (FixedArray)
195180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rdx: number of capture registers
195280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Store the capture count.
195380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ Integer32ToSmi(kScratchRegister, rdx);
195480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(FieldOperand(rbx, RegExpImpl::kLastCaptureCountOffset),
195580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen          kScratchRegister);
195680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Store last subject and last input.
195780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rax, Operand(rsp, kSubjectOffset));
195880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(FieldOperand(rbx, RegExpImpl::kLastSubjectOffset), rax);
195980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rcx, rbx);
196080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ RecordWrite(rcx, RegExpImpl::kLastSubjectOffset, rax, rdi);
196180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rax, Operand(rsp, kSubjectOffset));
196280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(FieldOperand(rbx, RegExpImpl::kLastInputOffset), rax);
196380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rcx, rbx);
196480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ RecordWrite(rcx, RegExpImpl::kLastInputOffset, rax, rdi);
196580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
196680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Get the static offsets vector filled by the native regexp code.
196780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rcx, ExternalReference::address_of_static_offsets_vector());
196880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
196980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rbx: last_match_info backing store (FixedArray)
197080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rcx: offsets vector
197180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rdx: number of capture registers
19720d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  NearLabel next_capture, done;
197380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Capture register counter starts from number of capture registers and
197480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // counts down until wraping after zero.
197580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&next_capture);
197680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ subq(rdx, Immediate(1));
197780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(negative, &done);
197880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Read the value from the static offsets vector buffer and make it a smi.
197980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movl(rdi, Operand(rcx, rdx, times_int_size, 0));
19800d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  __ Integer32ToSmi(rdi, rdi);
198180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Store the smi value in the last match info.
198280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(FieldOperand(rbx,
198380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                       rdx,
198480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                       times_pointer_size,
198580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                       RegExpImpl::kFirstCaptureOffset),
198680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen          rdi);
198780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ jmp(&next_capture);
198880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&done);
198980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
199080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Return last match info.
199180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rax, Operand(rsp, kLastMatchInfoOffset));
199280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ ret(4 * kPointerSize);
199380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
199480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Do the runtime call to execute the regexp.
199580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&runtime);
199680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ TailCallRuntime(Runtime::kRegExpExec, 4, 1);
199780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#endif  // V8_INTERPRETED_REGEXP
199880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
199980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
200080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
200180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid NumberToStringStub::GenerateLookupNumberStringCache(MacroAssembler* masm,
200280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                                         Register object,
200380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                                         Register result,
200480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                                         Register scratch1,
200580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                                         Register scratch2,
200680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                                         bool object_is_smi,
200780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                                         Label* not_found) {
200880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Use of registers. Register result is used as a temporary.
200980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Register number_string_cache = result;
201080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Register mask = scratch1;
201180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Register scratch = scratch2;
201280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
201380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Load the number string cache.
201480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ LoadRoot(number_string_cache, Heap::kNumberStringCacheRootIndex);
201580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
201680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Make the hash mask from the length of the number string cache. It
201780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // contains two elements (number and string) for each cache entry.
201880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiToInteger32(
201980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      mask, FieldOperand(number_string_cache, FixedArray::kLengthOffset));
202080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ shrl(mask, Immediate(1));
202180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ subq(mask, Immediate(1));  // Make mask.
202280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
202380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Calculate the entry in the number string cache. The hash value in the
202480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // number string cache for smis is just the smi value, and the hash for
202580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // doubles is the xor of the upper and lower words. See
202680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Heap::GetNumberStringCache.
202780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label is_smi;
202880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label load_result_from_cache;
202980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  if (!object_is_smi) {
203080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ JumpIfSmi(object, &is_smi);
203180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ CheckMap(object, Factory::heap_number_map(), not_found, true);
203280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
203380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    STATIC_ASSERT(8 == kDoubleSize);
203480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ movl(scratch, FieldOperand(object, HeapNumber::kValueOffset + 4));
203580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ xor_(scratch, FieldOperand(object, HeapNumber::kValueOffset));
203680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    GenerateConvertHashCodeToIndex(masm, scratch, mask);
203780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
203880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    Register index = scratch;
203980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    Register probe = mask;
204080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ movq(probe,
204180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen            FieldOperand(number_string_cache,
204280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                         index,
204380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                         times_1,
204480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                         FixedArray::kHeaderSize));
204580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ JumpIfSmi(probe, not_found);
204680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    ASSERT(CpuFeatures::IsSupported(SSE2));
204780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    CpuFeatures::Scope fscope(SSE2);
204880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ movsd(xmm0, FieldOperand(object, HeapNumber::kValueOffset));
204980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ movsd(xmm1, FieldOperand(probe, HeapNumber::kValueOffset));
205080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ ucomisd(xmm0, xmm1);
205180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ j(parity_even, not_found);  // Bail out if NaN is involved.
205280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ j(not_equal, not_found);  // The cache did not contain this value.
205380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ jmp(&load_result_from_cache);
205480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
205580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
205680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&is_smi);
205780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiToInteger32(scratch, object);
205880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  GenerateConvertHashCodeToIndex(masm, scratch, mask);
205980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
206080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Register index = scratch;
206180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check if the entry is the smi we are looking for.
206280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cmpq(object,
206380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen          FieldOperand(number_string_cache,
206480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                       index,
206580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                       times_1,
206680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                       FixedArray::kHeaderSize));
206780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(not_equal, not_found);
206880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
206980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Get the result from the cache.
207080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&load_result_from_cache);
207180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(result,
207280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen          FieldOperand(number_string_cache,
207380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                       index,
207480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                       times_1,
207580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                       FixedArray::kHeaderSize + kPointerSize));
207680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ IncrementCounter(&Counters::number_to_string_native, 1);
207780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
207880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
207980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
208080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid NumberToStringStub::GenerateConvertHashCodeToIndex(MacroAssembler* masm,
208180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                                        Register hash,
208280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                                        Register mask) {
208380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ and_(hash, mask);
208480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Each entry in string cache consists of two pointer sized fields,
208580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // but times_twice_pointer_size (multiplication by 16) scale factor
208680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // is not supported by addrmode on x64 platform.
208780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // So we have to premultiply entry index before lookup.
208880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ shl(hash, Immediate(kPointerSizeLog2 + 1));
208980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
209080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
209180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
209280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid NumberToStringStub::Generate(MacroAssembler* masm) {
209380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label runtime;
209480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
209580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rbx, Operand(rsp, kPointerSize));
209680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
209780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Generate code to lookup number in the number string cache.
209880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  GenerateLookupNumberStringCache(masm, rbx, rax, r8, r9, false, &runtime);
209980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ ret(1 * kPointerSize);
210080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
210180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&runtime);
210280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Handle number to string in the runtime system if not found in the cache.
210380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ TailCallRuntime(Runtime::kNumberToStringSkipCache, 1, 1);
210480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
210580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
210680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
210780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenstatic int NegativeComparisonResult(Condition cc) {
210880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  ASSERT(cc != equal);
210980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  ASSERT((cc == less) || (cc == less_equal)
211080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      || (cc == greater) || (cc == greater_equal));
211180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  return (cc == greater || cc == greater_equal) ? LESS : GREATER;
211280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
211380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
211480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
211580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid CompareStub::Generate(MacroAssembler* masm) {
211680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  ASSERT(lhs_.is(no_reg) && rhs_.is(no_reg));
211780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
211880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label check_unequal_objects, done;
21190d5e116f6aee03185f237311a943491bb079a768Kristian Monsen
21200d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  // Compare two smis if required.
21210d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  if (include_smi_compare_) {
21220d5e116f6aee03185f237311a943491bb079a768Kristian Monsen    Label non_smi, smi_done;
21230d5e116f6aee03185f237311a943491bb079a768Kristian Monsen    __ JumpIfNotBothSmi(rax, rdx, &non_smi);
21240d5e116f6aee03185f237311a943491bb079a768Kristian Monsen    __ subq(rdx, rax);
21250d5e116f6aee03185f237311a943491bb079a768Kristian Monsen    __ j(no_overflow, &smi_done);
2126f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    __ not_(rdx);  // Correct sign in case of overflow. rdx cannot be 0 here.
21270d5e116f6aee03185f237311a943491bb079a768Kristian Monsen    __ bind(&smi_done);
21280d5e116f6aee03185f237311a943491bb079a768Kristian Monsen    __ movq(rax, rdx);
21290d5e116f6aee03185f237311a943491bb079a768Kristian Monsen    __ ret(0);
21300d5e116f6aee03185f237311a943491bb079a768Kristian Monsen    __ bind(&non_smi);
21310d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  } else if (FLAG_debug_code) {
21320d5e116f6aee03185f237311a943491bb079a768Kristian Monsen    Label ok;
21330d5e116f6aee03185f237311a943491bb079a768Kristian Monsen    __ JumpIfNotSmi(rdx, &ok);
21340d5e116f6aee03185f237311a943491bb079a768Kristian Monsen    __ JumpIfNotSmi(rax, &ok);
21350d5e116f6aee03185f237311a943491bb079a768Kristian Monsen    __ Abort("CompareStub: smi operands");
21360d5e116f6aee03185f237311a943491bb079a768Kristian Monsen    __ bind(&ok);
21370d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  }
21380d5e116f6aee03185f237311a943491bb079a768Kristian Monsen
213980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // The compare stub returns a positive, negative, or zero 64-bit integer
214080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // value in rax, corresponding to result of comparing the two inputs.
214180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // NOTICE! This code is only reached after a smi-fast-case check, so
214280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // it is certain that at least one operand isn't a smi.
214380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
214480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Two identical objects are equal unless they are both NaN or undefined.
214580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  {
21460d5e116f6aee03185f237311a943491bb079a768Kristian Monsen    NearLabel not_identical;
214780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ cmpq(rax, rdx);
214880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ j(not_equal, &not_identical);
214980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
215080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    if (cc_ != equal) {
215180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      // Check for undefined.  undefined OP undefined is false even though
215280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      // undefined == undefined.
21530d5e116f6aee03185f237311a943491bb079a768Kristian Monsen      NearLabel check_for_nan;
215480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ CompareRoot(rdx, Heap::kUndefinedValueRootIndex);
215580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ j(not_equal, &check_for_nan);
215680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ Set(rax, NegativeComparisonResult(cc_));
215780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ ret(0);
215880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ bind(&check_for_nan);
215980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    }
216080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
216180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // Test for NaN. Sadly, we can't just compare to Factory::nan_value(),
216280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // so we do the second best thing - test it ourselves.
216380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // Note: if cc_ != equal, never_nan_nan_ is not used.
216480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // We cannot set rax to EQUAL until just before return because
216580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // rax must be unchanged on jump to not_identical.
216680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
216780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    if (never_nan_nan_ && (cc_ == equal)) {
216880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ Set(rax, EQUAL);
216980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ ret(0);
217080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    } else {
21710d5e116f6aee03185f237311a943491bb079a768Kristian Monsen      NearLabel heap_number;
217280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      // If it's not a heap number, then return equal for (in)equality operator.
217380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ Cmp(FieldOperand(rdx, HeapObject::kMapOffset),
217480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen             Factory::heap_number_map());
217580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ j(equal, &heap_number);
217680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      if (cc_ != equal) {
217780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen        // Call runtime on identical JSObjects.  Otherwise return equal.
217880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen        __ CmpObjectType(rax, FIRST_JS_OBJECT_TYPE, rcx);
217980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen        __ j(above_equal, &not_identical);
218080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      }
218180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ Set(rax, EQUAL);
218280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ ret(0);
218380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
218480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ bind(&heap_number);
218580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      // It is a heap number, so return  equal if it's not NaN.
218680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      // For NaN, return 1 for every condition except greater and
218780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      // greater-equal.  Return -1 for them, so the comparison yields
218880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      // false for all conditions except not-equal.
218980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ Set(rax, EQUAL);
219080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ movsd(xmm0, FieldOperand(rdx, HeapNumber::kValueOffset));
219180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ ucomisd(xmm0, xmm0);
219280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ setcc(parity_even, rax);
219380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      // rax is 0 for equal non-NaN heapnumbers, 1 for NaNs.
219480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      if (cc_ == greater_equal || cc_ == greater) {
219580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen        __ neg(rax);
219680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      }
219780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ ret(0);
219880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    }
219980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
220080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ bind(&not_identical);
220180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
220280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
220380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  if (cc_ == equal) {  // Both strict and non-strict.
220480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    Label slow;  // Fallthrough label.
220580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
220680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // If we're doing a strict equality comparison, we don't have to do
220780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // type conversion, so we generate code to do fast comparison for objects
220880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // and oddballs. Non-smi numbers and strings still go through the usual
220980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // slow-case code.
221080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    if (strict_) {
221180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      // If either is a Smi (we know that not both are), then they can only
221280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      // be equal if the other is a HeapNumber. If so, use the slow case.
221380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      {
221480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen        Label not_smis;
221580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen        __ SelectNonSmi(rbx, rax, rdx, &not_smis);
221680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
221780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen        // Check if the non-smi operand is a heap number.
221880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen        __ Cmp(FieldOperand(rbx, HeapObject::kMapOffset),
221980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen               Factory::heap_number_map());
222080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen        // If heap number, handle it in the slow case.
222180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen        __ j(equal, &slow);
222280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen        // Return non-equal.  ebx (the lower half of rbx) is not zero.
222380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen        __ movq(rax, rbx);
222480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen        __ ret(0);
222580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
222680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen        __ bind(&not_smis);
222780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      }
222880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
222980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      // If either operand is a JSObject or an oddball value, then they are not
223080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      // equal since their pointers are different
223180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      // There is no test for undetectability in strict equality.
223280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
223380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      // If the first object is a JS object, we have done pointer comparison.
223480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      STATIC_ASSERT(LAST_TYPE == JS_FUNCTION_TYPE);
22350d5e116f6aee03185f237311a943491bb079a768Kristian Monsen      NearLabel first_non_object;
223680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ CmpObjectType(rax, FIRST_JS_OBJECT_TYPE, rcx);
223780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ j(below, &first_non_object);
223880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      // Return non-zero (eax (not rax) is not zero)
223980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      Label return_not_equal;
224080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      STATIC_ASSERT(kHeapObjectTag != 0);
224180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ bind(&return_not_equal);
224280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ ret(0);
224380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
224480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ bind(&first_non_object);
224580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      // Check for oddballs: true, false, null, undefined.
224680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ CmpInstanceType(rcx, ODDBALL_TYPE);
224780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ j(equal, &return_not_equal);
224880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
224980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ CmpObjectType(rdx, FIRST_JS_OBJECT_TYPE, rcx);
225080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ j(above_equal, &return_not_equal);
225180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
225280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      // Check for oddballs: true, false, null, undefined.
225380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ CmpInstanceType(rcx, ODDBALL_TYPE);
225480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ j(equal, &return_not_equal);
225580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
225680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      // Fall through to the general case.
225780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    }
225880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ bind(&slow);
225980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
226080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
226180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Generate the number comparison code.
226280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  if (include_number_compare_) {
226380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    Label non_number_comparison;
22640d5e116f6aee03185f237311a943491bb079a768Kristian Monsen    NearLabel unordered;
226580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    FloatingPointHelper::LoadSSE2UnknownOperands(masm, &non_number_comparison);
226680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ xorl(rax, rax);
226780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ xorl(rcx, rcx);
226880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ ucomisd(xmm0, xmm1);
226980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
227080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // Don't base result on EFLAGS when a NaN is involved.
227180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ j(parity_even, &unordered);
227280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // Return a result of -1, 0, or 1, based on EFLAGS.
227380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ setcc(above, rax);
227480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ setcc(below, rcx);
227580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ subq(rax, rcx);
227680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ ret(0);
227780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
227880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // If one of the numbers was NaN, then the result is always false.
227980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // The cc is never not-equal.
228080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ bind(&unordered);
228180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    ASSERT(cc_ != not_equal);
228280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    if (cc_ == less || cc_ == less_equal) {
228380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ Set(rax, 1);
228480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    } else {
228580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ Set(rax, -1);
228680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    }
228780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ ret(0);
228880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
228980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // The number comparison code did not provide a valid result.
229080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ bind(&non_number_comparison);
229180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
229280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
229380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Fast negative check for symbol-to-symbol equality.
229480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label check_for_strings;
229580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  if (cc_ == equal) {
229680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    BranchIfNonSymbol(masm, &check_for_strings, rax, kScratchRegister);
229780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    BranchIfNonSymbol(masm, &check_for_strings, rdx, kScratchRegister);
229880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
229980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // We've already checked for object identity, so if both operands
230080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // are symbols they aren't equal. Register eax (not rax) already holds a
230180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // non-zero value, which indicates not equal, so just return.
230280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ ret(0);
230380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
230480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
230580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&check_for_strings);
230680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
230780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ JumpIfNotBothSequentialAsciiStrings(
230880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      rdx, rax, rcx, rbx, &check_unequal_objects);
230980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
231080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Inline comparison of ascii strings.
231180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  StringCompareStub::GenerateCompareFlatAsciiStrings(masm,
231280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                                     rdx,
231380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                                     rax,
231480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                                     rcx,
231580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                                     rbx,
231680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                                     rdi,
231780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                                     r8);
231880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
231980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#ifdef DEBUG
232080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ Abort("Unexpected fall-through from string comparison");
232180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#endif
232280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
232380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&check_unequal_objects);
232480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  if (cc_ == equal && !strict_) {
232580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // Not strict equality.  Objects are unequal if
232680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // they are both JSObjects and not undetectable,
232780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // and their pointers are different.
23280d5e116f6aee03185f237311a943491bb079a768Kristian Monsen    NearLabel not_both_objects, return_unequal;
232980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // At most one is a smi, so we can test for smi by adding the two.
233080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // A smi plus a heap object has the low bit set, a heap object plus
233180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // a heap object has the low bit clear.
233280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    STATIC_ASSERT(kSmiTag == 0);
233380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    STATIC_ASSERT(kSmiTagMask == 1);
233480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ lea(rcx, Operand(rax, rdx, times_1, 0));
233580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ testb(rcx, Immediate(kSmiTagMask));
233680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ j(not_zero, &not_both_objects);
233780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ CmpObjectType(rax, FIRST_JS_OBJECT_TYPE, rbx);
233880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ j(below, &not_both_objects);
233980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ CmpObjectType(rdx, FIRST_JS_OBJECT_TYPE, rcx);
234080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ j(below, &not_both_objects);
234180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ testb(FieldOperand(rbx, Map::kBitFieldOffset),
234280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen             Immediate(1 << Map::kIsUndetectable));
234380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ j(zero, &return_unequal);
234480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ testb(FieldOperand(rcx, Map::kBitFieldOffset),
234580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen             Immediate(1 << Map::kIsUndetectable));
234680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ j(zero, &return_unequal);
234780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // The objects are both undetectable, so they both compare as the value
234880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // undefined, and are equal.
234980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ Set(rax, EQUAL);
235080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ bind(&return_unequal);
235180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // Return non-equal by returning the non-zero object pointer in eax,
235280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // or return equal if we fell through to here.
235380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ ret(0);
235480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ bind(&not_both_objects);
235580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
235680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
235780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Push arguments below the return address to prepare jump to builtin.
235880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ pop(rcx);
235980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ push(rdx);
236080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ push(rax);
236180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
236280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Figure out which native to call and setup the arguments.
236380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Builtins::JavaScript builtin;
236480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  if (cc_ == equal) {
236580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    builtin = strict_ ? Builtins::STRICT_EQUALS : Builtins::EQUALS;
236680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  } else {
236780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    builtin = Builtins::COMPARE;
236880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ Push(Smi::FromInt(NegativeComparisonResult(cc_)));
236980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
237080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
237180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Restore return address on the stack.
237280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ push(rcx);
237380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
237480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Call the native; it returns -1 (less), 0 (equal), or 1 (greater)
237580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // tagged as a small integer.
237680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ InvokeBuiltin(builtin, JUMP_FUNCTION);
237780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
237880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
237980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
238080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid CompareStub::BranchIfNonSymbol(MacroAssembler* masm,
238180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                    Label* label,
238280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                    Register object,
238380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                    Register scratch) {
238480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ JumpIfSmi(object, label);
238580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(scratch, FieldOperand(object, HeapObject::kMapOffset));
238680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movzxbq(scratch,
238780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen             FieldOperand(scratch, Map::kInstanceTypeOffset));
238880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Ensure that no non-strings have the symbol bit set.
238980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  STATIC_ASSERT(LAST_TYPE < kNotStringTag + kIsSymbolMask);
239080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  STATIC_ASSERT(kSymbolTag != 0);
239180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ testb(scratch, Immediate(kIsSymbolMask));
239280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(zero, label);
239380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
239480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
239580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
239680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StackCheckStub::Generate(MacroAssembler* masm) {
2397f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  __ TailCallRuntime(Runtime::kStackGuard, 0, 1);
239880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
239980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
240080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
240180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid CallFunctionStub::Generate(MacroAssembler* masm) {
240280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label slow;
240380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
240480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // If the receiver might be a value (string, number or boolean) check for this
240580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // and box it if it is.
240680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  if (ReceiverMightBeValue()) {
240780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // Get the receiver from the stack.
240880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // +1 ~ return address
240980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    Label receiver_is_value, receiver_is_js_object;
241080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ movq(rax, Operand(rsp, (argc_ + 1) * kPointerSize));
241180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
241280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // Check if receiver is a smi (which is a number value).
241380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ JumpIfSmi(rax, &receiver_is_value);
241480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
241580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // Check if the receiver is a valid JS object.
241680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ CmpObjectType(rax, FIRST_JS_OBJECT_TYPE, rdi);
241780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ j(above_equal, &receiver_is_js_object);
241880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
241980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // Call the runtime to box the value.
242080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ bind(&receiver_is_value);
242180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ EnterInternalFrame();
242280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ push(rax);
242380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
242480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ LeaveInternalFrame();
242580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ movq(Operand(rsp, (argc_ + 1) * kPointerSize), rax);
242680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
242780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ bind(&receiver_is_js_object);
242880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
242980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
243080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Get the function to call from the stack.
243180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // +2 ~ receiver, return address
243280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rdi, Operand(rsp, (argc_ + 2) * kPointerSize));
243380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
243480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check that the function really is a JavaScript function.
243580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ JumpIfSmi(rdi, &slow);
243680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Goto slow case if we do not have a function.
243780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ CmpObjectType(rdi, JS_FUNCTION_TYPE, rcx);
243880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(not_equal, &slow);
243980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
244080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Fast-case: Just invoke the function.
244180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  ParameterCount actual(argc_);
244280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ InvokeFunction(rdi, actual, JUMP_FUNCTION);
244380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
244480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Slow-case: Non-function called.
244580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&slow);
244680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // CALL_NON_FUNCTION expects the non-function callee as receiver (instead
244780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // of the original receiver from the call site).
244880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(Operand(rsp, (argc_ + 1) * kPointerSize), rdi);
244980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ Set(rax, argc_);
245080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ Set(rbx, 0);
245180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ GetBuiltinEntry(rdx, Builtins::CALL_NON_FUNCTION);
245280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Handle<Code> adaptor(Builtins::builtin(Builtins::ArgumentsAdaptorTrampoline));
245380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ Jump(adaptor, RelocInfo::CODE_TARGET);
245480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
245580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
245680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
245780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid CEntryStub::GenerateThrowTOS(MacroAssembler* masm) {
245880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check that stack should contain next handler, frame pointer, state and
245980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // return address in that order.
246080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  STATIC_ASSERT(StackHandlerConstants::kFPOffset + kPointerSize ==
246180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen            StackHandlerConstants::kStateOffset);
246280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  STATIC_ASSERT(StackHandlerConstants::kStateOffset + kPointerSize ==
246380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen            StackHandlerConstants::kPCOffset);
246480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
246580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  ExternalReference handler_address(Top::k_handler_address);
246680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(kScratchRegister, handler_address);
246780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rsp, Operand(kScratchRegister, 0));
246880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // get next in chain
246980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ pop(rcx);
247080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(Operand(kScratchRegister, 0), rcx);
247180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ pop(rbp);  // pop frame pointer
247280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ pop(rdx);  // remove state
247380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
247480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Before returning we restore the context from the frame pointer if not NULL.
247580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // The frame pointer is NULL in the exception handler of a JS entry frame.
247680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ xor_(rsi, rsi);  // tentatively set context pointer to NULL
24770d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  NearLabel skip;
247880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cmpq(rbp, Immediate(0));
247980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(equal, &skip);
248080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
248180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&skip);
248280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ ret(0);
248380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
248480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
248580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
248680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid ApiGetterEntryStub::Generate(MacroAssembler* masm) {
248780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label empty_result;
248880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label prologue;
248980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label promote_scheduled_exception;
249080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ EnterApiExitFrame(kStackSpace, 0);
249180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  ASSERT_EQ(kArgc, 4);
249280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#ifdef _WIN64
249380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // All the parameters should be set up by a caller.
249480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#else
249580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Set 1st parameter register with property name.
249680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rsi, rdx);
249780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Second parameter register rdi should be set with pointer to AccessorInfo
249880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // by a caller.
249980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#endif
250080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Call the api function!
250180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rax,
250280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen          reinterpret_cast<int64_t>(fun()->address()),
250380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen          RelocInfo::RUNTIME_ENTRY);
250480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ call(rax);
250580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check if the function scheduled an exception.
250680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  ExternalReference scheduled_exception_address =
250780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      ExternalReference::scheduled_exception_address();
250880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rsi, scheduled_exception_address);
250980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ Cmp(Operand(rsi, 0), Factory::the_hole_value());
251080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(not_equal, &promote_scheduled_exception);
251180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#ifdef _WIN64
251280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rax keeps a pointer to v8::Handle, unpack it.
251380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rax, Operand(rax, 0));
251480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#endif
251580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check if the result handle holds 0.
251680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ testq(rax, rax);
251780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(zero, &empty_result);
251880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // It was non-zero.  Dereference to get the result value.
251980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rax, Operand(rax, 0));
252080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&prologue);
252180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ LeaveExitFrame();
252280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ ret(0);
252380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&promote_scheduled_exception);
252480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ TailCallRuntime(Runtime::kPromoteScheduledException, 0, 1);
252580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&empty_result);
252680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // It was zero; the result is undefined.
252780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ Move(rax, Factory::undefined_value());
252880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ jmp(&prologue);
252980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
253080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
253180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
253280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid CEntryStub::GenerateCore(MacroAssembler* masm,
253380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                              Label* throw_normal_exception,
253480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                              Label* throw_termination_exception,
253580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                              Label* throw_out_of_memory_exception,
253680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                              bool do_gc,
253780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                              bool always_allocate_scope,
253880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                              int /* alignment_skew */) {
253980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rax: result parameter for PerformGC, if any.
254080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rbx: pointer to C function  (C callee-saved).
254180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rbp: frame pointer  (restored after C call).
254280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rsp: stack pointer  (restored after C call).
254380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // r14: number of arguments including receiver (C callee-saved).
254480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // r12: pointer to the first argument (C callee-saved).
254580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  //      This pointer is reused in LeaveExitFrame(), so it is stored in a
254680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  //      callee-saved register.
254780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
254880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Simple results returned in rax (both AMD64 and Win64 calling conventions).
254980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Complex results must be written to address passed as first argument.
255080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // AMD64 calling convention: a struct of two pointers in rax+rdx
255180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
255280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check stack alignment.
255380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  if (FLAG_debug_code) {
255480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ CheckStackAlignment();
255580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
255680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
255780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  if (do_gc) {
255880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // Pass failure code returned from last attempt as first argument to
255980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // PerformGC. No need to use PrepareCallCFunction/CallCFunction here as the
256080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // stack is known to be aligned. This function takes one argument which is
256180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // passed in register.
256280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#ifdef _WIN64
256380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ movq(rcx, rax);
256480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#else  // _WIN64
256580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ movq(rdi, rax);
256680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#endif
256780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ movq(kScratchRegister,
256880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen            FUNCTION_ADDR(Runtime::PerformGC),
256980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen            RelocInfo::RUNTIME_ENTRY);
257080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ call(kScratchRegister);
257180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
257280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
257380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  ExternalReference scope_depth =
257480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      ExternalReference::heap_always_allocate_scope_depth();
257580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  if (always_allocate_scope) {
257680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ movq(kScratchRegister, scope_depth);
257780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ incl(Operand(kScratchRegister, 0));
257880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
257980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
258080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Call C function.
258180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#ifdef _WIN64
258280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Windows 64-bit ABI passes arguments in rcx, rdx, r8, r9
258380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Store Arguments object on stack, below the 4 WIN64 ABI parameter slots.
258480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(Operand(rsp, 4 * kPointerSize), r14);  // argc.
258580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(Operand(rsp, 5 * kPointerSize), r12);  // argv.
258680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  if (result_size_ < 2) {
258780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // Pass a pointer to the Arguments object as the first argument.
258880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // Return result in single register (rax).
258980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ lea(rcx, Operand(rsp, 4 * kPointerSize));
259080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  } else {
259180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    ASSERT_EQ(2, result_size_);
259280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // Pass a pointer to the result location as the first argument.
259380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ lea(rcx, Operand(rsp, 6 * kPointerSize));
259480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // Pass a pointer to the Arguments object as the second argument.
259580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ lea(rdx, Operand(rsp, 4 * kPointerSize));
259680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
259780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
259880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#else  // _WIN64
259980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // GCC passes arguments in rdi, rsi, rdx, rcx, r8, r9.
260080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rdi, r14);  // argc.
260180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rsi, r12);  // argv.
260280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#endif
260380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ call(rbx);
260480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Result is in rax - do not destroy this register!
260580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
260680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  if (always_allocate_scope) {
260780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ movq(kScratchRegister, scope_depth);
260880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ decl(Operand(kScratchRegister, 0));
260980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
261080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
261180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check for failure result.
261280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label failure_returned;
261380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  STATIC_ASSERT(((kFailureTag + 1) & kFailureTagMask) == 0);
261480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#ifdef _WIN64
261580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // If return value is on the stack, pop it to registers.
261680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  if (result_size_ > 1) {
261780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    ASSERT_EQ(2, result_size_);
261880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // Read result values stored on stack. Result is stored
261980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // above the four argument mirror slots and the two
262080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // Arguments object slots.
262180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ movq(rax, Operand(rsp, 6 * kPointerSize));
262280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ movq(rdx, Operand(rsp, 7 * kPointerSize));
262380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
262480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#endif
262580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ lea(rcx, Operand(rax, 1));
262680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Lower 2 bits of rcx are 0 iff rax has failure tag.
262780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ testl(rcx, Immediate(kFailureTagMask));
262880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(zero, &failure_returned);
262980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
263080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Exit the JavaScript to C++ exit frame.
263180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ LeaveExitFrame(result_size_);
263280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ ret(0);
263380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
263480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Handling of failure.
263580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&failure_returned);
263680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
26370d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  NearLabel retry;
263880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // If the returned exception is RETRY_AFTER_GC continue at retry label
263980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  STATIC_ASSERT(Failure::RETRY_AFTER_GC == 0);
264080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ testl(rax, Immediate(((1 << kFailureTypeTagSize) - 1) << kFailureTagSize));
264180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(zero, &retry);
264280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
264380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Special handling of out of memory exceptions.
264480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(kScratchRegister, Failure::OutOfMemoryException(), RelocInfo::NONE);
264580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cmpq(rax, kScratchRegister);
264680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(equal, throw_out_of_memory_exception);
264780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
264880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Retrieve the pending exception and clear the variable.
264980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  ExternalReference pending_exception_address(Top::k_pending_exception_address);
265080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(kScratchRegister, pending_exception_address);
265180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rax, Operand(kScratchRegister, 0));
265280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rdx, ExternalReference::the_hole_value_location());
265380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rdx, Operand(rdx, 0));
265480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(Operand(kScratchRegister, 0), rdx);
265580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
265680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Special handling of termination exceptions which are uncatchable
265780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // by javascript code.
265880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ CompareRoot(rax, Heap::kTerminationExceptionRootIndex);
265980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(equal, throw_termination_exception);
266080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
266180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Handle normal exception.
266280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ jmp(throw_normal_exception);
266380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
266480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Retry.
266580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&retry);
266680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
266780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
266880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
266980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid CEntryStub::GenerateThrowUncatchable(MacroAssembler* masm,
267080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                          UncatchableExceptionType type) {
267180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Fetch top stack handler.
267280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  ExternalReference handler_address(Top::k_handler_address);
267380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(kScratchRegister, handler_address);
267480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rsp, Operand(kScratchRegister, 0));
267580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
267680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Unwind the handlers until the ENTRY handler is found.
26770d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  NearLabel loop, done;
267880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&loop);
267980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Load the type of the current stack handler.
268080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  const int kStateOffset = StackHandlerConstants::kStateOffset;
268180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cmpq(Operand(rsp, kStateOffset), Immediate(StackHandler::ENTRY));
268280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(equal, &done);
268380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Fetch the next handler in the list.
268480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  const int kNextOffset = StackHandlerConstants::kNextOffset;
268580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rsp, Operand(rsp, kNextOffset));
268680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ jmp(&loop);
268780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&done);
268880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
268980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Set the top handler address to next handler past the current ENTRY handler.
269080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(kScratchRegister, handler_address);
269180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ pop(Operand(kScratchRegister, 0));
269280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
269380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  if (type == OUT_OF_MEMORY) {
269480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // Set external caught exception to false.
269580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    ExternalReference external_caught(Top::k_external_caught_exception_address);
269680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ movq(rax, Immediate(false));
269780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ store_rax(external_caught);
269880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
269980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // Set pending exception and rax to out of memory exception.
270080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    ExternalReference pending_exception(Top::k_pending_exception_address);
270180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ movq(rax, Failure::OutOfMemoryException(), RelocInfo::NONE);
270280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ store_rax(pending_exception);
270380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
270480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
270580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Clear the context pointer.
270680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ xor_(rsi, rsi);
270780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
270880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Restore registers from handler.
270980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  STATIC_ASSERT(StackHandlerConstants::kNextOffset + kPointerSize ==
271080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen            StackHandlerConstants::kFPOffset);
271180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ pop(rbp);  // FP
271280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  STATIC_ASSERT(StackHandlerConstants::kFPOffset + kPointerSize ==
271380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen            StackHandlerConstants::kStateOffset);
271480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ pop(rdx);  // State
271580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
271680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  STATIC_ASSERT(StackHandlerConstants::kStateOffset + kPointerSize ==
271780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen            StackHandlerConstants::kPCOffset);
271880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ ret(0);
271980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
272080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
272180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
272280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid CEntryStub::Generate(MacroAssembler* masm) {
272380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rax: number of arguments including receiver
272480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rbx: pointer to C function  (C callee-saved)
272580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rbp: frame pointer of calling JS frame (restored after C call)
272680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rsp: stack pointer  (restored after C call)
272780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rsi: current context (restored)
272880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
272980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // NOTE: Invocations of builtins may return failure objects
273080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // instead of a proper result. The builtin entry handles
273180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // this by performing a garbage collection and retrying the
273280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // builtin once.
273380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
273480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Enter the exit frame that transitions from JavaScript to C++.
273580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ EnterExitFrame(result_size_);
273680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
273780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rax: Holds the context at this point, but should not be used.
273880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  //      On entry to code generated by GenerateCore, it must hold
273980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  //      a failure result if the collect_garbage argument to GenerateCore
274080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  //      is true.  This failure result can be the result of code
274180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  //      generated by a previous call to GenerateCore.  The value
274280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  //      of rax is then passed to Runtime::PerformGC.
274380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rbx: pointer to builtin function  (C callee-saved).
274480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rbp: frame pointer of exit frame  (restored after C call).
274580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rsp: stack pointer (restored after C call).
274680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // r14: number of arguments including receiver (C callee-saved).
274780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // r12: argv pointer (C callee-saved).
274880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
274980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label throw_normal_exception;
275080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label throw_termination_exception;
275180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label throw_out_of_memory_exception;
275280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
275380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Call into the runtime system.
275480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  GenerateCore(masm,
275580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen               &throw_normal_exception,
275680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen               &throw_termination_exception,
275780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen               &throw_out_of_memory_exception,
275880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen               false,
275980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen               false);
276080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
276180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Do space-specific GC and retry runtime call.
276280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  GenerateCore(masm,
276380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen               &throw_normal_exception,
276480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen               &throw_termination_exception,
276580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen               &throw_out_of_memory_exception,
276680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen               true,
276780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen               false);
276880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
276980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Do full GC and retry runtime call one final time.
277080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Failure* failure = Failure::InternalError();
277180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rax, failure, RelocInfo::NONE);
277280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  GenerateCore(masm,
277380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen               &throw_normal_exception,
277480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen               &throw_termination_exception,
277580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen               &throw_out_of_memory_exception,
277680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen               true,
277780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen               true);
277880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
277980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&throw_out_of_memory_exception);
278080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  GenerateThrowUncatchable(masm, OUT_OF_MEMORY);
278180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
278280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&throw_termination_exception);
278380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  GenerateThrowUncatchable(masm, TERMINATION);
278480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
278580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&throw_normal_exception);
278680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  GenerateThrowTOS(masm);
278780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
278880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
278980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
279080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid JSEntryStub::GenerateBody(MacroAssembler* masm, bool is_construct) {
279180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label invoke, exit;
279280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#ifdef ENABLE_LOGGING_AND_PROFILING
279380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label not_outermost_js, not_outermost_js_2;
279480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#endif
279580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
279680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Setup frame.
279780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ push(rbp);
279880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rbp, rsp);
279980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
280080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Push the stack frame type marker twice.
280180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  int marker = is_construct ? StackFrame::ENTRY_CONSTRUCT : StackFrame::ENTRY;
280280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Scratch register is neither callee-save, nor an argument register on any
280380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // platform. It's free to use at this point.
280480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Cannot use smi-register for loading yet.
280580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(kScratchRegister,
280680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen          reinterpret_cast<uint64_t>(Smi::FromInt(marker)),
280780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen          RelocInfo::NONE);
280880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ push(kScratchRegister);  // context slot
280980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ push(kScratchRegister);  // function slot
281080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Save callee-saved registers (X64/Win64 calling conventions).
281180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ push(r12);
281280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ push(r13);
281380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ push(r14);
281480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ push(r15);
281580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#ifdef _WIN64
281680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ push(rdi);  // Only callee save in Win64 ABI, argument in AMD64 ABI.
281780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ push(rsi);  // Only callee save in Win64 ABI, argument in AMD64 ABI.
281880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#endif
281980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ push(rbx);
282080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // TODO(X64): On Win64, if we ever use XMM6-XMM15, the low low 64 bits are
282180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // callee save as well.
282280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
282380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Save copies of the top frame descriptor on the stack.
282480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  ExternalReference c_entry_fp(Top::k_c_entry_fp_address);
282580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ load_rax(c_entry_fp);
282680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ push(rax);
282780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
282880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Set up the roots and smi constant registers.
282980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Needs to be done before any further smi loads.
283080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  ExternalReference roots_address = ExternalReference::roots_address();
283180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(kRootRegister, roots_address);
283280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ InitializeSmiConstantRegister();
283380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
283480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#ifdef ENABLE_LOGGING_AND_PROFILING
283580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // If this is the outermost JS call, set js_entry_sp value.
283680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  ExternalReference js_entry_sp(Top::k_js_entry_sp_address);
283780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ load_rax(js_entry_sp);
283880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ testq(rax, rax);
283980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(not_zero, &not_outermost_js);
284080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rax, rbp);
284180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ store_rax(js_entry_sp);
284280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&not_outermost_js);
284380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#endif
284480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
284580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Call a faked try-block that does the invoke.
284680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ call(&invoke);
284780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
284880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Caught exception: Store result (exception) in the pending
284980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // exception field in the JSEnv and return a failure sentinel.
285080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  ExternalReference pending_exception(Top::k_pending_exception_address);
285180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ store_rax(pending_exception);
285280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rax, Failure::Exception(), RelocInfo::NONE);
285380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ jmp(&exit);
285480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
285580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Invoke: Link this frame into the handler chain.
285680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&invoke);
285780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ PushTryHandler(IN_JS_ENTRY, JS_ENTRY_HANDLER);
285880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
285980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Clear any pending exceptions.
286080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ load_rax(ExternalReference::the_hole_value_location());
286180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ store_rax(pending_exception);
286280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
286380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Fake a receiver (NULL).
286480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ push(Immediate(0));  // receiver
286580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
286680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Invoke the function by calling through JS entry trampoline
286780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // builtin and pop the faked function when we return. We load the address
286880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // from an external reference instead of inlining the call target address
286980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // directly in the code, because the builtin stubs may not have been
287080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // generated yet at the time this code is generated.
287180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  if (is_construct) {
287280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    ExternalReference construct_entry(Builtins::JSConstructEntryTrampoline);
287380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ load_rax(construct_entry);
287480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  } else {
287580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    ExternalReference entry(Builtins::JSEntryTrampoline);
287680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ load_rax(entry);
287780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
287880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ lea(kScratchRegister, FieldOperand(rax, Code::kHeaderSize));
287980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ call(kScratchRegister);
288080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
288180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Unlink this frame from the handler chain.
288280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(kScratchRegister, ExternalReference(Top::k_handler_address));
288380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ pop(Operand(kScratchRegister, 0));
288480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Pop next_sp.
288580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ addq(rsp, Immediate(StackHandlerConstants::kSize - kPointerSize));
288680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
288780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#ifdef ENABLE_LOGGING_AND_PROFILING
288880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // If current EBP value is the same as js_entry_sp value, it means that
288980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // the current function is the outermost.
289080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(kScratchRegister, js_entry_sp);
289180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cmpq(rbp, Operand(kScratchRegister, 0));
289280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(not_equal, &not_outermost_js_2);
289380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(Operand(kScratchRegister, 0), Immediate(0));
289480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&not_outermost_js_2);
289580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#endif
289680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
289780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Restore the top frame descriptor from the stack.
289880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&exit);
289980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(kScratchRegister, ExternalReference(Top::k_c_entry_fp_address));
290080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ pop(Operand(kScratchRegister, 0));
290180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
290280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Restore callee-saved registers (X64 conventions).
290380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ pop(rbx);
290480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#ifdef _WIN64
290580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Callee save on in Win64 ABI, arguments/volatile in AMD64 ABI.
290680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ pop(rsi);
290780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ pop(rdi);
290880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#endif
290980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ pop(r15);
291080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ pop(r14);
291180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ pop(r13);
291280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ pop(r12);
291380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ addq(rsp, Immediate(2 * kPointerSize));  // remove markers
291480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
291580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Restore frame pointer and return.
291680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ pop(rbp);
291780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ ret(0);
291880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
291980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
292080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
292180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid InstanceofStub::Generate(MacroAssembler* masm) {
292280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Implements "value instanceof function" operator.
292380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Expected input state:
292480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  //   rsp[0] : return address
292580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  //   rsp[1] : function pointer
292680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  //   rsp[2] : value
292780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Returns a bitwise zero to indicate that the value
292880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // is and instance of the function and anything else to
292980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // indicate that the value is not an instance.
293080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
293180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Get the object - go slow case if it's a smi.
293280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label slow;
293380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rax, Operand(rsp, 2 * kPointerSize));
293480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ JumpIfSmi(rax, &slow);
293580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
293680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check that the left hand is a JS object. Leave its map in rax.
293780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ CmpObjectType(rax, FIRST_JS_OBJECT_TYPE, rax);
293880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(below, &slow);
293980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ CmpInstanceType(rax, LAST_JS_OBJECT_TYPE);
294080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(above, &slow);
294180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
294280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Get the prototype of the function.
294380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rdx, Operand(rsp, 1 * kPointerSize));
294480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rdx is function, rax is map.
294580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
294680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Look up the function and the map in the instanceof cache.
29470d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  NearLabel miss;
294880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ CompareRoot(rdx, Heap::kInstanceofCacheFunctionRootIndex);
294980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(not_equal, &miss);
295080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ CompareRoot(rax, Heap::kInstanceofCacheMapRootIndex);
295180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(not_equal, &miss);
295280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ LoadRoot(rax, Heap::kInstanceofCacheAnswerRootIndex);
295380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ ret(2 * kPointerSize);
295480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
295580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&miss);
295680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ TryGetFunctionPrototype(rdx, rbx, &slow);
295780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
295880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check that the function prototype is a JS object.
295980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ JumpIfSmi(rbx, &slow);
296080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ CmpObjectType(rbx, FIRST_JS_OBJECT_TYPE, kScratchRegister);
296180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(below, &slow);
296280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ CmpInstanceType(kScratchRegister, LAST_JS_OBJECT_TYPE);
296380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(above, &slow);
296480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
296580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Register mapping:
296680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  //   rax is object map.
296780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  //   rdx is function.
296880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  //   rbx is function prototype.
296980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ StoreRoot(rdx, Heap::kInstanceofCacheFunctionRootIndex);
297080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ StoreRoot(rax, Heap::kInstanceofCacheMapRootIndex);
297180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
297280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rcx, FieldOperand(rax, Map::kPrototypeOffset));
297380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
297480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Loop through the prototype chain looking for the function prototype.
29750d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  NearLabel loop, is_instance, is_not_instance;
297680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ LoadRoot(kScratchRegister, Heap::kNullValueRootIndex);
297780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&loop);
297880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cmpq(rcx, rbx);
297980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(equal, &is_instance);
298080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cmpq(rcx, kScratchRegister);
298180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // The code at is_not_instance assumes that kScratchRegister contains a
298280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // non-zero GCable value (the null object in this case).
298380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(equal, &is_not_instance);
298480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rcx, FieldOperand(rcx, HeapObject::kMapOffset));
298580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rcx, FieldOperand(rcx, Map::kPrototypeOffset));
298680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ jmp(&loop);
298780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
298880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&is_instance);
298980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ xorl(rax, rax);
299080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Store bitwise zero in the cache.  This is a Smi in GC terms.
299180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  STATIC_ASSERT(kSmiTag == 0);
299280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ StoreRoot(rax, Heap::kInstanceofCacheAnswerRootIndex);
299380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ ret(2 * kPointerSize);
299480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
299580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&is_not_instance);
299680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // We have to store a non-zero value in the cache.
299780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ StoreRoot(kScratchRegister, Heap::kInstanceofCacheAnswerRootIndex);
299880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ ret(2 * kPointerSize);
299980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
300080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Slow-case: Go through the JavaScript implementation.
300180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&slow);
300280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION);
300380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
300480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
300580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
300680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenint CompareStub::MinorKey() {
300780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Encode the three parameters in a unique 16 bit value. To avoid duplicate
300880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // stubs the never NaN NaN condition is only taken into account if the
300980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // condition is equals.
301080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  ASSERT(static_cast<unsigned>(cc_) < (1 << 12));
301180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  ASSERT(lhs_.is(no_reg) && rhs_.is(no_reg));
301280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  return ConditionField::encode(static_cast<unsigned>(cc_))
301380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen         | RegisterField::encode(false)    // lhs_ and rhs_ are not used
301480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen         | StrictField::encode(strict_)
301580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen         | NeverNanNanField::encode(cc_ == equal ? never_nan_nan_ : false)
30160d5e116f6aee03185f237311a943491bb079a768Kristian Monsen         | IncludeNumberCompareField::encode(include_number_compare_)
30170d5e116f6aee03185f237311a943491bb079a768Kristian Monsen         | IncludeSmiCompareField::encode(include_smi_compare_);
301880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
301980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
302080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
302180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// Unfortunately you have to run without snapshots to see most of these
302280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// names in the profile since most compare stubs end up in the snapshot.
302380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenconst char* CompareStub::GetName() {
302480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  ASSERT(lhs_.is(no_reg) && rhs_.is(no_reg));
302580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
302680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  if (name_ != NULL) return name_;
302780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  const int kMaxNameLength = 100;
302880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  name_ = Bootstrapper::AllocateAutoDeletedArray(kMaxNameLength);
302980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  if (name_ == NULL) return "OOM";
303080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
303180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  const char* cc_name;
303280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  switch (cc_) {
303380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    case less: cc_name = "LT"; break;
303480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    case greater: cc_name = "GT"; break;
303580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    case less_equal: cc_name = "LE"; break;
303680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    case greater_equal: cc_name = "GE"; break;
303780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    case equal: cc_name = "EQ"; break;
303880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    case not_equal: cc_name = "NE"; break;
303980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    default: cc_name = "UnknownCondition"; break;
304080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
304180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
304280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  const char* strict_name = "";
304380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  if (strict_ && (cc_ == equal || cc_ == not_equal)) {
304480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    strict_name = "_STRICT";
304580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
304680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
304780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  const char* never_nan_nan_name = "";
304880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  if (never_nan_nan_ && (cc_ == equal || cc_ == not_equal)) {
304980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    never_nan_nan_name = "_NO_NAN";
305080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
305180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
305280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  const char* include_number_compare_name = "";
305380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  if (!include_number_compare_) {
305480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    include_number_compare_name = "_NO_NUMBER";
305580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
305680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
30570d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  const char* include_smi_compare_name = "";
30580d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  if (!include_smi_compare_) {
30590d5e116f6aee03185f237311a943491bb079a768Kristian Monsen    include_smi_compare_name = "_NO_SMI";
30600d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  }
30610d5e116f6aee03185f237311a943491bb079a768Kristian Monsen
306280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  OS::SNPrintF(Vector<char>(name_, kMaxNameLength),
306380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen               "CompareStub_%s%s%s%s",
306480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen               cc_name,
306580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen               strict_name,
306680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen               never_nan_nan_name,
30670d5e116f6aee03185f237311a943491bb079a768Kristian Monsen               include_number_compare_name,
30680d5e116f6aee03185f237311a943491bb079a768Kristian Monsen               include_smi_compare_name);
306980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  return name_;
307080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
307180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
307280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
307380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// -------------------------------------------------------------------------
307480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// StringCharCodeAtGenerator
307580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
307680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StringCharCodeAtGenerator::GenerateFast(MacroAssembler* masm) {
307780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label flat_string;
307880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label ascii_string;
307980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label got_char_code;
308080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
308180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // If the receiver is a smi trigger the non-string case.
308280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ JumpIfSmi(object_, receiver_not_string_);
308380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
308480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Fetch the instance type of the receiver into result register.
308580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(result_, FieldOperand(object_, HeapObject::kMapOffset));
308680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movzxbl(result_, FieldOperand(result_, Map::kInstanceTypeOffset));
308780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // If the receiver is not a string trigger the non-string case.
308880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ testb(result_, Immediate(kIsNotStringMask));
308980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(not_zero, receiver_not_string_);
309080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
309180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // If the index is non-smi trigger the non-smi case.
309280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ JumpIfNotSmi(index_, &index_not_smi_);
309380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
309480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Put smi-tagged index into scratch register.
309580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(scratch_, index_);
309680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&got_smi_index_);
309780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
309880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check for index out of range.
309980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiCompare(scratch_, FieldOperand(object_, String::kLengthOffset));
310080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(above_equal, index_out_of_range_);
310180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
310280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // We need special handling for non-flat strings.
310380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  STATIC_ASSERT(kSeqStringTag == 0);
310480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ testb(result_, Immediate(kStringRepresentationMask));
310580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(zero, &flat_string);
310680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
310780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Handle non-flat strings.
310880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ testb(result_, Immediate(kIsConsStringMask));
310980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(zero, &call_runtime_);
311080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
311180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // ConsString.
311280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check whether the right hand side is the empty string (i.e. if
311380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // this is really a flat string in a cons string). If that is not
311480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // the case we would rather go to the runtime system now to flatten
311580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // the string.
311680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ CompareRoot(FieldOperand(object_, ConsString::kSecondOffset),
311780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                 Heap::kEmptyStringRootIndex);
311880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(not_equal, &call_runtime_);
311980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Get the first of the two strings and load its instance type.
312080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(object_, FieldOperand(object_, ConsString::kFirstOffset));
312180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(result_, FieldOperand(object_, HeapObject::kMapOffset));
312280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movzxbl(result_, FieldOperand(result_, Map::kInstanceTypeOffset));
312380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // If the first cons component is also non-flat, then go to runtime.
312480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  STATIC_ASSERT(kSeqStringTag == 0);
312580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ testb(result_, Immediate(kStringRepresentationMask));
312680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(not_zero, &call_runtime_);
312780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
312880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check for 1-byte or 2-byte string.
312980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&flat_string);
313080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  STATIC_ASSERT(kAsciiStringTag != 0);
313180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ testb(result_, Immediate(kStringEncodingMask));
313280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(not_zero, &ascii_string);
313380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
313480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // 2-byte string.
313580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Load the 2-byte character code into the result register.
313680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiToInteger32(scratch_, scratch_);
313780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movzxwl(result_, FieldOperand(object_,
313880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                   scratch_, times_2,
313980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                   SeqTwoByteString::kHeaderSize));
314080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ jmp(&got_char_code);
314180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
314280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // ASCII string.
314380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Load the byte into the result register.
314480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&ascii_string);
314580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiToInteger32(scratch_, scratch_);
314680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movzxbl(result_, FieldOperand(object_,
314780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                   scratch_, times_1,
314880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                   SeqAsciiString::kHeaderSize));
314980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&got_char_code);
315080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ Integer32ToSmi(result_, result_);
315180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&exit_);
315280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
315380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
315480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
315580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StringCharCodeAtGenerator::GenerateSlow(
315680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    MacroAssembler* masm, const RuntimeCallHelper& call_helper) {
315780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ Abort("Unexpected fallthrough to CharCodeAt slow case");
315880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
315980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Index is not a smi.
316080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&index_not_smi_);
316180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // If index is a heap number, try converting it to an integer.
316280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ CheckMap(index_, Factory::heap_number_map(), index_not_number_, true);
316380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  call_helper.BeforeCall(masm);
316480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ push(object_);
316580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ push(index_);
316680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ push(index_);  // Consumed by runtime conversion function.
316780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  if (index_flags_ == STRING_INDEX_IS_NUMBER) {
316880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ CallRuntime(Runtime::kNumberToIntegerMapMinusZero, 1);
316980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  } else {
317080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    ASSERT(index_flags_ == STRING_INDEX_IS_ARRAY_INDEX);
317180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // NumberToSmi discards numbers that are not exact integers.
317280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ CallRuntime(Runtime::kNumberToSmi, 1);
317380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
317480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  if (!scratch_.is(rax)) {
317580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // Save the conversion result before the pop instructions below
317680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // have a chance to overwrite it.
317780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ movq(scratch_, rax);
317880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
317980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ pop(index_);
318080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ pop(object_);
318180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Reload the instance type.
318280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(result_, FieldOperand(object_, HeapObject::kMapOffset));
318380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movzxbl(result_, FieldOperand(result_, Map::kInstanceTypeOffset));
318480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  call_helper.AfterCall(masm);
318580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // If index is still not a smi, it must be out of range.
318680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ JumpIfNotSmi(scratch_, index_out_of_range_);
318780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Otherwise, return to the fast path.
318880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ jmp(&got_smi_index_);
318980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
319080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Call runtime. We get here when the receiver is a string and the
319180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // index is a number, but the code of getting the actual character
319280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // is too complex (e.g., when the string needs to be flattened).
319380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&call_runtime_);
319480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  call_helper.BeforeCall(masm);
319580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ push(object_);
319680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ push(index_);
319780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ CallRuntime(Runtime::kStringCharCodeAt, 2);
319880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  if (!result_.is(rax)) {
319980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ movq(result_, rax);
320080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
320180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  call_helper.AfterCall(masm);
320280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ jmp(&exit_);
320380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
320480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ Abort("Unexpected fallthrough from CharCodeAt slow case");
320580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
320680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
320780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
320880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// -------------------------------------------------------------------------
320980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// StringCharFromCodeGenerator
321080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
321180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StringCharFromCodeGenerator::GenerateFast(MacroAssembler* masm) {
321280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Fast case of Heap::LookupSingleCharacterStringFromCode.
321380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ JumpIfNotSmi(code_, &slow_case_);
321480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiCompare(code_, Smi::FromInt(String::kMaxAsciiCharCode));
321580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(above, &slow_case_);
321680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
321780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ LoadRoot(result_, Heap::kSingleCharacterStringCacheRootIndex);
321880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  SmiIndex index = masm->SmiToIndex(kScratchRegister, code_, kPointerSizeLog2);
321980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(result_, FieldOperand(result_, index.reg, index.scale,
322080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                FixedArray::kHeaderSize));
322180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ CompareRoot(result_, Heap::kUndefinedValueRootIndex);
322280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(equal, &slow_case_);
322380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&exit_);
322480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
322580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
322680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
322780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StringCharFromCodeGenerator::GenerateSlow(
322880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    MacroAssembler* masm, const RuntimeCallHelper& call_helper) {
322980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ Abort("Unexpected fallthrough to CharFromCode slow case");
323080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
323180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&slow_case_);
323280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  call_helper.BeforeCall(masm);
323380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ push(code_);
323480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ CallRuntime(Runtime::kCharFromCode, 1);
323580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  if (!result_.is(rax)) {
323680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ movq(result_, rax);
323780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
323880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  call_helper.AfterCall(masm);
323980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ jmp(&exit_);
324080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
324180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ Abort("Unexpected fallthrough from CharFromCode slow case");
324280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
324380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
324480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
324580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// -------------------------------------------------------------------------
324680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen// StringCharAtGenerator
324780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
324880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StringCharAtGenerator::GenerateFast(MacroAssembler* masm) {
324980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  char_code_at_generator_.GenerateFast(masm);
325080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  char_from_code_generator_.GenerateFast(masm);
325180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
325280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
325380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
325480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StringCharAtGenerator::GenerateSlow(
325580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    MacroAssembler* masm, const RuntimeCallHelper& call_helper) {
325680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  char_code_at_generator_.GenerateSlow(masm, call_helper);
325780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  char_from_code_generator_.GenerateSlow(masm, call_helper);
325880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
325980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
326080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
326180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StringAddStub::Generate(MacroAssembler* masm) {
326280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label string_add_runtime;
326380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
326480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Load the two arguments.
326580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rax, Operand(rsp, 2 * kPointerSize));  // First argument.
326680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rdx, Operand(rsp, 1 * kPointerSize));  // Second argument.
326780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
326880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Make sure that both arguments are strings if not known in advance.
326980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  if (string_check_) {
327080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    Condition is_smi;
327180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    is_smi = masm->CheckSmi(rax);
327280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ j(is_smi, &string_add_runtime);
327380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ CmpObjectType(rax, FIRST_NONSTRING_TYPE, r8);
327480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ j(above_equal, &string_add_runtime);
327580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
327680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // First argument is a a string, test second.
327780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    is_smi = masm->CheckSmi(rdx);
327880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ j(is_smi, &string_add_runtime);
327980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ CmpObjectType(rdx, FIRST_NONSTRING_TYPE, r9);
328080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ j(above_equal, &string_add_runtime);
328180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
328280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
328380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Both arguments are strings.
328480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rax: first string
328580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rdx: second string
328680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check if either of the strings are empty. In that case return the other.
32870d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  NearLabel second_not_zero_length, both_not_zero_length;
328880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rcx, FieldOperand(rdx, String::kLengthOffset));
328980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiTest(rcx);
329080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(not_zero, &second_not_zero_length);
329180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Second string is empty, result is first string which is already in rax.
329280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ IncrementCounter(&Counters::string_add_native, 1);
329380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ ret(2 * kPointerSize);
329480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&second_not_zero_length);
329580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rbx, FieldOperand(rax, String::kLengthOffset));
329680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiTest(rbx);
329780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(not_zero, &both_not_zero_length);
329880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // First string is empty, result is second string which is in rdx.
329980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rax, rdx);
330080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ IncrementCounter(&Counters::string_add_native, 1);
330180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ ret(2 * kPointerSize);
330280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
330380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Both strings are non-empty.
330480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rax: first string
330580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rbx: length of first string
330680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rcx: length of second string
330780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rdx: second string
330880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // r8: map of first string if string check was performed above
330980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // r9: map of second string if string check was performed above
331080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label string_add_flat_result, longer_than_two;
331180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&both_not_zero_length);
331280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
331380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // If arguments where known to be strings, maps are not loaded to r8 and r9
331480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // by the code above.
331580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  if (!string_check_) {
331680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ movq(r8, FieldOperand(rax, HeapObject::kMapOffset));
331780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ movq(r9, FieldOperand(rdx, HeapObject::kMapOffset));
331880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
331980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Get the instance types of the two strings as they will be needed soon.
332080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movzxbl(r8, FieldOperand(r8, Map::kInstanceTypeOffset));
332180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movzxbl(r9, FieldOperand(r9, Map::kInstanceTypeOffset));
332280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
332380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Look at the length of the result of adding the two strings.
332480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  STATIC_ASSERT(String::kMaxLength <= Smi::kMaxValue / 2);
33250d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  __ SmiAdd(rbx, rbx, rcx);
332680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Use the runtime system when adding two one character strings, as it
332780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // contains optimizations for this specific case using the symbol table.
332880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiCompare(rbx, Smi::FromInt(2));
332980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(not_equal, &longer_than_two);
333080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
333180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check that both strings are non-external ascii strings.
333280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ JumpIfBothInstanceTypesAreNotSequentialAscii(r8, r9, rbx, rcx,
333380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                                  &string_add_runtime);
333480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
333580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Get the two characters forming the sub string.
333680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movzxbq(rbx, FieldOperand(rax, SeqAsciiString::kHeaderSize));
333780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movzxbq(rcx, FieldOperand(rdx, SeqAsciiString::kHeaderSize));
333880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
333980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Try to lookup two character string in symbol table. If it is not found
334080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // just allocate a new one.
334180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label make_two_character_string, make_flat_ascii_string;
334280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  StringHelper::GenerateTwoCharacterSymbolTableProbe(
334380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      masm, rbx, rcx, r14, r11, rdi, r12, &make_two_character_string);
334480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ IncrementCounter(&Counters::string_add_native, 1);
334580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ ret(2 * kPointerSize);
334680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
334780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&make_two_character_string);
334880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ Set(rbx, 2);
334980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ jmp(&make_flat_ascii_string);
335080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
335180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&longer_than_two);
335280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check if resulting string will be flat.
335380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiCompare(rbx, Smi::FromInt(String::kMinNonFlatLength));
335480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(below, &string_add_flat_result);
335580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Handle exceptionally long strings in the runtime system.
335680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  STATIC_ASSERT((String::kMaxLength & 0x80000000) == 0);
335780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiCompare(rbx, Smi::FromInt(String::kMaxLength));
335880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(above, &string_add_runtime);
335980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
336080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // If result is not supposed to be flat, allocate a cons string object. If
336180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // both strings are ascii the result is an ascii cons string.
336280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rax: first string
336380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rbx: length of resulting flat string
336480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rdx: second string
336580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // r8: instance type of first string
336680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // r9: instance type of second string
336780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label non_ascii, allocated, ascii_data;
336880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movl(rcx, r8);
336980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ and_(rcx, r9);
337080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  STATIC_ASSERT(kStringEncodingMask == kAsciiStringTag);
337180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ testl(rcx, Immediate(kAsciiStringTag));
337280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(zero, &non_ascii);
337380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&ascii_data);
337480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Allocate an acsii cons string.
337580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ AllocateAsciiConsString(rcx, rdi, no_reg, &string_add_runtime);
337680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&allocated);
337780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Fill the fields of the cons string.
337880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(FieldOperand(rcx, ConsString::kLengthOffset), rbx);
337980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(FieldOperand(rcx, ConsString::kHashFieldOffset),
338080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen          Immediate(String::kEmptyHashField));
338180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(FieldOperand(rcx, ConsString::kFirstOffset), rax);
338280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(FieldOperand(rcx, ConsString::kSecondOffset), rdx);
338380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rax, rcx);
338480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ IncrementCounter(&Counters::string_add_native, 1);
338580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ ret(2 * kPointerSize);
338680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&non_ascii);
338780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // At least one of the strings is two-byte. Check whether it happens
338880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // to contain only ascii characters.
338980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rcx: first instance type AND second instance type.
339080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // r8: first instance type.
339180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // r9: second instance type.
339280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ testb(rcx, Immediate(kAsciiDataHintMask));
339380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(not_zero, &ascii_data);
339480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ xor_(r8, r9);
339580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  STATIC_ASSERT(kAsciiStringTag != 0 && kAsciiDataHintTag != 0);
339680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ andb(r8, Immediate(kAsciiStringTag | kAsciiDataHintTag));
339780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cmpb(r8, Immediate(kAsciiStringTag | kAsciiDataHintTag));
339880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(equal, &ascii_data);
339980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Allocate a two byte cons string.
340080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ AllocateConsString(rcx, rdi, no_reg, &string_add_runtime);
340180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ jmp(&allocated);
340280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
340380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Handle creating a flat result. First check that both strings are not
340480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // external strings.
340580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rax: first string
340680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rbx: length of resulting flat string as smi
340780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rdx: second string
340880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // r8: instance type of first string
340980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // r9: instance type of first string
341080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&string_add_flat_result);
341180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiToInteger32(rbx, rbx);
341280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movl(rcx, r8);
341380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ and_(rcx, Immediate(kStringRepresentationMask));
341480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cmpl(rcx, Immediate(kExternalStringTag));
341580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(equal, &string_add_runtime);
341680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movl(rcx, r9);
341780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ and_(rcx, Immediate(kStringRepresentationMask));
341880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cmpl(rcx, Immediate(kExternalStringTag));
341980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(equal, &string_add_runtime);
342080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Now check if both strings are ascii strings.
342180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rax: first string
342280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rbx: length of resulting flat string
342380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rdx: second string
342480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // r8: instance type of first string
342580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // r9: instance type of second string
342680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label non_ascii_string_add_flat_result;
342780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  STATIC_ASSERT(kStringEncodingMask == kAsciiStringTag);
342880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ testl(r8, Immediate(kAsciiStringTag));
342980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(zero, &non_ascii_string_add_flat_result);
343080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ testl(r9, Immediate(kAsciiStringTag));
343180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(zero, &string_add_runtime);
343280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
343380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&make_flat_ascii_string);
343480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Both strings are ascii strings. As they are short they are both flat.
343580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ AllocateAsciiString(rcx, rbx, rdi, r14, r11, &string_add_runtime);
343680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rcx: result string
343780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rbx, rcx);
343880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Locate first character of result.
343980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ addq(rcx, Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag));
344080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Locate first character of first argument
344180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiToInteger32(rdi, FieldOperand(rax, String::kLengthOffset));
344280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ addq(rax, Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag));
344380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rax: first char of first argument
344480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rbx: result string
344580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rcx: first character of result
344680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rdx: second string
344780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rdi: length of first argument
344880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  StringHelper::GenerateCopyCharacters(masm, rcx, rax, rdi, true);
344980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Locate first character of second argument.
345080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiToInteger32(rdi, FieldOperand(rdx, String::kLengthOffset));
345180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ addq(rdx, Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag));
345280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rbx: result string
345380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rcx: next character of result
345480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rdx: first char of second argument
345580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rdi: length of second argument
345680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  StringHelper::GenerateCopyCharacters(masm, rcx, rdx, rdi, true);
345780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rax, rbx);
345880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ IncrementCounter(&Counters::string_add_native, 1);
345980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ ret(2 * kPointerSize);
346080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
346180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Handle creating a flat two byte result.
346280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rax: first string - known to be two byte
346380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rbx: length of resulting flat string
346480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rdx: second string
346580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // r8: instance type of first string
346680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // r9: instance type of first string
346780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&non_ascii_string_add_flat_result);
346880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ and_(r9, Immediate(kAsciiStringTag));
346980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(not_zero, &string_add_runtime);
347080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Both strings are two byte strings. As they are short they are both
347180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // flat.
347280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ AllocateTwoByteString(rcx, rbx, rdi, r14, r11, &string_add_runtime);
347380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rcx: result string
347480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rbx, rcx);
347580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Locate first character of result.
347680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ addq(rcx, Immediate(SeqTwoByteString::kHeaderSize - kHeapObjectTag));
347780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Locate first character of first argument.
347880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiToInteger32(rdi, FieldOperand(rax, String::kLengthOffset));
347980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ addq(rax, Immediate(SeqTwoByteString::kHeaderSize - kHeapObjectTag));
348080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rax: first char of first argument
348180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rbx: result string
348280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rcx: first character of result
348380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rdx: second argument
348480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rdi: length of first argument
348580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  StringHelper::GenerateCopyCharacters(masm, rcx, rax, rdi, false);
348680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Locate first character of second argument.
348780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiToInteger32(rdi, FieldOperand(rdx, String::kLengthOffset));
348880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ addq(rdx, Immediate(SeqTwoByteString::kHeaderSize - kHeapObjectTag));
348980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rbx: result string
349080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rcx: next character of result
349180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rdx: first char of second argument
349280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rdi: length of second argument
349380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  StringHelper::GenerateCopyCharacters(masm, rcx, rdx, rdi, false);
349480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rax, rbx);
349580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ IncrementCounter(&Counters::string_add_native, 1);
349680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ ret(2 * kPointerSize);
349780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
349880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Just jump to runtime to add the two strings.
349980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&string_add_runtime);
350080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ TailCallRuntime(Runtime::kStringAdd, 2, 1);
350180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
350280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
350380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
350480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StringHelper::GenerateCopyCharacters(MacroAssembler* masm,
350580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                          Register dest,
350680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                          Register src,
350780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                          Register count,
350880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                          bool ascii) {
350980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label loop;
351080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&loop);
351180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // This loop just copies one character at a time, as it is only used for very
351280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // short strings.
351380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  if (ascii) {
351480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ movb(kScratchRegister, Operand(src, 0));
351580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ movb(Operand(dest, 0), kScratchRegister);
351680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ incq(src);
351780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ incq(dest);
351880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  } else {
351980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ movzxwl(kScratchRegister, Operand(src, 0));
352080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ movw(Operand(dest, 0), kScratchRegister);
352180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ addq(src, Immediate(2));
352280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ addq(dest, Immediate(2));
352380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
352480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ decl(count);
352580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(not_zero, &loop);
352680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
352780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
352880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
352980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StringHelper::GenerateCopyCharactersREP(MacroAssembler* masm,
353080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                             Register dest,
353180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                             Register src,
353280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                             Register count,
353380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                             bool ascii) {
353480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Copy characters using rep movs of doublewords. Align destination on 4 byte
353580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // boundary before starting rep movs. Copy remaining characters after running
353680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rep movs.
353780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Count is positive int32, dest and src are character pointers.
353880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  ASSERT(dest.is(rdi));  // rep movs destination
353980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  ASSERT(src.is(rsi));  // rep movs source
354080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  ASSERT(count.is(rcx));  // rep movs count
354180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
354280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Nothing to do for zero characters.
35430d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  NearLabel done;
354480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ testl(count, count);
354580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(zero, &done);
354680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
354780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Make count the number of bytes to copy.
354880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  if (!ascii) {
354980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    STATIC_ASSERT(2 == sizeof(uc16));
355080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ addl(count, count);
355180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
355280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
355380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Don't enter the rep movs if there are less than 4 bytes to copy.
35540d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  NearLabel last_bytes;
355580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ testl(count, Immediate(~7));
355680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(zero, &last_bytes);
355780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
355880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Copy from edi to esi using rep movs instruction.
355980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movl(kScratchRegister, count);
356080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ shr(count, Immediate(3));  // Number of doublewords to copy.
356180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ repmovsq();
356280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
356380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Find number of bytes left.
356480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movl(count, kScratchRegister);
356580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ and_(count, Immediate(7));
356680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
356780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check if there are more bytes to copy.
356880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&last_bytes);
356980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ testl(count, count);
357080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(zero, &done);
357180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
357280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Copy remaining characters.
357380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label loop;
357480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&loop);
357580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movb(kScratchRegister, Operand(src, 0));
357680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movb(Operand(dest, 0), kScratchRegister);
357780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ incq(src);
357880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ incq(dest);
357980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ decl(count);
358080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(not_zero, &loop);
358180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
358280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&done);
358380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
358480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
358580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StringHelper::GenerateTwoCharacterSymbolTableProbe(MacroAssembler* masm,
358680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                                        Register c1,
358780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                                        Register c2,
358880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                                        Register scratch1,
358980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                                        Register scratch2,
359080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                                        Register scratch3,
359180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                                        Register scratch4,
359280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                                        Label* not_found) {
359380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Register scratch3 is the general scratch register in this function.
359480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Register scratch = scratch3;
359580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
359680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Make sure that both characters are not digits as such strings has a
359780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // different hash algorithm. Don't try to look for these in the symbol table.
35980d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  NearLabel not_array_index;
359980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ leal(scratch, Operand(c1, -'0'));
360080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cmpl(scratch, Immediate(static_cast<int>('9' - '0')));
360180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(above, &not_array_index);
360280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ leal(scratch, Operand(c2, -'0'));
360380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cmpl(scratch, Immediate(static_cast<int>('9' - '0')));
360480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(below_equal, not_found);
360580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
360680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&not_array_index);
360780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Calculate the two character string hash.
360880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Register hash = scratch1;
360980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  GenerateHashInit(masm, hash, c1, scratch);
361080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  GenerateHashAddCharacter(masm, hash, c2, scratch);
361180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  GenerateHashGetHash(masm, hash, scratch);
361280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
361380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Collect the two characters in a register.
361480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Register chars = c1;
361580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ shl(c2, Immediate(kBitsPerByte));
361680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ orl(chars, c2);
361780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
361880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // chars: two character string, char 1 in byte 0 and char 2 in byte 1.
361980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // hash:  hash of two character string.
362080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
362180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Load the symbol table.
362280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Register symbol_table = c2;
362380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ LoadRoot(symbol_table, Heap::kSymbolTableRootIndex);
362480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
362580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Calculate capacity mask from the symbol table capacity.
362680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Register mask = scratch2;
362780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiToInteger32(mask,
362880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                    FieldOperand(symbol_table, SymbolTable::kCapacityOffset));
362980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ decl(mask);
363080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
363180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Register undefined = scratch4;
363280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ LoadRoot(undefined, Heap::kUndefinedValueRootIndex);
363380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
363480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Registers
363580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // chars:        two character string, char 1 in byte 0 and char 2 in byte 1.
363680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // hash:         hash of two character string (32-bit int)
363780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // symbol_table: symbol table
363880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // mask:         capacity mask (32-bit int)
363980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // undefined:    undefined value
364080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // scratch:      -
364180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
364280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Perform a number of probes in the symbol table.
364380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  static const int kProbes = 4;
364480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label found_in_symbol_table;
364580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label next_probe[kProbes];
364680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  for (int i = 0; i < kProbes; i++) {
364780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // Calculate entry in symbol table.
364880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ movl(scratch, hash);
364980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    if (i > 0) {
365080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      __ addl(scratch, Immediate(SymbolTable::GetProbeOffset(i)));
365180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    }
365280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ andl(scratch, mask);
365380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
365480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // Load the entry from the symble table.
365580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    Register candidate = scratch;  // Scratch register contains candidate.
365680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    STATIC_ASSERT(SymbolTable::kEntrySize == 1);
365780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ movq(candidate,
365880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen            FieldOperand(symbol_table,
365980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                         scratch,
366080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                         times_pointer_size,
366180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                         SymbolTable::kElementsStartOffset));
366280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
366380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // If entry is undefined no string with this hash can be found.
366480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ cmpq(candidate, undefined);
366580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ j(equal, not_found);
366680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
366780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // If length is not 2 the string is not a candidate.
366880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ SmiCompare(FieldOperand(candidate, String::kLengthOffset),
366980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                  Smi::FromInt(2));
367080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ j(not_equal, &next_probe[i]);
367180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
367280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // We use kScratchRegister as a temporary register in assumption that
367380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // JumpIfInstanceTypeIsNotSequentialAscii does not use it implicitly
367480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    Register temp = kScratchRegister;
367580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
367680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // Check that the candidate is a non-external ascii string.
367780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ movq(temp, FieldOperand(candidate, HeapObject::kMapOffset));
367880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ movzxbl(temp, FieldOperand(temp, Map::kInstanceTypeOffset));
367980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ JumpIfInstanceTypeIsNotSequentialAscii(
368080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen        temp, temp, &next_probe[i]);
368180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
368280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // Check if the two characters match.
368380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ movl(temp, FieldOperand(candidate, SeqAsciiString::kHeaderSize));
368480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ andl(temp, Immediate(0x0000ffff));
368580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ cmpl(chars, temp);
368680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ j(equal, &found_in_symbol_table);
368780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ bind(&next_probe[i]);
368880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
368980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
369080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // No matching 2 character string found by probing.
369180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ jmp(not_found);
369280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
369380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Scratch register contains result when we fall through to here.
369480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Register result = scratch;
369580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&found_in_symbol_table);
369680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  if (!result.is(rax)) {
369780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ movq(rax, result);
369880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
369980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
370080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
370180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
370280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StringHelper::GenerateHashInit(MacroAssembler* masm,
370380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                    Register hash,
370480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                    Register character,
370580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                    Register scratch) {
370680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // hash = character + (character << 10);
370780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movl(hash, character);
370880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ shll(hash, Immediate(10));
370980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ addl(hash, character);
371080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // hash ^= hash >> 6;
371180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movl(scratch, hash);
371280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ sarl(scratch, Immediate(6));
371380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ xorl(hash, scratch);
371480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
371580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
371680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
371780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StringHelper::GenerateHashAddCharacter(MacroAssembler* masm,
371880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                            Register hash,
371980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                            Register character,
372080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                            Register scratch) {
372180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // hash += character;
372280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ addl(hash, character);
372380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // hash += hash << 10;
372480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movl(scratch, hash);
372580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ shll(scratch, Immediate(10));
372680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ addl(hash, scratch);
372780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // hash ^= hash >> 6;
372880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movl(scratch, hash);
372980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ sarl(scratch, Immediate(6));
373080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ xorl(hash, scratch);
373180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
373280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
373380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
373480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StringHelper::GenerateHashGetHash(MacroAssembler* masm,
373580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                       Register hash,
373680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                       Register scratch) {
373780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // hash += hash << 3;
373880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ leal(hash, Operand(hash, hash, times_8, 0));
373980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // hash ^= hash >> 11;
374080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movl(scratch, hash);
374180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ sarl(scratch, Immediate(11));
374280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ xorl(hash, scratch);
374380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // hash += hash << 15;
374480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movl(scratch, hash);
374580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ shll(scratch, Immediate(15));
374680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ addl(hash, scratch);
374780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
374880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // if (hash == 0) hash = 27;
374980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label hash_not_zero;
375080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(not_zero, &hash_not_zero);
375180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movl(hash, Immediate(27));
375280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&hash_not_zero);
375380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
375480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
375580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid SubStringStub::Generate(MacroAssembler* masm) {
375680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label runtime;
375780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
375880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Stack frame on entry.
375980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  //  rsp[0]: return address
376080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  //  rsp[8]: to
376180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  //  rsp[16]: from
376280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  //  rsp[24]: string
376380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
376480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  const int kToOffset = 1 * kPointerSize;
376580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  const int kFromOffset = kToOffset + kPointerSize;
376680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  const int kStringOffset = kFromOffset + kPointerSize;
376780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  const int kArgumentsSize = (kStringOffset + kPointerSize) - kToOffset;
376880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
376980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Make sure first argument is a string.
377080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rax, Operand(rsp, kStringOffset));
377180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  STATIC_ASSERT(kSmiTag == 0);
377280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ testl(rax, Immediate(kSmiTagMask));
377380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(zero, &runtime);
377480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Condition is_string = masm->IsObjectStringType(rax, rbx, rbx);
377580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(NegateCondition(is_string), &runtime);
377680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
377780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rax: string
377880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rbx: instance type
377980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Calculate length of sub string using the smi values.
378080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label result_longer_than_two;
378180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rcx, Operand(rsp, kToOffset));
378280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rdx, Operand(rsp, kFromOffset));
3783f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  __ JumpUnlessBothNonNegativeSmi(rcx, rdx, &runtime);
378480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
37850d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  __ SmiSub(rcx, rcx, rdx);  // Overflow doesn't happen.
378680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cmpq(FieldOperand(rax, String::kLengthOffset), rcx);
378780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label return_rax;
378880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(equal, &return_rax);
378980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Special handling of sub-strings of length 1 and 2. One character strings
379080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // are handled in the runtime system (looked up in the single character
379180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // cache). Two character strings are looked for in the symbol cache.
379280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiToInteger32(rcx, rcx);
379380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cmpl(rcx, Immediate(2));
379480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(greater, &result_longer_than_two);
379580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(less, &runtime);
379680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
379780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Sub string of length 2 requested.
379880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rax: string
379980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rbx: instance type
380080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rcx: sub string length (value is 2)
380180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rdx: from index (smi)
380280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ JumpIfInstanceTypeIsNotSequentialAscii(rbx, rbx, &runtime);
380380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
380480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Get the two characters forming the sub string.
380580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiToInteger32(rdx, rdx);  // From index is no longer smi.
380680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movzxbq(rbx, FieldOperand(rax, rdx, times_1, SeqAsciiString::kHeaderSize));
380780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movzxbq(rcx,
380880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen             FieldOperand(rax, rdx, times_1, SeqAsciiString::kHeaderSize + 1));
380980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
381080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Try to lookup two character string in symbol table.
381180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label make_two_character_string;
381280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  StringHelper::GenerateTwoCharacterSymbolTableProbe(
381380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      masm, rbx, rcx, rax, rdx, rdi, r14, &make_two_character_string);
381480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ ret(3 * kPointerSize);
381580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
381680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&make_two_character_string);
381780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Setup registers for allocating the two character string.
381880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rax, Operand(rsp, kStringOffset));
381980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rbx, FieldOperand(rax, HeapObject::kMapOffset));
382080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movzxbl(rbx, FieldOperand(rbx, Map::kInstanceTypeOffset));
382180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ Set(rcx, 2);
382280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
382380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&result_longer_than_two);
382480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
382580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rax: string
382680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rbx: instance type
382780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rcx: result string length
382880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check for flat ascii string
382980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label non_ascii_flat;
383080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ JumpIfInstanceTypeIsNotSequentialAscii(rbx, rbx, &non_ascii_flat);
383180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
383280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Allocate the result.
383380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ AllocateAsciiString(rax, rcx, rbx, rdx, rdi, &runtime);
383480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
383580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rax: result string
383680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rcx: result string length
383780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rdx, rsi);  // esi used by following code.
383880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Locate first character of result.
383980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ lea(rdi, FieldOperand(rax, SeqAsciiString::kHeaderSize));
384080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Load string argument and locate character of sub string start.
384180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rsi, Operand(rsp, kStringOffset));
384280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rbx, Operand(rsp, kFromOffset));
384380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  {
384480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    SmiIndex smi_as_index = masm->SmiToIndex(rbx, rbx, times_1);
384580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ lea(rsi, Operand(rsi, smi_as_index.reg, smi_as_index.scale,
384680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                        SeqAsciiString::kHeaderSize - kHeapObjectTag));
384780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
384880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
384980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rax: result string
385080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rcx: result length
385180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rdx: original value of rsi
385280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rdi: first character of result
385380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rsi: character of sub string start
385480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  StringHelper::GenerateCopyCharactersREP(masm, rdi, rsi, rcx, true);
385580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rsi, rdx);  // Restore rsi.
385680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ IncrementCounter(&Counters::sub_string_native, 1);
385780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ ret(kArgumentsSize);
385880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
385980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&non_ascii_flat);
386080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rax: string
386180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rbx: instance type & kStringRepresentationMask | kStringEncodingMask
386280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rcx: result string length
386380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check for sequential two byte string
386480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cmpb(rbx, Immediate(kSeqStringTag | kTwoByteStringTag));
386580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(not_equal, &runtime);
386680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
386780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Allocate the result.
386880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ AllocateTwoByteString(rax, rcx, rbx, rdx, rdi, &runtime);
386980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
387080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rax: result string
387180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rcx: result string length
387280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rdx, rsi);  // esi used by following code.
387380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Locate first character of result.
387480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ lea(rdi, FieldOperand(rax, SeqTwoByteString::kHeaderSize));
387580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Load string argument and locate character of sub string start.
387680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rsi, Operand(rsp, kStringOffset));
387780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rbx, Operand(rsp, kFromOffset));
387880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  {
387980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    SmiIndex smi_as_index = masm->SmiToIndex(rbx, rbx, times_2);
388080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ lea(rsi, Operand(rsi, smi_as_index.reg, smi_as_index.scale,
388180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                        SeqAsciiString::kHeaderSize - kHeapObjectTag));
388280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
388380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
388480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rax: result string
388580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rcx: result length
388680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rdx: original value of rsi
388780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rdi: first character of result
388880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // rsi: character of sub string start
388980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  StringHelper::GenerateCopyCharactersREP(masm, rdi, rsi, rcx, false);
389080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rsi, rdx);  // Restore esi.
389180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
389280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&return_rax);
389380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ IncrementCounter(&Counters::sub_string_native, 1);
389480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ ret(kArgumentsSize);
389580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
389680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Just jump to runtime to create the sub string.
389780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&runtime);
389880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ TailCallRuntime(Runtime::kSubString, 3, 1);
389980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
390080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
390180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
390280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StringCompareStub::GenerateCompareFlatAsciiStrings(MacroAssembler* masm,
390380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                                        Register left,
390480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                                        Register right,
390580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                                        Register scratch1,
390680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                                        Register scratch2,
390780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                                        Register scratch3,
390880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                                        Register scratch4) {
390980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Ensure that you can always subtract a string length from a non-negative
391080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // number (e.g. another length).
391180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  STATIC_ASSERT(String::kMaxLength < 0x7fffffff);
391280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
391380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Find minimum length and length difference.
391480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(scratch1, FieldOperand(left, String::kLengthOffset));
391580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(scratch4, scratch1);
391680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiSub(scratch4,
391780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen            scratch4,
39180d5e116f6aee03185f237311a943491bb079a768Kristian Monsen            FieldOperand(right, String::kLengthOffset));
391980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Register scratch4 now holds left.length - right.length.
392080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  const Register length_difference = scratch4;
39210d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  NearLabel left_shorter;
392280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(less, &left_shorter);
392380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // The right string isn't longer that the left one.
392480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Get the right string's length by subtracting the (non-negative) difference
392580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // from the left string's length.
39260d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  __ SmiSub(scratch1, scratch1, length_difference);
392780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&left_shorter);
392880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Register scratch1 now holds Min(left.length, right.length).
392980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  const Register min_length = scratch1;
393080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
39310d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  NearLabel compare_lengths;
393280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // If min-length is zero, go directly to comparing lengths.
393380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiTest(min_length);
393480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(zero, &compare_lengths);
393580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
393680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiToInteger32(min_length, min_length);
393780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
393880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Registers scratch2 and scratch3 are free.
39390d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  NearLabel result_not_equal;
394080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label loop;
394180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  {
394280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // Check characters 0 .. min_length - 1 in a loop.
394380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // Use scratch3 as loop index, min_length as limit and scratch2
394480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // for computation.
394580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    const Register index = scratch3;
394680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ movl(index, Immediate(0));  // Index into strings.
394780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ bind(&loop);
394880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // Compare characters.
394980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // TODO(lrn): Could we load more than one character at a time?
395080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ movb(scratch2, FieldOperand(left,
395180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                   index,
395280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                   times_1,
395380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                   SeqAsciiString::kHeaderSize));
395480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // Increment index and use -1 modifier on next load to give
395580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    // the previous load extra time to complete.
395680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ addl(index, Immediate(1));
395780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ cmpb(scratch2, FieldOperand(right,
395880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                   index,
395980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                   times_1,
396080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                   SeqAsciiString::kHeaderSize - 1));
396180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ j(not_equal, &result_not_equal);
396280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ cmpl(index, min_length);
396380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    __ j(not_equal, &loop);
396480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
396580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Completed loop without finding different characters.
396680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Compare lengths (precomputed).
396780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&compare_lengths);
396880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiTest(length_difference);
396980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(not_zero, &result_not_equal);
397080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
397180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Result is EQUAL.
397280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ Move(rax, Smi::FromInt(EQUAL));
397380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ ret(0);
397480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
39750d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  NearLabel result_greater;
397680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&result_not_equal);
397780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Unequal comparison of left to right, either character or length.
397880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(greater, &result_greater);
397980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
398080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Result is LESS.
398180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ Move(rax, Smi::FromInt(LESS));
398280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ ret(0);
398380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
398480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Result is GREATER.
398580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&result_greater);
398680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ Move(rax, Smi::FromInt(GREATER));
398780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ ret(0);
398880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
398980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
399080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
399180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid StringCompareStub::Generate(MacroAssembler* masm) {
399280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label runtime;
399380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
399480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Stack frame on entry.
399580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  //  rsp[0]: return address
399680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  //  rsp[8]: right string
399780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  //  rsp[16]: left string
399880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
399980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rdx, Operand(rsp, 2 * kPointerSize));  // left
400080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ movq(rax, Operand(rsp, 1 * kPointerSize));  // right
400180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
400280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check for identity.
40030d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  NearLabel not_same;
400480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ cmpq(rdx, rax);
400580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(not_equal, &not_same);
400680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ Move(rax, Smi::FromInt(EQUAL));
400780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ IncrementCounter(&Counters::string_compare_native, 1);
400880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ ret(2 * kPointerSize);
400980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
401080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&not_same);
401180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
401280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Check that both are sequential ASCII strings.
401380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ JumpIfNotBothSequentialAsciiStrings(rdx, rax, rcx, rbx, &runtime);
401480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
401580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Inline comparison of ascii strings.
401680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ IncrementCounter(&Counters::string_compare_native, 1);
401780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Drop arguments from the stack
401880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ pop(rcx);
401980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ addq(rsp, Immediate(2 * kPointerSize));
402080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ push(rcx);
402180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  GenerateCompareFlatAsciiStrings(masm, rdx, rax, rcx, rbx, rdi, r8);
402280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
402380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Call the runtime; it returns -1 (less), 0 (equal), or 1 (greater)
402480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // tagged as a small integer.
402580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&runtime);
402680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ TailCallRuntime(Runtime::kStringCompare, 2, 1);
402780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
402880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
402980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#undef __
403080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
403180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen} }  // namespace v8::internal
403280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
403380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#endif  // V8_TARGET_ARCH_X64
4034