1b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch// Copyright 2013 the V8 project authors. All rights reserved.
2b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch// Use of this source code is governed by a BSD-style license that can be
3b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch// found in the LICENSE file.
480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
5b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#if V8_TARGET_ARCH_X64
680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
73b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch#include "src/api-arguments.h"
83b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch#include "src/bootstrapper.h"
962ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch#include "src/code-stubs.h"
10b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#include "src/codegen.h"
1162ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch#include "src/counters.h"
1262ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch#include "src/double.h"
1362ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch#include "src/heap/heap-inl.h"
14b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#include "src/ic/handler-compiler.h"
15b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#include "src/ic/ic.h"
16014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch#include "src/ic/stub-cache.h"
17b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#include "src/isolate.h"
1862ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch#include "src/objects-inl.h"
1962ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch#include "src/objects/regexp-match-info.h"
20014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch#include "src/regexp/jsregexp.h"
21014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch#include "src/regexp/regexp-macro-assembler.h"
22958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier#include "src/runtime/runtime.h"
2362ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch
2462ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch#include "src/x64/code-stubs-x64.h"  // Cannot be the first include.
2580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
26b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochnamespace v8 {
27b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochnamespace internal {
2880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
2913e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch#define __ ACCESS_MASM(masm)
3080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
3113e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdochvoid ArrayNArgumentsConstructorStub::Generate(MacroAssembler* masm) {
3213e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  __ popq(rcx);
3313e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  __ movq(MemOperand(rsp, rax, times_8, 0), rdi);
3413e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  __ pushq(rdi);
3513e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  __ pushq(rbx);
3613e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  __ pushq(rcx);
3713e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  __ addq(rax, Immediate(3));
3813e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  __ TailCallRuntime(Runtime::kNewArray);
3980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
4080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
41b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochvoid HydrogenCodeStub::GenerateLightweightMiss(MacroAssembler* masm,
42b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                                               ExternalReference miss) {
43b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // Update the static counter each time a new code stub is generated.
44b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  isolate()->counters()->code_stubs()->Increment();
4580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
46b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  CallInterfaceDescriptor descriptor = GetCallInterfaceDescriptor();
47014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  int param_count = descriptor.GetRegisterParameterCount();
48b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  {
49b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    // Call the runtime system in a fresh internal frame.
50b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    FrameScope scope(masm, StackFrame::INTERNAL);
51b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    DCHECK(param_count == 0 ||
52014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch           rax.is(descriptor.GetRegisterParameter(param_count - 1)));
53b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    // Push arguments
54b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    for (int i = 0; i < param_count; ++i) {
55014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      __ Push(descriptor.GetRegisterParameter(i));
5669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    }
57b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    __ CallExternalReference(miss, param_count);
5869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  }
5980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
60b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ Ret();
6169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch}
6280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
6369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch
643ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochvoid StoreBufferOverflowStub::Generate(MacroAssembler* masm) {
65b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ PushCallerSaved(save_doubles() ? kSaveFPRegs : kDontSaveFPRegs);
663ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  const int argument_count = 1;
673ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ PrepareCallCFunction(argument_count);
68b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ LoadAddress(arg_reg_1,
69b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                 ExternalReference::isolate_address(isolate()));
703ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
713ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  AllowExternalCallThatCantCauseGC scope(masm);
723ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ CallCFunction(
73b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      ExternalReference::store_buffer_overflow_function(isolate()),
743ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      argument_count);
75b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ PopCallerSaved(save_doubles() ? kSaveFPRegs : kDontSaveFPRegs);
763ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ ret(0);
773ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch}
783ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
793ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
8080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenclass FloatingPointHelper : public AllStatic {
8180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen public:
82b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  enum ConvertUndefined {
83b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    CONVERT_UNDEFINED_TO_ZERO,
84b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    BAILOUT_ON_UNDEFINED
85b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  };
8680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Load the operands from rdx and rax into xmm0 and xmm1, as doubles.
8780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // If the operands are not both numbers, jump to not_numbers.
8880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Leaves rdx and rax unchanged.  SmiOperands assumes both are smis.
8980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // NumberOperands assumes both are smis or heap numbers.
9080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  static void LoadSSE2UnknownOperands(MacroAssembler* masm,
9180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                      Label* not_numbers);
928b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch};
9380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
9480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
95b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochvoid DoubleToIStub::Generate(MacroAssembler* masm) {
96b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    Register input_reg = this->source();
97b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    Register final_result_reg = this->destination();
98b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    DCHECK(is_truncating());
993fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
100b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    Label check_negative, process_64_bits, done;
101086aeeaae12517475c22695a200be45495516549Ben Murdoch
102b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    int double_offset = offset();
1031e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
104b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    // Account for return address and saved regs if input is rsp.
105b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    if (input_reg.is(rsp)) double_offset += 3 * kRegisterSize;
106086aeeaae12517475c22695a200be45495516549Ben Murdoch
107b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    MemOperand mantissa_operand(MemOperand(input_reg, double_offset));
108b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    MemOperand exponent_operand(MemOperand(input_reg,
109b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                                           double_offset + kDoubleSize / 2));
1101e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
111b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    Register scratch1;
112b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    Register scratch_candidates[3] = { rbx, rdx, rdi };
113b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    for (int i = 0; i < 3; i++) {
114b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      scratch1 = scratch_candidates[i];
115b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      if (!final_result_reg.is(scratch1) && !input_reg.is(scratch1)) break;
1168b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch    }
1171e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
118b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    // Since we must use rcx for shifts below, use some other register (rax)
119b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    // to calculate the result if ecx is the requested return register.
120b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    Register result_reg = final_result_reg.is(rcx) ? rax : final_result_reg;
121b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    // Save ecx if it isn't the return register and therefore volatile, or if it
122b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    // is the return register, then save the temp register we use in its stead
123b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    // for the result.
124b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    Register save_reg = final_result_reg.is(rcx) ? rax : rcx;
125b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    __ pushq(scratch1);
126b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    __ pushq(save_reg);
127b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
128b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    bool stash_exponent_copy = !input_reg.is(rsp);
129b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    __ movl(scratch1, mantissa_operand);
13013e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch    __ Movsd(kScratchDoubleReg, mantissa_operand);
131b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    __ movl(rcx, exponent_operand);
132b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    if (stash_exponent_copy) __ pushq(rcx);
133b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
134b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    __ andl(rcx, Immediate(HeapNumber::kExponentMask));
135b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    __ shrl(rcx, Immediate(HeapNumber::kExponentShift));
136b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    __ leal(result_reg, MemOperand(rcx, -HeapNumber::kExponentBias));
137b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    __ cmpl(result_reg, Immediate(HeapNumber::kMantissaBits));
138b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    __ j(below, &process_64_bits);
139b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
140b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    // Result is entirely in lower 32-bits of mantissa
141b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    int delta = HeapNumber::kExponentBias + Double::kPhysicalSignificandSize;
142b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    __ subl(rcx, Immediate(delta));
143b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    __ xorl(result_reg, result_reg);
144b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    __ cmpl(rcx, Immediate(31));
145b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    __ j(above, &done);
146b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    __ shll_cl(scratch1);
147b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    __ jmp(&check_negative);
148b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
149b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    __ bind(&process_64_bits);
15013e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch    __ Cvttsd2siq(result_reg, kScratchDoubleReg);
151b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    __ jmp(&done, Label::kNear);
152b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
153b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    // If the double was negative, negate the integer result.
154b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    __ bind(&check_negative);
155b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    __ movl(result_reg, scratch1);
156b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    __ negl(result_reg);
157b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    if (stash_exponent_copy) {
158b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        __ cmpl(MemOperand(rsp, 0), Immediate(0));
1598b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch    } else {
160b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        __ cmpl(exponent_operand, Immediate(0));
1611e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    }
162b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    __ cmovl(greater, result_reg, scratch1);
16380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
164b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    // Restore registers
165b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    __ bind(&done);
166b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    if (stash_exponent_copy) {
167b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        __ addp(rsp, Immediate(kDoubleSize));
168b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    }
169b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    if (!final_result_reg.is(result_reg)) {
170b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        DCHECK(final_result_reg.is(rcx));
171b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        __ movl(final_result_reg, result_reg);
172b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    }
173b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    __ popq(save_reg);
174b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    __ popq(scratch1);
175b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    __ ret(0);
17680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
17780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
17880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
17980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsenvoid FloatingPointHelper::LoadSSE2UnknownOperands(MacroAssembler* masm,
18080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                                                  Label* not_numbers) {
18180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  Label load_smi_rdx, load_nonsmi_rax, load_smi_rax, load_float_rax, done;
18280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Load operand in rdx into xmm0, or branch to not_numbers.
18380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ LoadRoot(rcx, Heap::kHeapNumberMapRootIndex);
18480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ JumpIfSmi(rdx, &load_smi_rdx);
185b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ cmpp(FieldOperand(rdx, HeapObject::kMapOffset), rcx);
18680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(not_equal, not_numbers);  // Argument in rdx is not a number.
187014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ Movsd(xmm0, FieldOperand(rdx, HeapNumber::kValueOffset));
18880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  // Load operand in rax into xmm1, or branch to not_numbers.
18980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ JumpIfSmi(rax, &load_smi_rax);
19080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
19180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&load_nonsmi_rax);
192b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ cmpp(FieldOperand(rax, HeapObject::kMapOffset), rcx);
19380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ j(not_equal, not_numbers);
194014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ Movsd(xmm1, FieldOperand(rax, HeapNumber::kValueOffset));
19580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ jmp(&done);
19680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
19780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&load_smi_rdx);
19880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiToInteger32(kScratchRegister, rdx);
199b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ Cvtlsi2sd(xmm0, kScratchRegister);
20080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ JumpIfNotSmi(rax, &load_nonsmi_rax);
20180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
20280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&load_smi_rax);
20380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ SmiToInteger32(kScratchRegister, rax);
204b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ Cvtlsi2sd(xmm1, kScratchRegister);
20580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ bind(&done);
20680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
20780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
20880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
209e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdochvoid MathPowStub::Generate(MacroAssembler* masm) {
210b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  const Register exponent = MathPowTaggedDescriptor::exponent();
211b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  DCHECK(exponent.is(rdx));
2123ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  const Register scratch = rcx;
2133ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  const XMMRegister double_result = xmm3;
2143ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  const XMMRegister double_base = xmm2;
2153ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  const XMMRegister double_exponent = xmm1;
2163ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  const XMMRegister double_scratch = xmm4;
217e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
2183ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  Label call_runtime, done, exponent_not_smi, int_exponent;
219e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
2203ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Save 1 in double_result - we need this several times later on.
221b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ movp(scratch, Immediate(1));
222b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ Cvtlsi2sd(double_result, scratch);
2233ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
224f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  if (exponent_type() == TAGGED) {
2253ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ JumpIfNotSmi(exponent, &exponent_not_smi, Label::kNear);
2263ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ SmiToInteger32(exponent, exponent);
2273ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ jmp(&int_exponent);
2283ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
2293ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ bind(&exponent_not_smi);
230014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ Movsd(double_exponent, FieldOperand(exponent, HeapNumber::kValueOffset));
2313ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  }
232e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
233b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  if (exponent_type() != INTEGER) {
234b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    Label fast_power, try_arithmetic_simplification;
2353ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    // Detect integer exponents stored as double.
236b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    __ DoubleToI(exponent, double_exponent, double_scratch,
237b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                 TREAT_MINUS_ZERO_AS_ZERO, &try_arithmetic_simplification,
238b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                 &try_arithmetic_simplification,
239b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                 &try_arithmetic_simplification);
240b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    __ jmp(&int_exponent);
241b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
242b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    __ bind(&try_arithmetic_simplification);
243014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ Cvttsd2si(exponent, double_exponent);
2443ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    // Skip to runtime if possibly NaN (indicated by the indefinite integer).
245b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    __ cmpl(exponent, Immediate(0x1));
246b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    __ j(overflow, &call_runtime);
247b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
2483ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    // Using FPU instructions to calculate power.
2493ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    Label fast_power_failed;
2503ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ bind(&fast_power);
2513ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ fnclex();  // Clear flags to catch exceptions later.
2523ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    // Transfer (B)ase and (E)xponent onto the FPU register stack.
253b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    __ subp(rsp, Immediate(kDoubleSize));
254014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ Movsd(Operand(rsp, 0), double_exponent);
2553ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ fld_d(Operand(rsp, 0));  // E
256014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ Movsd(Operand(rsp, 0), double_base);
2573ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ fld_d(Operand(rsp, 0));  // B, E
2583ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
2593ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    // Exponent is in st(1) and base is in st(0)
2603ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    // B ^ E = (2^(E * log2(B)) - 1) + 1 = (2^X - 1) + 1 for X = E * log2(B)
2613ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    // FYL2X calculates st(1) * log2(st(0))
2623ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ fyl2x();    // X
2633ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ fld(0);     // X, X
2643ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ frndint();  // rnd(X), X
2653ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ fsub(1);    // rnd(X), X-rnd(X)
2663ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ fxch(1);    // X - rnd(X), rnd(X)
2673ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    // F2XM1 calculates 2^st(0) - 1 for -1 < st(0) < 1
2683ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ f2xm1();    // 2^(X-rnd(X)) - 1, rnd(X)
2693ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ fld1();     // 1, 2^(X-rnd(X)) - 1, rnd(X)
270b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    __ faddp(1);   // 2^(X-rnd(X)), rnd(X)
2713ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    // FSCALE calculates st(0) * 2^st(1)
2723ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ fscale();   // 2^X, rnd(X)
2733ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ fstp(1);
2743ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    // Bail out to runtime in case of exceptions in the status word.
2753ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ fnstsw_ax();
2763ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ testb(rax, Immediate(0x5F));  // Check for all but precision exception.
2773ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ j(not_zero, &fast_power_failed, Label::kNear);
2783ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ fstp_d(Operand(rsp, 0));
279014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ Movsd(double_result, Operand(rsp, 0));
280b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    __ addp(rsp, Immediate(kDoubleSize));
2813ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ jmp(&done);
282e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
2833ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ bind(&fast_power_failed);
2843ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ fninit();
285b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    __ addp(rsp, Immediate(kDoubleSize));
2863ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ jmp(&call_runtime);
2873ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  }
28885b71799222b55eb5dd74ea26efe0c64ab655c8cBen Murdoch
2893ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Calculate power with integer exponent.
2903ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ bind(&int_exponent);
2913ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  const XMMRegister double_scratch2 = double_exponent;
2923ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Back up exponent as we need to check if exponent is negative later.
293b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ movp(scratch, exponent);  // Back up exponent.
294014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ Movsd(double_scratch, double_base);     // Back up base.
295014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ Movsd(double_scratch2, double_result);  // Load double_exponent with 1.
296e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
297e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  // Get absolute value of exponent.
298b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  Label no_neg, while_true, while_false;
2993ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ testl(scratch, scratch);
3003ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ j(positive, &no_neg, Label::kNear);
3013ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ negl(scratch);
302e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ bind(&no_neg);
303e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
304b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ j(zero, &while_false, Label::kNear);
3053ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ shrl(scratch, Immediate(1));
306b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // Above condition means CF==0 && ZF==0.  This means that the
307b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // bit that has been shifted out is 0 and the result is not 0.
308b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ j(above, &while_true, Label::kNear);
309014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ Movsd(double_result, double_scratch);
310b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ j(zero, &while_false, Label::kNear);
311e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
312b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ bind(&while_true);
313b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ shrl(scratch, Immediate(1));
314014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ Mulsd(double_scratch, double_scratch);
315b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ j(above, &while_true, Label::kNear);
316014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ Mulsd(double_result, double_scratch);
3173ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ j(not_zero, &while_true);
31885b71799222b55eb5dd74ea26efe0c64ab655c8cBen Murdoch
319b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ bind(&while_false);
3203ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // If the exponent is negative, return 1/result.
3213ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ testl(exponent, exponent);
3223ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ j(greater, &done);
323014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ Divsd(double_scratch2, double_result);
324014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ Movsd(double_result, double_scratch2);
3253ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Test whether result is zero.  Bail out to check for subnormal result.
3263ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Due to subnormals, x^-y == (1/x)^y does not hold in all cases.
327014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ Xorpd(double_scratch2, double_scratch2);
328014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ Ucomisd(double_scratch2, double_result);
3293ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // double_exponent aliased as double_scratch2 has already been overwritten
3303ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // and may not have contained the exponent value in the first place when the
3313ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // input was a smi.  We reset it with exponent value before bailing out.
3323ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ j(not_equal, &done);
333b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ Cvtlsi2sd(double_exponent, exponent);
3343ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
3353ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Returning or bailing out.
336f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  __ bind(&call_runtime);
337f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  // Move base to the correct argument register.  Exponent is already in xmm1.
338f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  __ Movsd(xmm0, double_base);
339f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  DCHECK(double_exponent.is(xmm1));
340f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  {
341f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    AllowExternalCallThatCantCauseGC scope(masm);
342f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    __ PrepareCallCFunction(2);
343f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    __ CallCFunction(ExternalReference::power_double_double_function(isolate()),
344f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch                     2);
3453ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  }
346f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  // Return value is in xmm0.
347f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  __ Movsd(double_result, xmm0);
348f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch
349f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  __ bind(&done);
350f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  __ ret(0);
351e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch}
352e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
353109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdochvoid RegExpExecStub::Generate(MacroAssembler* masm) {
354109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  // Just jump directly to runtime if native RegExp is not selected at compile
355109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  // time or if regexp entry in generated code is turned off runtime switch or
356109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  // at compilation.
357109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch#ifdef V8_INTERPRETED_REGEXP
358109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  __ TailCallRuntime(Runtime::kRegExpExec);
359109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch#else  // V8_INTERPRETED_REGEXP
3603fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
361109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  // Stack frame on entry.
362109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  //  rsp[0]  : return address
363109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  //  rsp[8]  : last_match_info (expected JSArray)
364109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  //  rsp[16] : previous index
365109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  //  rsp[24] : subject string
366109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  //  rsp[32] : JSRegExp object
3673fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
368109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  enum RegExpExecStubArgumentIndices {
369109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    JS_REG_EXP_OBJECT_ARGUMENT_INDEX,
370109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    SUBJECT_STRING_ARGUMENT_INDEX,
371109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    PREVIOUS_INDEX_ARGUMENT_INDEX,
372109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    LAST_MATCH_INFO_ARGUMENT_INDEX,
373109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    REG_EXP_EXEC_ARGUMENT_COUNT
374109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  };
3753fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
376109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  StackArgumentsAccessor args(rsp, REG_EXP_EXEC_ARGUMENT_COUNT,
377109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch                              ARGUMENTS_DONT_CONTAIN_RECEIVER);
378109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  Label runtime;
379109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  // Ensure that a RegExp stack is allocated.
380109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  ExternalReference address_of_regexp_stack_memory_address =
381109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch      ExternalReference::address_of_regexp_stack_memory_address(isolate());
382109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  ExternalReference address_of_regexp_stack_memory_size =
383109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch      ExternalReference::address_of_regexp_stack_memory_size(isolate());
384109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  __ Load(kScratchRegister, address_of_regexp_stack_memory_size);
385109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  __ testp(kScratchRegister, kScratchRegister);
386109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  __ j(zero, &runtime);
3873fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
388109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  // Check that the first argument is a JSRegExp object.
389109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  __ movp(rax, args.GetArgumentOperand(JS_REG_EXP_OBJECT_ARGUMENT_INDEX));
390109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  __ JumpIfSmi(rax, &runtime);
391109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  __ CmpObjectType(rax, JS_REGEXP_TYPE, kScratchRegister);
392109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  __ j(not_equal, &runtime);
3933fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
394109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  // Check that the RegExp has been compiled (data contains a fixed array).
395109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  __ movp(rax, FieldOperand(rax, JSRegExp::kDataOffset));
396109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  if (FLAG_debug_code) {
397109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    Condition is_smi = masm->CheckSmi(rax);
398109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ Check(NegateCondition(is_smi),
399109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch        kUnexpectedTypeForRegExpDataFixedArrayExpected);
400109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ CmpObjectType(rax, FIXED_ARRAY_TYPE, kScratchRegister);
401109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ Check(equal, kUnexpectedTypeForRegExpDataFixedArrayExpected);
402109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  }
4033fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
404109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  // rax: RegExp data (FixedArray)
405109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  // Check the type of the RegExp. Only continue if type is JSRegExp::IRREGEXP.
406109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  __ SmiToInteger32(rbx, FieldOperand(rax, JSRegExp::kDataTagOffset));
407109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  __ cmpl(rbx, Immediate(JSRegExp::IRREGEXP));
408109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  __ j(not_equal, &runtime);
4093fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
410109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  // rax: RegExp data (FixedArray)
411109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  // Check that the number of captures fit in the static offsets vector buffer.
412109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  __ SmiToInteger32(rdx,
413109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch                    FieldOperand(rax, JSRegExp::kIrregexpCaptureCountOffset));
414109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  // Check (number_of_captures + 1) * 2 <= offsets vector size
415109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  // Or              number_of_captures <= offsets vector size / 2 - 1
416109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  STATIC_ASSERT(Isolate::kJSRegexpStaticOffsetsVectorSize >= 2);
417109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  __ cmpl(rdx, Immediate(Isolate::kJSRegexpStaticOffsetsVectorSize / 2 - 1));
418109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  __ j(above, &runtime);
4193fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
420109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  // Reset offset for possibly sliced string.
421109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  __ Set(r14, 0);
422109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  __ movp(rdi, args.GetArgumentOperand(SUBJECT_STRING_ARGUMENT_INDEX));
423109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  __ JumpIfSmi(rdi, &runtime);
424109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  __ movp(r15, rdi);  // Make a copy of the original subject string.
425109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  // rax: RegExp data (FixedArray)
426109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  // rdi: subject string
427109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  // r15: subject string
428109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  // Handle subject string according to its encoding and representation:
429109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  // (1) Sequential two byte?  If yes, go to (9).
430109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  // (2) Sequential one byte?  If yes, go to (5).
431109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  // (3) Sequential or cons?  If not, go to (6).
432109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  // (4) Cons string.  If the string is flat, replace subject with first string
433109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  //     and go to (1). Otherwise bail out to runtime.
434109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  // (5) One byte sequential.  Load regexp code for one byte.
435109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  // (E) Carry on.
436109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  /// [...]
4373fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
438109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  // Deferred code at the end of the stub:
439109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  // (6) Long external string?  If not, go to (10).
440109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  // (7) External string.  Make it, offset-wise, look like a sequential string.
441109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  // (8) Is the external string one byte?  If yes, go to (5).
442109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  // (9) Two byte sequential.  Load regexp code for two byte. Go to (E).
443109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  // (10) Short external string or not a string?  If yes, bail out to runtime.
44462ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  // (11) Sliced or thin string.  Replace subject with parent. Go to (1).
4453fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
446109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  Label seq_one_byte_string /* 5 */, seq_two_byte_string /* 9 */,
447109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch      external_string /* 7 */, check_underlying /* 1 */,
448109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch      not_seq_nor_cons /* 6 */, check_code /* E */, not_long_external /* 10 */;
4493fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
450109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  __ bind(&check_underlying);
451109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  __ movp(rbx, FieldOperand(rdi, HeapObject::kMapOffset));
452109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  __ movzxbl(rbx, FieldOperand(rbx, Map::kInstanceTypeOffset));
4533fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
454109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  // (1) Sequential two byte?  If yes, go to (9).
455109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  __ andb(rbx, Immediate(kIsNotStringMask |
456109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch                         kStringRepresentationMask |
457109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch                         kStringEncodingMask |
458109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch                         kShortExternalStringMask));
459109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  STATIC_ASSERT((kStringTag | kSeqStringTag | kTwoByteStringTag) == 0);
460109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  __ j(zero, &seq_two_byte_string);  // Go to (9).
4613fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
462109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  // (2) Sequential one byte?  If yes, go to (5).
463109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  // Any other sequential string must be one byte.
464109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  __ andb(rbx, Immediate(kIsNotStringMask |
465109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch                         kStringRepresentationMask |
466109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch                         kShortExternalStringMask));
467109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  __ j(zero, &seq_one_byte_string, Label::kNear);  // Go to (5).
4683fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
469109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  // (3) Sequential or cons?  If not, go to (6).
470109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  // We check whether the subject string is a cons, since sequential strings
471109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  // have already been covered.
472109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  STATIC_ASSERT(kConsStringTag < kExternalStringTag);
473109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  STATIC_ASSERT(kSlicedStringTag > kExternalStringTag);
47462ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  STATIC_ASSERT(kThinStringTag > kExternalStringTag);
475109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  STATIC_ASSERT(kIsNotStringMask > kExternalStringTag);
476109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  STATIC_ASSERT(kShortExternalStringTag > kExternalStringTag);
477109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  __ cmpp(rbx, Immediate(kExternalStringTag));
478109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  __ j(greater_equal, &not_seq_nor_cons);  // Go to (6).
4793fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
480109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  // (4) Cons string.  Check that it's flat.
481109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  // Replace subject with first string and reload instance type.
482109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  __ CompareRoot(FieldOperand(rdi, ConsString::kSecondOffset),
483109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch                 Heap::kempty_stringRootIndex);
484109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  __ j(not_equal, &runtime);
485109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  __ movp(rdi, FieldOperand(rdi, ConsString::kFirstOffset));
486109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  __ jmp(&check_underlying);
48780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
488109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  // (5) One byte sequential.  Load regexp code for one byte.
489f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ bind(&seq_one_byte_string);
490f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // rax: RegExp data (FixedArray)
491f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ movp(r11, FieldOperand(rax, JSRegExp::kDataOneByteCodeOffset));
492f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ Set(rcx, 1);  // Type is one byte.
4938389745919cae02139ddc085a63c00d024269cf2Ben Murdoch
494f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // (E) Carry on.  String handling is done.
495f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ bind(&check_code);
496f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // r11: irregexp code
497f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // Check that the irregexp code has been generated for the actual string
498f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // encoding. If it has, the field contains a code object otherwise it contains
499f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // smi (code flushing support)
500f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ JumpIfSmi(r11, &runtime);
5018389745919cae02139ddc085a63c00d024269cf2Ben Murdoch
502f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // rdi: sequential subject string (or look-alike, external string)
503f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // r15: original subject string
504f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // rcx: encoding of subject string (1 if one_byte, 0 if two_byte);
505f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // r11: code
506f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // Load used arguments before starting to push arguments for call to native
507f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // RegExp code to avoid handling changing stack height.
508f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // We have to use r15 instead of rdi to load the length because rdi might
509f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // have been only made to look like a sequential string when it actually
510f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // is an external string.
511f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ movp(rbx, args.GetArgumentOperand(PREVIOUS_INDEX_ARGUMENT_INDEX));
512f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ JumpIfNotSmi(rbx, &runtime);
513f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ SmiCompare(rbx, FieldOperand(r15, String::kLengthOffset));
514f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ j(above_equal, &runtime);
515f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ SmiToInteger64(rbx, rbx);
516014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
517f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // rdi: subject string
518f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // rbx: previous index
519f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // rcx: encoding of subject string (1 if one_byte 0 if two_byte);
520f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // r11: code
521f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // All checks done. Now push arguments for native regexp code.
522f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  Counters* counters = isolate()->counters();
523f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ IncrementCounter(counters->regexp_entry_native(), 1);
524014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
525f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // Isolates: note we add an additional parameter here (isolate pointer).
526f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  static const int kRegExpExecuteArguments = 9;
527f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  int argument_slots_on_stack =
528f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch      masm->ArgumentStackSlotsForCFunctionCall(kRegExpExecuteArguments);
529f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ EnterApiExitFrame(argument_slots_on_stack);
530014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
531f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // Argument 9: Pass current isolate address.
532f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ LoadAddress(kScratchRegister,
533f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch                 ExternalReference::isolate_address(isolate()));
534f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ movq(Operand(rsp, (argument_slots_on_stack - 1) * kRegisterSize),
535f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch          kScratchRegister);
536014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
537f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // Argument 8: Indicate that this is a direct call from JavaScript.
538f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ movq(Operand(rsp, (argument_slots_on_stack - 2) * kRegisterSize),
539f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch          Immediate(1));
5403ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
541f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // Argument 7: Start (high end) of backtracking stack memory area.
542f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ Move(kScratchRegister, address_of_regexp_stack_memory_address);
543f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ movp(r9, Operand(kScratchRegister, 0));
544f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ Move(kScratchRegister, address_of_regexp_stack_memory_size);
545f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ addp(r9, Operand(kScratchRegister, 0));
546f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ movq(Operand(rsp, (argument_slots_on_stack - 3) * kRegisterSize), r9);
5473ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
548f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // Argument 6: Set the number of capture registers to zero to force global
549f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // regexps to behave as non-global.  This does not affect non-global regexps.
550f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // Argument 6 is passed in r9 on Linux and on the stack on Windows.
551f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch#ifdef _WIN64
552f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ movq(Operand(rsp, (argument_slots_on_stack - 4) * kRegisterSize),
553f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch          Immediate(0));
554f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch#else
555f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ Set(r9, 0);
556f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch#endif
557014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
558f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // Argument 5: static offsets vector buffer.
559f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ LoadAddress(
560f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch      r8, ExternalReference::address_of_static_offsets_vector(isolate()));
561f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // Argument 5 passed in r8 on Linux and on the stack on Windows.
562f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch#ifdef _WIN64
563f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ movq(Operand(rsp, (argument_slots_on_stack - 5) * kRegisterSize), r8);
564f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch#endif
565014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
566f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // rdi: subject string
567f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // rbx: previous index
568f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // rcx: encoding of subject string (1 if one_byte 0 if two_byte);
569f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // r11: code
570f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // r14: slice offset
571f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // r15: original subject string
572b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
573f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // Argument 2: Previous index.
574f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ movp(arg_reg_2, rbx);
575b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
576f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // Argument 4: End of string data
577f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // Argument 3: Start of string data
578f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  Label setup_two_byte, setup_rest, got_length, length_not_from_slice;
579f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // Prepare start and end index of the input.
580f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // Load the length from the original sliced string if that is the case.
581f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ addp(rbx, r14);
582f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ SmiToInteger32(arg_reg_3, FieldOperand(r15, String::kLengthOffset));
583f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ addp(r14, arg_reg_3);  // Using arg3 as scratch.
5843ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
585f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // rbx: start index of the input
586f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // r14: end index of the input
587f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // r15: original subject string
588f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ testb(rcx, rcx);  // Last use of rcx as encoding of subject string.
589f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ j(zero, &setup_two_byte, Label::kNear);
590f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ leap(arg_reg_4,
591f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch         FieldOperand(rdi, r14, times_1, SeqOneByteString::kHeaderSize));
592f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ leap(arg_reg_3,
593f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch         FieldOperand(rdi, rbx, times_1, SeqOneByteString::kHeaderSize));
594f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ jmp(&setup_rest, Label::kNear);
595f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ bind(&setup_two_byte);
596f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ leap(arg_reg_4,
597f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch         FieldOperand(rdi, r14, times_2, SeqTwoByteString::kHeaderSize));
598f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ leap(arg_reg_3,
599f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch         FieldOperand(rdi, rbx, times_2, SeqTwoByteString::kHeaderSize));
600f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ bind(&setup_rest);
6013ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
602f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // Argument 1: Original subject string.
603f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // The original subject is in the previous stack frame. Therefore we have to
604f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // use rbp, which points exactly to one pointer size below the previous rsp.
605f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // (Because creating a new stack frame pushes the previous rbp onto the stack
606f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // and thereby moves up rsp by one kPointerSize.)
607f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ movp(arg_reg_1, r15);
6083ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
609f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // Locate the code entry and call it.
610f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ addp(r11, Immediate(Code::kHeaderSize - kHeapObjectTag));
611f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ call(r11);
61280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
613f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ LeaveApiExitFrame(true);
61480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
615f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // Check the result.
616f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  Label success;
617f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  Label exception;
618f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ cmpl(rax, Immediate(1));
619f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // We expect exactly one result since we force the called regexp to behave
620f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // as non-global.
621f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ j(equal, &success, Label::kNear);
622f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ cmpl(rax, Immediate(NativeRegExpMacroAssembler::EXCEPTION));
623f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ j(equal, &exception);
624f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ cmpl(rax, Immediate(NativeRegExpMacroAssembler::FAILURE));
625f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // If none of the above, it can only be retry.
626f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // Handle that in the runtime system.
627f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ j(not_equal, &runtime);
628257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
629f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // For failure return null.
630f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ LoadRoot(rax, Heap::kNullValueRootIndex);
631f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ ret(REG_EXP_EXEC_ARGUMENT_COUNT * kPointerSize);
63280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
633f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // Load RegExp data.
634f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ bind(&success);
635f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ movp(rax, args.GetArgumentOperand(JS_REG_EXP_OBJECT_ARGUMENT_INDEX));
636f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ movp(rcx, FieldOperand(rax, JSRegExp::kDataOffset));
637f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ SmiToInteger32(rax,
638f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch                    FieldOperand(rcx, JSRegExp::kIrregexpCaptureCountOffset));
639f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // Calculate number of capture registers (number_of_captures + 1) * 2.
640f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ leal(rdx, Operand(rax, rax, times_1, 2));
641b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
642f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // rdx: Number of capture registers
643c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch  // Check that the last match info is a FixedArray.
644c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch  __ movp(rbx, args.GetArgumentOperand(LAST_MATCH_INFO_ARGUMENT_INDEX));
645c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch  __ JumpIfSmi(rbx, &runtime);
646f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  // Check that the object has fast elements.
647f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ movp(rax, FieldOperand(rbx, HeapObject::kMapOffset));
648f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ CompareRoot(rax, Heap::kFixedArrayMapRootIndex);
649f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ j(not_equal, &runtime);
650f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // Check that the last match info has space for the capture registers and the
651f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // additional information. Ensure no overflow in add.
652f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  STATIC_ASSERT(FixedArray::kMaxLength < kMaxInt - FixedArray::kLengthOffset);
653f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ SmiToInteger32(rax, FieldOperand(rbx, FixedArray::kLengthOffset));
654c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch  __ subl(rax, Immediate(RegExpMatchInfo::kLastMatchOverhead));
655f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ cmpl(rdx, rax);
656f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ j(greater, &runtime);
657b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
658c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch  // rbx: last_match_info (FixedArray)
659f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // rdx: number of capture registers
660f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // Store the capture count.
661f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ Integer32ToSmi(kScratchRegister, rdx);
662c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch  __ movp(FieldOperand(rbx, RegExpMatchInfo::kNumberOfCapturesOffset),
663f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch          kScratchRegister);
664f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // Store last subject and last input.
665f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ movp(rax, args.GetArgumentOperand(SUBJECT_STRING_ARGUMENT_INDEX));
666c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch  __ movp(FieldOperand(rbx, RegExpMatchInfo::kLastSubjectOffset), rax);
667f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ movp(rcx, rax);
668c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch  __ RecordWriteField(rbx, RegExpMatchInfo::kLastSubjectOffset, rax, rdi,
669f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch                      kDontSaveFPRegs);
670f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ movp(rax, rcx);
671c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch  __ movp(FieldOperand(rbx, RegExpMatchInfo::kLastInputOffset), rax);
672c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch  __ RecordWriteField(rbx, RegExpMatchInfo::kLastInputOffset, rax, rdi,
673f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch                      kDontSaveFPRegs);
674b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
675f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // Get the static offsets vector filled by the native regexp code.
676f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ LoadAddress(
677f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch      rcx, ExternalReference::address_of_static_offsets_vector(isolate()));
6783ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
679c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch  // rbx: last_match_info (FixedArray)
680f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // rcx: offsets vector
681f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // rdx: number of capture registers
682f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  Label next_capture, done;
683f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // Capture register counter starts from number of capture registers and
684c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch  // counts down until wrapping after zero.
685f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ bind(&next_capture);
686f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ subp(rdx, Immediate(1));
687f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ j(negative, &done, Label::kNear);
688f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // Read the value from the static offsets vector buffer and make it a smi.
689f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ movl(rdi, Operand(rcx, rdx, times_int_size, 0));
690f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ Integer32ToSmi(rdi, rdi);
691f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // Store the smi value in the last match info.
692c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch  __ movp(FieldOperand(rbx, rdx, times_pointer_size,
693c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch                       RegExpMatchInfo::kFirstCaptureOffset),
694f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch          rdi);
695f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ jmp(&next_capture);
696f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ bind(&done);
697014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
698f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // Return last match info.
699c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch  __ movp(rax, rbx);
700f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ ret(REG_EXP_EXEC_ARGUMENT_COUNT * kPointerSize);
701014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
702f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ bind(&exception);
703f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // Result must now be exception. If there is no pending exception already a
704f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // stack overflow (on the backtrack stack) was detected in RegExp code but
705f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // haven't created the exception yet. Handle that in the runtime system.
706f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // TODO(592): Rerunning the RegExp to get the stack overflow exception.
707f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  ExternalReference pending_exception_address(
708f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch      Isolate::kPendingExceptionAddress, isolate());
709f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  Operand pending_exception_operand =
710f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch      masm->ExternalOperand(pending_exception_address, rbx);
711f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ movp(rax, pending_exception_operand);
712f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ LoadRoot(rdx, Heap::kTheHoleValueRootIndex);
713f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ cmpp(rax, rdx);
714f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ j(equal, &runtime);
7153ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
716f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // For exception, throw the exception again.
717f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ TailCallRuntime(Runtime::kRegExpExecReThrow);
7183ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
719f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // Do the runtime call to execute the regexp.
720f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ bind(&runtime);
721f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ TailCallRuntime(Runtime::kRegExpExec);
72244f0eee88ff00398ff7f715fab053374d808c90dSteve Block
723f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // Deferred code for string handling.
724109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  // (6) Long external string?  If not, go to (10).
725f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ bind(&not_seq_nor_cons);
726f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // Compare flags are still set from (3).
727f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ j(greater, &not_long_external, Label::kNear);  // Go to (10).
72844f0eee88ff00398ff7f715fab053374d808c90dSteve Block
729109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  // (7) External string.  Short external strings have been ruled out.
730f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ bind(&external_string);
731f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ movp(rbx, FieldOperand(rdi, HeapObject::kMapOffset));
732f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ movzxbl(rbx, FieldOperand(rbx, Map::kInstanceTypeOffset));
733f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  if (FLAG_debug_code) {
734f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    // Assert that we do not have a cons or slice (indirect strings) here.
735f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    // Sequential strings have already been ruled out.
736f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ testb(rbx, Immediate(kIsIndirectStringMask));
737f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ Assert(zero, kExternalStringExpectedButNotFound);
738f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  }
739f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ movp(rdi, FieldOperand(rdi, ExternalString::kResourceDataOffset));
740f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // Move the pointer so that offset-wise, it looks like a sequential string.
741f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqOneByteString::kHeaderSize);
742f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ subp(rdi, Immediate(SeqTwoByteString::kHeaderSize - kHeapObjectTag));
743f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  STATIC_ASSERT(kTwoByteStringTag == 0);
744109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  // (8) Is the external string one byte?  If yes, go to (5).
745f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ testb(rbx, Immediate(kStringEncodingMask));
746109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  __ j(not_zero, &seq_one_byte_string);  // Go to (5).
747b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
748f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // rdi: subject string (flat two-byte)
749f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // rax: RegExp data (FixedArray)
750109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  // (9) Two byte sequential.  Load regexp code for two byte.  Go to (E).
751f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ bind(&seq_two_byte_string);
752f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ movp(r11, FieldOperand(rax, JSRegExp::kDataUC16CodeOffset));
753f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ Set(rcx, 0);  // Type is two byte.
754f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ jmp(&check_code);  // Go to (E).
755014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
756f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // (10) Not a string or a short external string?  If yes, bail out to runtime.
757f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ bind(&not_long_external);
758f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // Catch non-string subject or short external string.
759f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  STATIC_ASSERT(kNotStringTag != 0 && kShortExternalStringTag !=0);
760f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ testb(rbx, Immediate(kIsNotStringMask | kShortExternalStringMask));
761f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ j(not_zero, &runtime);
762b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
76362ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  // (11) Sliced or thin string.  Replace subject with parent. Go to (1).
76462ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  Label thin_string;
76562ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  __ cmpl(rbx, Immediate(kThinStringTag));
76662ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  __ j(equal, &thin_string, Label::kNear);
767f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // Load offset into r14 and replace subject string with parent.
768f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ SmiToInteger32(r14, FieldOperand(rdi, SlicedString::kOffsetOffset));
769f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ movp(rdi, FieldOperand(rdi, SlicedString::kParentOffset));
770f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ jmp(&check_underlying);
77162ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch
77262ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  __ bind(&thin_string);
77362ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  __ movp(rdi, FieldOperand(rdi, ThinString::kActualOffset));
77462ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  __ jmp(&check_underlying);
775f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch#endif  // V8_INTERPRETED_REGEXP
776b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch}
777b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
778b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
779f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdochstatic int NegativeComparisonResult(Condition cc) {
780f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  DCHECK(cc != equal);
781f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  DCHECK((cc == less) || (cc == less_equal)
782f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch      || (cc == greater) || (cc == greater_equal));
783f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  return (cc == greater || cc == greater_equal) ? LESS : GREATER;
784f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch}
785b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
786014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
787f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdochstatic void CheckInputType(MacroAssembler* masm, Register input,
788f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch                           CompareICState::State expected, Label* fail) {
789f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  Label ok;
790f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  if (expected == CompareICState::SMI) {
791f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ JumpIfNotSmi(input, fail);
792f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  } else if (expected == CompareICState::NUMBER) {
793f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ JumpIfSmi(input, &ok);
794f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ CompareMap(input, masm->isolate()->factory()->heap_number_map());
795f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ j(not_equal, fail);
796f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  }
797f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // We could be strict about internalized/non-internalized here, but as long as
798f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // hydrogen doesn't care, the stub doesn't have to care either.
799f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ bind(&ok);
800f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch}
801014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
802b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
803f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdochstatic void BranchIfNotInternalizedString(MacroAssembler* masm,
804f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch                                          Label* label,
805f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch                                          Register object,
806f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch                                          Register scratch) {
807f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ JumpIfSmi(object, label);
808f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ movp(scratch, FieldOperand(object, HeapObject::kMapOffset));
809f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ movzxbp(scratch,
810f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch             FieldOperand(scratch, Map::kInstanceTypeOffset));
811f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  STATIC_ASSERT(kInternalizedTag == 0 && kStringTag == 0);
812f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ testb(scratch, Immediate(kIsNotStringMask | kIsNotInternalizedMask));
813f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ j(not_zero, label);
814f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch}
815b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
816b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
817f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdochvoid CompareICStub::GenerateGeneric(MacroAssembler* masm) {
818f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  Label runtime_call, check_unequal_objects, done;
819f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  Condition cc = GetCondition();
820f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  Factory* factory = isolate()->factory();
821b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
822f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  Label miss;
823f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  CheckInputType(masm, rdx, left(), &miss);
824f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  CheckInputType(masm, rax, right(), &miss);
825b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
826f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // Compare two smis.
827f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  Label non_smi, smi_done;
828f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ JumpIfNotBothSmi(rax, rdx, &non_smi);
829f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ subp(rdx, rax);
830f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ j(no_overflow, &smi_done);
831f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ notp(rdx);  // Correct sign in case of overflow. rdx cannot be 0 here.
832f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ bind(&smi_done);
833f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ movp(rax, rdx);
834f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ ret(0);
835f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ bind(&non_smi);
836b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
837f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // The compare stub returns a positive, negative, or zero 64-bit integer
838f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // value in rax, corresponding to result of comparing the two inputs.
839f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // NOTICE! This code is only reached after a smi-fast-case check, so
840f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // it is certain that at least one operand isn't a smi.
841b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
842f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // Two identical objects are equal unless they are both NaN or undefined.
843f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  {
844f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    Label not_identical;
845f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ cmpp(rax, rdx);
846f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ j(not_equal, &not_identical, Label::kNear);
847b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
848f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    if (cc != equal) {
849f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch      // Check for undefined.  undefined OP undefined is false even though
850f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch      // undefined == undefined.
851f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch      __ CompareRoot(rdx, Heap::kUndefinedValueRootIndex);
852109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch      Label check_for_nan;
853109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch      __ j(not_equal, &check_for_nan, Label::kNear);
854109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch      __ Set(rax, NegativeComparisonResult(cc));
855109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch      __ ret(0);
856109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch      __ bind(&check_for_nan);
857f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    }
858958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier
859f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    // Test for NaN. Sadly, we can't just compare to Factory::nan_value(),
860f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    // so we do the second best thing - test it ourselves.
861f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    Label heap_number;
862f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    // If it's not a heap number, then return equal for (in)equality operator.
863f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ Cmp(FieldOperand(rdx, HeapObject::kMapOffset),
864f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch           factory->heap_number_map());
865f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ j(equal, &heap_number, Label::kNear);
866f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    if (cc != equal) {
867f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch      __ movp(rcx, FieldOperand(rax, HeapObject::kMapOffset));
868f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch      __ movzxbl(rcx, FieldOperand(rcx, Map::kInstanceTypeOffset));
869f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch      // Call runtime on identical objects.  Otherwise return equal.
870f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch      __ cmpb(rcx, Immediate(static_cast<uint8_t>(FIRST_JS_RECEIVER_TYPE)));
871f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch      __ j(above_equal, &runtime_call, Label::kFar);
872f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch      // Call runtime on identical symbols since we need to throw a TypeError.
873f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch      __ cmpb(rcx, Immediate(static_cast<uint8_t>(SYMBOL_TYPE)));
874f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch      __ j(equal, &runtime_call, Label::kFar);
875f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    }
876f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ Set(rax, EQUAL);
877f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ ret(0);
878f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch
879f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ bind(&heap_number);
880f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    // It is a heap number, so return  equal if it's not NaN.
881f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    // For NaN, return 1 for every condition except greater and
882f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    // greater-equal.  Return -1 for them, so the comparison yields
883f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    // false for all conditions except not-equal.
884f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ Set(rax, EQUAL);
885f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ Movsd(xmm0, FieldOperand(rdx, HeapNumber::kValueOffset));
886f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ Ucomisd(xmm0, xmm0);
887f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ setcc(parity_even, rax);
888f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    // rax is 0 for equal non-NaN heapnumbers, 1 for NaNs.
889f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    if (cc == greater_equal || cc == greater) {
890f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch      __ negp(rax);
891f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    }
892f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ ret(0);
893f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch
894f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ bind(&not_identical);
895958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier  }
896958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier
897f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  if (cc == equal) {  // Both strict and non-strict.
898f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    Label slow;  // Fallthrough label.
899958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier
900f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    // If we're doing a strict equality comparison, we don't have to do
901f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    // type conversion, so we generate code to do fast comparison for objects
902f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    // and oddballs. Non-smi numbers and strings still go through the usual
903f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    // slow-case code.
904f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    if (strict()) {
905f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch      // If either is a Smi (we know that not both are), then they can only
906f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch      // be equal if the other is a HeapNumber. If so, use the slow case.
907f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch      {
908f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch        Label not_smis;
909f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch        __ SelectNonSmi(rbx, rax, rdx, &not_smis);
910014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
911f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch        // Check if the non-smi operand is a heap number.
912f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch        __ Cmp(FieldOperand(rbx, HeapObject::kMapOffset),
913f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch               factory->heap_number_map());
914f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch        // If heap number, handle it in the slow case.
915f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch        __ j(equal, &slow);
916f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch        // Return non-equal.  ebx (the lower half of rbx) is not zero.
917f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch        __ movp(rax, rbx);
918f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch        __ ret(0);
919958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier
920f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch        __ bind(&not_smis);
921f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch      }
922958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier
923f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch      // If either operand is a JSObject or an oddball value, then they are not
924f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch      // equal since their pointers are different
925f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch      // There is no test for undetectability in strict equality.
926958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier
927f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch      // If the first object is a JS object, we have done pointer comparison.
928f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch      STATIC_ASSERT(LAST_TYPE == LAST_JS_RECEIVER_TYPE);
929f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch      Label first_non_object;
930f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch      __ CmpObjectType(rax, FIRST_JS_RECEIVER_TYPE, rcx);
931f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch      __ j(below, &first_non_object, Label::kNear);
932f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch      // Return non-zero (rax (not rax) is not zero)
933f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch      Label return_not_equal;
934f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch      STATIC_ASSERT(kHeapObjectTag != 0);
935f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch      __ bind(&return_not_equal);
936f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch      __ ret(0);
937958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier
938f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch      __ bind(&first_non_object);
939f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch      // Check for oddballs: true, false, null, undefined.
940f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch      __ CmpInstanceType(rcx, ODDBALL_TYPE);
941f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch      __ j(equal, &return_not_equal);
942b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
943f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch      __ CmpObjectType(rdx, FIRST_JS_RECEIVER_TYPE, rcx);
944f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch      __ j(above_equal, &return_not_equal);
945014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
946f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch      // Check for oddballs: true, false, null, undefined.
947f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch      __ CmpInstanceType(rcx, ODDBALL_TYPE);
948f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch      __ j(equal, &return_not_equal);
949b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
950f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch      // Fall through to the general case.
951f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    }
952f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ bind(&slow);
953f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  }
954958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier
955f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // Generate the number comparison code.
956f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  Label non_number_comparison;
957f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  Label unordered;
958f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  FloatingPointHelper::LoadSSE2UnknownOperands(masm, &non_number_comparison);
959f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ xorl(rax, rax);
960f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ xorl(rcx, rcx);
961f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ Ucomisd(xmm0, xmm1);
962f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch
963f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // Don't base result on EFLAGS when a NaN is involved.
964f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ j(parity_even, &unordered, Label::kNear);
965f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // Return a result of -1, 0, or 1, based on EFLAGS.
966f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ setcc(above, rax);
967f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ setcc(below, rcx);
968f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ subp(rax, rcx);
969f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ ret(0);
970f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch
971f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // If one of the numbers was NaN, then the result is always false.
972f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // The cc is never not-equal.
973f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ bind(&unordered);
974f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  DCHECK(cc != not_equal);
975f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  if (cc == less || cc == less_equal) {
976f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ Set(rax, 1);
977f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  } else {
978f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ Set(rax, -1);
979014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  }
980f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ ret(0);
981014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
982f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // The number comparison code did not provide a valid result.
983f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ bind(&non_number_comparison);
984958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier
985f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // Fast negative check for internalized-to-internalized equality.
986f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  Label check_for_strings;
987f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  if (cc == equal) {
988f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    BranchIfNotInternalizedString(
989f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch        masm, &check_for_strings, rax, kScratchRegister);
990f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    BranchIfNotInternalizedString(
991f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch        masm, &check_for_strings, rdx, kScratchRegister);
992b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
993f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    // We've already checked for object identity, so if both operands are
994f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    // internalized strings they aren't equal. Register rax (not rax) already
995f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    // holds a non-zero value, which indicates not equal, so just return.
996f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ ret(0);
997f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  }
998b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
999f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ bind(&check_for_strings);
1000b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1001f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ JumpIfNotBothSequentialOneByteStrings(rdx, rax, rcx, rbx,
1002f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch                                           &check_unequal_objects);
1003b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1004f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // Inline comparison of one-byte strings.
1005f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  if (cc == equal) {
1006f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    StringHelper::GenerateFlatOneByteStringEquals(masm, rdx, rax, rcx, rbx);
1007f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  } else {
1008f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    StringHelper::GenerateCompareFlatOneByteStrings(masm, rdx, rax, rcx, rbx,
1009f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch                                                    rdi, r8);
1010f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  }
1011b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1012f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch#ifdef DEBUG
1013f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ Abort(kUnexpectedFallThroughFromStringComparison);
1014f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch#endif
1015f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch
1016f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ bind(&check_unequal_objects);
1017f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  if (cc == equal && !strict()) {
1018f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    // Not strict equality.  Objects are unequal if
1019f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    // they are both JSObjects and not undetectable,
1020f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    // and their pointers are different.
10213b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch    Label return_equal, return_unequal, undetectable;
1022f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    // At most one is a smi, so we can test for smi by adding the two.
1023f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    // A smi plus a heap object has the low bit set, a heap object plus
1024f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    // a heap object has the low bit clear.
1025f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    STATIC_ASSERT(kSmiTag == 0);
1026f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    STATIC_ASSERT(kSmiTagMask == 1);
1027f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ leap(rcx, Operand(rax, rdx, times_1, 0));
1028f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ testb(rcx, Immediate(kSmiTagMask));
1029f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ j(not_zero, &runtime_call, Label::kNear);
1030109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch
1031109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ movp(rbx, FieldOperand(rax, HeapObject::kMapOffset));
1032109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ movp(rcx, FieldOperand(rdx, HeapObject::kMapOffset));
1033f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ testb(FieldOperand(rbx, Map::kBitFieldOffset),
1034f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch             Immediate(1 << Map::kIsUndetectable));
10353b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch    __ j(not_zero, &undetectable, Label::kNear);
1036f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ testb(FieldOperand(rcx, Map::kBitFieldOffset),
1037f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch             Immediate(1 << Map::kIsUndetectable));
10383b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch    __ j(not_zero, &return_unequal, Label::kNear);
1039109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch
1040109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ CmpInstanceType(rbx, FIRST_JS_RECEIVER_TYPE);
1041109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ j(below, &runtime_call, Label::kNear);
1042109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ CmpInstanceType(rcx, FIRST_JS_RECEIVER_TYPE);
1043109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ j(below, &runtime_call, Label::kNear);
1044109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch
1045f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ bind(&return_unequal);
1046109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    // Return non-equal by returning the non-zero object pointer in rax.
1047109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ ret(0);
1048109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch
1049109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ bind(&undetectable);
1050109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ testb(FieldOperand(rcx, Map::kBitFieldOffset),
1051109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch             Immediate(1 << Map::kIsUndetectable));
10523b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch    __ j(zero, &return_unequal, Label::kNear);
10533b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch
10543b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch    // If both sides are JSReceivers, then the result is false according to
10553b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch    // the HTML specification, which says that only comparisons with null or
10563b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch    // undefined are affected by special casing for document.all.
10573b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch    __ CmpInstanceType(rbx, ODDBALL_TYPE);
10583b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch    __ j(zero, &return_equal, Label::kNear);
10593b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch    __ CmpInstanceType(rcx, ODDBALL_TYPE);
10603b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch    __ j(not_zero, &return_unequal, Label::kNear);
10613b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch
10623b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch    __ bind(&return_equal);
1063109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ Set(rax, EQUAL);
1064f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ ret(0);
1065f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  }
1066f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ bind(&runtime_call);
1067f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch
1068f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  if (cc == equal) {
1069109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    {
1070109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch      FrameScope scope(masm, StackFrame::INTERNAL);
107162ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch      __ Push(rsi);
107262ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch      __ Call(strict() ? isolate()->builtins()->StrictEqual()
107362ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch                       : isolate()->builtins()->Equal(),
107462ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch              RelocInfo::CODE_TARGET);
107562ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch      __ Pop(rsi);
1076109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    }
1077109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    // Turn true into 0 and false into some non-zero value.
1078109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    STATIC_ASSERT(EQUAL == 0);
1079109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ LoadRoot(rdx, Heap::kTrueValueRootIndex);
1080109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ subp(rax, rdx);
1081109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ Ret();
1082f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  } else {
1083109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    // Push arguments below the return address to prepare jump to builtin.
1084109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ PopReturnAddressTo(rcx);
1085109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ Push(rdx);
1086109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ Push(rax);
1087f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ Push(Smi::FromInt(NegativeComparisonResult(cc)));
1088f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ PushReturnAddressFrom(rcx);
1089109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ TailCallRuntime(Runtime::kCompare);
1090f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  }
1091b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1092f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ bind(&miss);
1093f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  GenerateMiss(masm);
1094b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch}
1095b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1096b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1097f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdochstatic void CallStubInRecordCallTarget(MacroAssembler* masm, CodeStub* stub) {
1098f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // rax : number of arguments to the construct function
1099f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // rbx : feedback vector
1100f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // rdx : slot in feedback vector (Smi)
1101f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // rdi : the function to call
1102f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  FrameScope scope(masm, StackFrame::INTERNAL);
1103f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch
1104f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // Number-of-arguments register must be smi-tagged to call out.
1105f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ Integer32ToSmi(rax, rax);
1106f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ Push(rax);
1107f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ Push(rdi);
1108f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ Integer32ToSmi(rdx, rdx);
1109f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ Push(rdx);
1110f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ Push(rbx);
1111f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  __ Push(rsi);
11123ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
1113f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ CallStub(stub);
11143ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
1115f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  __ Pop(rsi);
1116f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ Pop(rbx);
1117f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ Pop(rdx);
1118f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ Pop(rdi);
1119f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ Pop(rax);
1120f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  __ SmiToInteger32(rdx, rdx);
1121f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ SmiToInteger32(rax, rax);
11223ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch}
11233ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
11243ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
1125f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdochstatic void GenerateRecordCallTarget(MacroAssembler* masm) {
1126f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // Cache the called function in a feedback vector slot.  Cache states
1127f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // are uninitialized, monomorphic (indicated by a JSFunction), and
1128f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // megamorphic.
1129f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // rax : number of arguments to the construct function
1130f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // rbx : feedback vector
1131f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // rdx : slot in feedback vector (Smi)
1132f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // rdi : the function to call
1133f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  Isolate* isolate = masm->isolate();
113413e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  Label initialize, done, miss, megamorphic, not_array_function;
11353ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
1136f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // Load the cache state into r11.
1137f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ SmiToInteger32(rdx, rdx);
1138f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ movp(r11,
1139f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch          FieldOperand(rbx, rdx, times_pointer_size, FixedArray::kHeaderSize));
11403ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
1141f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // A monomorphic cache hit or an already megamorphic state: invoke the
1142f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // function without changing the state.
1143f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // We don't know if r11 is a WeakCell or a Symbol, but it's harmless to read
114462ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  // at this position in a symbol (see static asserts in feedback-vector.h).
1145f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  Label check_allocation_site;
1146f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ cmpp(rdi, FieldOperand(r11, WeakCell::kValueOffset));
1147f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  __ j(equal, &done, Label::kFar);
1148f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ CompareRoot(r11, Heap::kmegamorphic_symbolRootIndex);
1149f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ j(equal, &done, Label::kFar);
1150f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ CompareRoot(FieldOperand(r11, HeapObject::kMapOffset),
1151f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch                 Heap::kWeakCellMapRootIndex);
1152f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ j(not_equal, &check_allocation_site);
1153592a9fc1d8ea420377a2e7efd0600e20b058be2bBen Murdoch
1154f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // If the weak cell is cleared, we have a new chance to become monomorphic.
1155f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ CheckSmi(FieldOperand(r11, WeakCell::kValueOffset));
1156f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ j(equal, &initialize);
1157f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ jmp(&megamorphic);
1158592a9fc1d8ea420377a2e7efd0600e20b058be2bBen Murdoch
1159f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ bind(&check_allocation_site);
1160f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // If we came here, we need to see if we are the array function.
1161f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // If we didn't have a matching function, and we didn't find the megamorph
1162f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // sentinel, then we have in the slot either some other function or an
1163f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // AllocationSite.
1164f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ CompareRoot(FieldOperand(r11, 0), Heap::kAllocationSiteMapRootIndex);
1165f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ j(not_equal, &miss);
1166b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1167f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // Make sure the function is the Array() function
1168f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ LoadNativeContextSlot(Context::ARRAY_FUNCTION_INDEX, r11);
1169f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ cmpp(rdi, r11);
1170f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ j(not_equal, &megamorphic);
1171f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  __ jmp(&done);
1172b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1173f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ bind(&miss);
11748389745919cae02139ddc085a63c00d024269cf2Ben Murdoch
1175f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // A monomorphic miss (i.e, here the cache is not uninitialized) goes
1176f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // megamorphic.
1177f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ CompareRoot(r11, Heap::kuninitialized_symbolRootIndex);
1178f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ j(equal, &initialize);
1179f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // MegamorphicSentinel is an immortal immovable object (undefined) so no
1180f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // write-barrier is needed.
1181f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ bind(&megamorphic);
1182f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ Move(FieldOperand(rbx, rdx, times_pointer_size, FixedArray::kHeaderSize),
118362ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch          FeedbackVector::MegamorphicSentinel(isolate));
1184f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ jmp(&done);
1185b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1186f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // An uninitialized cache is patched with the function or sentinel to
1187f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // indicate the ElementsKind if function is the Array constructor.
1188f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ bind(&initialize);
118980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
1190f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // Make sure the function is the Array() function
1191f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ LoadNativeContextSlot(Context::ARRAY_FUNCTION_INDEX, r11);
1192f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ cmpp(rdi, r11);
1193f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ j(not_equal, &not_array_function);
119480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
1195f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  CreateAllocationSiteStub create_stub(isolate);
1196f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  CallStubInRecordCallTarget(masm, &create_stub);
1197f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  __ jmp(&done);
119880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
1199f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ bind(&not_array_function);
1200f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  CreateWeakCellStub weak_cell_stub(isolate);
1201f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  CallStubInRecordCallTarget(masm, &weak_cell_stub);
120213e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch
1203f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  __ bind(&done);
1204f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  // Increment the call count for all function calls.
120513e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  __ SmiAddConstant(FieldOperand(rbx, rdx, times_pointer_size,
120613e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch                                 FixedArray::kHeaderSize + kPointerSize),
120713e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch                    Smi::FromInt(1));
1208f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch}
120980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
121080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
1211f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdochvoid CallConstructStub::Generate(MacroAssembler* masm) {
1212f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // rax : number of arguments
1213f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // rbx : feedback vector
1214f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // rdx : slot in feedback vector (Smi)
1215f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // rdi : constructor function
121680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
1217f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  Label non_function;
1218f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // Check that the constructor is not a smi.
1219f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ JumpIfSmi(rdi, &non_function);
1220f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // Check that constructor is a JSFunction.
1221f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ CmpObjectType(rdi, JS_FUNCTION_TYPE, r11);
1222f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ j(not_equal, &non_function);
1223014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
1224f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  GenerateRecordCallTarget(masm);
122580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
1226f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  Label feedback_register_initialized;
1227f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // Put the AllocationSite from the feedback vector into rbx, or undefined.
1228f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ movp(rbx,
1229f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch          FieldOperand(rbx, rdx, times_pointer_size, FixedArray::kHeaderSize));
1230f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ CompareRoot(FieldOperand(rbx, 0), Heap::kAllocationSiteMapRootIndex);
1231f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ j(equal, &feedback_register_initialized, Label::kNear);
1232f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ LoadRoot(rbx, Heap::kUndefinedValueRootIndex);
1233f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ bind(&feedback_register_initialized);
1234014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
1235f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ AssertUndefinedOrAllocationSite(rbx);
1236014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
1237f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // Pass new target to construct stub.
1238f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ movp(rdx, rdi);
123980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
1240f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // Tail call to the function-specific construct stub (still in the caller
1241f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // context at this point).
1242f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ movp(rcx, FieldOperand(rdi, JSFunction::kSharedFunctionInfoOffset));
1243f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ movp(rcx, FieldOperand(rcx, SharedFunctionInfo::kConstructStubOffset));
1244f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ leap(rcx, FieldOperand(rcx, Code::kHeaderSize));
1245f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ jmp(rcx);
124680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
1247f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ bind(&non_function);
1248f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ movp(rdx, rdi);
1249f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ Jump(isolate()->builtins()->Construct(), RelocInfo::CODE_TARGET);
1250f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch}
1251b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1252f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdochbool CEntryStub::NeedsImmovableCode() {
1253f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  return false;
1254f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch}
125580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
125680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
1257f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdochvoid CodeStub::GenerateStubsAheadOfTime(Isolate* isolate) {
1258f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  CEntryStub::GenerateAheadOfTime(isolate);
1259f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  StoreBufferOverflowStub::GenerateFixedRegStubsAheadOfTime(isolate);
1260f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  StubFailureTrampolineStub::GenerateAheadOfTime(isolate);
1261f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // It is important that the store buffer overflow stubs are generated first.
126213e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  CommonArrayConstructorStub::GenerateStubsAheadOfTime(isolate);
1263f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  CreateAllocationSiteStub::GenerateAheadOfTime(isolate);
1264f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  CreateWeakCellStub::GenerateAheadOfTime(isolate);
1265f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  BinaryOpICStub::GenerateAheadOfTime(isolate);
1266f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  BinaryOpICWithAllocationSiteStub::GenerateAheadOfTime(isolate);
1267f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  StoreFastElementStub::GenerateAheadOfTime(isolate);
126880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
126980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
127080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
1271f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdochvoid CodeStub::GenerateFPStubs(Isolate* isolate) {
1272f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch}
127380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
127480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
1275f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdochvoid CEntryStub::GenerateAheadOfTime(Isolate* isolate) {
1276f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  CEntryStub stub(isolate, 1, kDontSaveFPRegs);
1277f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  stub.GetCode();
1278f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  CEntryStub save_doubles(isolate, 1, kSaveFPRegs);
1279f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  save_doubles.GetCode();
128080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
128180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
128280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
1283f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdochvoid CEntryStub::Generate(MacroAssembler* masm) {
1284f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // rax: number of arguments including receiver
1285f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // rbx: pointer to C function  (C callee-saved)
1286f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // rbp: frame pointer of calling JS frame (restored after C call)
1287f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // rsp: stack pointer  (restored after C call)
1288f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // rsi: current context (restored)
1289f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  //
1290f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // If argv_in_register():
1291f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // r15: pointer to the first argument
129280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
1293f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  ProfileEntryHookStub::MaybeCallEntryHook(masm);
1294f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch
1295f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch#ifdef _WIN64
1296109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  // Windows 64-bit ABI passes arguments in rcx, rdx, r8, r9. It requires the
1297109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  // stack to be aligned to 16 bytes. It only allows a single-word to be
1298109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  // returned in register rax. Larger return sizes must be written to an address
1299109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  // passed as a hidden first argument.
1300109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  const Register kCCallArg0 = rcx;
1301109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  const Register kCCallArg1 = rdx;
1302109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  const Register kCCallArg2 = r8;
1303109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  const Register kCCallArg3 = r9;
1304109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  const int kArgExtraStackSpace = 2;
1305109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  const int kMaxRegisterResultSize = 1;
1306109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch#else
1307109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  // GCC / Clang passes arguments in rdi, rsi, rdx, rcx, r8, r9. Simple results
1308109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  // are returned in rax, and a struct of two pointers are returned in rax+rdx.
1309109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  // Larger return sizes must be written to an address passed as a hidden first
1310109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  // argument.
1311109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  const Register kCCallArg0 = rdi;
1312109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  const Register kCCallArg1 = rsi;
1313109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  const Register kCCallArg2 = rdx;
1314109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  const Register kCCallArg3 = rcx;
1315109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  const int kArgExtraStackSpace = 0;
1316109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  const int kMaxRegisterResultSize = 2;
1317f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch#endif  // _WIN64
1318109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch
1319109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  // Enter the exit frame that transitions from JavaScript to C++.
1320109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  int arg_stack_space =
1321109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch      kArgExtraStackSpace +
1322109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch      (result_size() <= kMaxRegisterResultSize ? 0 : result_size());
1323f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  if (argv_in_register()) {
1324f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    DCHECK(!save_doubles());
1325f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    DCHECK(!is_builtin_exit());
1326f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ EnterApiExitFrame(arg_stack_space);
1327f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    // Move argc into r14 (argv is already in r15).
1328f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ movp(r14, rax);
1329f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  } else {
1330f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    __ EnterExitFrame(
1331f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch        arg_stack_space, save_doubles(),
1332f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch        is_builtin_exit() ? StackFrame::BUILTIN_EXIT : StackFrame::EXIT);
133380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
133480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
1335f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // rbx: pointer to builtin function  (C callee-saved).
1336f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // rbp: frame pointer of exit frame  (restored after C call).
1337f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // rsp: stack pointer (restored after C call).
1338f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // r14: number of arguments including receiver (C callee-saved).
1339f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // r15: argv pointer (C callee-saved).
134080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
1341f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // Check stack alignment.
1342f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  if (FLAG_debug_code) {
1343f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ CheckStackAlignment();
1344f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  }
134580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
1346109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  // Call C function. The arguments object will be created by stubs declared by
1347109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  // DECLARE_RUNTIME_FUNCTION().
1348109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  if (result_size() <= kMaxRegisterResultSize) {
1349f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    // Pass a pointer to the Arguments object as the first argument.
1350109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    // Return result in single register (rax), or a register pair (rax, rdx).
1351109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ movp(kCCallArg0, r14);  // argc.
1352109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ movp(kCCallArg1, r15);  // argv.
1353109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ Move(kCCallArg2, ExternalReference::isolate_address(isolate()));
1354f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  } else {
1355109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    DCHECK_LE(result_size(), 3);
1356f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    // Pass a pointer to the result location as the first argument.
1357109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ leap(kCCallArg0, StackSpaceOperand(kArgExtraStackSpace));
1358f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    // Pass a pointer to the Arguments object as the second argument.
1359109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ movp(kCCallArg1, r14);  // argc.
1360109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ movp(kCCallArg2, r15);  // argv.
1361109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ Move(kCCallArg3, ExternalReference::isolate_address(isolate()));
136280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  }
1363f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ call(rbx);
136480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
1365109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  if (result_size() > kMaxRegisterResultSize) {
1366f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    // Read result values stored on stack. Result is stored
1367109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    // above the the two Arguments object slots on Win64.
1368109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    DCHECK_LE(result_size(), 3);
1369109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ movq(kReturnRegister0, StackSpaceOperand(kArgExtraStackSpace + 0));
1370109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ movq(kReturnRegister1, StackSpaceOperand(kArgExtraStackSpace + 1));
1371109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    if (result_size() > 2) {
1372109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch      __ movq(kReturnRegister2, StackSpaceOperand(kArgExtraStackSpace + 2));
1373109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    }
1374f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  }
1375109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  // Result is in rax, rdx:rax or r8:rdx:rax - do not destroy these registers!
137680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
1377f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // Check result for exception sentinel.
1378f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  Label exception_returned;
1379f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ CompareRoot(rax, Heap::kExceptionRootIndex);
1380f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ j(equal, &exception_returned);
138180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
1382f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // Check that there is no pending exception, otherwise we
1383f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // should have returned the exception sentinel.
1384f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  if (FLAG_debug_code) {
1385f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    Label okay;
1386f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ LoadRoot(r14, Heap::kTheHoleValueRootIndex);
1387f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    ExternalReference pending_exception_address(
1388f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch        Isolate::kPendingExceptionAddress, isolate());
1389f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    Operand pending_exception_operand =
1390f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch        masm->ExternalOperand(pending_exception_address);
1391f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ cmpp(r14, pending_exception_operand);
1392f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ j(equal, &okay, Label::kNear);
1393f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ int3();
1394f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ bind(&okay);
1395f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  }
139680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
1397f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // Exit the JavaScript to C++ exit frame.
1398f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ LeaveExitFrame(save_doubles(), !argv_in_register());
1399f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ ret(0);
140080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
1401f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // Handling of exception.
1402f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ bind(&exception_returned);
1403b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1404f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  ExternalReference pending_handler_context_address(
1405f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch      Isolate::kPendingHandlerContextAddress, isolate());
1406f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  ExternalReference pending_handler_code_address(
1407f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch      Isolate::kPendingHandlerCodeAddress, isolate());
1408f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  ExternalReference pending_handler_offset_address(
1409f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch      Isolate::kPendingHandlerOffsetAddress, isolate());
1410f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  ExternalReference pending_handler_fp_address(
1411f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch      Isolate::kPendingHandlerFPAddress, isolate());
1412f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  ExternalReference pending_handler_sp_address(
1413f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch      Isolate::kPendingHandlerSPAddress, isolate());
141480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
1415f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // Ask the runtime for help to determine the handler. This will set rax to
1416f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // contain the current pending exception, don't clobber it.
1417f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  ExternalReference find_handler(Runtime::kUnwindAndFindExceptionHandler,
1418f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch                                 isolate());
1419f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  {
1420f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    FrameScope scope(masm, StackFrame::MANUAL);
1421f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ movp(arg_reg_1, Immediate(0));  // argc.
1422f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ movp(arg_reg_2, Immediate(0));  // argv.
1423f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ Move(arg_reg_3, ExternalReference::isolate_address(isolate()));
1424f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ PrepareCallCFunction(3);
1425f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ CallCFunction(find_handler, 3);
1426f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  }
142780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
1428f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // Retrieve the handler context, SP and FP.
1429f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ movp(rsi, masm->ExternalOperand(pending_handler_context_address));
1430f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ movp(rsp, masm->ExternalOperand(pending_handler_sp_address));
1431f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ movp(rbp, masm->ExternalOperand(pending_handler_fp_address));
143280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
1433f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // If the handler is a JS frame, restore the context to the frame. Note that
1434f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // the context will be set to (rsi == 0) for non-JS frames.
1435f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  Label skip;
1436f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ testp(rsi, rsi);
1437f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ j(zero, &skip, Label::kNear);
1438f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ movp(Operand(rbp, StandardFrameConstants::kContextOffset), rsi);
1439f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ bind(&skip);
144080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
1441f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // Compute the handler entry address and jump to it.
1442f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ movp(rdi, masm->ExternalOperand(pending_handler_code_address));
1443f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ movp(rdx, masm->ExternalOperand(pending_handler_offset_address));
1444f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ leap(rdi, FieldOperand(rdi, rdx, times_1, Code::kHeaderSize));
1445f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ jmp(rdi);
1446f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch}
144780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
14483ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
1449f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdochvoid JSEntryStub::Generate(MacroAssembler* masm) {
1450f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  Label invoke, handler_entry, exit;
1451f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  Label not_outermost_js, not_outermost_js_2;
14523ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
1453f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  ProfileEntryHookStub::MaybeCallEntryHook(masm);
14543ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
1455f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  {  // NOLINT. Scope block confuses linter.
1456f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    MacroAssembler::NoRootArrayScope uninitialized_root_register(masm);
1457f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    // Set up frame.
1458f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ pushq(rbp);
1459f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ movp(rbp, rsp);
14603ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
14613b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch    // Push the stack frame type.
146262ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    __ Push(Immediate(StackFrame::TypeToMarker(type())));  // context slot
14633b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch    ExternalReference context_address(Isolate::kContextAddress, isolate());
14643b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch    __ Load(kScratchRegister, context_address);
14653b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch    __ Push(kScratchRegister);  // context
1466f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    // Save callee-saved registers (X64/X32/Win64 calling conventions).
1467f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ pushq(r12);
1468f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ pushq(r13);
1469f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ pushq(r14);
1470f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ pushq(r15);
1471f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch#ifdef _WIN64
1472f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ pushq(rdi);  // Only callee save in Win64 ABI, argument in AMD64 ABI.
1473f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ pushq(rsi);  // Only callee save in Win64 ABI, argument in AMD64 ABI.
1474f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch#endif
1475f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ pushq(rbx);
14763ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
1477f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch#ifdef _WIN64
1478f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    // On Win64 XMM6-XMM15 are callee-save
1479f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ subp(rsp, Immediate(EntryFrameConstants::kXMMRegistersBlockSize));
1480f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ movdqu(Operand(rsp, EntryFrameConstants::kXMMRegisterSize * 0), xmm6);
1481f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ movdqu(Operand(rsp, EntryFrameConstants::kXMMRegisterSize * 1), xmm7);
1482f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ movdqu(Operand(rsp, EntryFrameConstants::kXMMRegisterSize * 2), xmm8);
1483f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ movdqu(Operand(rsp, EntryFrameConstants::kXMMRegisterSize * 3), xmm9);
1484f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ movdqu(Operand(rsp, EntryFrameConstants::kXMMRegisterSize * 4), xmm10);
1485f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ movdqu(Operand(rsp, EntryFrameConstants::kXMMRegisterSize * 5), xmm11);
1486f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ movdqu(Operand(rsp, EntryFrameConstants::kXMMRegisterSize * 6), xmm12);
1487f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ movdqu(Operand(rsp, EntryFrameConstants::kXMMRegisterSize * 7), xmm13);
1488f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ movdqu(Operand(rsp, EntryFrameConstants::kXMMRegisterSize * 8), xmm14);
1489f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ movdqu(Operand(rsp, EntryFrameConstants::kXMMRegisterSize * 9), xmm15);
1490f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch#endif
149180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
1492f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    // Set up the roots and smi constant registers.
1493f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    // Needs to be done before any further smi loads.
1494f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ InitializeRootRegister();
1495f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  }
1496589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch
1497f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // Save copies of the top frame descriptor on the stack.
1498f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  ExternalReference c_entry_fp(Isolate::kCEntryFPAddress, isolate());
1499f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  {
1500f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    Operand c_entry_fp_operand = masm->ExternalOperand(c_entry_fp);
1501f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ Push(c_entry_fp_operand);
1502589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch  }
150380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
1504f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // If this is the outermost JS call, set js_entry_sp value.
1505f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  ExternalReference js_entry_sp(Isolate::kJSEntrySPAddress, isolate());
1506f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ Load(rax, js_entry_sp);
1507f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ testp(rax, rax);
1508f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ j(not_zero, &not_outermost_js);
150962ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  __ Push(Immediate(StackFrame::OUTERMOST_JSENTRY_FRAME));
1510f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ movp(rax, rbp);
1511f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ Store(js_entry_sp, rax);
1512f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  Label cont;
1513f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ jmp(&cont);
1514f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ bind(&not_outermost_js);
151562ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  __ Push(Immediate(StackFrame::INNER_JSENTRY_FRAME));
1516f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ bind(&cont);
15173ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
1518f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // Jump to a faked try block that does the invoke, with a faked catch
1519f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // block that sets the pending exception.
1520f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ jmp(&invoke);
1521f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ bind(&handler_entry);
1522f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  handler_offset_ = handler_entry.pos();
1523f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // Caught exception: Store result (exception) in the pending exception
1524f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // field in the JSEnv and return a failure sentinel.
1525f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  ExternalReference pending_exception(Isolate::kPendingExceptionAddress,
1526f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch                                      isolate());
1527f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ Store(pending_exception, rax);
1528f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ LoadRoot(rax, Heap::kExceptionRootIndex);
1529f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ jmp(&exit);
15303ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
1531f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // Invoke: Link this frame into the handler chain.
1532f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ bind(&invoke);
1533f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ PushStackHandler();
153480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
1535f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // Fake a receiver (NULL).
1536f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ Push(Immediate(0));  // receiver
1537f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch
1538f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // Invoke the function by calling through JS entry trampoline builtin and
1539f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // pop the faked function when we return. We load the address from an
1540f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // external reference instead of inlining the call target address directly
1541f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // in the code, because the builtin stubs may not have been generated yet
1542f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // at the time this code is generated.
1543f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  if (type() == StackFrame::ENTRY_CONSTRUCT) {
1544f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    ExternalReference construct_entry(Builtins::kJSConstructEntryTrampoline,
1545f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch                                      isolate());
1546f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ Load(rax, construct_entry);
1547f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  } else {
1548f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    ExternalReference entry(Builtins::kJSEntryTrampoline, isolate());
1549f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ Load(rax, entry);
155085b71799222b55eb5dd74ea26efe0c64ab655c8cBen Murdoch  }
1551f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ leap(kScratchRegister, FieldOperand(rax, Code::kHeaderSize));
1552f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ call(kScratchRegister);
155380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
1554f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // Unlink this frame from the handler chain.
1555f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ PopStackHandler();
155680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
1557f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ bind(&exit);
1558f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // Check if the current stack frame is marked as the outermost JS frame.
1559f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ Pop(rbx);
156062ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  __ cmpp(rbx, Immediate(StackFrame::OUTERMOST_JSENTRY_FRAME));
1561f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ j(not_equal, &not_outermost_js_2);
1562f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ Move(kScratchRegister, js_entry_sp);
1563f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ movp(Operand(kScratchRegister, 0), Immediate(0));
1564f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ bind(&not_outermost_js_2);
156580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
1566f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // Restore the top frame descriptor from the stack.
1567f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  { Operand c_entry_fp_operand = masm->ExternalOperand(c_entry_fp);
1568f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ Pop(c_entry_fp_operand);
156985b71799222b55eb5dd74ea26efe0c64ab655c8cBen Murdoch  }
157080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
1571f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // Restore callee-saved registers (X64 conventions).
1572f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch#ifdef _WIN64
1573f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // On Win64 XMM6-XMM15 are callee-save
1574f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ movdqu(xmm6, Operand(rsp, EntryFrameConstants::kXMMRegisterSize * 0));
1575f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ movdqu(xmm7, Operand(rsp, EntryFrameConstants::kXMMRegisterSize * 1));
1576f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ movdqu(xmm8, Operand(rsp, EntryFrameConstants::kXMMRegisterSize * 2));
1577f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ movdqu(xmm9, Operand(rsp, EntryFrameConstants::kXMMRegisterSize * 3));
1578f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ movdqu(xmm10, Operand(rsp, EntryFrameConstants::kXMMRegisterSize * 4));
1579f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ movdqu(xmm11, Operand(rsp, EntryFrameConstants::kXMMRegisterSize * 5));
1580f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ movdqu(xmm12, Operand(rsp, EntryFrameConstants::kXMMRegisterSize * 6));
1581f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ movdqu(xmm13, Operand(rsp, EntryFrameConstants::kXMMRegisterSize * 7));
1582f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ movdqu(xmm14, Operand(rsp, EntryFrameConstants::kXMMRegisterSize * 8));
1583f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ movdqu(xmm15, Operand(rsp, EntryFrameConstants::kXMMRegisterSize * 9));
1584f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ addp(rsp, Immediate(EntryFrameConstants::kXMMRegistersBlockSize));
1585f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch#endif
158680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
1587f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ popq(rbx);
1588f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch#ifdef _WIN64
1589f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // Callee save on in Win64 ABI, arguments/volatile in AMD64 ABI.
1590f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ popq(rsi);
1591f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ popq(rdi);
1592f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch#endif
1593f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ popq(r15);
1594f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ popq(r14);
1595f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ popq(r13);
1596f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ popq(r12);
1597f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ addp(rsp, Immediate(2 * kPointerSize));  // remove markers
1598b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1599f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // Restore frame pointer and return.
1600f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ popq(rbp);
1601f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ ret(0);
160280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
160380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
160480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
1605f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch// -------------------------------------------------------------------------
1606f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch// StringCharCodeAtGenerator
16078389745919cae02139ddc085a63c00d024269cf2Ben Murdoch
1608f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdochvoid StringCharCodeAtGenerator::GenerateFast(MacroAssembler* masm) {
1609f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // If the receiver is a smi trigger the non-string case.
1610f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  if (check_mode_ == RECEIVER_IS_UNKNOWN) {
1611f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ JumpIfSmi(object_, receiver_not_string_);
16128389745919cae02139ddc085a63c00d024269cf2Ben Murdoch
1613f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    // Fetch the instance type of the receiver into result register.
1614f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ movp(result_, FieldOperand(object_, HeapObject::kMapOffset));
1615f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ movzxbl(result_, FieldOperand(result_, Map::kInstanceTypeOffset));
1616f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    // If the receiver is not a string trigger the non-string case.
1617f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ testb(result_, Immediate(kIsNotStringMask));
1618f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ j(not_zero, receiver_not_string_);
1619f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  }
16208389745919cae02139ddc085a63c00d024269cf2Ben Murdoch
1621f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // If the index is non-smi trigger the non-smi case.
1622f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ JumpIfNotSmi(index_, &index_not_smi_);
1623f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ bind(&got_smi_index_);
16248389745919cae02139ddc085a63c00d024269cf2Ben Murdoch
1625f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // Check for index out of range.
1626f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ SmiCompare(index_, FieldOperand(object_, String::kLengthOffset));
1627f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ j(above_equal, index_out_of_range_);
16288389745919cae02139ddc085a63c00d024269cf2Ben Murdoch
1629f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ SmiToInteger32(index_, index_);
16308389745919cae02139ddc085a63c00d024269cf2Ben Murdoch
1631f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  StringCharLoadGenerator::Generate(
1632f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch      masm, object_, index_, result_, &call_runtime_);
1633014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
1634f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ Integer32ToSmi(result_, result_);
1635f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ bind(&exit_);
1636014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch}
1637014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
1638014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
1639f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdochvoid StringCharCodeAtGenerator::GenerateSlow(
1640f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    MacroAssembler* masm, EmbedMode embed_mode,
1641f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    const RuntimeCallHelper& call_helper) {
1642f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ Abort(kUnexpectedFallthroughToCharCodeAtSlowCase);
1643014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
1644f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  Factory* factory = masm->isolate()->factory();
1645f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // Index is not a smi.
1646f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ bind(&index_not_smi_);
1647f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // If index is a heap number, try converting it to an integer.
1648f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ CheckMap(index_,
1649f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch              factory->heap_number_map(),
1650f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch              index_not_number_,
1651f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch              DONT_DO_SMI_CHECK);
1652f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  call_helper.BeforeCall(masm);
1653f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  if (embed_mode == PART_OF_IC_HANDLER) {
1654f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ Push(LoadWithVectorDescriptor::VectorRegister());
1655f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ Push(LoadDescriptor::SlotRegister());
1656f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  }
1657f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ Push(object_);
1658f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ Push(index_);  // Consumed by runtime conversion function.
165913e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  __ CallRuntime(Runtime::kNumberToSmi);
1660f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  if (!index_.is(rax)) {
1661f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    // Save the conversion result before the pop instructions below
1662f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    // have a chance to overwrite it.
1663f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ movp(index_, rax);
1664f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  }
1665f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ Pop(object_);
1666f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  if (embed_mode == PART_OF_IC_HANDLER) {
1667f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ Pop(LoadDescriptor::SlotRegister());
1668f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ Pop(LoadWithVectorDescriptor::VectorRegister());
1669f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  }
1670f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // Reload the instance type.
1671f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ movp(result_, FieldOperand(object_, HeapObject::kMapOffset));
1672f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ movzxbl(result_, FieldOperand(result_, Map::kInstanceTypeOffset));
1673f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  call_helper.AfterCall(masm);
1674f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // If index is still not a smi, it must be out of range.
1675f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ JumpIfNotSmi(index_, index_out_of_range_);
1676f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // Otherwise, return to the fast path.
1677f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ jmp(&got_smi_index_);
1678014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
1679f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // Call runtime. We get here when the receiver is a string and the
1680f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // index is a number, but the code of getting the actual character
1681f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // is too complex (e.g., when the string needs to be flattened).
1682f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ bind(&call_runtime_);
1683f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  call_helper.BeforeCall(masm);
1684f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ Push(object_);
1685f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ Integer32ToSmi(index_, index_);
1686f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ Push(index_);
1687f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ CallRuntime(Runtime::kStringCharCodeAtRT);
1688f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  if (!result_.is(rax)) {
1689f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ movp(result_, rax);
1690f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  }
1691f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  call_helper.AfterCall(masm);
1692f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ jmp(&exit_);
1693014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
1694f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ Abort(kUnexpectedFallthroughFromCharCodeAtSlowCase);
1695f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch}
1696014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
1697f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdochvoid StringHelper::GenerateFlatOneByteStringEquals(MacroAssembler* masm,
1698f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch                                                   Register left,
1699f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch                                                   Register right,
1700f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch                                                   Register scratch1,
1701f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch                                                   Register scratch2) {
1702f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  Register length = scratch1;
1703b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1704f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // Compare lengths.
1705f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  Label check_zero_length;
1706f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ movp(length, FieldOperand(left, String::kLengthOffset));
1707f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ SmiCompare(length, FieldOperand(right, String::kLengthOffset));
1708f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ j(equal, &check_zero_length, Label::kNear);
1709f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ Move(rax, Smi::FromInt(NOT_EQUAL));
1710f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ ret(0);
1711b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1712f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // Check if the length is zero.
1713f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  Label compare_chars;
1714f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ bind(&check_zero_length);
1715f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  STATIC_ASSERT(kSmiTag == 0);
1716f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ SmiTest(length);
1717f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ j(not_zero, &compare_chars, Label::kNear);
1718f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ Move(rax, Smi::FromInt(EQUAL));
1719f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ ret(0);
1720b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1721f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // Compare characters.
1722f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ bind(&compare_chars);
1723f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  Label strings_not_equal;
1724f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  GenerateOneByteCharsCompareLoop(masm, left, right, length, scratch2,
1725f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch                                  &strings_not_equal, Label::kNear);
1726b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1727f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // Characters are equal.
1728b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ Move(rax, Smi::FromInt(EQUAL));
1729b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ ret(0);
1730b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1731f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // Characters are not equal.
1732f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ bind(&strings_not_equal);
1733f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ Move(rax, Smi::FromInt(NOT_EQUAL));
1734f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ ret(0);
1735b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch}
1736b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1737b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1738f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdochvoid StringHelper::GenerateCompareFlatOneByteStrings(
1739f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    MacroAssembler* masm, Register left, Register right, Register scratch1,
1740f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    Register scratch2, Register scratch3, Register scratch4) {
1741f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // Ensure that you can always subtract a string length from a non-negative
1742f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // number (e.g. another length).
1743f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  STATIC_ASSERT(String::kMaxLength < 0x7fffffff);
1744257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1745f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // Find minimum length and length difference.
1746f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ movp(scratch1, FieldOperand(left, String::kLengthOffset));
1747f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ movp(scratch4, scratch1);
1748f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ SmiSub(scratch4,
1749f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch            scratch4,
1750f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch            FieldOperand(right, String::kLengthOffset));
1751f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // Register scratch4 now holds left.length - right.length.
1752f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  const Register length_difference = scratch4;
1753f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  Label left_shorter;
1754f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ j(less, &left_shorter, Label::kNear);
1755f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // The right string isn't longer that the left one.
1756f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // Get the right string's length by subtracting the (non-negative) difference
1757f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // from the left string's length.
1758f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ SmiSub(scratch1, scratch1, length_difference);
1759f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ bind(&left_shorter);
1760f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // Register scratch1 now holds Min(left.length, right.length).
1761f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  const Register min_length = scratch1;
1762257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1763f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  Label compare_lengths;
1764f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // If min-length is zero, go directly to comparing lengths.
1765f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ SmiTest(min_length);
1766f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ j(zero, &compare_lengths, Label::kNear);
1767257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1768f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // Compare loop.
1769f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  Label result_not_equal;
1770f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  GenerateOneByteCharsCompareLoop(
1771f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch      masm, left, right, min_length, scratch2, &result_not_equal,
1772f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch      // In debug-code mode, SmiTest below might push
1773f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch      // the target label outside the near range.
1774f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch      Label::kFar);
1775b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1776f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // Completed loop without finding different characters.
1777f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // Compare lengths (precomputed).
1778f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ bind(&compare_lengths);
1779f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ SmiTest(length_difference);
1780f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  Label length_not_equal;
1781f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ j(not_zero, &length_not_equal, Label::kNear);
1782b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1783f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // Result is EQUAL.
1784257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ Move(rax, Smi::FromInt(EQUAL));
1785257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  __ ret(0);
1786257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1787f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  Label result_greater;
1788f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  Label result_less;
1789f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ bind(&length_not_equal);
1790f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ j(greater, &result_greater, Label::kNear);
1791f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ jmp(&result_less, Label::kNear);
1792f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ bind(&result_not_equal);
1793f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // Unequal comparison of left to right, either character or length.
1794f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ j(above, &result_greater, Label::kNear);
1795f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ bind(&result_less);
1796257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1797f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // Result is LESS.
1798f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ Move(rax, Smi::FromInt(LESS));
1799f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ ret(0);
1800257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1801f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // Result is GREATER.
1802f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ bind(&result_greater);
1803f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ Move(rax, Smi::FromInt(GREATER));
1804f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ ret(0);
1805f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch}
1806257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
18073ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
1808f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdochvoid StringHelper::GenerateOneByteCharsCompareLoop(
1809f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    MacroAssembler* masm, Register left, Register right, Register length,
1810f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    Register scratch, Label* chars_not_equal, Label::Distance near_jump) {
1811f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // Change index to run from -length to -1 by adding length to string
1812f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // start. This means that loop ends when index reaches zero, which
1813f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // doesn't need an additional compare.
1814f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ SmiToInteger32(length, length);
1815f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ leap(left,
1816f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch         FieldOperand(left, length, times_1, SeqOneByteString::kHeaderSize));
1817f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ leap(right,
1818f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch         FieldOperand(right, length, times_1, SeqOneByteString::kHeaderSize));
1819f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ negq(length);
1820f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  Register index = length;  // index = -length;
1821257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1822f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // Compare loop.
1823f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  Label loop;
1824f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ bind(&loop);
1825f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ movb(scratch, Operand(left, index, times_1, 0));
1826f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ cmpb(scratch, Operand(right, index, times_1, 0));
1827f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ j(not_equal, chars_not_equal, near_jump);
1828f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ incq(index);
1829f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ j(not_zero, &loop);
1830f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch}
1831257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1832257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1833f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdochvoid BinaryOpICWithAllocationSiteStub::Generate(MacroAssembler* masm) {
1834f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // ----------- S t a t e -------------
1835f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  //  -- rdx    : left
1836f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  //  -- rax    : right
1837f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  //  -- rsp[0] : return address
1838f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // -----------------------------------
18391e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
1840f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // Load rcx with the allocation site.  We stick an undefined dummy value here
1841f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // and replace it with the real allocation site later when we instantiate this
1842f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // stub in BinaryOpICWithAllocationSiteStub::GetCodeCopyFromTemplate().
184313e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  __ Move(rcx, isolate()->factory()->undefined_value());
18441e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
1845f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // Make sure that we actually patched the allocation site.
1846f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  if (FLAG_debug_code) {
1847f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ testb(rcx, Immediate(kSmiTagMask));
1848f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ Assert(not_equal, kExpectedAllocationSite);
1849f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ Cmp(FieldOperand(rcx, HeapObject::kMapOffset),
1850f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch           isolate()->factory()->allocation_site_map());
1851f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ Assert(equal, kExpectedAllocationSite);
1852f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  }
18531e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
1854f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // Tail call into the stub that handles binary operations with allocation
1855f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // sites.
1856f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  BinaryOpWithAllocationSiteStub stub(isolate(), state());
1857f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ TailCallStub(&stub);
1858b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch}
1859b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1860b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1861f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdochvoid CompareICStub::GenerateBooleans(MacroAssembler* masm) {
1862f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  DCHECK_EQ(CompareICState::BOOLEAN, state());
18633ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  Label miss;
1864f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  Label::Distance const miss_distance =
1865f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch      masm->emit_debug_code() ? Label::kFar : Label::kNear;
18661e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
1867f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ JumpIfSmi(rdx, &miss, miss_distance);
1868f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ movp(rcx, FieldOperand(rdx, HeapObject::kMapOffset));
1869f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ JumpIfSmi(rax, &miss, miss_distance);
1870f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ movp(rbx, FieldOperand(rax, HeapObject::kMapOffset));
1871f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ JumpIfNotRoot(rcx, Heap::kBooleanMapRootIndex, &miss, miss_distance);
1872f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ JumpIfNotRoot(rbx, Heap::kBooleanMapRootIndex, &miss, miss_distance);
1873109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  if (!Token::IsEqualityOp(op())) {
1874109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ movp(rax, FieldOperand(rax, Oddball::kToNumberOffset));
1875109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ AssertSmi(rax);
1876109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ movp(rdx, FieldOperand(rdx, Oddball::kToNumberOffset));
1877109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ AssertSmi(rdx);
1878109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ pushq(rax);
1879109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ movq(rax, rdx);
1880109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ popq(rdx);
1881014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  }
1882109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  __ subp(rax, rdx);
1883109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  __ Ret();
188485b71799222b55eb5dd74ea26efe0c64ab655c8cBen Murdoch
18853ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ bind(&miss);
18863ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  GenerateMiss(masm);
18873ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch}
18883ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
18893ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
1890f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdochvoid CompareICStub::GenerateSmis(MacroAssembler* masm) {
1891f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  DCHECK(state() == CompareICState::SMI);
1892f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  Label miss;
1893f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ JumpIfNotBothSmi(rdx, rax, &miss, Label::kNear);
18943ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
1895f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  if (GetCondition() == equal) {
1896f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    // For equality we do not care about the sign of the result.
1897f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ subp(rax, rdx);
1898f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  } else {
1899f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    Label done;
1900f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ subp(rdx, rax);
1901f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ j(no_overflow, &done, Label::kNear);
1902f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    // Correct sign of result in case of overflow.
1903f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ notp(rdx);
1904f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ bind(&done);
1905f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ movp(rax, rdx);
19063ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  }
1907f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ ret(0);
19081e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
1909f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ bind(&miss);
1910f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  GenerateMiss(masm);
19111e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block}
19121e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
19131e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
1914f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdochvoid CompareICStub::GenerateNumbers(MacroAssembler* masm) {
1915f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  DCHECK(state() == CompareICState::NUMBER);
1916257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1917f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  Label generic_stub;
1918f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  Label unordered, maybe_undefined1, maybe_undefined2;
1919f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  Label miss;
19203ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
1921f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  if (left() == CompareICState::SMI) {
1922f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ JumpIfNotSmi(rdx, &miss);
1923f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  }
1924f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  if (right() == CompareICState::SMI) {
1925f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ JumpIfNotSmi(rax, &miss);
1926257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
1927257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1928f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // Load left and right operand.
1929f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  Label done, left, left_smi, right_smi;
1930f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ JumpIfSmi(rax, &right_smi, Label::kNear);
1931f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ CompareMap(rax, isolate()->factory()->heap_number_map());
1932f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ j(not_equal, &maybe_undefined1, Label::kNear);
1933f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ Movsd(xmm1, FieldOperand(rax, HeapNumber::kValueOffset));
1934f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ jmp(&left, Label::kNear);
1935f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ bind(&right_smi);
1936f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ SmiToInteger32(rcx, rax);  // Can't clobber rax yet.
1937f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ Cvtlsi2sd(xmm1, rcx);
1938257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1939f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ bind(&left);
1940f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ JumpIfSmi(rdx, &left_smi, Label::kNear);
1941f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ CompareMap(rdx, isolate()->factory()->heap_number_map());
1942f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ j(not_equal, &maybe_undefined2, Label::kNear);
1943f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ Movsd(xmm0, FieldOperand(rdx, HeapNumber::kValueOffset));
1944f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ jmp(&done);
1945f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ bind(&left_smi);
1946f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ SmiToInteger32(rcx, rdx);  // Can't clobber rdx yet.
1947f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ Cvtlsi2sd(xmm0, rcx);
1948257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1949f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ bind(&done);
1950f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // Compare operands
1951f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ Ucomisd(xmm0, xmm1);
1952257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1953f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // Don't base result on EFLAGS when a NaN is involved.
1954f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ j(parity_even, &unordered, Label::kNear);
1955257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1956f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // Return a result of -1, 0, or 1, based on EFLAGS.
1957f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // Performing mov, because xor would destroy the flag register.
1958f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ movl(rax, Immediate(0));
1959f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ movl(rcx, Immediate(0));
1960f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ setcc(above, rax);  // Add one to zero if carry clear and not equal.
1961f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ sbbp(rax, rcx);  // Subtract one if below (aka. carry set).
1962f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ ret(0);
1963f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch
1964f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ bind(&unordered);
1965f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ bind(&generic_stub);
1966109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  CompareICStub stub(isolate(), op(), CompareICState::GENERIC,
1967f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch                     CompareICState::GENERIC, CompareICState::GENERIC);
1968f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ jmp(stub.GetCode(), RelocInfo::CODE_TARGET);
1969f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch
1970f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ bind(&maybe_undefined1);
1971f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  if (Token::IsOrderedRelationalCompareOp(op())) {
1972f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ Cmp(rax, isolate()->factory()->undefined_value());
1973f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ j(not_equal, &miss);
1974f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ JumpIfSmi(rdx, &unordered);
1975f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ CmpObjectType(rdx, HEAP_NUMBER_TYPE, rcx);
1976f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ j(not_equal, &maybe_undefined2, Label::kNear);
1977f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ jmp(&unordered);
1978257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
1979257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1980f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ bind(&maybe_undefined2);
1981f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  if (Token::IsOrderedRelationalCompareOp(op())) {
1982f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ Cmp(rdx, isolate()->factory()->undefined_value());
1983f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ j(equal, &unordered);
1984f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  }
1985257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1986f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ bind(&miss);
1987f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  GenerateMiss(masm);
1988257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch}
1989257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1990257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1991f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdochvoid CompareICStub::GenerateInternalizedStrings(MacroAssembler* masm) {
1992f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  DCHECK(state() == CompareICState::INTERNALIZED_STRING);
1993f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  DCHECK(GetCondition() == equal);
1994257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
1995f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // Registers containing left and right operands respectively.
1996f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  Register left = rdx;
1997f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  Register right = rax;
1998f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  Register tmp1 = rcx;
1999f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  Register tmp2 = rbx;
2000257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
2001f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // Check that both operands are heap objects.
2002f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  Label miss;
2003f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  Condition cond = masm->CheckEitherSmi(left, right, tmp1);
2004f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ j(cond, &miss, Label::kNear);
2005257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
2006f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // Check that both operands are internalized strings.
2007f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ movp(tmp1, FieldOperand(left, HeapObject::kMapOffset));
2008f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ movp(tmp2, FieldOperand(right, HeapObject::kMapOffset));
2009f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ movzxbp(tmp1, FieldOperand(tmp1, Map::kInstanceTypeOffset));
2010f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ movzxbp(tmp2, FieldOperand(tmp2, Map::kInstanceTypeOffset));
2011f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  STATIC_ASSERT(kInternalizedTag == 0 && kStringTag == 0);
2012f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ orp(tmp1, tmp2);
2013f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ testb(tmp1, Immediate(kIsNotStringMask | kIsNotInternalizedMask));
2014f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ j(not_zero, &miss, Label::kNear);
2015257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
2016f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // Internalized strings are compared by identity.
2017f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  Label done;
2018f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ cmpp(left, right);
2019f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // Make sure rax is non-zero. At this point input operands are
2020f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // guaranteed to be non-zero.
2021f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  DCHECK(right.is(rax));
2022f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ j(not_equal, &done, Label::kNear);
2023f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  STATIC_ASSERT(EQUAL == 0);
2024f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  STATIC_ASSERT(kSmiTag == 0);
2025f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ Move(rax, Smi::FromInt(EQUAL));
2026f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ bind(&done);
2027f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ ret(0);
2028257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
2029f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ bind(&miss);
2030f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  GenerateMiss(masm);
2031f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch}
2032257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
2033257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
2034f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdochvoid CompareICStub::GenerateUniqueNames(MacroAssembler* masm) {
2035f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  DCHECK(state() == CompareICState::UNIQUE_NAME);
2036f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  DCHECK(GetCondition() == equal);
2037257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
2038f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // Registers containing left and right operands respectively.
2039f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  Register left = rdx;
2040f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  Register right = rax;
2041f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  Register tmp1 = rcx;
2042f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  Register tmp2 = rbx;
2043257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
2044f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // Check that both operands are heap objects.
2045f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  Label miss;
2046f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  Condition cond = masm->CheckEitherSmi(left, right, tmp1);
2047f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ j(cond, &miss, Label::kNear);
2048257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
2049f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // Check that both operands are unique names. This leaves the instance
2050f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // types loaded in tmp1 and tmp2.
2051f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ movp(tmp1, FieldOperand(left, HeapObject::kMapOffset));
2052f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ movp(tmp2, FieldOperand(right, HeapObject::kMapOffset));
2053f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ movzxbp(tmp1, FieldOperand(tmp1, Map::kInstanceTypeOffset));
2054f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ movzxbp(tmp2, FieldOperand(tmp2, Map::kInstanceTypeOffset));
2055257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
2056f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ JumpIfNotUniqueNameInstanceType(tmp1, &miss, Label::kNear);
2057f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ JumpIfNotUniqueNameInstanceType(tmp2, &miss, Label::kNear);
2058257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
2059f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // Unique names are compared by identity.
2060f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  Label done;
2061f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ cmpp(left, right);
2062f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // Make sure rax is non-zero. At this point input operands are
2063f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // guaranteed to be non-zero.
2064f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  DCHECK(right.is(rax));
2065f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ j(not_equal, &done, Label::kNear);
2066f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  STATIC_ASSERT(EQUAL == 0);
2067f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  STATIC_ASSERT(kSmiTag == 0);
2068f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ Move(rax, Smi::FromInt(EQUAL));
2069f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ bind(&done);
2070f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ ret(0);
2071257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
2072f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ bind(&miss);
2073f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  GenerateMiss(masm);
2074257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch}
2075257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
2076257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
2077f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdochvoid CompareICStub::GenerateStrings(MacroAssembler* masm) {
2078f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  DCHECK(state() == CompareICState::STRING);
2079f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  Label miss;
20803ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
2081f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  bool equality = Token::IsEqualityOp(op());
20823ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
2083f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // Registers containing left and right operands respectively.
2084f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  Register left = rdx;
2085f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  Register right = rax;
2086f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  Register tmp1 = rcx;
2087f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  Register tmp2 = rbx;
2088f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  Register tmp3 = rdi;
20893ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
2090f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // Check that both operands are heap objects.
2091f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  Condition cond = masm->CheckEitherSmi(left, right, tmp1);
2092f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ j(cond, &miss);
20933ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
2094f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // Check that both operands are strings. This leaves the instance
2095f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // types loaded in tmp1 and tmp2.
2096f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ movp(tmp1, FieldOperand(left, HeapObject::kMapOffset));
2097f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ movp(tmp2, FieldOperand(right, HeapObject::kMapOffset));
2098f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ movzxbp(tmp1, FieldOperand(tmp1, Map::kInstanceTypeOffset));
2099f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ movzxbp(tmp2, FieldOperand(tmp2, Map::kInstanceTypeOffset));
2100f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ movp(tmp3, tmp1);
2101f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  STATIC_ASSERT(kNotStringTag != 0);
2102f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ orp(tmp3, tmp2);
2103f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ testb(tmp3, Immediate(kIsNotStringMask));
2104f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ j(not_zero, &miss);
2105f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch
2106f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // Fast check for identical strings.
2107f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  Label not_same;
2108f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ cmpp(left, right);
2109f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ j(not_equal, &not_same, Label::kNear);
2110f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  STATIC_ASSERT(EQUAL == 0);
2111f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  STATIC_ASSERT(kSmiTag == 0);
2112f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ Move(rax, Smi::FromInt(EQUAL));
2113f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ ret(0);
2114f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch
2115f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // Handle not identical strings.
2116f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ bind(&not_same);
2117f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch
2118f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // Check that both strings are internalized strings. If they are, we're done
2119f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // because we already know they are not identical. We also know they are both
2120f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // strings.
2121f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  if (equality) {
2122f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    Label do_compare;
2123f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    STATIC_ASSERT(kInternalizedTag == 0);
2124f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ orp(tmp1, tmp2);
2125f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ testb(tmp1, Immediate(kIsNotInternalizedMask));
2126f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ j(not_zero, &do_compare, Label::kNear);
2127f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    // Make sure rax is non-zero. At this point input operands are
2128f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    // guaranteed to be non-zero.
2129f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    DCHECK(right.is(rax));
21303ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    __ ret(0);
2131f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ bind(&do_compare);
21323ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  }
21333ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
2134f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // Check that both strings are sequential one-byte.
2135f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  Label runtime;
2136f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ JumpIfNotBothSequentialOneByteStrings(left, right, tmp1, tmp2, &runtime);
21373ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
2138f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // Compare flat one-byte strings. Returns when done.
2139f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  if (equality) {
2140f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    StringHelper::GenerateFlatOneByteStringEquals(masm, left, right, tmp1,
2141f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch                                                  tmp2);
2142f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  } else {
2143f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    StringHelper::GenerateCompareFlatOneByteStrings(
2144f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch        masm, left, right, tmp1, tmp2, tmp3, kScratchRegister);
2145f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  }
21463ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
2147f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // Handle more complex cases in runtime.
2148f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ bind(&runtime);
2149f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  if (equality) {
21503b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch    {
21513b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch      FrameScope scope(masm, StackFrame::INTERNAL);
21523b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch      __ Push(left);
21533b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch      __ Push(right);
21543b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch      __ CallRuntime(Runtime::kStringEqual);
21553b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch    }
21563b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch    __ LoadRoot(rdx, Heap::kTrueValueRootIndex);
21573b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch    __ subp(rax, rdx);
21583b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch    __ Ret();
2159f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  } else {
21603b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch    __ PopReturnAddressTo(tmp1);
21613b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch    __ Push(left);
21623b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch    __ Push(right);
21633b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch    __ PushReturnAddressFrom(tmp1);
2164f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ TailCallRuntime(Runtime::kStringCompare);
2165f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  }
21663ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
2167f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ bind(&miss);
2168f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  GenerateMiss(masm);
2169f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch}
21703ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
21713ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
2172f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdochvoid CompareICStub::GenerateReceivers(MacroAssembler* masm) {
2173f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  DCHECK_EQ(CompareICState::RECEIVER, state());
2174f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  Label miss;
2175f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  Condition either_smi = masm->CheckEitherSmi(rdx, rax);
2176f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ j(either_smi, &miss, Label::kNear);
21773ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
2178f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  STATIC_ASSERT(LAST_TYPE == LAST_JS_RECEIVER_TYPE);
2179f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ CmpObjectType(rax, FIRST_JS_RECEIVER_TYPE, rcx);
2180f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ j(below, &miss, Label::kNear);
2181f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ CmpObjectType(rdx, FIRST_JS_RECEIVER_TYPE, rcx);
2182f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ j(below, &miss, Label::kNear);
21833ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
2184f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  DCHECK_EQ(equal, GetCondition());
2185f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ subp(rax, rdx);
21863ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __ ret(0);
2187f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch
2188f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ bind(&miss);
2189f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  GenerateMiss(masm);
21903ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch}
21913ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
21923ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
2193f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdochvoid CompareICStub::GenerateKnownReceivers(MacroAssembler* masm) {
2194f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  Label miss;
2195f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  Handle<WeakCell> cell = Map::WeakCellForMap(known_map_);
2196f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  Condition either_smi = masm->CheckEitherSmi(rdx, rax);
2197f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ j(either_smi, &miss, Label::kNear);
21983ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
2199f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ GetWeakValue(rdi, cell);
2200f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ cmpp(FieldOperand(rdx, HeapObject::kMapOffset), rdi);
2201f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ j(not_equal, &miss, Label::kNear);
2202f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ cmpp(FieldOperand(rax, HeapObject::kMapOffset), rdi);
2203f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ j(not_equal, &miss, Label::kNear);
22043ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
2205f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  if (Token::IsEqualityOp(op())) {
2206f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ subp(rax, rdx);
2207f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ ret(0);
2208f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  } else {
2209f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ PopReturnAddressTo(rcx);
2210f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ Push(rdx);
2211f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ Push(rax);
2212f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ Push(Smi::FromInt(NegativeComparisonResult(GetCondition())));
2213f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ PushReturnAddressFrom(rcx);
2214f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ TailCallRuntime(Runtime::kCompare);
2215f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  }
22163ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
2217f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ bind(&miss);
2218f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  GenerateMiss(masm);
2219f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch}
22203ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
2221b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
2222f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdochvoid CompareICStub::GenerateMiss(MacroAssembler* masm) {
2223f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  {
2224f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    // Call the runtime system in a fresh internal frame.
2225f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    FrameScope scope(masm, StackFrame::INTERNAL);
2226f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ Push(rdx);
2227f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ Push(rax);
2228f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ Push(rdx);
2229f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ Push(rax);
2230f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ Push(Smi::FromInt(op()));
2231f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ CallRuntime(Runtime::kCompareIC_Miss);
22323ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
2233f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    // Compute the entry point of the rewritten stub.
2234f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ leap(rdi, FieldOperand(rax, Code::kHeaderSize));
2235f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ Pop(rax);
2236f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ Pop(rdx);
22373ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  }
22383ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
2239f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // Do a tail call to the rewritten stub.
2240f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ jmp(rdi);
2241f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch}
22423ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
22433ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
2244f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdochvoid NameDictionaryLookupStub::GenerateNegativeLookup(MacroAssembler* masm,
2245f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch                                                      Label* miss,
2246f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch                                                      Label* done,
2247f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch                                                      Register properties,
2248f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch                                                      Handle<Name> name,
2249f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch                                                      Register r0) {
2250f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  DCHECK(name->IsUniqueName());
2251f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // If names of slots in range from 1 to kProbes - 1 for the hash value are
2252f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // not equal to the name and kProbes-th slot is not used (its name is the
2253f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // undefined value), it guarantees the hash table doesn't contain the
2254f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // property. It's true even if some slots represent deleted properties
2255f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // (their names are the hole value).
2256f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  for (int i = 0; i < kInlinedProbes; i++) {
2257f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    // r0 points to properties hash.
2258f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    // Compute the masked index: (hash + i + i * i) & mask.
2259f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    Register index = r0;
2260f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    // Capacity is smi 2^n.
2261f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ SmiToInteger32(index, FieldOperand(properties, kCapacityOffset));
2262f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ decl(index);
2263f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ andp(index,
2264f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch            Immediate(name->Hash() + NameDictionary::GetProbeOffset(i)));
22653ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
2266f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    // Scale the index by multiplying by the entry size.
2267f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    STATIC_ASSERT(NameDictionary::kEntrySize == 3);
2268f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ leap(index, Operand(index, index, times_2, 0));  // index *= 3.
22693ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
2270f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    Register entity_name = r0;
2271f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    // Having undefined at this place means the name is not contained.
2272f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    STATIC_ASSERT(kSmiTagSize == 1);
2273f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ movp(entity_name, Operand(properties,
2274f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch                                 index,
2275f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch                                 times_pointer_size,
2276f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch                                 kElementsStartOffset - kHeapObjectTag));
2277f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ Cmp(entity_name, masm->isolate()->factory()->undefined_value());
2278f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ j(equal, done);
22793ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
2280f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    // Stop if found the property.
2281f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ Cmp(entity_name, Handle<Name>(name));
2282f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ j(equal, miss);
22833ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
2284f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    Label good;
2285f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    // Check for the hole and skip.
2286f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ CompareRoot(entity_name, Heap::kTheHoleValueRootIndex);
2287f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ j(equal, &good, Label::kNear);
22883ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
2289f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    // Check if the entry name is not a unique name.
2290f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ movp(entity_name, FieldOperand(entity_name, HeapObject::kMapOffset));
2291f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ JumpIfNotUniqueNameInstanceType(
2292f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch        FieldOperand(entity_name, Map::kInstanceTypeOffset), miss);
2293f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ bind(&good);
22943ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  }
22953ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
2296f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  NameDictionaryLookupStub stub(masm->isolate(), properties, r0, r0,
2297f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch                                NEGATIVE_LOOKUP);
2298f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ Push(Handle<Object>(name));
2299f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ Push(Immediate(name->Hash()));
2300f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ CallStub(&stub);
2301f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ testp(r0, r0);
2302f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ j(not_zero, miss);
2303f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ jmp(done);
2304f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch}
2305f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch
2306f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdochvoid NameDictionaryLookupStub::Generate(MacroAssembler* masm) {
2307f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // This stub overrides SometimesSetsUpAFrame() to return false.  That means
2308f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // we cannot call anything that could cause a GC from this stub.
2309f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // Stack frame on entry:
2310f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  //  rsp[0 * kPointerSize] : return address.
2311f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  //  rsp[1 * kPointerSize] : key's hash.
2312f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  //  rsp[2 * kPointerSize] : key.
2313f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // Registers:
2314f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  //  dictionary_: NameDictionary to probe.
2315f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  //  result_: used as scratch.
2316f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  //  index_: will hold an index of entry if lookup is successful.
2317f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  //          might alias with result_.
2318f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // Returns:
2319f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  //  result_ is zero if lookup failed, non zero otherwise.
2320014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2321f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  Label in_dictionary, maybe_in_dictionary, not_in_dictionary;
2322014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2323f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  Register scratch = result();
2324014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2325f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ SmiToInteger32(scratch, FieldOperand(dictionary(), kCapacityOffset));
2326f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ decl(scratch);
2327f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ Push(scratch);
2328014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2329f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // If names of slots in range from 1 to kProbes - 1 for the hash value are
2330f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // not equal to the name and kProbes-th slot is not used (its name is the
2331f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // undefined value), it guarantees the hash table doesn't contain the
2332f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // property. It's true even if some slots represent deleted properties
2333f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // (their names are the null value).
2334f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  StackArgumentsAccessor args(rsp, 2, ARGUMENTS_DONT_CONTAIN_RECEIVER,
2335f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch                              kPointerSize);
2336f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  for (int i = kInlinedProbes; i < kTotalProbes; i++) {
2337f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    // Compute the masked index: (hash + i + i * i) & mask.
2338f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ movp(scratch, args.GetArgumentOperand(1));
2339f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    if (i > 0) {
2340f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch      __ addl(scratch, Immediate(NameDictionary::GetProbeOffset(i)));
2341f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    }
2342f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ andp(scratch, Operand(rsp, 0));
2343014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2344f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    // Scale the index by multiplying by the entry size.
2345f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    STATIC_ASSERT(NameDictionary::kEntrySize == 3);
2346f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ leap(index(), Operand(scratch, scratch, times_2, 0));  // index *= 3.
2347014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2348f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    // Having undefined at this place means the name is not contained.
2349f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ movp(scratch, Operand(dictionary(), index(), times_pointer_size,
2350f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch                             kElementsStartOffset - kHeapObjectTag));
2351014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2352f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ Cmp(scratch, isolate()->factory()->undefined_value());
2353f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ j(equal, &not_in_dictionary);
2354014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2355f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    // Stop if found the property.
2356f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ cmpp(scratch, args.GetArgumentOperand(0));
2357f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ j(equal, &in_dictionary);
2358014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2359f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    if (i != kTotalProbes - 1 && mode() == NEGATIVE_LOOKUP) {
2360f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch      // If we hit a key that is not a unique name during negative
2361f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch      // lookup we have to bailout as this key might be equal to the
2362f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch      // key we are looking for.
2363014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2364f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch      // Check if the entry name is not a unique name.
2365f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch      __ movp(scratch, FieldOperand(scratch, HeapObject::kMapOffset));
2366f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch      __ JumpIfNotUniqueNameInstanceType(
2367f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch          FieldOperand(scratch, Map::kInstanceTypeOffset),
2368f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch          &maybe_in_dictionary);
2369f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    }
2370f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  }
2371014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2372f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ bind(&maybe_in_dictionary);
2373f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // If we are doing negative lookup then probing failure should be
2374f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // treated as a lookup success. For positive lookup probing failure
2375f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // should be treated as lookup failure.
2376f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  if (mode() == POSITIVE_LOOKUP) {
2377f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ movp(scratch, Immediate(0));
2378f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ Drop(1);
2379f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ ret(2 * kPointerSize);
2380f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  }
2381014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2382f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ bind(&in_dictionary);
2383f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ movp(scratch, Immediate(1));
2384f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ Drop(1);
2385f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ ret(2 * kPointerSize);
2386014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2387f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ bind(&not_in_dictionary);
2388f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ movp(scratch, Immediate(0));
2389f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ Drop(1);
2390f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ ret(2 * kPointerSize);
2391014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch}
2392014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2393014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2394f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdochvoid StoreBufferOverflowStub::GenerateFixedRegStubsAheadOfTime(
2395f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    Isolate* isolate) {
2396f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  StoreBufferOverflowStub stub1(isolate, kDontSaveFPRegs);
2397f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  stub1.GetCode();
2398f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  StoreBufferOverflowStub stub2(isolate, kSaveFPRegs);
2399f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  stub2.GetCode();
2400f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch}
2401014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2402014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2403f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch// Takes the input in 3 registers: address_ value_ and object_.  A pointer to
2404f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch// the value has just been written into the object, now this stub makes sure
2405f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch// we keep the GC informed.  The word in the object where the value has been
2406f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch// written is in the address register.
2407f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdochvoid RecordWriteStub::Generate(MacroAssembler* masm) {
2408f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  Label skip_to_incremental_noncompacting;
2409f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  Label skip_to_incremental_compacting;
2410014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2411f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // The first two instructions are generated with labels so as to get the
2412f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // offset fixed up correctly by the bind(Label*) call.  We patch it back and
2413f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // forth between a compare instructions (a nop in this position) and the
2414f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // real branch when we start and stop incremental heap marking.
2415f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // See RecordWriteStub::Patch for details.
2416f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ jmp(&skip_to_incremental_noncompacting, Label::kNear);
2417f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ jmp(&skip_to_incremental_compacting, Label::kFar);
2418014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2419f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  if (remembered_set_action() == EMIT_REMEMBERED_SET) {
2420f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ RememberedSetHelper(object(), address(), value(), save_fp_regs_mode(),
2421f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch                           MacroAssembler::kReturnAtEnd);
2422f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  } else {
2423f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ ret(0);
2424f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  }
2425014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2426f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ bind(&skip_to_incremental_noncompacting);
2427f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  GenerateIncremental(masm, INCREMENTAL);
2428014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2429f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ bind(&skip_to_incremental_compacting);
2430f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  GenerateIncremental(masm, INCREMENTAL_COMPACTION);
2431014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2432f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // Initial mode of the stub is expected to be STORE_BUFFER_ONLY.
2433f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // Will be checked in IncrementalMarking::ActivateGeneratedStub.
2434f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  masm->set_byte_at(0, kTwoByteNopInstruction);
2435f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  masm->set_byte_at(2, kFiveByteNopInstruction);
2436014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch}
2437014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2438014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2439f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdochvoid RecordWriteStub::GenerateIncremental(MacroAssembler* masm, Mode mode) {
2440f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  regs_.Save(masm);
2441014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2442f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  if (remembered_set_action() == EMIT_REMEMBERED_SET) {
2443f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    Label dont_need_remembered_set;
2444014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2445f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ movp(regs_.scratch0(), Operand(regs_.address(), 0));
2446f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ JumpIfNotInNewSpace(regs_.scratch0(),
2447f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch                           regs_.scratch0(),
2448f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch                           &dont_need_remembered_set);
2449014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2450109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ JumpIfInNewSpace(regs_.object(), regs_.scratch0(),
2451109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch                        &dont_need_remembered_set);
2452014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2453f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    // First notify the incremental marker if necessary, then update the
2454f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    // remembered set.
2455f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    CheckNeedsToInformIncrementalMarker(
2456f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch        masm, kUpdateRememberedSetOnNoNeedToInformIncrementalMarker, mode);
2457f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    InformIncrementalMarker(masm);
2458f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    regs_.Restore(masm);
2459f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ RememberedSetHelper(object(), address(), value(), save_fp_regs_mode(),
2460f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch                           MacroAssembler::kReturnAtEnd);
2461014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2462f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ bind(&dont_need_remembered_set);
2463f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  }
2464014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2465f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  CheckNeedsToInformIncrementalMarker(
2466f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch      masm, kReturnOnNoNeedToInformIncrementalMarker, mode);
2467f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  InformIncrementalMarker(masm);
2468f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  regs_.Restore(masm);
2469f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ ret(0);
2470f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch}
2471014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2472014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2473f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdochvoid RecordWriteStub::InformIncrementalMarker(MacroAssembler* masm) {
2474f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  regs_.SaveCallerSaveRegisters(masm, save_fp_regs_mode());
2475f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  Register address =
2476f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch      arg_reg_1.is(regs_.address()) ? kScratchRegister : regs_.address();
2477f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  DCHECK(!address.is(regs_.object()));
2478f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  DCHECK(!address.is(arg_reg_1));
2479f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ Move(address, regs_.address());
2480f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ Move(arg_reg_1, regs_.object());
2481f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // TODO(gc) Can we just set address arg2 in the beginning?
2482f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ Move(arg_reg_2, address);
2483f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ LoadAddress(arg_reg_3,
2484f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch                 ExternalReference::isolate_address(isolate()));
2485f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  int argument_count = 3;
2486f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch
2487f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  AllowExternalCallThatCantCauseGC scope(masm);
2488f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ PrepareCallCFunction(argument_count);
2489f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ CallCFunction(
2490f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch      ExternalReference::incremental_marking_record_write_function(isolate()),
2491f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch      argument_count);
2492f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  regs_.RestoreCallerSaveRegisters(masm, save_fp_regs_mode());
2493014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch}
2494014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
249562ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdochvoid RecordWriteStub::Activate(Code* code) {
249662ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch  code->GetHeap()->incremental_marking()->ActivateGeneratedStub(code);
249762ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch}
2498014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2499f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdochvoid RecordWriteStub::CheckNeedsToInformIncrementalMarker(
2500f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    MacroAssembler* masm,
2501f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    OnNoNeedToInformIncrementalMarker on_no_need,
2502f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    Mode mode) {
2503f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  Label on_black;
2504f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  Label need_incremental;
2505f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  Label need_incremental_pop_object;
25068389745919cae02139ddc085a63c00d024269cf2Ben Murdoch
2507f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // Let's look at the color of the object:  If it is not black we don't have
2508f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // to inform the incremental marker.
2509f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ JumpIfBlack(regs_.object(),
2510f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch                 regs_.scratch0(),
2511f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch                 regs_.scratch1(),
2512f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch                 &on_black,
2513f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch                 Label::kNear);
25148389745919cae02139ddc085a63c00d024269cf2Ben Murdoch
2515f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  regs_.Restore(masm);
2516f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  if (on_no_need == kUpdateRememberedSetOnNoNeedToInformIncrementalMarker) {
2517f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ RememberedSetHelper(object(), address(), value(), save_fp_regs_mode(),
2518f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch                           MacroAssembler::kReturnAtEnd);
2519f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  } else {
2520f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ ret(0);
2521f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  }
25228389745919cae02139ddc085a63c00d024269cf2Ben Murdoch
2523f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ bind(&on_black);
25248389745919cae02139ddc085a63c00d024269cf2Ben Murdoch
2525f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // Get the value from the slot.
2526f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ movp(regs_.scratch0(), Operand(regs_.address(), 0));
25278389745919cae02139ddc085a63c00d024269cf2Ben Murdoch
2528f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  if (mode == INCREMENTAL_COMPACTION) {
2529f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    Label ensure_not_white;
25308389745919cae02139ddc085a63c00d024269cf2Ben Murdoch
2531f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ CheckPageFlag(regs_.scratch0(),  // Contains value.
2532f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch                     regs_.scratch1(),  // Scratch.
2533f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch                     MemoryChunk::kEvacuationCandidateMask,
2534f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch                     zero,
2535f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch                     &ensure_not_white,
2536f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch                     Label::kNear);
25378389745919cae02139ddc085a63c00d024269cf2Ben Murdoch
2538f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ CheckPageFlag(regs_.object(),
2539f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch                     regs_.scratch1(),  // Scratch.
2540f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch                     MemoryChunk::kSkipEvacuationSlotsRecordingMask,
2541f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch                     zero,
2542f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch                     &need_incremental);
25438389745919cae02139ddc085a63c00d024269cf2Ben Murdoch
2544f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ bind(&ensure_not_white);
2545f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  }
25468389745919cae02139ddc085a63c00d024269cf2Ben Murdoch
2547f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // We need an extra register for this, so we push the object register
2548f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // temporarily.
2549f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ Push(regs_.object());
2550f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ JumpIfWhite(regs_.scratch0(),  // The value.
2551f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch                 regs_.scratch1(),  // Scratch.
2552f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch                 regs_.object(),    // Scratch.
2553f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch                 &need_incremental_pop_object, Label::kNear);
2554f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ Pop(regs_.object());
25558389745919cae02139ddc085a63c00d024269cf2Ben Murdoch
2556f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  regs_.Restore(masm);
2557f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  if (on_no_need == kUpdateRememberedSetOnNoNeedToInformIncrementalMarker) {
2558f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ RememberedSetHelper(object(), address(), value(), save_fp_regs_mode(),
2559f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch                           MacroAssembler::kReturnAtEnd);
2560f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  } else {
2561f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch    __ ret(0);
2562f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  }
25638389745919cae02139ddc085a63c00d024269cf2Ben Murdoch
2564f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ bind(&need_incremental_pop_object);
2565f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ Pop(regs_.object());
25668389745919cae02139ddc085a63c00d024269cf2Ben Murdoch
2567f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ bind(&need_incremental);
25688389745919cae02139ddc085a63c00d024269cf2Ben Murdoch
2569f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  // Fall through when we need to inform the incremental marker.
2570f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch}
25718389745919cae02139ddc085a63c00d024269cf2Ben Murdoch
2572f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch
2573f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdochvoid StubFailureTrampolineStub::Generate(MacroAssembler* masm) {
2574f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  CEntryStub ces(isolate(), 1, kSaveFPRegs);
2575f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ Call(ces.GetCode(), RelocInfo::CODE_TARGET);
2576f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  int parameter_count_offset =
25773b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch      StubFailureTrampolineFrameConstants::kArgumentsLengthOffset;
2578f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ movp(rbx, MemOperand(rbp, parameter_count_offset));
2579f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  masm->LeaveFrame(StackFrame::STUB_FAILURE_TRAMPOLINE);
2580f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ PopReturnAddressTo(rcx);
2581f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  int additional_offset =
2582f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch      function_mode() == JS_FUNCTION_STUB_MODE ? kPointerSize : 0;
2583f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ leap(rsp, MemOperand(rsp, rbx, times_pointer_size, additional_offset));
2584f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch  __ jmp(rcx);  // Return to IC Miss stub, continuation still on stack.
25858389745919cae02139ddc085a63c00d024269cf2Ben Murdoch}
25868389745919cae02139ddc085a63c00d024269cf2Ben Murdoch
2587109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch
2588109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdochvoid ProfileEntryHookStub::MaybeCallEntryHook(MacroAssembler* masm) {
2589109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  if (masm->isolate()->function_entry_hook() != NULL) {
2590109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    ProfileEntryHookStub stub(masm->isolate());
2591109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    masm->CallStub(&stub);
2592109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  }
2593109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch}
2594109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch
2595109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch
2596109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdochvoid ProfileEntryHookStub::Generate(MacroAssembler* masm) {
2597109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  // This stub can be called from essentially anywhere, so it needs to save
2598109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  // all volatile and callee-save registers.
2599109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  const size_t kNumSavedRegisters = 2;
2600109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  __ pushq(arg_reg_1);
2601109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  __ pushq(arg_reg_2);
2602109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch
2603109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  // Calculate the original stack pointer and store it in the second arg.
2604109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  __ leap(arg_reg_2,
2605109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch         Operand(rsp, kNumSavedRegisters * kRegisterSize + kPCOnStackSize));
2606109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch
2607109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  // Calculate the function address to the first arg.
2608109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  __ movp(arg_reg_1, Operand(rsp, kNumSavedRegisters * kRegisterSize));
2609109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  __ subp(arg_reg_1, Immediate(Assembler::kShortCallInstructionLength));
2610109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch
2611109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  // Save the remainder of the volatile registers.
2612109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  masm->PushCallerSaved(kSaveFPRegs, arg_reg_1, arg_reg_2);
2613109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch
2614109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  // Call the entry hook function.
2615109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  __ Move(rax, FUNCTION_ADDR(isolate()->function_entry_hook()),
2616109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch          Assembler::RelocInfoNone());
2617014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2618109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  AllowExternalCallThatCantCauseGC scope(masm);
2619014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2620109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  const int kArgumentCount = 2;
2621109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  __ PrepareCallCFunction(kArgumentCount);
2622109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  __ CallCFunction(rax, kArgumentCount);
2623014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2624109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  // Restore volatile regs.
2625109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  masm->PopCallerSaved(kSaveFPRegs, arg_reg_1, arg_reg_2);
2626109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  __ popq(arg_reg_2);
2627109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  __ popq(arg_reg_1);
2628014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2629109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  __ Ret();
2630f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch}
2631014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2632014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2633109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdochtemplate<class T>
2634109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdochstatic void CreateArrayDispatch(MacroAssembler* masm,
2635109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch                                AllocationSiteOverrideMode mode) {
2636109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  if (mode == DISABLE_ALLOCATION_SITES) {
2637109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    T stub(masm->isolate(), GetInitialFastElementsKind(), mode);
2638109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ TailCallStub(&stub);
2639109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  } else if (mode == DONT_OVERRIDE) {
2640109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    int last_index = GetSequenceIndexFromFastElementsKind(
2641109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch        TERMINAL_FAST_ELEMENTS_KIND);
2642109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    for (int i = 0; i <= last_index; ++i) {
2643109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch      Label next;
2644109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch      ElementsKind kind = GetFastElementsKindFromSequenceIndex(i);
2645109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch      __ cmpl(rdx, Immediate(kind));
2646109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch      __ j(not_equal, &next);
2647109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch      T stub(masm->isolate(), kind);
2648109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch      __ TailCallStub(&stub);
2649109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch      __ bind(&next);
2650109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    }
2651109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch
2652109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    // If we reached this point there is a problem.
2653109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ Abort(kUnexpectedElementsKindInArrayConstructor);
2654109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  } else {
2655109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    UNREACHABLE();
2656109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  }
2657014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch}
2658014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2659014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2660109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdochstatic void CreateArrayDispatchOneArgument(MacroAssembler* masm,
2661109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch                                           AllocationSiteOverrideMode mode) {
2662109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  // rbx - allocation site (if mode != DISABLE_ALLOCATION_SITES)
2663109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  // rdx - kind (if mode != DISABLE_ALLOCATION_SITES)
2664109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  // rax - number of arguments
2665109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  // rdi - constructor?
2666109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  // rsp[0] - return address
2667109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  // rsp[8] - last argument
2668014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2669109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  Label normal_sequence;
2670109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  if (mode == DONT_OVERRIDE) {
2671109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    STATIC_ASSERT(FAST_SMI_ELEMENTS == 0);
2672109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    STATIC_ASSERT(FAST_HOLEY_SMI_ELEMENTS == 1);
2673109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    STATIC_ASSERT(FAST_ELEMENTS == 2);
2674109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    STATIC_ASSERT(FAST_HOLEY_ELEMENTS == 3);
2675109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    STATIC_ASSERT(FAST_DOUBLE_ELEMENTS == 4);
2676109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    STATIC_ASSERT(FAST_HOLEY_DOUBLE_ELEMENTS == 5);
2677014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2678109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    // is the low bit set? If so, we are holey and that is good.
2679109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ testb(rdx, Immediate(1));
2680109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ j(not_zero, &normal_sequence);
2681109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  }
2682014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2683109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  // look at the first argument
2684109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  StackArgumentsAccessor args(rsp, 1, ARGUMENTS_DONT_CONTAIN_RECEIVER);
2685109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  __ movp(rcx, args.GetArgumentOperand(0));
2686109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  __ testp(rcx, rcx);
2687109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  __ j(zero, &normal_sequence);
2688014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2689109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  if (mode == DISABLE_ALLOCATION_SITES) {
2690109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    ElementsKind initial = GetInitialFastElementsKind();
2691109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    ElementsKind holey_initial = GetHoleyElementsKind(initial);
2692014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2693109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    ArraySingleArgumentConstructorStub stub_holey(masm->isolate(),
2694109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch                                                  holey_initial,
2695109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch                                                  DISABLE_ALLOCATION_SITES);
2696109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ TailCallStub(&stub_holey);
2697014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2698109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ bind(&normal_sequence);
2699109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    ArraySingleArgumentConstructorStub stub(masm->isolate(),
2700109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch                                            initial,
2701109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch                                            DISABLE_ALLOCATION_SITES);
2702109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ TailCallStub(&stub);
2703109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  } else if (mode == DONT_OVERRIDE) {
2704109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    // We are going to create a holey array, but our kind is non-holey.
2705109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    // Fix kind and retry (only if we have an allocation site in the slot).
2706109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ incl(rdx);
2707f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch
2708109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    if (FLAG_debug_code) {
2709109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch      Handle<Map> allocation_site_map =
2710109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch          masm->isolate()->factory()->allocation_site_map();
2711109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch      __ Cmp(FieldOperand(rbx, 0), allocation_site_map);
2712109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch      __ Assert(equal, kExpectedAllocationSite);
2713109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    }
2714014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2715109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    // Save the resulting elements kind in type info. We can't just store r3
2716109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    // in the AllocationSite::transition_info field because elements kind is
2717109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    // restricted to a portion of the field...upper bits need to be left alone.
2718109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    STATIC_ASSERT(AllocationSite::ElementsKindBits::kShift == 0);
2719109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ SmiAddConstant(FieldOperand(rbx, AllocationSite::kTransitionInfoOffset),
2720109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch                      Smi::FromInt(kFastElementsKindPackedToHoley));
2721014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2722109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ bind(&normal_sequence);
2723109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    int last_index = GetSequenceIndexFromFastElementsKind(
2724109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch        TERMINAL_FAST_ELEMENTS_KIND);
2725109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    for (int i = 0; i <= last_index; ++i) {
2726109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch      Label next;
2727109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch      ElementsKind kind = GetFastElementsKindFromSequenceIndex(i);
2728109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch      __ cmpl(rdx, Immediate(kind));
2729109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch      __ j(not_equal, &next);
2730109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch      ArraySingleArgumentConstructorStub stub(masm->isolate(), kind);
2731109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch      __ TailCallStub(&stub);
2732109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch      __ bind(&next);
2733109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    }
2734109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch
2735109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    // If we reached this point there is a problem.
2736109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ Abort(kUnexpectedElementsKindInArrayConstructor);
2737109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  } else {
2738109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    UNREACHABLE();
2739109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  }
2740014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch}
2741014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2742014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2743109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdochtemplate<class T>
2744109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdochstatic void ArrayConstructorStubAheadOfTimeHelper(Isolate* isolate) {
2745109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  int to_index = GetSequenceIndexFromFastElementsKind(
2746109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch      TERMINAL_FAST_ELEMENTS_KIND);
2747109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  for (int i = 0; i <= to_index; ++i) {
2748109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    ElementsKind kind = GetFastElementsKindFromSequenceIndex(i);
2749109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    T stub(isolate, kind);
2750109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    stub.GetCode();
2751109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    if (AllocationSite::GetMode(kind) != DONT_TRACK_ALLOCATION_SITE) {
2752109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch      T stub1(isolate, kind, DISABLE_ALLOCATION_SITES);
2753109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch      stub1.GetCode();
2754109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    }
2755109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  }
2756f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch}
2757b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
275813e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdochvoid CommonArrayConstructorStub::GenerateStubsAheadOfTime(Isolate* isolate) {
2759109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  ArrayConstructorStubAheadOfTimeHelper<ArrayNoArgumentConstructorStub>(
2760109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch      isolate);
2761109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  ArrayConstructorStubAheadOfTimeHelper<ArraySingleArgumentConstructorStub>(
2762109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch      isolate);
276313e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  ArrayNArgumentsConstructorStub stub(isolate);
276413e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  stub.GetCode();
2765b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
2766109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  ElementsKind kinds[2] = { FAST_ELEMENTS, FAST_HOLEY_ELEMENTS };
2767109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  for (int i = 0; i < 2; i++) {
2768109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    // For internal arrays we only need a few things
2769109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    InternalArrayNoArgumentConstructorStub stubh1(isolate, kinds[i]);
2770109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    stubh1.GetCode();
2771109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    InternalArraySingleArgumentConstructorStub stubh2(isolate, kinds[i]);
2772109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    stubh2.GetCode();
2773109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  }
2774109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch}
2775b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
2776109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdochvoid ArrayConstructorStub::GenerateDispatchToArrayStub(
2777c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch    MacroAssembler* masm, AllocationSiteOverrideMode mode) {
2778c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch  Label not_zero_case, not_one_case;
2779c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch  __ testp(rax, rax);
2780c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch  __ j(not_zero, &not_zero_case);
2781c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch  CreateArrayDispatch<ArrayNoArgumentConstructorStub>(masm, mode);
2782c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch
2783c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch  __ bind(&not_zero_case);
2784c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch  __ cmpl(rax, Immediate(1));
2785c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch  __ j(greater, &not_one_case);
2786c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch  CreateArrayDispatchOneArgument(masm, mode);
2787b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
2788c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch  __ bind(&not_one_case);
2789c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch  ArrayNArgumentsConstructorStub stub(masm->isolate());
2790c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch  __ TailCallStub(&stub);
2791c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch}
2792b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
2793109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdochvoid ArrayConstructorStub::Generate(MacroAssembler* masm) {
2794109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  // ----------- S t a t e -------------
2795109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  //  -- rax    : argc
2796109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  //  -- rbx    : AllocationSite or undefined
2797109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  //  -- rdi    : constructor
2798109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  //  -- rdx    : new target
2799109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  //  -- rsp[0] : return address
2800109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  //  -- rsp[8] : last argument
2801109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  // -----------------------------------
2802109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  if (FLAG_debug_code) {
2803109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    // The array construct code is only set for the global and natives
2804109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    // builtin Array functions which always have maps.
2805b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
2806109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    // Initial map for the builtin Array function should be a map.
2807109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ movp(rcx, FieldOperand(rdi, JSFunction::kPrototypeOrInitialMapOffset));
2808109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    // Will both indicate a NULL and a Smi.
2809109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    STATIC_ASSERT(kSmiTag == 0);
2810109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    Condition not_smi = NegateCondition(masm->CheckSmi(rcx));
2811109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ Check(not_smi, kUnexpectedInitialMapForArrayFunction);
2812109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ CmpObjectType(rcx, MAP_TYPE, rcx);
2813109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ Check(equal, kUnexpectedInitialMapForArrayFunction);
2814b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
2815109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    // We should either have undefined in rbx or a valid AllocationSite
2816109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ AssertUndefinedOrAllocationSite(rbx);
2817109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  }
2818b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
2819109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  // Enter the context of the Array function.
2820109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  __ movp(rsi, FieldOperand(rdi, JSFunction::kContextOffset));
2821b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
2822109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  Label subclassing;
2823109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  __ cmpp(rdi, rdx);
2824109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  __ j(not_equal, &subclassing);
2825b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
2826109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  Label no_info;
2827109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  // If the feedback vector is the undefined value call an array constructor
2828109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  // that doesn't use AllocationSites.
2829109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  __ CompareRoot(rbx, Heap::kUndefinedValueRootIndex);
2830109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  __ j(equal, &no_info);
2831b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
2832109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  // Only look at the lower 16 bits of the transition info.
2833109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  __ movp(rdx, FieldOperand(rbx, AllocationSite::kTransitionInfoOffset));
2834109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  __ SmiToInteger32(rdx, rdx);
2835109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  STATIC_ASSERT(AllocationSite::ElementsKindBits::kShift == 0);
2836109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  __ andp(rdx, Immediate(AllocationSite::ElementsKindBits::kMask));
2837109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  GenerateDispatchToArrayStub(masm, DONT_OVERRIDE);
2838b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
2839109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  __ bind(&no_info);
2840109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  GenerateDispatchToArrayStub(masm, DISABLE_ALLOCATION_SITES);
2841b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
2842109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  // Subclassing
2843109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  __ bind(&subclassing);
2844c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch  StackArgumentsAccessor args(rsp, rax);
2845c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch  __ movp(args.GetReceiverOperand(), rdi);
2846c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch  __ addp(rax, Immediate(3));
2847109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  __ PopReturnAddressTo(rcx);
2848109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  __ Push(rdx);
2849109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  __ Push(rbx);
2850109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  __ PushReturnAddressFrom(rcx);
2851109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  __ JumpToExternalReference(ExternalReference(Runtime::kNewArray, isolate()));
2852f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch}
2853b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
28548389745919cae02139ddc085a63c00d024269cf2Ben Murdoch
2855109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdochvoid InternalArrayConstructorStub::GenerateCase(
2856109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    MacroAssembler* masm, ElementsKind kind) {
2857109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  Label not_zero_case, not_one_case;
2858109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  Label normal_sequence;
2859b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
2860109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  __ testp(rax, rax);
2861109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  __ j(not_zero, &not_zero_case);
2862109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  InternalArrayNoArgumentConstructorStub stub0(isolate(), kind);
2863109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  __ TailCallStub(&stub0);
2864b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
2865109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  __ bind(&not_zero_case);
2866109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  __ cmpl(rax, Immediate(1));
2867109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  __ j(greater, &not_one_case);
2868b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
2869109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  if (IsFastPackedElementsKind(kind)) {
2870109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    // We might need to create a holey array
2871109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    // look at the first argument
2872109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    StackArgumentsAccessor args(rsp, 1, ARGUMENTS_DONT_CONTAIN_RECEIVER);
2873109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ movp(rcx, args.GetArgumentOperand(0));
2874109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ testp(rcx, rcx);
2875109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ j(zero, &normal_sequence);
2876b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
2877109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    InternalArraySingleArgumentConstructorStub
2878109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch        stub1_holey(isolate(), GetHoleyElementsKind(kind));
2879109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ TailCallStub(&stub1_holey);
2880109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  }
2881f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch
2882109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  __ bind(&normal_sequence);
2883109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  InternalArraySingleArgumentConstructorStub stub1(isolate(), kind);
2884109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  __ TailCallStub(&stub1);
2885f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch
2886109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  __ bind(&not_one_case);
288713e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  ArrayNArgumentsConstructorStub stubN(isolate());
2888109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  __ TailCallStub(&stubN);
2889109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch}
2890f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch
2891f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch
2892109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdochvoid InternalArrayConstructorStub::Generate(MacroAssembler* masm) {
2893109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  // ----------- S t a t e -------------
2894109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  //  -- rax    : argc
2895109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  //  -- rdi    : constructor
2896109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  //  -- rsp[0] : return address
2897109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  //  -- rsp[8] : last argument
2898109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  // -----------------------------------
2899f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch
2900109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  if (FLAG_debug_code) {
2901109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    // The array construct code is only set for the global and natives
2902109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    // builtin Array functions which always have maps.
2903f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch
2904109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    // Initial map for the builtin Array function should be a map.
2905109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ movp(rcx, FieldOperand(rdi, JSFunction::kPrototypeOrInitialMapOffset));
2906109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    // Will both indicate a NULL and a Smi.
2907109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    STATIC_ASSERT(kSmiTag == 0);
2908109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    Condition not_smi = NegateCondition(masm->CheckSmi(rcx));
2909109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ Check(not_smi, kUnexpectedInitialMapForArrayFunction);
2910109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ CmpObjectType(rcx, MAP_TYPE, rcx);
2911109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ Check(equal, kUnexpectedInitialMapForArrayFunction);
2912109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  }
2913b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
2914109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  // Figure out the right elements kind
2915109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  __ movp(rcx, FieldOperand(rdi, JSFunction::kPrototypeOrInitialMapOffset));
2916b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
2917109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  // Load the map's "bit field 2" into |result|. We only need the first byte,
2918109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  // but the following masking takes care of that anyway.
2919109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  __ movzxbp(rcx, FieldOperand(rcx, Map::kBitField2Offset));
2920109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  // Retrieve elements_kind from bit field 2.
2921109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  __ DecodeField<Map::ElementsKindBits>(rcx);
2922b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
2923109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  if (FLAG_debug_code) {
2924109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    Label done;
2925109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ cmpl(rcx, Immediate(FAST_ELEMENTS));
2926109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ j(equal, &done);
2927109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ cmpl(rcx, Immediate(FAST_HOLEY_ELEMENTS));
2928109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ Assert(equal,
2929109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch              kInvalidElementsKindForInternalArrayOrInternalPackedArray);
2930109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ bind(&done);
2931109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  }
2932b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
2933109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  Label fast_elements_case;
2934109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  __ cmpl(rcx, Immediate(FAST_ELEMENTS));
2935109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  __ j(equal, &fast_elements_case);
2936109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  GenerateCase(masm, FAST_HOLEY_ELEMENTS);
2937f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch
2938109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  __ bind(&fast_elements_case);
2939109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  GenerateCase(masm, FAST_ELEMENTS);
2940f2e3994fa5148cc3d9946666f0b0596290192b0eBen Murdoch}
2941b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
2942014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdochstatic int Offset(ExternalReference ref0, ExternalReference ref1) {
2943014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  int64_t offset = (ref0.address() - ref1.address());
2944014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // Check that fits into int.
2945014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  DCHECK(static_cast<int>(offset) == offset);
2946014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  return static_cast<int>(offset);
2947014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch}
2948014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2949014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch// Prepares stack to put arguments (aligns and so on).  WIN64 calling
2950014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch// convention requires to put the pointer to the return value slot into
2951014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch// rcx (rcx must be preserverd until CallApiFunctionAndReturn).  Saves
2952014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch// context (rsi).  Clobbers rax.  Allocates arg_stack_space * kPointerSize
2953014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch// inside the exit frame (not GCed) accessible via StackSpaceOperand.
2954014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdochstatic void PrepareCallApiFunction(MacroAssembler* masm, int arg_stack_space) {
2955014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ EnterApiExitFrame(arg_stack_space);
2956014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch}
2957014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2958014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2959014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch// Calls an API function.  Allocates HandleScope, extracts returned value
2960014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch// from handle and propagates exceptions.  Clobbers r14, r15, rbx and
2961014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch// caller-save registers.  Restores context.  On return removes
2962014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch// stack_space * kPointerSize (GCed).
2963014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdochstatic void CallApiFunctionAndReturn(MacroAssembler* masm,
2964014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch                                     Register function_address,
2965014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch                                     ExternalReference thunk_ref,
2966014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch                                     Register thunk_last_arg, int stack_space,
2967014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch                                     Operand* stack_space_operand,
2968014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch                                     Operand return_value_operand,
2969014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch                                     Operand* context_restore_operand) {
2970014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  Label prologue;
2971014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  Label promote_scheduled_exception;
2972014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  Label delete_allocated_handles;
2973014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  Label leave_exit_frame;
2974014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  Label write_back;
2975014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2976014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  Isolate* isolate = masm->isolate();
2977014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  Factory* factory = isolate->factory();
2978014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  ExternalReference next_address =
2979014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      ExternalReference::handle_scope_next_address(isolate);
2980014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  const int kNextOffset = 0;
2981014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  const int kLimitOffset = Offset(
2982014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      ExternalReference::handle_scope_limit_address(isolate), next_address);
2983014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  const int kLevelOffset = Offset(
2984014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      ExternalReference::handle_scope_level_address(isolate), next_address);
2985014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  ExternalReference scheduled_exception_address =
2986014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      ExternalReference::scheduled_exception_address(isolate);
2987014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2988014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  DCHECK(rdx.is(function_address) || r8.is(function_address));
2989014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // Allocate HandleScope in callee-save registers.
2990014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  Register prev_next_address_reg = r14;
2991014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  Register prev_limit_reg = rbx;
2992014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  Register base_reg = r15;
2993014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ Move(base_reg, next_address);
2994014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ movp(prev_next_address_reg, Operand(base_reg, kNextOffset));
2995014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ movp(prev_limit_reg, Operand(base_reg, kLimitOffset));
2996014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ addl(Operand(base_reg, kLevelOffset), Immediate(1));
2997014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2998014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  if (FLAG_log_timer_events) {
2999014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    FrameScope frame(masm, StackFrame::MANUAL);
3000014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ PushSafepointRegisters();
3001014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ PrepareCallCFunction(1);
3002014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ LoadAddress(arg_reg_1, ExternalReference::isolate_address(isolate));
3003014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ CallCFunction(ExternalReference::log_enter_external_function(isolate),
3004014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch                     1);
3005014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ PopSafepointRegisters();
3006014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  }
3007014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
3008014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  Label profiler_disabled;
3009014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  Label end_profiler_check;
3010014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ Move(rax, ExternalReference::is_profiling_address(isolate));
3011014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ cmpb(Operand(rax, 0), Immediate(0));
3012014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ j(zero, &profiler_disabled);
3013014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
3014014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // Third parameter is the address of the actual getter function.
3015014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ Move(thunk_last_arg, function_address);
3016014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ Move(rax, thunk_ref);
3017014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ jmp(&end_profiler_check);
3018014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
3019014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ bind(&profiler_disabled);
3020014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // Call the api function!
3021014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ Move(rax, function_address);
3022014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
3023014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ bind(&end_profiler_check);
3024014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
3025014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // Call the api function!
3026014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ call(rax);
3027014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
3028014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  if (FLAG_log_timer_events) {
3029014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    FrameScope frame(masm, StackFrame::MANUAL);
3030014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ PushSafepointRegisters();
3031014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ PrepareCallCFunction(1);
3032014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ LoadAddress(arg_reg_1, ExternalReference::isolate_address(isolate));
3033014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ CallCFunction(ExternalReference::log_leave_external_function(isolate),
3034014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch                     1);
3035014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ PopSafepointRegisters();
3036014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  }
3037014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
3038014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // Load the value from ReturnValue
3039014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ movp(rax, return_value_operand);
3040014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ bind(&prologue);
3041014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
3042014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // No more valid handles (the result handle was the last one). Restore
3043014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // previous handle scope.
3044014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ subl(Operand(base_reg, kLevelOffset), Immediate(1));
3045014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ movp(Operand(base_reg, kNextOffset), prev_next_address_reg);
3046014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ cmpp(prev_limit_reg, Operand(base_reg, kLimitOffset));
3047014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ j(not_equal, &delete_allocated_handles);
3048014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
3049014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // Leave the API exit frame.
3050014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ bind(&leave_exit_frame);
3051014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  bool restore_context = context_restore_operand != NULL;
3052014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  if (restore_context) {
3053014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ movp(rsi, *context_restore_operand);
3054014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  }
3055014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  if (stack_space_operand != nullptr) {
3056014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ movp(rbx, *stack_space_operand);
3057014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  }
3058014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ LeaveApiExitFrame(!restore_context);
3059014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
3060014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // Check if the function scheduled an exception.
3061014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ Move(rdi, scheduled_exception_address);
3062014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ Cmp(Operand(rdi, 0), factory->the_hole_value());
3063014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ j(not_equal, &promote_scheduled_exception);
3064014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
3065014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch#if DEBUG
3066014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // Check if the function returned a valid JavaScript value.
3067014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  Label ok;
3068014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  Register return_value = rax;
3069014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  Register map = rcx;
3070014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
3071014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ JumpIfSmi(return_value, &ok, Label::kNear);
3072014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ movp(map, FieldOperand(return_value, HeapObject::kMapOffset));
3073014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
3074014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ CmpInstanceType(map, LAST_NAME_TYPE);
3075014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ j(below_equal, &ok, Label::kNear);
3076014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
3077014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ CmpInstanceType(map, FIRST_JS_RECEIVER_TYPE);
3078014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ j(above_equal, &ok, Label::kNear);
3079014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
3080014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ CompareRoot(map, Heap::kHeapNumberMapRootIndex);
3081014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ j(equal, &ok, Label::kNear);
3082014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
3083014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ CompareRoot(return_value, Heap::kUndefinedValueRootIndex);
3084014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ j(equal, &ok, Label::kNear);
3085014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
3086014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ CompareRoot(return_value, Heap::kTrueValueRootIndex);
3087014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ j(equal, &ok, Label::kNear);
3088014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
3089014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ CompareRoot(return_value, Heap::kFalseValueRootIndex);
3090014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ j(equal, &ok, Label::kNear);
3091014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
3092014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ CompareRoot(return_value, Heap::kNullValueRootIndex);
3093014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ j(equal, &ok, Label::kNear);
3094014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
3095014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ Abort(kAPICallReturnedInvalidObject);
3096014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
3097014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ bind(&ok);
3098014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch#endif
3099014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
3100014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  if (stack_space_operand != nullptr) {
3101014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    DCHECK_EQ(stack_space, 0);
3102014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ PopReturnAddressTo(rcx);
3103014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ addq(rsp, rbx);
3104014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ jmp(rcx);
3105014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  } else {
3106014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    __ ret(stack_space * kPointerSize);
3107014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  }
3108014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
3109014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // Re-throw by promoting a scheduled exception.
3110014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ bind(&promote_scheduled_exception);
3111014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ TailCallRuntime(Runtime::kPromoteScheduledException);
3112014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
3113014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // HandleScope limit has changed. Delete allocated extensions.
3114014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ bind(&delete_allocated_handles);
3115014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ movp(Operand(base_reg, kLimitOffset), prev_limit_reg);
3116014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ movp(prev_limit_reg, rax);
3117014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ LoadAddress(arg_reg_1, ExternalReference::isolate_address(isolate));
3118014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ LoadAddress(rax,
3119014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch                 ExternalReference::delete_handle_scope_extensions(isolate));
3120014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ call(rax);
3121014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ movp(rax, prev_limit_reg);
3122014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ jmp(&leave_exit_frame);
3123014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch}
3124014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
31253b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdochvoid CallApiCallbackStub::Generate(MacroAssembler* masm) {
3126b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // ----------- S t a t e -------------
3127014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- rdi                 : callee
3128b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  //  -- rbx                 : call_data
3129b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  //  -- rcx                 : holder
3130b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  //  -- rdx                 : api_function_address
3131b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  //  -- rsi                 : context
3132014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  //  -- rax                 : number of arguments if argc is a register
3133b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  //  -- rsp[0]              : return address
3134b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  //  -- rsp[8]              : last argument
3135b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  //  -- ...
3136b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  //  -- rsp[argc * 8]       : first argument
3137b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  //  -- rsp[(argc + 1) * 8] : receiver
3138b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // -----------------------------------
3139b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
3140014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  Register callee = rdi;
3141b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  Register call_data = rbx;
3142b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  Register holder = rcx;
3143b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  Register api_function_address = rdx;
3144b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  Register context = rsi;
3145014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  Register return_address = r8;
3146b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
3147b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  typedef FunctionCallbackArguments FCA;
3148b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
3149b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  STATIC_ASSERT(FCA::kContextSaveIndex == 6);
3150b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  STATIC_ASSERT(FCA::kCalleeIndex == 5);
3151b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  STATIC_ASSERT(FCA::kDataIndex == 4);
3152b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  STATIC_ASSERT(FCA::kReturnValueOffset == 3);
3153b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  STATIC_ASSERT(FCA::kReturnValueDefaultValueIndex == 2);
3154b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  STATIC_ASSERT(FCA::kIsolateIndex == 1);
3155b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  STATIC_ASSERT(FCA::kHolderIndex == 0);
3156bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  STATIC_ASSERT(FCA::kNewTargetIndex == 7);
3157bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  STATIC_ASSERT(FCA::kArgsLength == 8);
3158b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
3159b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ PopReturnAddressTo(return_address);
3160b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
3161bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  // new target
3162bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ PushRoot(Heap::kUndefinedValueRootIndex);
3163bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch
3164b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // context save
3165b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ Push(context);
3166b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
3167b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // callee
3168b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ Push(callee);
3169b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
3170b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // call data
3171b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ Push(call_data);
3172b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  Register scratch = call_data;
31733b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch  if (!this->call_data_undefined()) {
3174b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    __ LoadRoot(scratch, Heap::kUndefinedValueRootIndex);
3175b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  }
3176b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // return value
3177b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ Push(scratch);
3178b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // return value default
3179b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ Push(scratch);
3180b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // isolate
3181014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  __ Move(scratch, ExternalReference::isolate_address(masm->isolate()));
3182b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ Push(scratch);
3183b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // holder
3184b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ Push(holder);
3185b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
3186b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ movp(scratch, rsp);
3187b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // Push return address back on stack.
3188b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ PushReturnAddressFrom(return_address);
3189b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
31903b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch  if (!this->is_lazy()) {
3191109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    // load context from callee
3192109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    __ movp(context, FieldOperand(callee, JSFunction::kContextOffset));
3193109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  }
3194014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
3195b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // Allocate the v8::Arguments structure in the arguments' space since
3196b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // it's not controlled by GC.
3197bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  const int kApiStackSpace = 3;
3198b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
3199014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  PrepareCallApiFunction(masm, kApiStackSpace);
3200b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
3201b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // FunctionCallbackInfo::implicit_args_.
32023b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch  int argc = this->argc();
3203b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ movp(StackSpaceOperand(0), scratch);
32043b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch  __ addp(scratch, Immediate((argc + FCA::kArgsLength - 1) * kPointerSize));
32053b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch  // FunctionCallbackInfo::values_.
32063b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch  __ movp(StackSpaceOperand(1), scratch);
32073b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch  // FunctionCallbackInfo::length_.
32083b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch  __ Set(StackSpaceOperand(2), argc);
3209b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
3210b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#if defined(__MINGW64__) || defined(_WIN64)
3211b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  Register arguments_arg = rcx;
3212b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  Register callback_arg = rdx;
3213b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#else
3214b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  Register arguments_arg = rdi;
3215b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  Register callback_arg = rsi;
3216b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#endif
3217b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
3218b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // It's okay if api_function_address == callback_arg
3219b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // but not arguments_arg
3220b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  DCHECK(!api_function_address.is(arguments_arg));
3221b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
3222b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // v8::InvocationCallback's argument.
3223b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  __ leap(arguments_arg, StackSpaceOperand(0));
3224b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
3225b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  ExternalReference thunk_ref =
3226014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      ExternalReference::invoke_function_callback(masm->isolate());
3227b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
3228b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // Accessor for FunctionCallbackInfo and first js arg.
3229b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  StackArgumentsAccessor args_from_rbp(rbp, FCA::kArgsLength + 1,
3230b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                                       ARGUMENTS_DONT_CONTAIN_RECEIVER);
3231b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  Operand context_restore_operand = args_from_rbp.GetArgumentOperand(
3232b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      FCA::kArgsLength - FCA::kContextSaveIndex);
3233bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  Operand length_operand = StackSpaceOperand(2);
3234b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  Operand return_value_operand = args_from_rbp.GetArgumentOperand(
32353b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch      this->is_store() ? 0 : FCA::kArgsLength - FCA::kReturnValueOffset);
3236014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  int stack_space = 0;
3237bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  Operand* stack_space_operand = &length_operand;
32383b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch  stack_space = argc + FCA::kArgsLength + 1;
32393b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch  stack_space_operand = nullptr;
3240014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  CallApiFunctionAndReturn(masm, api_function_address, thunk_ref, callback_arg,
3241014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch                           stack_space, stack_space_operand,
3242014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch                           return_value_operand, &context_restore_operand);
3243014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch}
3244014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
3245014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
3246b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochvoid CallApiGetterStub::Generate(MacroAssembler* masm) {
3247b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#if defined(__MINGW64__) || defined(_WIN64)
3248b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  Register getter_arg = r8;
3249b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  Register accessor_info_arg = rdx;
3250b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  Register name_arg = rcx;
3251b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#else
3252b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  Register getter_arg = rdx;
3253b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  Register accessor_info_arg = rsi;
3254b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  Register name_arg = rdi;
3255b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#endif
3256bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  Register api_function_address = r8;
3257bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  Register receiver = ApiGetterDescriptor::ReceiverRegister();
3258bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  Register holder = ApiGetterDescriptor::HolderRegister();
3259bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  Register callback = ApiGetterDescriptor::CallbackRegister();
3260b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  Register scratch = rax;
3261bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  DCHECK(!AreAliased(receiver, holder, callback, scratch));
3262bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch
3263bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  // Build v8::PropertyCallbackInfo::args_ array on the stack and push property
3264bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  // name below the exit frame to make GC aware of them.
3265bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  STATIC_ASSERT(PropertyCallbackArguments::kShouldThrowOnErrorIndex == 0);
3266bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  STATIC_ASSERT(PropertyCallbackArguments::kHolderIndex == 1);
3267bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  STATIC_ASSERT(PropertyCallbackArguments::kIsolateIndex == 2);
3268bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  STATIC_ASSERT(PropertyCallbackArguments::kReturnValueDefaultValueIndex == 3);
3269bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  STATIC_ASSERT(PropertyCallbackArguments::kReturnValueOffset == 4);
3270bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  STATIC_ASSERT(PropertyCallbackArguments::kDataIndex == 5);
3271bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  STATIC_ASSERT(PropertyCallbackArguments::kThisIndex == 6);
3272bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  STATIC_ASSERT(PropertyCallbackArguments::kArgsLength == 7);
3273bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch
3274bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  // Insert additional parameters into the stack frame above return address.
3275bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ PopReturnAddressTo(scratch);
3276bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ Push(receiver);
3277bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ Push(FieldOperand(callback, AccessorInfo::kDataOffset));
3278bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ LoadRoot(kScratchRegister, Heap::kUndefinedValueRootIndex);
3279bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ Push(kScratchRegister);  // return value
3280bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ Push(kScratchRegister);  // return value default
3281bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ PushAddress(ExternalReference::isolate_address(isolate()));
3282bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ Push(holder);
3283c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch  __ Push(Smi::kZero);  // should_throw_on_error -> false
3284bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ Push(FieldOperand(callback, AccessorInfo::kNameOffset));
3285bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ PushReturnAddressFrom(scratch);
3286b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
3287109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  // v8::PropertyCallbackInfo::args_ array and name handle.
3288109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  const int kStackUnwindSpace = PropertyCallbackArguments::kArgsLength + 1;
3289b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
3290109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  // Allocate v8::PropertyCallbackInfo in non-GCed stack space.
3291b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  const int kArgStackSpace = 1;
3292b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
3293109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  // Load address of v8::PropertyAccessorInfo::args_ array.
3294109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  __ leap(scratch, Operand(rsp, 2 * kPointerSize));
3295b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
3296014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  PrepareCallApiFunction(masm, kArgStackSpace);
3297109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  // Create v8::PropertyCallbackInfo object on the stack and initialize
3298109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  // it's args_ field.
3299109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  Operand info_object = StackSpaceOperand(0);
3300109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  __ movp(info_object, scratch);
3301b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
3302109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  __ leap(name_arg, Operand(scratch, -kPointerSize));
3303b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // The context register (rsi) has been saved in PrepareCallApiFunction and
3304b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // could be used to pass arguments.
3305109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  __ leap(accessor_info_arg, info_object);
3306b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
3307b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  ExternalReference thunk_ref =
3308b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      ExternalReference::invoke_accessor_getter_callback(isolate());
3309b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
3310b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // It's okay if api_function_address == getter_arg
3311b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // but not accessor_info_arg or name_arg
3312bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  DCHECK(!api_function_address.is(accessor_info_arg));
3313bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  DCHECK(!api_function_address.is(name_arg));
3314bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ movp(scratch, FieldOperand(callback, AccessorInfo::kJsGetterOffset));
3315bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  __ movp(api_function_address,
3316bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch          FieldOperand(scratch, Foreign::kForeignAddressOffset));
3317b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
3318109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  // +3 is to skip prolog, return address and name handle.
3319109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch  Operand return_value_operand(
3320109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch      rbp, (PropertyCallbackArguments::kReturnValueOffset + 3) * kPointerSize);
3321014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  CallApiFunctionAndReturn(masm, api_function_address, thunk_ref, getter_arg,
3322109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch                           kStackUnwindSpace, nullptr, return_value_operand,
3323109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch                           NULL);
3324b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch}
3325b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
332680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#undef __
332780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
3328014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch}  // namespace internal
3329014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch}  // namespace v8
333080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
333180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen#endif  // V8_TARGET_ARCH_X64
3332